diff --git a/ChangeLog b/ChangeLog index ee4f888250e7..0b836353a03a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,116 @@ +2023-08-29 Tsukasa OI + + * MAINTAINERS: Add myself. + +2023-08-22 Filip Kastl + + * MAINTAINERS: Update my email address. + +2023-08-11 Eric Feng + + * MAINTAINERS: Add myself. + +2023-08-07 Indu Bhagat + + * Makefile.def: Reflect that libsframe needs to installed before + libbfd. Reorder a bit to better track libsframe dependencies. + * Makefile.in: Regenerate. + +2023-08-07 Indu Bhagat + + * Makefile.def: Add install dependency on libsframe for libbfd. + * Makefile.in: Regenerated. + +2023-08-07 Nick Alcock + + * libtool.m4 (lt_cv_sys_global_symbol_pipe): Augment symcode for + Solaris 11. + +2023-08-07 Alexander von Gluck IV + + * configure: Regenerate. + * configure.ac: Add Haiku to list of ELF OSes + * libtool.m4: Update sys_lib_dlsearch_path_spec on Haiku. + +2023-08-07 Nick Alcock + + * libtool.m4 (LT_PATH_NM): Handle user-specified NM with + options, including options containing paths. + +2023-08-07 Nick Alcock + + * libtool.m4 (LT_PATH_NM): Try BSDization flags with a user-provided + NM, if there is one. Run nm on itself, not on /dev/null, to avoid + errors from nms that refuse to work on non-regular files. Remove + other workarounds for this problem. Strip out blank lines from the + nm output. + +2023-08-07 Arsen Arsenović + + * configure.ac: Reinstate 32b PA-RISC HP-UX targets + * configure: Regenerate. + +2023-08-07 Simon Marchi + + * configure.ac: Add AC_SUBST(PKG_CONFIG_PATH). + * configure: Re-generate. + * Makefile.tpl (HOST_EXPORTS): Pass PKG_CONFIG_PATH. + (PKG_CONFIG_PATH): New. + * Makefile.in: Re-generate. + +2023-08-07 Luis Machado + + * configure.ac: Disable year2038 by default on 32-bit hosts. + * configure: Regenerate. + +2023-08-07 Vladimir Mezentsev + + * Makefile.def: Add gprofng module. + * configure.ac: Add --enable-gprofng option. + * Makefile.in: Regenerate. + * configure: Regenerate. + +2023-08-07 Martin Liska + + * configure.ac: Add --enable-default-compressed-debug-sections-algorithm. + * configure: Regenerate. + +2023-08-07 Fangrui Song + + * configure: Regenerate. + * configure.ac: Add --with-zstd. + +2023-08-07 Arsen Arsenović + + * configure: Regenerate. + * configure.ac: Recover tilegx/tilepro targets. + +2023-08-07 H.J. Lu + + * configure: Regenerated. + * libtool.m4 (_LT_CMD_OLD_ARCHIVE): Check if AR works with + --plugin and rc before enabling --plugin. + +2023-08-07 H.J. Lu + + * Makefile.tpl (AR): Add @AR_PLUGIN_OPTION@ + (RANLIB): Add @RANLIB_PLUGIN_OPTION@. + * configure.ac: Include config/gcc-plugin.m4. + AC_SUBST AR_PLUGIN_OPTION and RANLIB_PLUGIN_OPTION. + * libtool.m4 (_LT_CMD_OLD_ARCHIVE): Pass --plugin to AR and + RANLIB if possible. + * Makefile.in: Regenerated. + * configure: Likewise. + +2023-08-07 Arsen Arsenović + + * Makefile.tpl: Substitute @GDCFLAGS@ instead of using + $(CFLAGS). + +2023-08-07 David Faust + + * MAINTAINERS: Add the BPF port to my reviewer listing. + 2023-08-02 Jan Beulich * MAINTAINERS: Correct my email address. diff --git a/MAINTAINERS b/MAINTAINERS index eee5d0ea60e6..de31a27a17d0 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -412,6 +412,7 @@ Chris Fairles Alessandro Fanfarillo Changpeng Fang Sam Feifer +Eric Feng Li Feng Thomas Fitzsimmons Alexander Fomin @@ -490,7 +491,7 @@ Kean Johnston Phillip Jordan Tim Josling Victor Kaplansky -Filip Kastl +Filip Kastl Geoffrey Keating Brendan Kehoe Andi Kleen @@ -592,6 +593,7 @@ Carlos O'Donell Peter O'Gorman Patrick O'Neill Braden Obrzut +Tsukasa Oi Andrea Ornstein Maxim Ostapenko Jeevitha Palanisamy diff --git a/Makefile.def b/Makefile.def index 2d9f71d3a92a..8e7aa6138b42 100644 --- a/Makefile.def +++ b/Makefile.def @@ -462,11 +462,14 @@ dependencies = { module=all-gdbsupport; on=all-gnulib; }; dependencies = { module=all-gdbsupport; on=all-intl; }; // Host modules specific to binutils. +// build libsframe before bfd for encoder/decoder support for linking +// SFrame sections dependencies = { module=configure-bfd; on=configure-libiberty; hard=true; }; dependencies = { module=configure-bfd; on=configure-intl; }; dependencies = { module=all-bfd; on=all-libiberty; }; dependencies = { module=all-bfd; on=all-intl; }; dependencies = { module=all-bfd; on=all-zlib; }; +dependencies = { module=all-bfd; on=all-libsframe; }; dependencies = { module=configure-opcodes; on=configure-libiberty; hard=true; }; dependencies = { module=all-opcodes; on=all-libiberty; }; @@ -499,6 +502,10 @@ dependencies = { module=install-strip-libctf; on=install-strip-bfd; }; dependencies = { module=install-strip-ld; on=install-strip-bfd; }; dependencies = { module=install-strip-ld; on=install-strip-libctf; }; +// libbfd depends on libsframe +dependencies = { module=install-bfd; on=install-libsframe; }; +dependencies = { module=install-strip-bfd; on=install-strip-libsframe; }; + // libopcodes depends on libbfd dependencies = { module=configure-opcodes; on=configure-bfd; hard=true; }; dependencies = { module=install-opcodes; on=install-bfd; }; diff --git a/Makefile.in b/Makefile.in index 4fb489f47a03..bc4fa2c702fd 100644 --- a/Makefile.in +++ b/Makefile.in @@ -68138,6 +68138,16 @@ all-stagetrain-bfd: maybe-all-stagetrain-zlib all-stagefeedback-bfd: maybe-all-stagefeedback-zlib all-stageautoprofile-bfd: maybe-all-stageautoprofile-zlib all-stageautofeedback-bfd: maybe-all-stageautofeedback-zlib +all-bfd: maybe-all-libsframe +all-stage1-bfd: maybe-all-stage1-libsframe +all-stage2-bfd: maybe-all-stage2-libsframe +all-stage3-bfd: maybe-all-stage3-libsframe +all-stage4-bfd: maybe-all-stage4-libsframe +all-stageprofile-bfd: maybe-all-stageprofile-libsframe +all-stagetrain-bfd: maybe-all-stagetrain-libsframe +all-stagefeedback-bfd: maybe-all-stagefeedback-libsframe +all-stageautoprofile-bfd: maybe-all-stageautoprofile-libsframe +all-stageautofeedback-bfd: maybe-all-stageautofeedback-libsframe configure-opcodes: configure-libiberty configure-stage1-opcodes: configure-stage1-libiberty configure-stage2-opcodes: configure-stage2-libiberty @@ -68276,6 +68286,8 @@ install-ld: maybe-install-libctf install-strip-libctf: maybe-install-strip-bfd install-strip-ld: maybe-install-strip-bfd install-strip-ld: maybe-install-strip-libctf +install-bfd: maybe-install-libsframe +install-strip-bfd: maybe-install-strip-libsframe configure-opcodes: configure-bfd configure-stage1-opcodes: configure-stage1-bfd configure-stage2-opcodes: configure-stage2-bfd diff --git a/config/ChangeLog b/config/ChangeLog index 420372a9ab8f..b42f2bc2e088 100644 --- a/config/ChangeLog +++ b/config/ChangeLog @@ -1,3 +1,50 @@ +2023-08-11 Joseph Myers + + * gcc-plugin.m4 (GCC_ENABLE_PLUGINS): Use + export_sym_check="$ac_cv_prog_OBJDUMP -T" also when host is not + build or target. + +2023-08-07 H.J. Lu + + * pkg.m4 (PKG_CHECK_MODULES): Use AC_TRY_LINK only if + $pkg_failed = no. + +2023-08-07 H.J. Lu + + * pkg.m4 (PKG_CHECK_MODULES): Add AC_TRY_LINK to check if + $pkg_cv_[]$1[]_LIBS works. + +2023-08-07 John Ericson + + * picflag.m4: Simplify SHmedia NetBSD match by presuming ELF. + +2023-08-07 Alan Modra + + * override.m4: Correct comment grammar. + +2023-08-07 Alan Modra + + * lib-ld.m4 (AC_LIB_PROG_LD_GNU): Require AC_PROG_EGREP and + invoke $EGREP. + (AC_LIB_PROG_LD): Likewise. + +2023-08-07 Christophe Lyon + + * zstd.m4: Add minimum version requirement of 1.4.0. + +2023-08-07 Fangrui Song + + * zstd.m4: New file. + +2023-08-07 H.J. Lu + + * gcc-plugin.m4 (GCC_PLUGIN_OPTION): Check if AR works with + --plugin and rc before enabling --plugin. + +2023-08-07 H.J. Lu + + * gcc-plugin.m4 (GCC_PLUGIN_OPTION): New. + 2023-07-21 Sergei Trofimovich * mh-mingw: Drop assignment of unused BOOT_CXXFLAGS variable. diff --git a/config/gcc-plugin.m4 b/config/gcc-plugin.m4 index c731a6fab383..c30cfdd8fadb 100644 --- a/config/gcc-plugin.m4 +++ b/config/gcc-plugin.m4 @@ -49,7 +49,7 @@ AC_DEFUN([GCC_ENABLE_PLUGINS], elif test x$host = x$target; then export_sym_check="$gcc_cv_objdump -T" else - export_sym_check= + export_sym_check="$ac_cv_prog_OBJDUMP -T" fi ;; esac diff --git a/contrib/ChangeLog b/contrib/ChangeLog index 0baf78df3d2f..105726c39d3e 100644 --- a/contrib/ChangeLog +++ b/contrib/ChangeLog @@ -1,3 +1,11 @@ +2023-08-29 Lehua Ding + + * mklog.py: Fix bugs. + +2023-08-16 Andrew Pinski + + * gcc_update: Add libstdc++-v3/include/bits/version.h. + 2023-07-13 Lehua Ding * mklog.py: Add --append option. diff --git a/contrib/gcc_update b/contrib/gcc_update index 1bfc67ac91ad..1d7bfab4935b 100755 --- a/contrib/gcc_update +++ b/contrib/gcc_update @@ -182,6 +182,7 @@ libphobos/config.h.in: libphobos/configure.ac libphobos/aclocal.m4 libphobos/configure: libphobos/configure.ac libphobos/aclocal.m4 libphobos/src/Makefile.in: libphobos/src/Makefile.am libphobos/aclocal.m4 libphobos/testsuite/Makefile.in: libphobos/testsuite/Makefile.am libphobos/aclocal.m4 +libstdc++-v3/include/bits/version.h: libstdc++-v3/include/bits/version.def libstdc++-v3/include/bits/version.tpl # Top level Makefile.in: Makefile.tpl Makefile.def configure: configure.ac config/acx.m4 diff --git a/contrib/mklog.py b/contrib/mklog.py index 496780883fbf..705a848570d0 100755 --- a/contrib/mklog.py +++ b/contrib/mklog.py @@ -398,7 +398,8 @@ if __name__ == '__main__': args.fill_up_bug_titles, args.pr_numbers) if args.append: if (not args.input): - raise Exception("`-a or --append` option not support standard input") + raise Exception("`-a or --append` option not support standard " + "input") lines = [] with open(args.input, 'r', newline='\n') as f: # 1 -> not find the possible start of diff log @@ -408,13 +409,14 @@ if __name__ == '__main__': for line in f: if maybe_diff_log == 1 and line == "---\n": maybe_diff_log = 2 - elif maybe_diff_log == 2 and \ - re.match("\s[^\s]+\s+\|\s\d+\s[+\-]+\n", line): + elif (maybe_diff_log == 2 and + re.match(r"\s[^\s]+\s+\|\s+\d+\s[+\-]+\n", line)): lines += [output, "---\n", line] maybe_diff_log = 3 else: # the possible start is not the true start. if maybe_diff_log == 2: + lines.append("---\n") maybe_diff_log = 1 lines.append(line) with open(args.input, "w") as f: diff --git a/fixincludes/ChangeLog b/fixincludes/ChangeLog index ed4116e0dae4..5b49d8764053 100644 --- a/fixincludes/ChangeLog +++ b/fixincludes/ChangeLog @@ -1,3 +1,14 @@ +2023-08-17 Rainer Orth + + * inclhack.def (darwin_flt_eval_method): Handle macOS 14 guard + variant. + * fixincl.x: Regenerate. + * tests/base/math.h [DARWIN_FLT_EVAL_METHOD_CHECK]: Update test. + +2023-08-07 Nick Alcock + + * configure: Regenerate. + 2023-06-15 Marek Polacek * Makefile.in: Set and use PICFLAG and LD_PICFLAG. Use the "pic" diff --git a/fixincludes/fixincl.x b/fixincludes/fixincl.x index 416d2c2e3a4b..e52f11d8460f 100644 --- a/fixincludes/fixincl.x +++ b/fixincludes/fixincl.x @@ -2,11 +2,11 @@ * * DO NOT EDIT THIS FILE (fixincl.x) * - * It has been AutoGen-ed January 22, 2023 at 09:03:29 PM by AutoGen 5.18.12 + * It has been AutoGen-ed August 17, 2023 at 10:16:38 AM by AutoGen 5.18.12 * From the definitions inclhack.def * and the template file fixincl */ -/* DO NOT SVN-MERGE THIS FILE, EITHER Sun Jan 22 21:03:29 CET 2023 +/* DO NOT SVN-MERGE THIS FILE, EITHER Thu Aug 17 10:16:38 CEST 2023 * * You must regenerate it. Use the ./genfixes script. * @@ -3674,7 +3674,7 @@ tSCC* apzDarwin_Flt_Eval_MethodMachs[] = { * content selection pattern - do fix if pattern found */ tSCC zDarwin_Flt_Eval_MethodSelect0[] = - "^#if __FLT_EVAL_METHOD__ == 0$"; + "^#if __FLT_EVAL_METHOD__ == 0( \\|\\| __FLT_EVAL_METHOD__ == -1)?$"; #define DARWIN_FLT_EVAL_METHOD_TEST_CT 1 static tTestDesc aDarwin_Flt_Eval_MethodTests[] = { @@ -3685,7 +3685,7 @@ static tTestDesc aDarwin_Flt_Eval_MethodTests[] = { */ static const char* apzDarwin_Flt_Eval_MethodPatch[] = { "format", - "#if __FLT_EVAL_METHOD__ == 0 || __FLT_EVAL_METHOD__ == 16", + "%0 || __FLT_EVAL_METHOD__ == 16", (char*)NULL }; /* * * * * * * * * * * * * * * * * * * * * * * * * * diff --git a/fixincludes/inclhack.def b/fixincludes/inclhack.def index 45e0cbc0c10b..19e0ea2df662 100644 --- a/fixincludes/inclhack.def +++ b/fixincludes/inclhack.def @@ -1819,10 +1819,11 @@ fix = { hackname = darwin_flt_eval_method; mach = "*-*-darwin*"; files = math.h; - select = "^#if __FLT_EVAL_METHOD__ == 0$"; + select = "^#if __FLT_EVAL_METHOD__ == 0( \\|\\| __FLT_EVAL_METHOD__ == -1)?$"; c_fix = format; - c_fix_arg = "#if __FLT_EVAL_METHOD__ == 0 || __FLT_EVAL_METHOD__ == 16"; - test_text = "#if __FLT_EVAL_METHOD__ == 0"; + c_fix_arg = "%0 || __FLT_EVAL_METHOD__ == 16"; + test_text = "#if __FLT_EVAL_METHOD__ == 0\n" + "#if __FLT_EVAL_METHOD__ == 0 || __FLT_EVAL_METHOD__ == -1"; }; /* diff --git a/fixincludes/tests/base/math.h b/fixincludes/tests/base/math.h index 29b67579748c..7b92f29a409f 100644 --- a/fixincludes/tests/base/math.h +++ b/fixincludes/tests/base/math.h @@ -32,6 +32,7 @@ #if defined( DARWIN_FLT_EVAL_METHOD_CHECK ) #if __FLT_EVAL_METHOD__ == 0 || __FLT_EVAL_METHOD__ == 16 +#if __FLT_EVAL_METHOD__ == 0 || __FLT_EVAL_METHOD__ == -1 || __FLT_EVAL_METHOD__ == 16 #endif /* DARWIN_FLT_EVAL_METHOD_CHECK */ diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 9bef71e0d857..f5f82ea78446 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,3865 @@ +2023-09-03 Pan Li + + * config/riscv/autovec-vls.md (3): New pattern for + fmax/fmin + * config/riscv/vector.md: Add VLS modes to vfmax/vfmin. + +2023-09-02 Mikael Morin + + * tree-diagnostic.cc (tree_diagnostics_defaults): Delete allocated + pointer before overwriting it. + +2023-09-02 chenxiaolong + + * config/loongarch/loongarch-builtins.cc (loongarch_init_builtins): + Associate the __float128 type to float128_type_node so that it can + be recognized by the compiler. + * config/loongarch/loongarch-c.cc (loongarch_cpu_cpp_builtins): + Add the flag "FLOAT128_TYPE" to gcc and associate a function + with the suffix "q" to "f128". + * doc/extend.texi:Added support for 128-bit floating-point functions on + the LoongArch architecture. + +2023-09-01 Jakub Jelinek + + PR c++/111069 + * common.opt (fabi-version=): Document version 19. + * doc/invoke.texi (-fabi-version=): Likewise. + +2023-09-01 Lehua Ding + + * config/riscv/autovec-opt.md (*cond_): + New combine pattern. + (*cond_): Ditto. + (*cond_): Ditto. + (*cond_): Ditto. + (*cond_): Ditto. + (*cond_2): Ditto. + * config/riscv/autovec.md (2): Adjust. + (2): Adjust. + (2): Adjust. + (2): Adjust. + (2): Adjust. + (2): Adjust. + * config/riscv/riscv-v.cc (needs_fp_rounding): Add INT->FP extend. + +2023-09-01 Lehua Ding + + * config/riscv/autovec-opt.md (*cond_extend): + New combine pattern. + (*cond_trunc): Ditto. + * config/riscv/autovec.md: Adjust. + * config/riscv/riscv-v.cc (needs_fp_rounding): Add FP extend. + +2023-09-01 Lehua Ding + + * config/riscv/autovec-opt.md (*cond_): + New combine pattern. + (*cond_): Ditto. + (*cond_): Ditto. + (*cond_trunc): Ditto. + * config/riscv/autovec.md (2): Adjust. + (2): Ditto. + +2023-09-01 Lehua Ding + + * config/riscv/autovec.md: Adjust. + * config/riscv/riscv-protos.h (expand_cond_len_unop): Ditto. + (expand_cond_len_binop): Ditto. + * config/riscv/riscv-v.cc (needs_fp_rounding): Ditto. + (expand_cond_len_op): Ditto. + (expand_cond_len_unop): Ditto. + (expand_cond_len_binop): Ditto. + (expand_cond_len_ternop): Ditto. + +2023-09-01 Juzhe-Zhong + + * config/riscv/riscv-v.cc (autovectorize_vector_modes): Enable + VECT_COMPARE_COSTS by default. + +2023-09-01 Robin Dapp + + * config/riscv/autovec.md (vec_extractqi): New expander. + +2023-09-01 Juzhe-Zhong + + * config/riscv/riscv-opts.h (enum riscv_autovec_lmul_enum): Add + dynamic enum. + * config/riscv/riscv.opt: Add dynamic compile option. + +2023-09-01 Pan Li + + * config/riscv/autovec-vls.md (3): New pattern for + vls floating-point autovec. + * config/riscv/vector-iterators.md: New iterator for + floating-point V and VLS. + * config/riscv/vector.md: Add VLS to floating-point binop. + +2023-09-01 Andrew Pinski + + PR tree-optimization/19832 + * match.pd: Add pattern to optimize + `(a != b) ? a OP b : c`. + +2023-09-01 Lulu Cheng + Guo Jie + + PR target/110484 + * config/loongarch/loongarch.cc (loongarch_emit_stack_tie): Use the + frame_pointer_needed to determine whether to use the $fp register. + +2023-08-31 Andrew Pinski + + PR tree-optimization/110915 + * match.pd (min_value, max_value): Extend to vector constants. + +2023-08-31 Francois-Xavier Coudert + + * config.in: Regenerate. + * config/darwin-c.cc: Change spelling to macOS. + * config/darwin-driver.cc: Likewise. + * config/darwin.h: Likewise. + * configure.ac: Likewise. + * doc/contrib.texi: Likewise. + * doc/extend.texi: Likewise. + * doc/invoke.texi: Likewise. + * doc/plugins.texi: Likewise. + * doc/tm.texi: Regenerate. + * doc/tm.texi.in: Change spelling to macOS. + * plugin.cc: Likewise. + +2023-08-31 Pan Li + + * config/riscv/autovec-opt.md: Add FRM_REGNUM to vfnmadd/vfnmacc. + * config/riscv/autovec.md: Ditto. + +2023-08-31 Pan Li + + * config/riscv/autovec-opt.md: Add FRM_REGNUM to vfnmsac/vfnmsub + * config/riscv/autovec.md: Ditto. + +2023-08-31 Richard Sandiford + + * config/aarch64/aarch64.md (untyped_call): Emit a call_value + rather than a call. List each possible destination register + in the call pattern. + +2023-08-31 Pan Li + + * config/riscv/autovec-opt.md: Add FRM_REGNUM to vfmsac/vfmsub + * config/riscv/autovec.md: Ditto. + +2023-08-31 Pan Li + Ju-Zhe Zhong + + * config/riscv/autovec-opt.md: Add FRM_REGNUM to vfmadd/vfmacc. + * config/riscv/autovec.md: Ditto. + * config/riscv/vector-iterators.md: Add UNSPEC_VFFMA. + +2023-08-31 Palmer Dabbelt + + * config/riscv/autovec.md (shifts): Use + vector_scalar_shift_operand. + * config/riscv/predicates.md (vector_scalar_shift_operand): New + predicate. + +2023-08-31 Juzhe-Zhong + + * config.gcc: Add vector cost model framework for RVV. + * config/riscv/riscv.cc (riscv_vectorize_create_costs): Ditto. + (TARGET_VECTORIZE_CREATE_COSTS): Ditto. + * config/riscv/t-riscv: Ditto. + * config/riscv/riscv-vector-costs.cc: New file. + * config/riscv/riscv-vector-costs.h: New file. + +2023-08-31 Jeevitha Palanisamy + + PR target/110411 + * config/rs6000/mma.md (define_insn_and_split movoo): Disallow + AltiVec address operands. + (define_insn_and_split movxo): Likewise. + * config/rs6000/predicates.md (vsx_quad_dform_memory_operand): Remove + redundant mode size check. + +2023-08-31 Lehua Ding + + * config/riscv/riscv-protos.h (IS_AGNOSTIC): Move to here. + * config/riscv/riscv-v.cc (gen_no_side_effects_vsetvl_rtx): + Change to default policy. + * config/riscv/riscv-vector-builtins-bases.cc: Change to default policy. + * config/riscv/riscv-vsetvl.h (IS_AGNOSTIC): Delete. + * config/riscv/riscv.cc (riscv_print_operand): Use IS_AGNOSTIC to test. + +2023-08-31 Lehua Ding + + * config/riscv/autovec-opt.md: Adjust. + * config/riscv/autovec-vls.md: Ditto. + * config/riscv/autovec.md: Ditto. + * config/riscv/riscv-protos.h (enum insn_type): Add insn_type. + (enum insn_flags): Add insn flags. + (emit_vlmax_insn): Adjust. + (emit_vlmax_fp_insn): Delete. + (emit_vlmax_ternary_insn): Delete. + (emit_vlmax_fp_ternary_insn): Delete. + (emit_nonvlmax_insn): Adjust. + (emit_vlmax_slide_insn): Delete. + (emit_nonvlmax_slide_tu_insn): Delete. + (emit_vlmax_merge_insn): Delete. + (emit_vlmax_cmp_insn): Delete. + (emit_vlmax_cmp_mu_insn): Delete. + (emit_vlmax_masked_mu_insn): Delete. + (emit_scalar_move_insn): Delete. + (emit_nonvlmax_integer_move_insn): Delete. + (emit_vlmax_insn_lra): Add. + * config/riscv/riscv-v.cc (get_mask_mode_from_insn_flags): New. + (emit_vlmax_insn): Adjust. + (emit_nonvlmax_insn): Adjust. + (emit_vlmax_insn_lra): Add. + (emit_vlmax_fp_insn): Delete. + (emit_vlmax_ternary_insn): Delete. + (emit_vlmax_fp_ternary_insn): Delete. + (emit_vlmax_slide_insn): Delete. + (emit_nonvlmax_slide_tu_insn): Delete. + (emit_nonvlmax_slide_insn): Delete. + (emit_vlmax_merge_insn): Delete. + (emit_vlmax_cmp_insn): Delete. + (emit_vlmax_cmp_mu_insn): Delete. + (emit_vlmax_masked_insn): Delete. + (emit_nonvlmax_masked_insn): Delete. + (emit_vlmax_masked_store_insn): Delete. + (emit_nonvlmax_masked_store_insn): Delete. + (emit_vlmax_masked_mu_insn): Delete. + (emit_vlmax_masked_fp_mu_insn): Delete. + (emit_nonvlmax_tu_insn): Delete. + (emit_nonvlmax_fp_tu_insn): Delete. + (emit_nonvlmax_tumu_insn): Delete. + (emit_nonvlmax_fp_tumu_insn): Delete. + (emit_scalar_move_insn): Delete. + (emit_cpop_insn): Delete. + (emit_vlmax_integer_move_insn): Delete. + (emit_nonvlmax_integer_move_insn): Delete. + (emit_vlmax_gather_insn): Delete. + (emit_vlmax_masked_gather_mu_insn): Delete. + (emit_vlmax_compress_insn): Delete. + (emit_nonvlmax_compress_insn): Delete. + (emit_vlmax_reduction_insn): Delete. + (emit_vlmax_fp_reduction_insn): Delete. + (emit_nonvlmax_fp_reduction_insn): Delete. + (expand_vec_series): Adjust. + (expand_const_vector): Adjust. + (legitimize_move): Adjust. + (sew64_scalar_helper): Adjust. + (expand_tuple_move): Adjust. + (expand_vector_init_insert_elems): Adjust. + (expand_vector_init_merge_repeating_sequence): Adjust. + (expand_vec_cmp): Adjust. + (expand_vec_cmp_float): Adjust. + (expand_vec_perm): Adjust. + (shuffle_merge_patterns): Adjust. + (shuffle_compress_patterns): Adjust. + (shuffle_decompress_patterns): Adjust. + (expand_load_store): Adjust. + (expand_cond_len_op): Adjust. + (expand_cond_len_unop): Adjust. + (expand_cond_len_binop): Adjust. + (expand_gather_scatter): Adjust. + (expand_cond_len_ternop): Adjust. + (expand_reduction): Adjust. + (expand_lanes_load_store): Adjust. + (expand_fold_extract_last): Adjust. + * config/riscv/riscv.cc (vector_zero_call_used_regs): Adjust. + * config/riscv/vector.md: Adjust. + +2023-08-31 Haochen Gui + + PR target/96762 + * config/rs6000/rs6000-string.cc (expand_block_move): Call vector + load/store with length only on 64-bit Power10. + +2023-08-31 Claudiu Zissulescu + + * config/arc/arc.cc (arc_split_mov_const): Use LSL16 only when + SWAP option is enabled. + * config/arc/arc.md (ashlsi2_cnt16): Likewise. + +2023-08-31 Stamatis Markianos-Wright + + * config/arm/arm-mve-builtins-base.cc (vcaddq_rot90, vcaddq_rot270): + Use common insn for signed and unsigned front-end definitions. + * config/arm/arm_mve_builtins.def + (vcaddq_rot90_m_u, vcaddq_rot270_m_u): Make common. + (vcaddq_rot90_m_s, vcaddq_rot270_m_s): Remove. + * config/arm/iterators.md (mve_insn): Merge signed and unsigned defs. + (isu): Likewise. + (rot): Likewise. + (mve_rot): Likewise. + (supf): Likewise. + (VxCADDQ_M): Likewise. + * config/arm/unspecs.md (unspec): Likewise. + * config/arm/mve.md: Fix minor typo. + +2023-08-31 liuhongt + + * config/i386/sse.md (_blendm): Merge + VF_AVX512HFBFVL into VI12HFBF_AVX512VL. + (VF_AVX512HFBF16): Renamed to VHFBF. + (VF_AVX512FP16VL): Renamed to VHF_AVX512VL. + (VF_AVX512FP16): Removed. + (div3): Adjust VF_AVX512FP16VL to VHF_AVX512VL. + (avx512fp16_rcp2): Ditto. + (rsqrt2): Ditto. + (_rsqrt2): Ditto. + (vcond): Ditto. + (vcond): Ditto. + (_fmaddc__mask1): Ditto. + (_fmaddc__maskz): Ditto. + (_fcmaddc__mask1): Ditto. + (_fcmaddc__maskz): Ditto. + (cmla4): Ditto. + (fma__fadd_fmul): Ditto. + (fma__fadd_fcmul): Ditto. + (fma___fma_zero): Ditto. + (fma__fmaddc_bcst): Ditto. + (fma__fcmaddc_bcst): Ditto. + (___mask): Ditto. + (cmul3): Ditto. + (__): + Ditto. + (vec_unpacks_lo_): Ditto. + (vec_unpacks_hi_): Ditto. + (vec_unpack_fix_trunc_lo_): Ditto. + (vec_unpack_fix_trunc_lo_): Ditto. + (*vec_extract_0): Ditto. + (*_cmp3): Extend to V48H_AVX512VL. + +2023-08-31 Lehua Ding + + PR target/111234 + * config/riscv/riscv-vsetvl.cc (gen_vsetvl_pat): Remove condition. + +2023-08-31 Jiufu Guo + + * range-op-mixed.h (operator_plus::overflow_free_p): New declare. + (operator_minus::overflow_free_p): New declare. + (operator_mult::overflow_free_p): New declare. + * range-op.cc (range_op_handler::overflow_free_p): New function. + (range_operator::overflow_free_p): New default function. + (operator_plus::overflow_free_p): New function. + (operator_minus::overflow_free_p): New function. + (operator_mult::overflow_free_p): New function. + * range-op.h (range_op_handler::overflow_free_p): New declare. + (range_operator::overflow_free_p): New declare. + * value-range.cc (irange::nonnegative_p): New function. + (irange::nonpositive_p): New function. + * value-range.h (irange::nonnegative_p): New declare. + (irange::nonpositive_p): New declare. + +2023-08-30 Dimitar Dimitrov + + PR target/106562 + * config/pru/predicates.md (const_0_operand): New predicate. + (pru_cstore_comparison_operator): Ditto. + * config/pru/pru.md (cstore4): New pattern. + (cstoredi4): Ditto. + +2023-08-30 Richard Biener + + PR tree-optimization/111228 + * match.pd ((vec_perm (vec_perm ..) @5 ..) -> (vec_perm @x @5 ..)): + New simplifications. + +2023-08-30 Juzhe-Zhong + + * config/riscv/autovec.md (movmisalign): Delete. + +2023-08-30 Die Li + Fei Gao + + * config/riscv/peephole.md: New pattern. + * config/riscv/predicates.md (a0a1_reg_operand): New predicate. + (zcmp_mv_sreg_operand): New predicate. + * config/riscv/riscv.md: New predicate. + * config/riscv/zc.md (*mva01s): New pattern. + (*mvsa01): New pattern. + +2023-08-30 Fei Gao + + * config/riscv/riscv.cc + (riscv_zcmp_can_use_popretz): true if popretz can be used + (riscv_gen_multi_pop_insn): interface to generate cm.pop[ret][z] + (riscv_expand_epilogue): expand cm.pop[ret][z] in epilogue + * config/riscv/riscv.md: define A0_REGNUM + * config/riscv/zc.md + (@gpr_multi_popretz_up_to_ra_): md for popretz ra + (@gpr_multi_popretz_up_to_s0_): md for popretz ra, s0 + (@gpr_multi_popretz_up_to_s1_): likewise + (@gpr_multi_popretz_up_to_s2_): likewise + (@gpr_multi_popretz_up_to_s3_): likewise + (@gpr_multi_popretz_up_to_s4_): likewise + (@gpr_multi_popretz_up_to_s5_): likewise + (@gpr_multi_popretz_up_to_s6_): likewise + (@gpr_multi_popretz_up_to_s7_): likewise + (@gpr_multi_popretz_up_to_s8_): likewise + (@gpr_multi_popretz_up_to_s9_): likewise + (@gpr_multi_popretz_up_to_s11_): likewise + +2023-08-30 Fei Gao + + * config/riscv/iterators.md + (slot0_offset): slot 0 offset in stack GPRs area in bytes + (slot1_offset): slot 1 offset in stack GPRs area in bytes + (slot2_offset): likewise + (slot3_offset): likewise + (slot4_offset): likewise + (slot5_offset): likewise + (slot6_offset): likewise + (slot7_offset): likewise + (slot8_offset): likewise + (slot9_offset): likewise + (slot10_offset): likewise + (slot11_offset): likewise + (slot12_offset): likewise + * config/riscv/predicates.md + (stack_push_up_to_ra_operand): predicates of stack adjust pushing ra + (stack_push_up_to_s0_operand): predicates of stack adjust pushing ra, s0 + (stack_push_up_to_s1_operand): likewise + (stack_push_up_to_s2_operand): likewise + (stack_push_up_to_s3_operand): likewise + (stack_push_up_to_s4_operand): likewise + (stack_push_up_to_s5_operand): likewise + (stack_push_up_to_s6_operand): likewise + (stack_push_up_to_s7_operand): likewise + (stack_push_up_to_s8_operand): likewise + (stack_push_up_to_s9_operand): likewise + (stack_push_up_to_s11_operand): likewise + (stack_pop_up_to_ra_operand): predicates of stack adjust poping ra + (stack_pop_up_to_s0_operand): predicates of stack adjust poping ra, s0 + (stack_pop_up_to_s1_operand): likewise + (stack_pop_up_to_s2_operand): likewise + (stack_pop_up_to_s3_operand): likewise + (stack_pop_up_to_s4_operand): likewise + (stack_pop_up_to_s5_operand): likewise + (stack_pop_up_to_s6_operand): likewise + (stack_pop_up_to_s7_operand): likewise + (stack_pop_up_to_s8_operand): likewise + (stack_pop_up_to_s9_operand): likewise + (stack_pop_up_to_s11_operand): likewise + * config/riscv/riscv-protos.h + (riscv_zcmp_valid_stack_adj_bytes_p):declaration + * config/riscv/riscv.cc (struct riscv_frame_info): comment change + (riscv_avoid_multi_push): helper function of riscv_use_multi_push + (riscv_use_multi_push): true if multi push is used + (riscv_multi_push_sregs_count): num of sregs in multi-push + (riscv_multi_push_regs_count): num of regs in multi-push + (riscv_16bytes_align): align to 16 bytes + (riscv_stack_align): moved to a better place + (riscv_save_libcall_count): no functional change + (riscv_compute_frame_info): add zcmp frame info + (riscv_for_each_saved_reg): save or restore fprs in specified slot for zcmp + (riscv_adjust_multi_push_cfi_prologue): adjust cfi for cm.push + (riscv_gen_multi_push_pop_insn): gen function for multi push and pop + (get_multi_push_fpr_mask): get mask for the fprs pushed by cm.push + (riscv_expand_prologue): allocate stack by cm.push + (riscv_adjust_multi_pop_cfi_epilogue): adjust cfi for cm.pop[ret] + (riscv_expand_epilogue): allocate stack by cm.pop[ret] + (zcmp_base_adj): calculate stack adjustment base size + (zcmp_additional_adj): calculate stack adjustment additional size + (riscv_zcmp_valid_stack_adj_bytes_p): check if stack adjustment valid + * config/riscv/riscv.h (RETURN_ADDR_MASK): mask of ra + (S0_MASK): likewise + (S1_MASK): likewise + (S2_MASK): likewise + (S3_MASK): likewise + (S4_MASK): likewise + (S5_MASK): likewise + (S6_MASK): likewise + (S7_MASK): likewise + (S8_MASK): likewise + (S9_MASK): likewise + (S10_MASK): likewise + (S11_MASK): likewise + (MULTI_PUSH_GPR_MASK): GPR_MASK that cm.push can cover at most + (ZCMP_MAX_SPIMM): max spimm value + (ZCMP_SP_INC_STEP): zcmp sp increment step + (ZCMP_INVALID_S0S10_SREGS_COUNTS): num of s0-s10 + (ZCMP_S0S11_SREGS_COUNTS): num of s0-s11 + (ZCMP_MAX_GRP_SLOTS): max slots of pushing and poping in zcmp + (CALLEE_SAVED_FREG_NUMBER): get x of fsx(fs0 ~ fs11) + * config/riscv/riscv.md: include zc.md + * config/riscv/zc.md: New file. machine description for zcmp + +2023-08-30 Jakub Jelinek + + PR tree-optimization/110914 + * tree-ssa-strlen.cc (strlen_pass::handle_builtin_memcpy): Don't call + adjust_last_stmt unless len is known constant. + +2023-08-30 Jakub Jelinek + + PR tree-optimization/111015 + * gimple-ssa-store-merging.cc + (imm_store_chain_info::output_merged_store): Use wi::mask and + wide_int_to_tree instead of unsigned HOST_WIDE_INT shift and + build_int_cst to build BIT_AND_EXPR mask. + +2023-08-30 Juzhe-Zhong + + * tree-ssa-alias.cc (ref_maybe_used_by_call_p_1): Add MASK_LEN_ variant. + (call_may_clobber_ref_p_1): Ditto. + * tree-ssa-loop-ivopts.cc (get_mem_type_for_internal_fn): Ditto. + (get_alias_ptr_type_for_ptr_address): Ditto. + +2023-08-30 Juzhe-Zhong + + * config/riscv/riscv-vsetvl.cc + (vector_insn_info::get_avl_or_vl_reg): Fix bug. + +2023-08-30 Juzhe-Zhong + + * config/riscv/autovec-vls.md (movmisalign): New pattern. + * config/riscv/riscv.cc (riscv_support_vector_misalignment): Support + VLS misalign. + +2023-08-29 Philipp Tomsich + + * config/riscv/zicond.md: New splitters to rewrite single bit + sign extension as the condition to a czero in the desired form. + +2023-08-29 David Malcolm + + PR analyzer/99860 + * doc/invoke.texi: Add -Wanalyzer-overlapping-buffers. + +2023-08-29 David Malcolm + + PR analyzer/99860 + * Makefile.in (ANALYZER_OBJS): Add analyzer/ranges.o. + +2023-08-29 Jin Ma + + * config/riscv/riscv.cc (riscv_float_const_rtx_index_for_fli): + zvfh can generate zfa extended instruction fli.h, just like zfh. + +2023-08-29 Edwin Lu + Vineet Gupta + + * config/riscv/riscv-c.cc (riscv_cpu_cpp_builtins): Generate + __riscv_unaligned_avoid with value 1 or + __riscv_unaligned_slow with value 1 or + __riscv_unaligned_fast with value 1 + * config/riscv/riscv.cc (riscv_option_override): Define + riscv_user_wants_strict_align. Set + riscv_user_wants_strict_align to TARGET_STRICT_ALIGN + * config/riscv/riscv.h: Declare riscv_user_wants_strict_align + +2023-08-29 Edwin Lu + + * config/riscv/autovec-vls.md: Update types + * config/riscv/riscv.md: Add vector placeholder type + * config/riscv/vector.md: Update types + +2023-08-29 Carl Love + + * config/rs6000/dfp.md (UNSPEC_DQUAN): New unspec. + (dfp_dqua_, dfp_dquai_): New define_insn. + * config/rs6000/rs6000-builtins.def (__builtin_dfp_dqua, + __builtin_dfp_dquai, __builtin_dfp_dquaq, __builtin_dfp_dquaqi): + New buit-in definitions. + * config/rs6000/rs6000-overload.def (__builtin_dfp_quantize): New + overloaded definition. + * doc/extend.texi: Add documentation for __builtin_dfp_quantize. + +2023-08-29 Pan Li + Ju-Zhe Zhong + + * config/riscv/riscv.cc (riscv_legitimize_poly_move): New declaration. + (riscv_legitimize_const_move): Handle ref plus const poly. + +2023-08-29 Tsukasa OI + + * common/config/riscv/riscv-common.cc + (riscv_implied_info): Add implications from unprivileged extensions. + (riscv_ext_version_table): Add stub support for all unprivileged + extensions supported by Binutils as well as 'Zce', 'Zcmp', 'Zcmt'. + +2023-08-29 Tsukasa OI + + * common/config/riscv/riscv-common.cc (riscv_ext_version_table): + Add stub support for all vendor extensions supported by Binutils. + +2023-08-29 Tsukasa OI + + * common/config/riscv/riscv-common.cc + (riscv_implied_info): Add implications from privileged extensions. + (riscv_ext_version_table): Add stub support for all privileged + extensions supported by Binutils. + +2023-08-29 Lehua Ding + + * config/riscv/autovec.md: Adjust + * config/riscv/riscv-protos.h (RVV_VUNDEF): Clean. + (get_vlmax_rtx): Exported. + * config/riscv/riscv-v.cc (emit_nonvlmax_fp_ternary_tu_insn): Deleted. + (emit_vlmax_masked_gather_mu_insn): Adjust. + (get_vlmax_rtx): New func. + (expand_load_store): Adjust. + (expand_cond_len_unop): Call expand_cond_len_op. + (expand_cond_len_op): New subroutine. + (expand_cond_len_binop): Call expand_cond_len_op. + (expand_cond_len_ternop): Call expand_cond_len_op. + (expand_lanes_load_store): Adjust. + +2023-08-29 Jakub Jelinek + + PR middle-end/79173 + PR middle-end/111209 + * tree-ssa-math-opts.cc (match_uaddc_usubc): Match also + just 2 limb uaddc/usubc with 0 carry-in on lower limb and ignored + carry-out on higher limb. Don't match it though if it could be + matched later on 4 argument addition/subtraction. + +2023-08-29 Andrew Pinski + + PR tree-optimization/111147 + * match.pd (`(x | y) & (~x ^ y)`) Use bitwise_inverted_equal_p + instead of matching bit_not. + +2023-08-29 Christophe Lyon + + * config/arm/arm-mve-builtins.cc (type_suffixes): Add missing + initializer. + +2023-08-29 Juzhe-Zhong + + * config/riscv/riscv-vsetvl.cc (vector_insn_info::get_avl_or_vl_reg): New function. + (pass_vsetvl::compute_local_properties): Fix bug. + (pass_vsetvl::commit_vsetvls): Ditto. + * config/riscv/riscv-vsetvl.h: New function. + +2023-08-29 Lehua Ding + + PR target/110943 + * config/riscv/predicates.md (vector_const_int_or_double_0_operand): + New predicate. + * config/riscv/riscv-vector-builtins.cc (function_expander::function_expander): + force_reg mem target operand. + * config/riscv/vector.md (@pred_mov): Wrapper. + (*pred_mov): Remove imm -> reg pattern. + (*pred_broadcast_imm): Add imm -> reg pattern. + +2023-08-29 Lulu Cheng + + * common/config/loongarch/loongarch-common.cc: + Enable '-free' on O2 and above. + * doc/invoke.texi: Modify the description information + of the '-free' compilation option and add the LoongArch + description. + +2023-08-28 Tsukasa OI + + * doc/extend.texi: Fix the description of __builtin_riscv_pause. + +2023-08-28 Tsukasa OI + + * common/config/riscv/riscv-common.cc (riscv_ext_version_table): + Implement the 'Zihintpause' extension, version 2.0. + (riscv_ext_flag_table) Add 'Zihintpause' handling. + * config/riscv/riscv-builtins.cc: Remove availability predicate + "always" and add "hint_pause". + (riscv_builtins) : Add "pause" extension. + * config/riscv/riscv-opts.h (MASK_ZIHINTPAUSE, TARGET_ZIHINTPAUSE): New. + * config/riscv/riscv.md (riscv_pause): Adjust output based on + TARGET_ZIHINTPAUSE. + +2023-08-28 Andrew Pinski + + * match.pd (`(X & ~Y) | (~X & Y)`): Use bitwise_inverted_equal_p + instead of specifically checking for ~X. + +2023-08-28 Andrew Pinski + + PR tree-optimization/111146 + * match.pd (`(x | y) & ~x`, `(x & y) | ~x`): Remove + redundant pattern. + +2023-08-28 Andrew Pinski + + * tree-ssa-phiopt.cc (gimple_simplify_phiopt): Add dump information + when resimplify returns true. + (match_simplify_replacement): Print only if accepted the match-and-simplify + result rather than the full sequence. + +2023-08-28 Juzhe-Zhong + + * config/riscv/riscv-vsetvl.cc (pass_vsetvl::earliest_fusion): Skip + never probability. + (pass_vsetvl::compute_probabilities): Fix unitialized probability. + +2023-08-28 Juzhe-Zhong + + * config/riscv/riscv-vsetvl.cc (pass_vsetvl::earliest_fusion): Fix bug. + +2023-08-28 Christophe Lyon + + * config/arm/arm-mve-builtins-base.cc (vmullbq_poly) + (vmulltq_poly): New. + * config/arm/arm-mve-builtins-base.def (vmullbq_poly) + (vmulltq_poly): New. + * config/arm/arm-mve-builtins-base.h (vmullbq_poly) + (vmulltq_poly): New. + * config/arm/arm_mve.h (vmulltq_poly): Remove. + (vmullbq_poly): Remove. + (vmullbq_poly_m): Remove. + (vmulltq_poly_m): Remove. + (vmullbq_poly_x): Remove. + (vmulltq_poly_x): Remove. + (vmulltq_poly_p8): Remove. + (vmullbq_poly_p8): Remove. + (vmulltq_poly_p16): Remove. + (vmullbq_poly_p16): Remove. + (vmullbq_poly_m_p8): Remove. + (vmullbq_poly_m_p16): Remove. + (vmulltq_poly_m_p8): Remove. + (vmulltq_poly_m_p16): Remove. + (vmullbq_poly_x_p8): Remove. + (vmullbq_poly_x_p16): Remove. + (vmulltq_poly_x_p8): Remove. + (vmulltq_poly_x_p16): Remove. + (__arm_vmulltq_poly_p8): Remove. + (__arm_vmullbq_poly_p8): Remove. + (__arm_vmulltq_poly_p16): Remove. + (__arm_vmullbq_poly_p16): Remove. + (__arm_vmullbq_poly_m_p8): Remove. + (__arm_vmullbq_poly_m_p16): Remove. + (__arm_vmulltq_poly_m_p8): Remove. + (__arm_vmulltq_poly_m_p16): Remove. + (__arm_vmullbq_poly_x_p8): Remove. + (__arm_vmullbq_poly_x_p16): Remove. + (__arm_vmulltq_poly_x_p8): Remove. + (__arm_vmulltq_poly_x_p16): Remove. + (__arm_vmulltq_poly): Remove. + (__arm_vmullbq_poly): Remove. + (__arm_vmullbq_poly_m): Remove. + (__arm_vmulltq_poly_m): Remove. + (__arm_vmullbq_poly_x): Remove. + (__arm_vmulltq_poly_x): Remove. + +2023-08-28 Christophe Lyon + + * config/arm/arm-mve-builtins-functions.h (class + unspec_mve_function_exact_insn_vmull_poly): New. + +2023-08-28 Christophe Lyon + + * config/arm/arm-mve-builtins-shapes.cc (binary_widen_poly): New. + * config/arm/arm-mve-builtins-shapes.h (binary_widen_poly): New. + +2023-08-28 Christophe Lyon + + * config/arm/arm-mve-builtins-shapes.cc (parse_element_type): Add + support for 'U' and 'p' format specifiers. + +2023-08-28 Christophe Lyon + + * config/arm/arm-mve-builtins.cc (type_suffixes): Handle poly_p + field.. + (TYPES_poly_8_16): New. + (poly_8_16): New. + * config/arm/arm-mve-builtins.def (p8): New type suffix. + (p16): Likewise. + * config/arm/arm-mve-builtins.h (enum type_class_index): Add + TYPE_poly. + (struct type_suffix_info): Add poly_p field. + +2023-08-28 Christophe Lyon + + * config/arm/arm-mve-builtins-base.cc (vmullbq_int, vmulltq_int): + New. + * config/arm/arm-mve-builtins-base.def (vmullbq_int, vmulltq_int): + New. + * config/arm/arm-mve-builtins-base.h (vmullbq_int, vmulltq_int): + New. + * config/arm/arm_mve.h (vmulltq_int): Remove. + (vmullbq_int): Remove. + (vmullbq_int_m): Remove. + (vmulltq_int_m): Remove. + (vmullbq_int_x): Remove. + (vmulltq_int_x): Remove. + (vmulltq_int_u8): Remove. + (vmullbq_int_u8): Remove. + (vmulltq_int_s8): Remove. + (vmullbq_int_s8): Remove. + (vmulltq_int_u16): Remove. + (vmullbq_int_u16): Remove. + (vmulltq_int_s16): Remove. + (vmullbq_int_s16): Remove. + (vmulltq_int_u32): Remove. + (vmullbq_int_u32): Remove. + (vmulltq_int_s32): Remove. + (vmullbq_int_s32): Remove. + (vmullbq_int_m_s8): Remove. + (vmullbq_int_m_s32): Remove. + (vmullbq_int_m_s16): Remove. + (vmullbq_int_m_u8): Remove. + (vmullbq_int_m_u32): Remove. + (vmullbq_int_m_u16): Remove. + (vmulltq_int_m_s8): Remove. + (vmulltq_int_m_s32): Remove. + (vmulltq_int_m_s16): Remove. + (vmulltq_int_m_u8): Remove. + (vmulltq_int_m_u32): Remove. + (vmulltq_int_m_u16): Remove. + (vmullbq_int_x_s8): Remove. + (vmullbq_int_x_s16): Remove. + (vmullbq_int_x_s32): Remove. + (vmullbq_int_x_u8): Remove. + (vmullbq_int_x_u16): Remove. + (vmullbq_int_x_u32): Remove. + (vmulltq_int_x_s8): Remove. + (vmulltq_int_x_s16): Remove. + (vmulltq_int_x_s32): Remove. + (vmulltq_int_x_u8): Remove. + (vmulltq_int_x_u16): Remove. + (vmulltq_int_x_u32): Remove. + (__arm_vmulltq_int_u8): Remove. + (__arm_vmullbq_int_u8): Remove. + (__arm_vmulltq_int_s8): Remove. + (__arm_vmullbq_int_s8): Remove. + (__arm_vmulltq_int_u16): Remove. + (__arm_vmullbq_int_u16): Remove. + (__arm_vmulltq_int_s16): Remove. + (__arm_vmullbq_int_s16): Remove. + (__arm_vmulltq_int_u32): Remove. + (__arm_vmullbq_int_u32): Remove. + (__arm_vmulltq_int_s32): Remove. + (__arm_vmullbq_int_s32): Remove. + (__arm_vmullbq_int_m_s8): Remove. + (__arm_vmullbq_int_m_s32): Remove. + (__arm_vmullbq_int_m_s16): Remove. + (__arm_vmullbq_int_m_u8): Remove. + (__arm_vmullbq_int_m_u32): Remove. + (__arm_vmullbq_int_m_u16): Remove. + (__arm_vmulltq_int_m_s8): Remove. + (__arm_vmulltq_int_m_s32): Remove. + (__arm_vmulltq_int_m_s16): Remove. + (__arm_vmulltq_int_m_u8): Remove. + (__arm_vmulltq_int_m_u32): Remove. + (__arm_vmulltq_int_m_u16): Remove. + (__arm_vmullbq_int_x_s8): Remove. + (__arm_vmullbq_int_x_s16): Remove. + (__arm_vmullbq_int_x_s32): Remove. + (__arm_vmullbq_int_x_u8): Remove. + (__arm_vmullbq_int_x_u16): Remove. + (__arm_vmullbq_int_x_u32): Remove. + (__arm_vmulltq_int_x_s8): Remove. + (__arm_vmulltq_int_x_s16): Remove. + (__arm_vmulltq_int_x_s32): Remove. + (__arm_vmulltq_int_x_u8): Remove. + (__arm_vmulltq_int_x_u16): Remove. + (__arm_vmulltq_int_x_u32): Remove. + (__arm_vmulltq_int): Remove. + (__arm_vmullbq_int): Remove. + (__arm_vmullbq_int_m): Remove. + (__arm_vmulltq_int_m): Remove. + (__arm_vmullbq_int_x): Remove. + (__arm_vmulltq_int_x): Remove. + +2023-08-28 Christophe Lyon + + * config/arm/arm-mve-builtins-shapes.cc (binary_widen): New. + * config/arm/arm-mve-builtins-shapes.h (binary_widen): New. + +2023-08-28 Christophe Lyon + + * config/arm/arm-mve-builtins-functions.h (class + unspec_mve_function_exact_insn_vmull): New. + +2023-08-28 Christophe Lyon + + * config/arm/iterators.md (mve_insn): Add vmullb, vmullt. + (isu): Add VMULLBQ_INT_S, VMULLBQ_INT_U, VMULLTQ_INT_S, + VMULLTQ_INT_U. + (supf): Add VMULLBQ_POLY_P, VMULLTQ_POLY_P, VMULLBQ_POLY_M_P, + VMULLTQ_POLY_M_P. + (VMULLBQ_INT, VMULLTQ_INT, VMULLBQ_INT_M, VMULLTQ_INT_M): Delete. + (VMULLxQ_INT, VMULLxQ_POLY, VMULLxQ_INT_M, VMULLxQ_POLY_M): New. + * config/arm/mve.md (mve_vmullbq_int_) + (mve_vmulltq_int_): Merge into ... + (@mve_q_int_) ... this. + (mve_vmulltq_poly_p, mve_vmullbq_poly_p): Merge into ... + (@mve_q_poly_): ... this. + (mve_vmullbq_int_m_, mve_vmulltq_int_m_): Merge into ... + (@mve_q_int_m_): ... this. + (mve_vmullbq_poly_m_p, mve_vmulltq_poly_m_p): Merge into ... + (@mve_q_poly_m_): ... this. + +2023-08-28 Christophe Lyon + + * config/arm/arm-mve-builtins-shapes.cc (parse_element_type): + Remove dead check. + +2023-08-28 Christophe Lyon + + * config/arm/arm-mve-builtins-shapes.cc (binary_acca_int32): Fix loop bound. + (binary_acca_int64): Likewise. + +2023-08-28 Aldy Hernandez + + * range-op-float.cc (fold_range): Handle relations. + +2023-08-28 Lulu Cheng + + * config/loongarch/loongarch.cc (loongarch_expand_conditional_move): + Optimize the function implementation. + +2023-08-28 liuhongt + + PR target/111119 + * config/i386/sse.md (V48_AVX2): Rename to .. + (V48_128_256): .. this. + (ssefltmodesuffix): Extend to V4SF/V8SF/V2DF/V4DF. + (_maskload): Change + V48_AVX2 to V48_128_256, also generate vmaskmov{ps,pd} for + integral modes when TARGET_AVX2 is not available. + (_maskstore): Ditto. + (maskload): Change V48_AVX2 to + V48_128_256. + (maskstore): Ditto. + +2023-08-28 Juzhe-Zhong + + * config/riscv/riscv-vsetvl.cc (vsetvl_vtype_change_only_p): + New function. + (after_or_same_p): Ditto. + (find_reg_killed_by): Delete. + (has_vsetvl_killed_avl_p): Ditto. + (anticipatable_occurrence_p): Refactor. + (any_set_in_bb_p): Delete. + (count_regno_occurrences): Ditto. + (backward_propagate_worthwhile_p): Ditto. + (demands_can_be_fused_p): Ditto. + (earliest_pred_can_be_fused_p): New function. + (vsetvl_dominated_by_p): Ditto. + (vector_insn_info::parse_insn): Refactor. + (vector_insn_info::merge): Refactor. + (vector_insn_info::dump): Refactor. + (vector_infos_manager::vector_infos_manager): Refactor. + (vector_infos_manager::all_empty_predecessor_p): Delete. + (vector_infos_manager::all_same_avl_p): Ditto. + (vector_infos_manager::create_bitmap_vectors): Refactor. + (vector_infos_manager::free_bitmap_vectors): Refactor. + (vector_infos_manager::dump): Refactor. + (pass_vsetvl::update_block_info): New function. + (enum fusion_type): Ditto. + (pass_vsetvl::get_backward_fusion_type): Delete. + (pass_vsetvl::hard_empty_block_p): Ditto. + (pass_vsetvl::backward_demand_fusion): Ditto. + (pass_vsetvl::forward_demand_fusion): Ditto. + (pass_vsetvl::demand_fusion): Ditto. + (pass_vsetvl::cleanup_illegal_dirty_blocks): Ditto. + (pass_vsetvl::compute_local_properties): Ditto. + (pass_vsetvl::earliest_fusion): New function. + (pass_vsetvl::vsetvl_fusion): Ditto. + (pass_vsetvl::commit_vsetvls): Refactor. + (get_first_vsetvl_before_rvv_insns): Ditto. + (pass_vsetvl::global_eliminate_vsetvl_insn): Ditto. + (pass_vsetvl::cleanup_earliest_vsetvls): New function. + (pass_vsetvl::df_post_optimization): Refactor. + (pass_vsetvl::lazy_vsetvl): Ditto. + * config/riscv/riscv-vsetvl.h: Ditto. + +2023-08-26 Juzhe-Zhong + + * config/riscv/autovec.md (len_fold_extract_last_): New pattern. + * config/riscv/riscv-protos.h (enum insn_type): New enum. + (expand_fold_extract_last): New function. + * config/riscv/riscv-v.cc (emit_nonvlmax_slide_insn): Ditto. + (emit_cpop_insn): Ditto. + (emit_nonvlmax_compress_insn): Ditto. + (expand_fold_extract_last): Ditto. + * config/riscv/vector.md: Fix vcpop.m ratio demand. + +2023-08-25 Edwin Lu + + * config/riscv/sync-rvwmo.md: updated types to "multi" or + "atomic" based on number of assembly lines generated + * config/riscv/sync-ztso.md: likewise + * config/riscv/sync.md: likewise + +2023-08-25 Jin Ma + + * common/config/riscv/riscv-common.cc: Add zfa extension version, which depends on + the F extension. + * config/riscv/constraints.md (zfli): Constrain the floating point number that the + instructions FLI.H/S/D can load. + * config/riscv/iterators.md (ceil): New. + * config/riscv/riscv-opts.h (MASK_ZFA): New. + (TARGET_ZFA): New. + * config/riscv/riscv-protos.h (riscv_float_const_rtx_index_for_fli): New. + * config/riscv/riscv.cc (riscv_float_const_rtx_index_for_fli): New. + (riscv_cannot_force_const_mem): If instruction FLI.H/S/D can be used, memory is + not applicable. + (riscv_const_insns): Likewise. + (riscv_legitimize_const_move): Likewise. + (riscv_split_64bit_move_p): If instruction FLI.H/S/D can be used, no split is + required. + (riscv_split_doubleword_move): Likewise. + (riscv_output_move): Output the mov instructions in zfa extension. + (riscv_print_operand): Output the floating-point value of the FLI.H/S/D immediate + in assembly. + (riscv_secondary_memory_needed): Likewise. + * config/riscv/riscv.md (fminm3): New. + (fmaxm3): New. + (movsidf2_low_rv32): New. + (movsidf2_high_rv32): New. + (movdfsisi3_rv32): New. + (f_quiet4_zfa): New. + * config/riscv/riscv.opt: New. + +2023-08-25 Sandra Loosemore + + * omp-api.h: New. + * omp-general.cc (omp_runtime_api_procname): New. + (omp_runtime_api_call): Moved here from omp-low.cc, and make + non-static. + * omp-general.h: Include omp-api.h. + * omp-low.cc (omp_runtime_api_call): Delete this copy. + +2023-08-25 Sandra Loosemore + + * doc/generic.texi (OpenMP): Document OMP_STRUCTURED_BLOCK. + * doc/gimple.texi (GIMPLE instruction set): Add + GIMPLE_OMP_STRUCTURED_BLOCK. + (GIMPLE_OMP_STRUCTURED_BLOCK): New subsection. + * gimple-low.cc (lower_stmt): Error on GIMPLE_OMP_STRUCTURED_BLOCK. + * gimple-pretty-print.cc (dump_gimple_omp_block): Handle + GIMPLE_OMP_STRUCTURED_BLOCK. + (pp_gimple_stmt_1): Likewise. + * gimple-walk.cc (walk_gimple_stmt): Likewise. + * gimple.cc (gimple_build_omp_structured_block): New. + * gimple.def (GIMPLE_OMP_STRUCTURED_BLOCK): New. + * gimple.h (gimple_build_omp_structured_block): Declare. + (gimple_has_substatements): Handle GIMPLE_OMP_STRUCTURED_BLOCK. + (CASE_GIMPLE_OMP): Likewise. + * gimplify.cc (is_gimple_stmt): Handle OMP_STRUCTURED_BLOCK. + (gimplify_expr): Likewise. + * omp-expand.cc (GIMPLE_OMP_STRUCTURED_BLOCK): Error on + GIMPLE_OMP_STRUCTURED_BLOCK. + * omp-low.cc (scan_omp_1_stmt): Handle GIMPLE_OMP_STRUCTURED_BLOCK. + (lower_omp_1): Likewise. + (diagnose_sb_1): Likewise. + (diagnose_sb_2): Likewise. + * tree-inline.cc (remap_gimple_stmt): Handle + GIMPLE_OMP_STRUCTURED_BLOCK. + (estimate_num_insns): Likewise. + * tree-nested.cc (convert_nonlocal_reference_stmt): Likewise. + (convert_local_reference_stmt): Likewise. + (convert_gimple_call): Likewise. + * tree-pretty-print.cc (dump_generic_node): Handle + OMP_STRUCTURED_BLOCK. + * tree.def (OMP_STRUCTURED_BLOCK): New. + * tree.h (OMP_STRUCTURED_BLOCK_BODY): New. + +2023-08-25 Vineet Gupta + + * config/riscv/riscv.cc (riscv_rtx_costs): Adjust const_int + cost. Add some comments about different constants handling. + +2023-08-25 Andrew Pinski + + * match.pd (`a ? one_zero : one_zero`): Move + below detection of minmax. + +2023-08-25 Andrew Pinski + + * match.pd (`a | C -> C`): New pattern. + +2023-08-25 Uros Bizjak + + * caller-save.cc (new_saved_hard_reg): + Rename TRUE/FALSE to true/false. + (setup_save_areas): Ditto. + * gcc.cc (set_collect_gcc_options): Ditto. + (driver::build_multilib_strings): Ditto. + (print_multilib_info): Ditto. + * genautomata.cc (gen_cpu_unit): Ditto. + (gen_query_cpu_unit): Ditto. + (gen_bypass): Ditto. + (gen_excl_set): Ditto. + (gen_presence_absence_set): Ditto. + (gen_presence_set): Ditto. + (gen_final_presence_set): Ditto. + (gen_absence_set): Ditto. + (gen_final_absence_set): Ditto. + (gen_automaton): Ditto. + (gen_regexp_repeat): Ditto. + (gen_regexp_allof): Ditto. + (gen_regexp_oneof): Ditto. + (gen_regexp_sequence): Ditto. + (process_decls): Ditto. + (reserv_sets_are_intersected): Ditto. + (initiate_excl_sets): Ditto. + (form_reserv_sets_list): Ditto. + (check_presence_pattern_sets): Ditto. + (check_absence_pattern_sets): Ditto. + (check_regexp_units_distribution): Ditto. + (check_unit_distributions_to_automata): Ditto. + (create_ainsns): Ditto. + (output_insn_code_cases): Ditto. + (output_internal_dead_lock_func): Ditto. + (form_important_insn_automata_lists): Ditto. + * gengtype-state.cc (read_state_files_list): Ditto. + * gengtype.cc (main): Ditto. + * gimple-array-bounds.cc (array_bounds_checker::check_array_bounds): + Ditto. + * gimple.cc (gimple_build_call_from_tree): Ditto. + (preprocess_case_label_vec_for_gimple): Ditto. + * gimplify.cc (gimplify_call_expr): Ditto. + * ordered-hash-map-tests.cc (test_map_of_int_to_strings): Ditto. + +2023-08-25 Richard Biener + + PR tree-optimization/111137 + * tree-vect-data-refs.cc (vect_slp_analyze_load_dependences): + Properly handle grouped stores from other SLP instances. + +2023-08-25 Richard Biener + + * tree-vect-data-refs.cc (vect_slp_analyze_store_dependences): + Split out from vect_slp_analyze_node_dependences, remove + dead code. + (vect_slp_analyze_load_dependences): Split out from + vect_slp_analyze_node_dependences, adjust comments. Process + queued stores before any disambiguation. + (vect_slp_analyze_node_dependences): Remove. + (vect_slp_analyze_instance_dependence): Adjust. + +2023-08-25 Aldy Hernandez + + * range-op-float.cc (frelop_early_resolve): Rewrite for better NAN + handling. + (operator_not_equal::fold_range): Adjust for relations. + (operator_lt::fold_range): Same. + (operator_gt::fold_range): Same. + (foperator_unordered_equal::fold_range): Same. + (foperator_unordered_lt::fold_range): Same. + (foperator_unordered_le::fold_range): Same. + (foperator_unordered_gt::fold_range): Same. + (foperator_unordered_ge::fold_range): Same. + +2023-08-25 Richard Biener + + PR tree-optimization/111136 + * tree-vect-loop.cc (vect_dissolve_slp_only_groups): For + stores force STMT_VINFO_STRIDED_P and also duplicate that + to all elements. + +2023-08-25 Juzhe-Zhong + + * config/riscv/riscv-vsetvl.cc (pass_vsetvl::compute_local_properties): + Add early continue. + +2023-08-25 liuhongt + + * config/i386/sse.md (vec_set): Removed. + (V_128H): Merge into .. + (V_128): .. this. + (V_256H): Merge into .. + (V_256): .. this. + (V_512): Add V32HF, V32BF. + (*ssse3_palignr_perm): Adjust mode iterator from V_128H + to V_128. + (vcond): Removed + (vcondu): Removed. + (avx_vbroadcastf128_): Refator from V_256H to V_256. + +2023-08-25 Hongyu Wang + + PR target/111127 + * config/i386/sse.md (avx512f_cvtne2ps2bf16__maskz): + Adjust paramter order. + +2023-08-24 Uros Bizjak + + PR target/94866 + * config/i386/sse.md (*sse2_movq128__1): New insn pattern. + +2023-08-24 David Malcolm + + PR analyzer/105899 + * doc/invoke.texi (Static Analyzer Options): Add "strcat" to the + list of functions known to the analyzer. + +2023-08-24 Richard Biener + + PR tree-optimization/111123 + * tree-ssa-ccp.cc (pass_fold_builtins::execute): Do not + remove indirect clobbers here ... + * tree-outof-ssa.cc (rewrite_out_of_ssa): ... but here. + (remove_indirect_clobbers): New function. + +2023-08-24 Jan Hubicka + + * cfg.h (struct control_flow_graph): New field full_profile. + * auto-profile.cc (afdo_annotate_cfg): Set full_profile to true. + * cfg.cc (init_flow): Set full_profile to false. + * graphite.cc (graphite_transform_loops): Set full_profile to false. + * lto-streamer-in.cc (input_cfg): Initialize full_profile flag. + * predict.cc (pass_profile::execute): Set full_profile to true. + * symtab-thunks.cc (expand_thunk): Set full_profile to true. + * tree-cfg.cc (gimple_verify_flow_info): Verify that profile is full + if full_profile is set. + * tree-inline.cc (initialize_cfun): Initialize full_profile. + (expand_call_inline): Combine full_profile. + +2023-08-24 Richard Biener + + * tree-vect-slp.cc (vect_build_slp_tree_1): Rename + load_p to ldst_p, fix mistakes and rely on + STMT_VINFO_DATA_REF. + +2023-08-24 Jan Hubicka + + * gimple-harden-conditionals.cc (insert_check_and_trap): Set count + of newly build trap bb. + +2023-08-24 Juzhe-Zhong + + * config/riscv/riscv.cc (riscv_preferred_else_value): Remove it since + it forbid COND_LEN_FMS/COND_LEN_FNMS STMT fold. + (TARGET_PREFERRED_ELSE_VALUE): Ditto. + +2023-08-24 Robin Dapp + + * common/config/riscv/riscv-common.cc: Add -fsched-pressure. + * config/riscv/riscv.cc (riscv_option_override): Set sched + pressure algorithm. + +2023-08-24 Robin Dapp + + * config/riscv/riscv.cc (riscv_print_operand): Allow vk operand. + +2023-08-24 Richard Biener + + PR tree-optimization/111125 + * tree-vect-slp.cc (vect_slp_function): Split at novector + loop entry, do not push blocks in novector loops. + +2023-08-24 Richard Sandiford + + * doc/extend.texi: Document the C [[__extension__ ...]] construct. + +2023-08-24 Juzhe-Zhong + + * genmatch.cc (decision_tree::gen): Support + COND_LEN_FNMA/COND_LEN_FMS/COND_LEN_FNMS gimple fold. + * gimple-match-exports.cc (gimple_simplify): Ditto. + (gimple_resimplify6): New function. + (gimple_resimplify7): New function. + (gimple_match_op::resimplify): Support + COND_LEN_FNMA/COND_LEN_FMS/COND_LEN_FNMS gimple fold. + (convert_conditional_op): Ditto. + (build_call_internal): Ditto. + (try_conditional_simplification): Ditto. + (gimple_extract): Ditto. + * gimple-match.h (gimple_match_cond::gimple_match_cond): Ditto. + * internal-fn.cc (CASE): Ditto. + +2023-08-24 Richard Biener + + PR tree-optimization/111115 + * tree-vectorizer.h (vect_slp_child_index_for_operand): New. + * tree-vect-data-refs.cc (can_group_stmts_p): Also group + .MASK_STORE. + * tree-vect-slp.cc (arg3_arg2_map): New. + (vect_get_operand_map): Handle IFN_MASK_STORE. + (vect_slp_child_index_for_operand): New function. + (vect_build_slp_tree_1): Handle statements with no LHS, + masked store ifns. + (vect_remove_slp_scalar_calls): Likewise. + * tree-vect-stmts.cc (vect_check_store_rhs): Lookup the + SLP child corresponding to the ifn value index. + (vectorizable_store): Likewise for the mask index. Support + masked stores. + (vectorizable_load): Lookup the SLP child corresponding to the + ifn mask index. + +2023-08-24 Richard Biener + + PR tree-optimization/111125 + * tree-vect-slp.cc (vectorizable_bb_reduc_epilogue): Account + for the remain_defs processing. + +2023-08-24 Richard Sandiford + + * config/aarch64/aarch64.cc: Include ssa.h. + (aarch64_multiply_add_p): Require the second operand of an + Advanced SIMD subtraction to be a multiplication. Assume that + such an operation won't be fused if the second operand is used + multiple times and if the first operand is also a multiplication. + +2023-08-24 Juzhe-Zhong + + * tree-vect-loop.cc (vectorizable_reduction): Apply + LEN_FOLD_EXTRACT_LAST. + * tree-vect-stmts.cc (vectorizable_condition): Ditto. + +2023-08-24 Richard Biener + + PR tree-optimization/111128 + * tree-vect-patterns.cc (vect_recog_over_widening_pattern): + Emit external shift operand inline if we promoted it with + another pattern stmt. + +2023-08-24 Pan Li + + * config/riscv/autovec.md: Fix typo. + +2023-08-24 Pan Li + + * config/riscv/riscv-vector-builtins-bases.cc + (class binop_frm): Removed. + (class reverse_binop_frm): Ditto. + (class widen_binop_frm): Ditto. + (class vfmacc_frm): Ditto. + (class vfnmacc_frm): Ditto. + (class vfmsac_frm): Ditto. + (class vfnmsac_frm): Ditto. + (class vfmadd_frm): Ditto. + (class vfnmadd_frm): Ditto. + (class vfmsub_frm): Ditto. + (class vfnmsub_frm): Ditto. + (class vfwmacc_frm): Ditto. + (class vfwnmacc_frm): Ditto. + (class vfwmsac_frm): Ditto. + (class vfwnmsac_frm): Ditto. + (class unop_frm): Ditto. + (class vfrec7_frm): Ditto. + (class binop): Add frm_op_type template arg. + (class unop): Ditto. + (class widen_binop): Ditto. + (class widen_binop_fp): Ditto. + (class reverse_binop): Ditto. + (class vfmacc): Ditto. + (class vfnmsac): Ditto. + (class vfmadd): Ditto. + (class vfnmsub): Ditto. + (class vfnmacc): Ditto. + (class vfmsac): Ditto. + (class vfnmadd): Ditto. + (class vfmsub): Ditto. + (class vfwmacc): Ditto. + (class vfwnmacc): Ditto. + (class vfwmsac): Ditto. + (class vfwnmsac): Ditto. + (class float_misc): Ditto. + +2023-08-24 Andrew Pinski + + PR tree-optimization/111109 + * match.pd (ior(cond,cond), ior(vec_cond,vec_cond)): + Add check to make sure cmp and icmp are inverse. + +2023-08-24 Andrew Pinski + + PR tree-optimization/95929 + * match.pd (convert?(-a)): New pattern + for 1bit integer types. + +2023-08-24 Haochen Jiang + + Revert: + 2023-08-17 Haochen Jiang + + * common/config/i386/cpuinfo.h (get_available_features): + Add avx10_set and version and detect avx10.1. + (cpu_indicator_init): Handle avx10.1-512. + * common/config/i386/i386-common.cc + (OPTION_MASK_ISA2_AVX10_512BIT_SET): New. + (OPTION_MASK_ISA2_AVX10_1_SET): Ditto. + (OPTION_MASK_ISA2_AVX10_512BIT_UNSET): Ditto. + (OPTION_MASK_ISA2_AVX10_1_UNSET): Ditto. + (OPTION_MASK_ISA2_AVX2_UNSET): Modify for AVX10_1. + (ix86_handle_option): Handle -mavx10.1, -mavx10.1-256 and + -mavx10.1-512. + * common/config/i386/i386-cpuinfo.h (enum processor_features): + Add FEATURE_AVX10_512BIT, FEATURE_AVX10_1 and + FEATURE_AVX10_512BIT. + * common/config/i386/i386-isas.h: Add ISA_NAME_TABLE_ENTRY for + AVX10_512BIT, AVX10_1 and AVX10_1_512. + * config/i386/constraints.md (Yk): Add AVX10_1. + (Yv): Ditto. + (k): Ditto. + * config/i386/cpuid.h (bit_AVX10): New. + (bit_AVX10_256): Ditto. + (bit_AVX10_512): Ditto. + * config/i386/i386-c.cc (ix86_target_macros_internal): + Define AVX10_512BIT and AVX10_1. + * config/i386/i386-isa.def + (AVX10_512BIT): Add DEF_PTA(AVX10_512BIT). + (AVX10_1): Add DEF_PTA(AVX10_1). + * config/i386/i386-options.cc (isa2_opts): Add -mavx10.1. + (ix86_valid_target_attribute_inner_p): Handle avx10-512bit, avx10.1 + and avx10.1-512. + (ix86_option_override_internal): Enable AVX512{F,VL,BW,DQ,CD,BF16, + FP16,VBMI,VBMI2,VNNI,IFMA,BITALG,VPOPCNTDQ} features for avx10.1-512. + (ix86_valid_target_attribute_inner_p): Handle AVX10_1. + * config/i386/i386.cc (ix86_get_ssemov): Add AVX10_1. + (ix86_conditional_register_usage): Ditto. + (ix86_hard_regno_mode_ok): Ditto. + (ix86_rtx_costs): Ditto. + * config/i386/i386.h (VALID_MASK_AVX10_MODE): New macro. + * config/i386/i386.opt: Add option -mavx10.1, -mavx10.1-256 and + -mavx10.1-512. + * doc/extend.texi: Document avx10.1, avx10.1-256 and avx10.1-512. + * doc/invoke.texi: Document -mavx10.1, -mavx10.1-256 and -mavx10.1-512. + * doc/sourcebuild.texi: Document target avx10.1, avx10.1-256 + and avx10.1-512. + +2023-08-24 Haochen Jiang + + Revert: + 2023-08-17 Haochen Jiang + + * common/config/i386/i386-common.cc + (ix86_check_avx10): New function to check isa_flags and + isa_flags_explicit to emit warning when AVX10 is enabled + by "-m" option. + (ix86_check_avx512): New function to check isa_flags and + isa_flags_explicit to emit warning when AVX512 is enabled + by "-m" option. + (ix86_handle_option): Do not change the flags when warning + is emitted. + * config/i386/driver-i386.cc (host_detect_local_cpu): + Do not append -mno-avx10.1 for -march=native. + +2023-08-24 Haochen Jiang + + Revert: + 2023-08-17 Haochen Jiang + + * common/config/i386/i386-common.cc + (ix86_check_avx10_vector_width): New function to check isa_flags + to emit a warning when there is a conflict in AVX10 options for + vector width. + (ix86_handle_option): Add check for avx10.1-256 and avx10.1-512. + * config/i386/driver-i386.cc (host_detect_local_cpu): + Do not append -mno-avx10-max-512bit for -march=native. + +2023-08-24 Haochen Jiang + + Revert: + 2023-08-17 Haochen Jiang + + * config/i386/avx512vldqintrin.h: Remove target attribute. + * config/i386/i386-builtin.def (BDESC): + Add OPTION_MASK_ISA2_AVX10_1. + * config/i386/i386-builtins.cc (def_builtin): Handle AVX10_1. + * config/i386/i386-expand.cc + (ix86_check_builtin_isa_match): Ditto. + (ix86_expand_sse2_mulvxdi3): Add TARGET_AVX10_1. + * config/i386/i386.md: Add new isa attribute avx10_1_or_avx512dq + and avx10_1_or_avx512vl. + * config/i386/sse.md: (VF2_AVX512VLDQ_AVX10_1): New. + (VF1_128_256VLDQ_AVX10_1): Ditto. + (VI8_AVX512VLDQ_AVX10_1): Ditto. + (_andnot3): + Add TARGET_AVX10_1 and change isa attr from avx512dq to + avx10_1_or_avx512dq. + (*andnot3): Add TARGET_AVX10_1 and change isa attr from + avx512vl to avx10_1_or_avx512vl. + (fix_trunc2): + Change iterator to VF2_AVX512VLDQ_AVX10_1. Remove target check. + (fix_notrunc2): + Ditto. + (ufix_notrunc2): + Ditto. + (fix_trunc2): + Change iterator to VF1_128_256VLDQ_AVX10_1. Remove target check. + (avx512dq_fix_truncv2sfv2di2): + Add TARGET_AVX10_1. + (fix_truncv2sfv2di2): Ditto. + (cond_mul): Change iterator to VI8_AVX10_1_AVX512DQVL. + Remove target check. + (avx512dq_mul3): Ditto. + (*avx512dq_mul3): Ditto. + (VI4F_BRCST32x2): Add TARGET_AVX512DQ and TARGET_AVX10_1. + (avx512dq_broadcast): + Remove target check. + (VI8F_BRCST64x2): Add TARGET_AVX512DQ and TARGET_AVX10_1. + (avx512dq_broadcast_1): + Remove target check. + * config/i386/subst.md (mask_mode512bit_condition): Add TARGET_AVX10_1. + (mask_avx512vl_condition): Ditto. + (mask): Ditto. + +2023-08-24 Haochen Jiang + + Revert: + 2023-08-17 Haochen Jiang + + * config/i386/avx512vldqintrin.h: Remove target attribute. + * config/i386/i386-builtin.def (BDESC): + Add OPTION_MASK_ISA2_AVX10_1. + * config/i386/i386.cc (standard_sse_constant_opcode): Add TARGET_AVX10_1. + * config/i386/sse.md: (VI48_AVX512VL_AVX10_1): New. + (VI48_AVX512VLDQ_AVX10_1): Ditto. + (VF2_AVX512VL): Remove. + (VI8_256_512VLDQ_AVX10_1): Rename from VI8_256_512. + Add TARGET_AVX10_1. + (*3): Change isa attribute to + avx10_1_or_avx512dq. Add TARGET_AVX10_1. + (3): Add TARGET_AVX10_1. Change isa attr + to avx10_1_or_avx512vl. + (avx512dq_cvtps2qq): + Change iterator to VI8_256_512VLDQ_AVX10_1. Remove target check. + (avx512dq_cvtps2qqv2di): + Add TARGET_AVX10_1. + (avx512dq_cvtps2uqq): + Change iterator to VI8_256_512VLDQ_AVX10_1. Remove target check. + (avx512dq_cvtps2uqqv2di): + Add TARGET_AVX10_1. + (float2): + Change iterator to VF2_AVX512VLDQ_AVX10_1. Remove target check. + (float2): + Change iterator to VF1_128_256VLDQ_AVX10_1. Remove target check. + (floatv4div4sf2): + Add TARGET_AVX10_1. + (avx512dq_floatv2div2sf2): Ditto. + (*avx512dq_floatv2div2sf2): Ditto. + (floatv2div2sf2): Ditto. + (floatv2div2sf2_mask): Ditto. + (*floatv2div2sf2_mask): Ditto. + (*floatv2div2sf2_mask_1): Ditto. + (_cvt2mask): + Change iterator to VI48_AVX512VLDQ_AVX10_1. Remove target check. + (_cvtmask2): Ditto. + (*_cvtmask2): + Change iterator to VI48_AVX512VL_AVX10_1. Remove target check. + Change when constraint is enabled. + +2023-08-24 Haochen Jiang + + Revert: + 2023-08-17 Haochen Jiang + + * config/i386/avx512vldqintrin.h: Remove target attribute. + * config/i386/i386-builtin.def (BDESC): + Add OPTION_MASK_ISA2_AVX10_1. + * config/i386/sse.md (VF_AVX512VLDQ_AVX10_1): New. + (VFH_AVX512VLDQ_AVX10_1): Ditto. + (VF1_AVX512VLDQ_AVX10_1): Ditto. + (reducep): + Change iterator to VFH_AVX512VLDQ_AVX10_1. Remove target check. + (vec_pack_float_): Change iterator to + VI8_AVX512VLDQ_AVX10_1. Remove target check. + (vec_unpack_fix_trunc_lo_): Change iterator to + VF1_AVX512VLDQ_AVX10_1. Remove target check. + (vec_unpack_fix_trunc_hi_): Ditto. + (VI48F_256_DQVL_AVX10_1): Rename from VI48F_256_DQ. + (avx512vl_vextractf128): Change iterator to + VI48F_256_DQVL_AVX10_1. Remove target check. + (vec_extract_hi__mask): Add TARGET_AVX10_1. + (vec_extract_hi_): Ditto. + (avx512vl_vinsert): Ditto. + (vec_set_lo_): Ditto. + (vec_set_hi_): Ditto. + (avx512dq_rangep): Change + iterator to VF_AVX512VLDQ_AVX10_1. Remove target check. + (avx512dq_fpclass): Change + iterator to VFH_AVX512VLDQ_AVX10_1. Remove target check. + * config/i386/subst.md (mask_avx512dq_condition): Add + TARGET_AVX10_1. + (mask_scalar_merge): Ditto. + +2023-08-24 Haochen Jiang + + Revert: + 2023-08-18 Haochen Jiang + + PR target/111051 + * config/i386/avx512vldqintrin.h: Push AVX2 when AVX2 is + disabled. + +2023-08-24 Richard Biener + + PR debug/111080 + * dwarf2out.cc (prune_unused_types_walk): Handle + DW_TAG_restrict_type, DW_TAG_shared_type, DW_TAG_atomic_type, + DW_TAG_immutable_type, DW_TAG_coarray_type, DW_TAG_unspecified_type + and DW_TAG_dynamic_type as to only output them when referenced. + +2023-08-24 liuhongt + + * config/i386/i386.cc (ix86_invalid_conversion): Adjust GCC + V13 to GCC 13.1. + +2023-08-24 liuhongt + + * common/config/i386/i386-common.cc (processor_names): Add new + member graniterapids-s and arrowlake-s. + * config/i386/i386-options.cc (processor_alias_table): Update + table with PROCESSOR_ARROWLAKE_S and + PROCESSOR_GRANITERAPIDS_D. + (m_GRANITERAPID_D): New macro. + (m_ARROWLAKE_S): Ditto. + (m_CORE_AVX512): Add m_GRANITERAPIDS_D. + (processor_cost_table): Add icelake_cost for + PROCESSOR_GRANITERAPIDS_D and alderlake_cost for + PROCESSOR_ARROWLAKE_S. + * config/i386/x86-tune.def: Hanlde m_ARROWLAKE_S same as + m_ARROWLAKE. + * config/i386/i386.h (enum processor_type): Add new member + PROCESSOR_GRANITERAPIDS_D and PROCESSOR_ARROWLAKE_S. + * config/i386/i386-c.cc (ix86_target_macros_internal): Handle + PROCESSOR_GRANITERAPIDS_D and PROCESSOR_ARROWLAKE_S + +2023-08-23 Jivan Hakobyan + + * lra-eliminations.cc (eliminate_regs_in_insn): Use equivalences to + to help simplify code further. + +2023-08-23 Andrew MacLeod + + * gimple-range-fold.cc (fold_using_range::range_of_phi): Tweak output. + * gimple-range-phi.cc (phi_group::phi_group): Remove unused members. + Initialize using a range instead of value and edge. + (phi_group::calculate_using_modifier): Use initializer value and + process for relations after trying for iteration convergence. + (phi_group::refine_using_relation): Use initializer range. + (phi_group::dump): Rework the dump output. + (phi_analyzer::process_phi): Allow multiple constant initilizers. + Dump groups immediately as created. + (phi_analyzer::dump): Tweak output. + * gimple-range-phi.h (phi_group::phi_group): Adjust prototype. + (phi_group::initial_value): Delete. + (phi_group::refine_using_relation): Adjust prototype. + (phi_group::m_initial_value): Delete. + (phi_group::m_initial_edge): Delete. + (phi_group::m_vr): Use int_range_max. + * tree-vrp.cc (execute_ranger_vrp): Don't dump phi groups. + +2023-08-23 Andrew MacLeod + + * gimple-range-phi.cc (phi_analyzer::operator[]): Return NULL if + no group was created. + (phi_analyzer::process_phi): Do not create groups of one phi node. + +2023-08-23 Richard Earnshaw + + * target.def (gen_ccmp_first, gen_ccmp_next): Use rtx_code for + CODE, CMP_CODE and BIT_CODE arguments. + * config/aarch64/aarch64.cc (aarch64_gen_ccmp_first): Likewise. + (aarch64_gen_ccmp_next): Likewise. + * doc/tm.texi: Regenerated. + +2023-08-23 Richard Earnshaw + + * coretypes.h (rtx_code): Add forward declaration. + * rtl.h (rtx_code): Make compatible with forward declaration. + +2023-08-23 Uros Bizjak + + PR target/111010 + * config/i386/i386.md (*concat3_3): + Merge pattern from *concatditi3_3 and *concatsidi3_3 using + DWIH mode iterator. Disable (=&r,m,m) alternative for + 32-bit targets. + (*concat3_3): Disable (=&r,m,m) + alternative for 32-bit targets. + +2023-08-23 Zhangjin Liao + + * config/riscv/bitmanip.md (*disi2_sext): Add a more + appropriate type attribute. + +2023-08-23 Lehua Ding + + * config/riscv/autovec-opt.md (*cond_abs): New combine pattern. + (*copysign_neg): Ditto. + * config/riscv/autovec.md (@vcond_mask_): Adjust. + (2): Ditto. + (cond_): New. + (cond_len_): Ditto. + * config/riscv/riscv-protos.h (enum insn_type): New. + (expand_cond_len_unop): New helper func. + * config/riscv/riscv-v.cc (shuffle_merge_patterns): Adjust. + (expand_cond_len_unop): New helper func. + +2023-08-23 Jan Hubicka + + * tree-ssa-loop-ch.cc (enum ch_decision): Fix comment. + (should_duplicate_loop_header_p): Fix return value for static exits. + (ch_base::copy_headers): Improve handling of ch_possible_zero_cost. + +2023-08-23 Kewen Lin + + * tree-vect-stmts.cc (vectorizable_store): Move the handlings on + VMAT_GATHER_SCATTER in the final loop nest to its own loop, + and update the final nest accordingly. + +2023-08-23 Kewen Lin + + * tree-vect-stmts.cc (vectorizable_store): Move the handlings on + VMAT_LOAD_STORE_LANES in the final loop nest to its own loop, + and update the final nest accordingly. + +2023-08-23 Kewen Lin + + * tree-vect-stmts.cc (vectorizable_store): Remove vec oprnds, + adjust vec result_chain, vec_oprnd with auto_vec, and adjust + gvec_oprnds with auto_delete_vec. + +2023-08-23 Juzhe-Zhong + + * config/riscv/riscv-vsetvl.cc + (pass_vsetvl::global_eliminate_vsetvl_insn): Fix potential ICE. + +2023-08-23 Juzhe-Zhong + + * config/riscv/riscv-vsetvl.cc (ge_sew_ratio_unavailable_p): + Fix fuse rule bug. + * config/riscv/riscv-vsetvl.def (DEF_SEW_LMUL_FUSE_RULE): Ditto. + +2023-08-23 Juzhe-Zhong + + * config/riscv/vector.md: Add attribute. + +2023-08-22 Juzhe-Zhong + + * config/riscv/riscv-vsetvl.cc (change_insn): Clang format. + (vector_infos_manager::all_same_ratio_p): Ditto. + (vector_infos_manager::all_same_avl_p): Ditto. + (pass_vsetvl::refine_vsetvls): Ditto. + (pass_vsetvl::cleanup_vsetvls): Ditto. + (pass_vsetvl::commit_vsetvls): Ditto. + (pass_vsetvl::local_eliminate_vsetvl_insn): Ditto. + (pass_vsetvl::global_eliminate_vsetvl_insn): Ditto. + (pass_vsetvl::compute_probabilities): Ditto. + +2023-08-22 Juzhe-Zhong + + * config/riscv/t-riscv: Add riscv-vsetvl.def + +2023-08-22 Vineet Gupta + + * config/riscv/riscv.opt: Add --param names + riscv-autovec-preference and riscv-autovec-lmul + +2023-08-22 Raphael Moreira Zinsly + + * config/riscv/t-linux: Add MULTIARCH_DIRNAME. + +2023-08-22 Tobias Burnus + + * tree-core.h (enum omp_clause_defaultmap_kind): Add + OMP_CLAUSE_DEFAULTMAP_CATEGORY_ALL. + * gimplify.cc (gimplify_scan_omp_clauses): Handle it. + * tree-pretty-print.cc (dump_omp_clause): Likewise. + +2023-08-22 Jakub Jelinek + + PR c++/106652 + * doc/extend.texi (_Float): Drop obsolete sentence that the + types aren't supported in C++. + +2023-08-22 Juzhe-Zhong + + * doc/md.texi: Add LEN_FOLD_EXTRACT_LAST pattern. + * internal-fn.cc (fold_len_extract_direct): Ditto. + (expand_fold_len_extract_optab_fn): Ditto. + (direct_fold_len_extract_optab_supported_p): Ditto. + * internal-fn.def (LEN_FOLD_EXTRACT_LAST): Ditto. + * optabs.def (OPTAB_D): Ditto. + +2023-08-22 Richard Biener + + * tree-vect-stmts.cc (vectorizable_store): Do not bump + DR_GROUP_STORE_COUNT here. Remove early out. + (vect_transform_stmt): Only call vectorizable_store on + the last element of an interleaving chain. + +2023-08-22 Richard Biener + + PR tree-optimization/94864 + PR tree-optimization/94865 + PR tree-optimization/93080 + * match.pd (bit_insert @0 (BIT_FIELD_REF @1 ..) ..): New pattern + for vector insertion from vector extraction. + +2023-08-22 Juzhe-Zhong + Kewen.Lin + + * tree-vect-loop.cc (vect_verify_loop_lens): Add exists check. + (vectorizable_live_operation): Add live vectorization for length loop + control. + +2023-08-22 David Malcolm + + PR analyzer/105899 + * doc/invoke.texi: Remove -Wanalyzer-unterminated-string. + +2023-08-22 Pan Li + + * config/riscv/riscv-vector-builtins-bases.cc + (vfwredusum_frm_obj): New declaration. + (BASE): Ditto. + * config/riscv/riscv-vector-builtins-bases.h: Ditto. + * config/riscv/riscv-vector-builtins-functions.def + (vfwredusum_frm): New intrinsic function def. + +2023-08-21 David Faust + + * config/bpf/bpf.md (neg): Second operand must be a register. + +2023-08-21 Edwin Lu + + * config/riscv/bitmanip.md: Added bitmanip type to insns + that are missing types. + +2023-08-21 Jeff Law + + * config/riscv/sync-ztso.md (atomic_load_ztso): Avoid extraenous + newline. + +2023-08-21 Francois-Xavier Coudert + + * config/aarch64/falkor-tag-collision-avoidance.cc (dump_insn_list): + Fix format specifier. + +2023-08-21 Aldy Hernandez + + * value-range.cc (frange::union_nans): Return false if nothing + changed. + (range_tests_floats): New test. + +2023-08-21 Prathamesh Kulkarni + + PR tree-optimization/111048 + * fold-const.cc (valid_mask_for_fold_vec_perm_cst_p): Set arg_npatterns + correctly. + (fold_vec_perm_cst): Remove workaround and again call + valid_mask_fold_vec_perm_cst_p for both VLS and VLA vectors. + (test_fold_vec_perm_cst::test_nunits_min_4): Add test-case. + +2023-08-21 Richard Biener + + PR tree-optimization/111082 + * tree-vect-slp.cc (vectorize_slp_instance_root_stmt): Only + pun operations that can overflow. + +2023-08-21 Juzhe-Zhong + + * lcm.cc (compute_antinout_edge): Export as global use. + (compute_earliest): Ditto. + (compute_rev_insert_delete): Ditto. + * lcm.h (compute_antinout_edge): Ditto. + (compute_earliest): Ditto. + +2023-08-21 Richard Biener + + PR tree-optimization/111070 + * tree-ssa-ifcombine.cc (ifcombine_ifandif): Check we have + an SSA name before checking SSA_NAME_OCCURS_IN_ABNORMAL_PHI. + +2023-08-21 Andrew Pinski + + PR tree-optimization/111002 + * match.pd (view_convert(vec_cond(a,b,c))): New pattern. + +2023-08-21 liuhongt + + * common/config/i386/cpuinfo.h (get_intel_cpu): Detect + Alderlake-N. + * common/config/i386/i386-common.cc (alias_table): Support + -march=gracemont as an alias of -march=alderlake. + +2023-08-20 Uros Bizjak + + * config/i386/i386-expand.cc (ix86_expand_sse_extend): Use ops[1] + instead of src in the call to ix86_expand_sse_cmp. + * config/i386/sse.md (v8qiv8hi2): Do not + force operands[1] to a register. + (v4hiv4si2): Ditto. + (v2siv2di2): Ditto. + +2023-08-20 Andrew Pinski + + PR tree-optimization/111006 + PR tree-optimization/110986 + * match.pd: (op(vec_cond(a,b,c))): Handle convert for op. + +2023-08-20 Eric Gallager + + PR target/90835 + * Makefile.in: improve error message when /usr/include is + missing + +2023-08-19 Tobias Burnus + + PR middle-end/111017 + * omp-expand.cc (expand_omp_for_init_vars): Pass after=true + to expand_omp_build_cond for 'factor != 0' condition, resulting + in pre-r12-5295-g47de0b56ee455e code for the gimple insert. + +2023-08-19 Guo Jie + Lulu Cheng + + * config/loongarch/t-loongarch: Add loongarch-driver.h into + TM_H. Add loongarch-def.h and loongarch-tune.h into + OPTIONS_H_EXTRA. + +2023-08-18 Uros Bizjak + + PR target/111023 + * config/i386/i386-expand.cc (ix86_split_mmx_punpck): + Also handle V2QImode. + (ix86_expand_sse_extend): New function. + * config/i386/i386-protos.h (ix86_expand_sse_extend): New prototype. + * config/i386/mmx.md (v4qiv4hi2): Enable for + TARGET_SSE2. Expand through ix86_expand_sse_extend for !TARGET_SSE4_1. + (v2hiv2si2): Ditto. + (v2qiv2hi2): Ditto. + * config/i386/sse.md (v8qiv8hi2): Ditto. + (v4hiv4si2): Ditto. + (v2siv2di2): Ditto. + +2023-08-18 Aldy Hernandez + + PR ipa/110753 + * value-range.cc (irange::union_bitmask): Return FALSE if updated + bitmask is semantically equivalent to the original mask. + (irange::intersect_bitmask): Same. + (irange::get_bitmask): Add comment. + +2023-08-18 Richard Biener + + PR tree-optimization/111019 + * tree-ssa-loop-im.cc (gather_mem_refs_stmt): When canonicalizing + also scrap base and offset in case the ref is indirect. + +2023-08-18 Jose E. Marchesi + + * config/bpf/bpf.opt (mframe-limit): Set default to 32767. + +2023-08-18 Kewen Lin + + PR bootstrap/111021 + * Makefile.in (TM_P_H): Add $(TREE_H) as dependence. + +2023-08-18 Kewen Lin + + * tree-vect-stmts.cc (vect_build_scatter_store_calls): New, factor + out from ... + (vectorizable_store): ... here. + +2023-08-18 Richard Biener + + PR tree-optimization/111048 + * fold-const.cc (fold_vec_perm_cst): Check for non-VLA + vectors first. + +2023-08-18 Haochen Jiang + + PR target/111051 + * config/i386/avx512vldqintrin.h: Push AVX2 when AVX2 is + disabled. + +2023-08-18 Kewen Lin + + * tree-vect-stmts.cc (vectorizable_load): Move the handlings on + VMAT_GATHER_SCATTER in the final loop nest to its own loop, + and update the final nest accordingly. + +2023-08-18 Andrew Pinski + + * doc/md.texi (Standard patterns): Document cond_neg, cond_one_cmpl, + cond_len_neg and cond_len_one_cmpl. + +2023-08-18 Lehua Ding + + * config/riscv/iterators.md (TARGET_HARD_FLOAT || TARGET_ZFINX): New. + * config/riscv/pic.md (*local_pic_load): Change ANYF. + (*local_pic_load): To ANYLSF. + (*local_pic_load_32d): Ditto. + (*local_pic_load_32d): Ditto. + (*local_pic_store): Ditto. + (*local_pic_store): Ditto. + (*local_pic_store_32d): Ditto. + (*local_pic_store_32d): Ditto. + +2023-08-18 Lehua Ding + Ju-Zhe Zhong + + * config/riscv/predicates.md (vector_const_0_operand): New. + * config/riscv/vector.md (*pred_broadcast_zero): Ditto. + +2023-08-18 Lehua Ding + + * config/riscv/riscv-vsetvl.cc (pass_vsetvl::backward_demand_fusion): + Forbidden. + +2023-08-17 Andrew MacLeod + + PR tree-optimization/111009 + * range-op.cc (operator_addr_expr::op1_range): Be more restrictive. + +2023-08-17 Vladimir N. Makarov + + * lra-spills.cc (assign_stack_slot_num_and_sort_pseudos): Moving + slots_num initialization from here ... + (lra_spill): ... to here before the 1st call of + assign_stack_slot_num_and_sort_pseudos. Add the 2nd call after + fp->sp elimination. + +2023-08-17 Jose E. Marchesi + + PR c/106537 + * doc/invoke.texi (Option Summary): Mention + -Wcompare-distinct-pointer-types under `Warning Options'. + (Warning Options): Document -Wcompare-distinct-pointer-types. + +2023-08-17 Jan-Benedict Glaw + + * recog.cc (memory_address_addr_space_p): Mark possibly unused + argument as unused. + +2023-08-17 Richard Biener + + PR tree-optimization/111039 + * tree-ssa-ifcombine.cc (ifcombine_ifandif): Check for + SSA_NAME_OCCURS_IN_ABNORMAL_PHI. + +2023-08-17 Alex Coplan + + * doc/rtl.texi: Fix up sample code for RTL-SSA insn changes. + +2023-08-17 Jose E. Marchesi + + PR target/111046 + * config/bpf/bpf.cc (bpf_attribute_table): Add entry for the + `naked' function attribute. + (bpf_warn_func_return): New function. + (TARGET_WARN_FUNC_RETURN): Define. + (bpf_expand_prologue): Add preventive comment. + (bpf_expand_epilogue): Likewise. + * doc/extend.texi (BPF Function Attributes): Document the `naked' + function attribute. + +2023-08-17 Richard Biener + + * tree-vect-slp.cc (vect_slp_check_for_roots): Use + !needs_fold_left_reduction_p to decide whether we can + handle the reduction with association. + (vectorize_slp_instance_root_stmt): For TYPE_OVERFLOW_UNDEFINED + reductions perform all arithmetic in an unsigned type. + +2023-08-17 Rainer Orth + + * configure.ac (gcc_cv_ld64_version): Allow for dyld in ld -v + output. + * configure: Regenerate. + +2023-08-17 Pan Li + + * config/riscv/riscv-vector-builtins-bases.cc + (widen_freducop): Add frm_opt_type template arg. + (vfwredosum_frm_obj): New declaration. + (BASE): Ditto. + * config/riscv/riscv-vector-builtins-bases.h: Ditto. + * config/riscv/riscv-vector-builtins-functions.def + (vfwredosum_frm): New intrinsic function def. + +2023-08-17 Pan Li + + * config/riscv/riscv-vector-builtins-bases.cc + (vfredosum_frm_obj): New declaration. + (BASE): Ditto. + * config/riscv/riscv-vector-builtins-bases.h: Ditto. + * config/riscv/riscv-vector-builtins-functions.def + (vfredosum_frm): New intrinsic function def. + +2023-08-17 Pan Li + + * config/riscv/riscv-vector-builtins-bases.cc + (class freducop): Add frm_op_type template arg. + (vfredusum_frm_obj): New declaration. + (BASE): Ditto. + * config/riscv/riscv-vector-builtins-bases.h: Ditto. + * config/riscv/riscv-vector-builtins-functions.def + (vfredusum_frm): New intrinsic function def. + * config/riscv/riscv-vector-builtins-shapes.cc + (struct reduc_alu_frm_def): New class for frm shape. + (SHAPE): New declaration. + * config/riscv/riscv-vector-builtins-shapes.h: Ditto. + +2023-08-17 Pan Li + + * config/riscv/riscv-vector-builtins-bases.cc + (class vfncvt_f): Add frm_op_type template arg. + (vfncvt_f_frm_obj): New declaration. + (BASE): Ditto. + * config/riscv/riscv-vector-builtins-bases.h: Ditto. + * config/riscv/riscv-vector-builtins-functions.def + (vfncvt_f_frm): New intrinsic function def. + +2023-08-17 Pan Li + + * config/riscv/riscv-vector-builtins-bases.cc + (vfncvt_xu_frm_obj): New declaration. + (BASE): Ditto. + * config/riscv/riscv-vector-builtins-bases.h: Ditto. + * config/riscv/riscv-vector-builtins-functions.def + (vfncvt_xu_frm): New intrinsic function def. + +2023-08-17 Pan Li + + * config/riscv/riscv-vector-builtins-bases.cc + (class vfncvt_x): Add frm_op_type template arg. + (BASE): New declaration. + * config/riscv/riscv-vector-builtins-bases.h: Ditto. + * config/riscv/riscv-vector-builtins-functions.def + (vfncvt_x_frm): New intrinsic function def. + * config/riscv/riscv-vector-builtins-shapes.cc + (struct narrow_alu_frm_def): New shape function for frm. + (SHAPE): New declaration. + * config/riscv/riscv-vector-builtins-shapes.h: Ditto. + +2023-08-17 Haochen Jiang + + * config/i386/avx512vldqintrin.h: Remove target attribute. + * config/i386/i386-builtin.def (BDESC): + Add OPTION_MASK_ISA2_AVX10_1. + * config/i386/sse.md (VF_AVX512VLDQ_AVX10_1): New. + (VFH_AVX512VLDQ_AVX10_1): Ditto. + (VF1_AVX512VLDQ_AVX10_1): Ditto. + (reducep): + Change iterator to VFH_AVX512VLDQ_AVX10_1. Remove target check. + (vec_pack_float_): Change iterator to + VI8_AVX512VLDQ_AVX10_1. Remove target check. + (vec_unpack_fix_trunc_lo_): Change iterator to + VF1_AVX512VLDQ_AVX10_1. Remove target check. + (vec_unpack_fix_trunc_hi_): Ditto. + (VI48F_256_DQVL_AVX10_1): Rename from VI48F_256_DQ. + (avx512vl_vextractf128): Change iterator to + VI48F_256_DQVL_AVX10_1. Remove target check. + (vec_extract_hi__mask): Add TARGET_AVX10_1. + (vec_extract_hi_): Ditto. + (avx512vl_vinsert): Ditto. + (vec_set_lo_): Ditto. + (vec_set_hi_): Ditto. + (avx512dq_rangep): Change + iterator to VF_AVX512VLDQ_AVX10_1. Remove target check. + (avx512dq_fpclass): Change + iterator to VFH_AVX512VLDQ_AVX10_1. Remove target check. + * config/i386/subst.md (mask_avx512dq_condition): Add + TARGET_AVX10_1. + (mask_scalar_merge): Ditto. + +2023-08-17 Haochen Jiang + + * config/i386/avx512vldqintrin.h: Remove target attribute. + * config/i386/i386-builtin.def (BDESC): + Add OPTION_MASK_ISA2_AVX10_1. + * config/i386/i386.cc (standard_sse_constant_opcode): Add TARGET_AVX10_1. + * config/i386/sse.md: (VI48_AVX512VL_AVX10_1): New. + (VI48_AVX512VLDQ_AVX10_1): Ditto. + (VF2_AVX512VL): Remove. + (VI8_256_512VLDQ_AVX10_1): Rename from VI8_256_512. + Add TARGET_AVX10_1. + (*3): Change isa attribute to + avx10_1_or_avx512dq. Add TARGET_AVX10_1. + (3): Add TARGET_AVX10_1. Change isa attr + to avx10_1_or_avx512vl. + (avx512dq_cvtps2qq): + Change iterator to VI8_256_512VLDQ_AVX10_1. Remove target check. + (avx512dq_cvtps2qqv2di): + Add TARGET_AVX10_1. + (avx512dq_cvtps2uqq): + Change iterator to VI8_256_512VLDQ_AVX10_1. Remove target check. + (avx512dq_cvtps2uqqv2di): + Add TARGET_AVX10_1. + (float2): + Change iterator to VF2_AVX512VLDQ_AVX10_1. Remove target check. + (float2): + Change iterator to VF1_128_256VLDQ_AVX10_1. Remove target check. + (floatv4div4sf2): + Add TARGET_AVX10_1. + (avx512dq_floatv2div2sf2): Ditto. + (*avx512dq_floatv2div2sf2): Ditto. + (floatv2div2sf2): Ditto. + (floatv2div2sf2_mask): Ditto. + (*floatv2div2sf2_mask): Ditto. + (*floatv2div2sf2_mask_1): Ditto. + (_cvt2mask): + Change iterator to VI48_AVX512VLDQ_AVX10_1. Remove target check. + (_cvtmask2): Ditto. + (*_cvtmask2): + Change iterator to VI48_AVX512VL_AVX10_1. Remove target check. + Change when constraint is enabled. + +2023-08-17 Juzhe-Zhong + + PR target/111037 + * config/riscv/riscv-vsetvl.cc (float_insn_valid_sew_p): New function. + (second_sew_less_than_first_sew_p): Fix bug. + (first_sew_less_than_second_sew_p): Ditto. + +2023-08-17 Haochen Jiang + + * config/i386/avx512vldqintrin.h: Remove target attribute. + * config/i386/i386-builtin.def (BDESC): + Add OPTION_MASK_ISA2_AVX10_1. + * config/i386/i386-builtins.cc (def_builtin): Handle AVX10_1. + * config/i386/i386-expand.cc + (ix86_check_builtin_isa_match): Ditto. + (ix86_expand_sse2_mulvxdi3): Add TARGET_AVX10_1. + * config/i386/i386.md: Add new isa attribute avx10_1_or_avx512dq + and avx10_1_or_avx512vl. + * config/i386/sse.md: (VF2_AVX512VLDQ_AVX10_1): New. + (VF1_128_256VLDQ_AVX10_1): Ditto. + (VI8_AVX512VLDQ_AVX10_1): Ditto. + (_andnot3): + Add TARGET_AVX10_1 and change isa attr from avx512dq to + avx10_1_or_avx512dq. + (*andnot3): Add TARGET_AVX10_1 and change isa attr from + avx512vl to avx10_1_or_avx512vl. + (fix_trunc2): + Change iterator to VF2_AVX512VLDQ_AVX10_1. Remove target check. + (fix_notrunc2): + Ditto. + (ufix_notrunc2): + Ditto. + (fix_trunc2): + Change iterator to VF1_128_256VLDQ_AVX10_1. Remove target check. + (avx512dq_fix_truncv2sfv2di2): + Add TARGET_AVX10_1. + (fix_truncv2sfv2di2): Ditto. + (cond_mul): Change iterator to VI8_AVX10_1_AVX512DQVL. + Remove target check. + (avx512dq_mul3): Ditto. + (*avx512dq_mul3): Ditto. + (VI4F_BRCST32x2): Add TARGET_AVX512DQ and TARGET_AVX10_1. + (avx512dq_broadcast): + Remove target check. + (VI8F_BRCST64x2): Add TARGET_AVX512DQ and TARGET_AVX10_1. + (avx512dq_broadcast_1): + Remove target check. + * config/i386/subst.md (mask_mode512bit_condition): Add TARGET_AVX10_1. + (mask_avx512vl_condition): Ditto. + (mask): Ditto. + +2023-08-17 Haochen Jiang + + * common/config/i386/i386-common.cc + (ix86_check_avx10_vector_width): New function to check isa_flags + to emit a warning when there is a conflict in AVX10 options for + vector width. + (ix86_handle_option): Add check for avx10.1-256 and avx10.1-512. + * config/i386/driver-i386.cc (host_detect_local_cpu): + Do not append -mno-avx10-max-512bit for -march=native. + +2023-08-17 Haochen Jiang + + * common/config/i386/i386-common.cc + (ix86_check_avx10): New function to check isa_flags and + isa_flags_explicit to emit warning when AVX10 is enabled + by "-m" option. + (ix86_check_avx512): New function to check isa_flags and + isa_flags_explicit to emit warning when AVX512 is enabled + by "-m" option. + (ix86_handle_option): Do not change the flags when warning + is emitted. + * config/i386/driver-i386.cc (host_detect_local_cpu): + Do not append -mno-avx10.1 for -march=native. + +2023-08-17 Haochen Jiang + + * common/config/i386/cpuinfo.h (get_available_features): + Add avx10_set and version and detect avx10.1. + (cpu_indicator_init): Handle avx10.1-512. + * common/config/i386/i386-common.cc + (OPTION_MASK_ISA2_AVX10_512BIT_SET): New. + (OPTION_MASK_ISA2_AVX10_1_SET): Ditto. + (OPTION_MASK_ISA2_AVX10_512BIT_UNSET): Ditto. + (OPTION_MASK_ISA2_AVX10_1_UNSET): Ditto. + (OPTION_MASK_ISA2_AVX2_UNSET): Modify for AVX10_1. + (ix86_handle_option): Handle -mavx10.1, -mavx10.1-256 and + -mavx10.1-512. + * common/config/i386/i386-cpuinfo.h (enum processor_features): + Add FEATURE_AVX10_512BIT, FEATURE_AVX10_1 and + FEATURE_AVX10_512BIT. + * common/config/i386/i386-isas.h: Add ISA_NAME_TABLE_ENTRY for + AVX10_512BIT, AVX10_1 and AVX10_1_512. + * config/i386/constraints.md (Yk): Add AVX10_1. + (Yv): Ditto. + (k): Ditto. + * config/i386/cpuid.h (bit_AVX10): New. + (bit_AVX10_256): Ditto. + (bit_AVX10_512): Ditto. + * config/i386/i386-c.cc (ix86_target_macros_internal): + Define AVX10_512BIT and AVX10_1. + * config/i386/i386-isa.def + (AVX10_512BIT): Add DEF_PTA(AVX10_512BIT). + (AVX10_1): Add DEF_PTA(AVX10_1). + * config/i386/i386-options.cc (isa2_opts): Add -mavx10.1. + (ix86_valid_target_attribute_inner_p): Handle avx10-512bit, avx10.1 + and avx10.1-512. + (ix86_option_override_internal): Enable AVX512{F,VL,BW,DQ,CD,BF16, + FP16,VBMI,VBMI2,VNNI,IFMA,BITALG,VPOPCNTDQ} features for avx10.1-512. + (ix86_valid_target_attribute_inner_p): Handle AVX10_1. + * config/i386/i386.cc (ix86_get_ssemov): Add AVX10_1. + (ix86_conditional_register_usage): Ditto. + (ix86_hard_regno_mode_ok): Ditto. + (ix86_rtx_costs): Ditto. + * config/i386/i386.h (VALID_MASK_AVX10_MODE): New macro. + * config/i386/i386.opt: Add option -mavx10.1, -mavx10.1-256 and + -mavx10.1-512. + * doc/extend.texi: Document avx10.1, avx10.1-256 and avx10.1-512. + * doc/invoke.texi: Document -mavx10.1, -mavx10.1-256 and -mavx10.1-512. + * doc/sourcebuild.texi: Document target avx10.1, avx10.1-256 + and avx10.1-512. + +2023-08-17 Sergei Trofimovich + + * flag-types.h (vrp_mode): Remove unused. + +2023-08-17 Yanzhang Wang + + * simplify-rtx.cc (simplify_context::simplify_binary_operation_1): Use + CONSTM1_RTX. + +2023-08-17 Andrew Pinski + + * internal-fn.def (COND_NOT): New internal function. + * match.pd (UNCOND_UNARY, COND_UNARY): Add bit_not/not + to the lists. + (`vec (a ? -1 : 0) ^ b`): New pattern to convert + into conditional not. + * optabs.def (cond_one_cmpl): New optab. + (cond_len_one_cmpl): Likewise. + +2023-08-16 Surya Kumari Jangala + + PR rtl-optimization/110254 + * ira-color.cc (improve_allocation): Update array + allocated_hard_reg_p. + +2023-08-16 Vladimir N. Makarov + + * lra-int.h (lra_update_fp2sp_elimination): Change the prototype. + * lra-eliminations.cc (spill_pseudos): Record spilled pseudos. + (lra_update_fp2sp_elimination): Ditto. + (update_reg_eliminate): Adjust spill_pseudos call. + * lra-spills.cc (lra_spill): Assign stack slots to pseudos spilled + in lra_update_fp2sp_elimination. + +2023-08-16 Richard Ball + + * config/aarch64/aarch64-cores.def (AARCH64_CORE): Add Cortex-A720 CPU. + * config/aarch64/aarch64-tune.md: Regenerate. + * doc/invoke.texi: Document Cortex-A720 CPU. + +2023-08-16 Robin Dapp + + * config/riscv/autovec.md (avg3_floor): + Implement expander. + (avg3_ceil): Ditto. + * config/riscv/vector-iterators.md (ashiftrt): New iterator. + (ASHIFTRT): Ditto. + +2023-08-16 Robin Dapp + + * internal-fn.cc (vec_extract_direct): Change type argument + numbers. + (expand_vec_extract_optab_fn): Call convert_optab_fn. + (direct_vec_extract_optab_supported_p): Use + convert_optab_supported_p. + +2023-08-16 Prathamesh Kulkarni + Richard Sandiford + + * fold-const.cc (INCLUDE_ALGORITHM): Add Include. + (valid_mask_for_fold_vec_perm_cst_p): New function. + (fold_vec_perm_cst): Likewise. + (fold_vec_perm): Adjust assert and call fold_vec_perm_cst. + (test_fold_vec_perm_cst): New namespace. + (test_fold_vec_perm_cst::build_vec_cst_rand): New function. + (test_fold_vec_perm_cst::validate_res): Likewise. + (test_fold_vec_perm_cst::validate_res_vls): Likewise. + (test_fold_vec_perm_cst::builder_push_elems): Likewise. + (test_fold_vec_perm_cst::test_vnx4si_v4si): Likewise. + (test_fold_vec_perm_cst::test_v4si_vnx4si): Likewise. + (test_fold_vec_perm_cst::test_all_nunits): Likewise. + (test_fold_vec_perm_cst::test_nunits_min_2): Likewise. + (test_fold_vec_perm_cst::test_nunits_min_4): Likewise. + (test_fold_vec_perm_cst::test_nunits_min_8): Likewise. + (test_fold_vec_perm_cst::test_nunits_max_4): Likewise. + (test_fold_vec_perm_cst::is_simple_vla_size): Likewise. + (test_fold_vec_perm_cst::test): Likewise. + (fold_const_cc_tests): Call test_fold_vec_perm_cst::test. + +2023-08-16 Pan Li + + * config/riscv/riscv-vector-builtins-bases.cc + (BASE): New declaration. + * config/riscv/riscv-vector-builtins-bases.h: Ditto. + * config/riscv/riscv-vector-builtins-functions.def + (vfwcvt_xu_frm): New intrinsic function def. + +2023-08-16 Pan Li + + * config/riscv/riscv-vector-builtins-bases.cc: Use explicit argument. + +2023-08-16 Pan Li + + * config/riscv/riscv-vector-builtins-bases.cc + (BASE): New declaration. + * config/riscv/riscv-vector-builtins-bases.h: Ditto. + * config/riscv/riscv-vector-builtins-functions.def + (vfwcvt_x_frm): New intrinsic function def. + +2023-08-16 Pan Li + + * config/riscv/riscv-vector-builtins-bases.cc (BASE): New declaration. + * config/riscv/riscv-vector-builtins-bases.h: Ditto. + * config/riscv/riscv-vector-builtins-functions.def + (vfcvt_f_frm): New intrinsic function def. + +2023-08-16 Pan Li + + * config/riscv/riscv-vector-builtins-bases.cc + (BASE): New declaration. + * config/riscv/riscv-vector-builtins-bases.h: Ditto. + * config/riscv/riscv-vector-builtins-functions.def + (vfcvt_xu_frm): New intrinsic function def.. + +2023-08-16 Haochen Gui + + PR target/110429 + * config/rs6000/vsx.md (*vsx_extract__store_p9): Skip vector + extract when the element is 7 on BE while 8 on LE for byte or 3 on + BE while 4 on LE for halfword. + +2023-08-16 Haochen Gui + + PR target/106769 + * config/rs6000/vsx.md (expand vsx_extract_): Set it only + for V8HI and V16QI. + (vsx_extract_v4si): New expand for V4SI extraction. + (vsx_extract_v4si_w1): New insn pattern for V4SI extraction on + word 1 from BE order. + (*mfvsrwz): New insn pattern for mfvsrwz. + (*vsx_extract__di_p9): Assert that it won't be generated on + word 1 from BE order. + (*vsx_extract_si): Remove. + (*vsx_extract_v4si_w023): New insn and split pattern on word 0, 2, + 3 from BE order. + +2023-08-16 Juzhe-Zhong + + * config/riscv/autovec.md (vec_mask_len_load_lanes): + New pattern. + (vec_mask_len_store_lanes): Ditto. + * config/riscv/riscv-protos.h (expand_lanes_load_store): New function. + * config/riscv/riscv-v.cc (get_mask_mode): Add tuple mask mode. + (expand_lanes_load_store): New function. + * config/riscv/vector-iterators.md: New iterator. + +2023-08-16 Juzhe-Zhong + + * internal-fn.cc (internal_load_fn_p): Apply + MASK_LEN_{LOAD_LANES,STORE_LANES} into vectorizer. + (internal_store_fn_p): Ditto. + (internal_fn_len_index): Ditto. + (internal_fn_mask_index): Ditto. + (internal_fn_stored_value_index): Ditto. + * tree-vect-data-refs.cc (vect_store_lanes_supported): Ditto. + (vect_load_lanes_supported): Ditto. + * tree-vect-loop.cc: Ditto. + * tree-vect-slp.cc (vect_slp_prefer_store_lanes_p): Ditto. + * tree-vect-stmts.cc (check_load_store_for_partial_vectors): Ditto. + (get_group_load_store_type): Ditto. + (vectorizable_store): Ditto. + (vectorizable_load): Ditto. + * tree-vectorizer.h (vect_store_lanes_supported): Ditto. + (vect_load_lanes_supported): Ditto. + +2023-08-16 Pan Li + + * config/riscv/riscv-vector-builtins-bases.cc + (enum frm_op_type): New type for frm. + (BASE): New declaration. + * config/riscv/riscv-vector-builtins-bases.h: Ditto. + * config/riscv/riscv-vector-builtins-functions.def + (vfcvt_x_frm): New intrinsic function def. + +2023-08-16 liuhongt + + * config/i386/i386-builtins.cc + (ix86_vectorize_builtin_gather): Adjust for use_gather_8parts. + * config/i386/i386-options.cc (parse_mtune_ctrl_str): + Set/Clear tune features use_{gather,scatter}_{2parts, 4parts, + 8parts} for -mtune-crtl={,^}{use_gather,use_scatter}. + * config/i386/i386.cc (ix86_vectorize_builtin_scatter): Adjust + for use_scatter_8parts + * config/i386/i386.h (TARGET_USE_GATHER): Rename to .. + (TARGET_USE_GATHER_8PARTS): .. this. + (TARGET_USE_SCATTER): Rename to .. + (TARGET_USE_SCATTER_8PARTS): .. this. + * config/i386/x86-tune.def (X86_TUNE_USE_GATHER): Rename to + (X86_TUNE_USE_GATHER_8PARTS): .. this. + (X86_TUNE_USE_SCATTER): Rename to + (X86_TUNE_USE_SCATTER_8PARTS): .. this. + * config/i386/i386.opt: Add new options mgather, mscatter. + +2023-08-16 liuhongt + + * config/i386/i386-options.cc (m_GDS): New macro. + * config/i386/x86-tune.def (X86_TUNE_USE_GATHER_2PARTS): Don't + enable for m_GDS. + (X86_TUNE_USE_GATHER_4PARTS): Ditto. + (X86_TUNE_USE_GATHER): Ditto. + +2023-08-16 liuhongt + + * config/i386/i386.md (movdf_internal): Generate vmovapd instead of + vmovsd when moving DFmode between SSE_REGS. + (movhi_internal): Generate vmovdqa instead of vmovsh when + moving HImode between SSE_REGS. + (mov_internal): Use vmovaps instead of vmovsh when + moving HF/BFmode between SSE_REGS. + +2023-08-15 David Faust + + * config/bpf/bpf.md (extendsisi2): Delete useless define_insn. + +2023-08-15 David Faust + + PR target/111029 + * config/bpf/bpf.cc (bpf_print_register): Print 'w' registers + for any mode 32-bits or smaller, not just SImode. + +2023-08-15 Martin Jambor + + PR ipa/68930 + PR ipa/92497 + * ipa-prop.h (ipcp_get_aggregate_const): Declare. + * ipa-prop.cc (ipcp_get_aggregate_const): New function. + (ipcp_transform_function): Do not deallocate transformation info. + * tree-ssa-sccvn.cc: Include alloc-pool.h, symbol-summary.h and + ipa-prop.h. + (vn_reference_lookup_2): When hitting default-def vuse, query + IPA-CP transformation info for any known constants. + +2023-08-15 Chung-Lin Tang + Thomas Schwinge + + * gimplify.cc (oacc_region_type_name): New function. + (oacc_default_clause): If no 'default' clause appears on this + compute construct, see if one appears on a lexically containing + 'data' construct. + (gimplify_scan_omp_clauses): Upon OMP_CLAUSE_DEFAULT case, set + ctx->oacc_default_clause_ctx to current context. + +2023-08-15 Juzhe-Zhong + + PR target/110989 + * config/riscv/predicates.md: Fix predicate. + +2023-08-15 Richard Biener + + * tree-vect-slp.cc (vect_analyze_slp_instance): Remove + slp_inst_kind_ctor handling. + (vect_analyze_slp): Simplify. + (vect_build_slp_instance): Dump when we analyze a CTOR. + (vect_slp_check_for_constructors): Rename to ... + (vect_slp_check_for_roots): ... this. Register a + slp_root for CONSTRUCTORs instead of shoving them to + the set of grouped stores. + (vect_slp_analyze_bb_1): Adjust. + +2023-08-15 Richard Biener + + * tree-vectorizer.h (_slp_instance::remain_stmts): Change + to ... + (_slp_instance::remain_defs): ... this. + (SLP_INSTANCE_REMAIN_STMTS): Rename to ... + (SLP_INSTANCE_REMAIN_DEFS): ... this. + (slp_root::remain): New. + (slp_root::slp_root): Adjust. + * tree-vect-slp.cc (vect_free_slp_instance): Adjust. + (vect_build_slp_instance): Get extra remain parameter, + adjust former handling of a cut off stmt. + (vect_analyze_slp_instance): Adjust. + (vect_analyze_slp): Likewise. + (_bb_vec_info::~_bb_vec_info): Likewise. + (vectorizable_bb_reduc_epilogue): Dump something if we fail. + (vect_slp_check_for_constructors): Handle non-internal + defs as remain defs of a reduction. + (vectorize_slp_instance_root_stmt): Adjust. + +2023-08-15 Richard Biener + + * tree-ssa-loop-ivcanon.cc: Include tree-vectorizer.h + (canonicalize_loop_induction_variables): Use find_loop_location. + +2023-08-15 Hans-Peter Nilsson + + PR bootstrap/111021 + * config/cris/cris-protos.h: Revert recent change. + * config/cris/cris.cc (cris_legitimate_address_p): Remove + code_helper unused parameter. + (cris_legitimate_address_p_hook): New wrapper function. + (TARGET_LEGITIMATE_ADDRESS_P): Change to + cris_legitimate_address_p_hook. + +2023-08-15 Richard Biener + + PR tree-optimization/110963 + * tree-ssa-pre.cc (do_pre_regular_insertion): Also insert + a PHI node when the expression is available on all edges + and we insert at most one copy from a constant. + +2023-08-15 Richard Biener + + PR tree-optimization/110991 + * tree-ssa-loop-ivcanon.cc (constant_after_peeling): Handle + VIEW_CONVERT_EXPR , handle more simple IV-like SSA cycles + that will end up constant. + +2023-08-15 Kewen Lin + + PR bootstrap/111021 + * Makefile.in (RECOG_H): Add $(TREE_H) as dependence. + +2023-08-15 Kewen Lin + + * tree-vect-stmts.cc (vectorizable_load): Move the handlings on + VMAT_LOAD_STORE_LANES in the final loop nest to its own loop, + and update the final nest accordingly. + +2023-08-15 Kewen Lin + + * tree-vect-stmts.cc (vectorizable_load): Remove some useless checks + on VMAT_INVARIANT. + +2023-08-15 Pan Li + + * mode-switching.cc (create_pre_exit): Add SET insn check. + +2023-08-15 Pan Li + + * config/riscv/riscv-vector-builtins-bases.cc + (class vfrec7_frm): New class for frm. + (vfrec7_frm_obj): New declaration. + (BASE): Ditto. + * config/riscv/riscv-vector-builtins-bases.h: Ditto. + * config/riscv/riscv-vector-builtins-functions.def + (vfrec7_frm): New intrinsic function definition. + * config/riscv/vector-iterators.md + (VFMISC): Remove VFREC7. + (misc_op): Ditto. + (float_insn_type): Ditto. + (VFMISC_FRM): New int iterator. + (misc_frm_op): New op for frm. + (float_frm_insn_type): New type for frm. + * config/riscv/vector.md (@pred_): + New pattern for misc frm. + +2023-08-14 Vladimir N. Makarov + + * lra-constraints.cc (curr_insn_transform): Process output stack + pointer reloads before emitting reload insns. + +2023-08-14 benjamin priour + + PR analyzer/110543 + * doc/invoke.texi: Add documentation of + fanalyzer-show-events-in-system-headers + +2023-08-14 Jan Hubicka + + PR gcov-profile/110988 + * tree-cfg.cc (fold_loop_internal_call): Avoid division by zero. + +2023-08-14 Jiawei + + * config/riscv/riscv-c.cc (riscv_cpu_cpp_builtins): + Enable compressed builtins when ZC* extensions enabled. + * config/riscv/riscv-shorten-memrefs.cc: + Enable shorten_memrefs pass when ZC* extensions enabled. + * config/riscv/riscv.cc (riscv_compressed_reg_p): + Enable compressible registers when ZC* extensions enabled. + (riscv_rtx_costs): Allow adjusting rtx costs when ZC* extensions enabled. + (riscv_address_cost): Allow adjusting address cost when ZC* extensions enabled. + (riscv_first_stack_step): Allow compression of the register saves + without adding extra instructions. + * config/riscv/riscv.h (FUNCTION_BOUNDARY): Adjusts function boundary + to 16 bits when ZC* extensions enabled. + +2023-08-14 Jiawei + + * common/config/riscv/riscv-common.cc (riscv_subset_list::parse): New extensions. + * config/riscv/riscv-opts.h (MASK_ZCA): New mask. + (MASK_ZCB): Ditto. + (MASK_ZCE): Ditto. + (MASK_ZCF): Ditto. + (MASK_ZCD): Ditto. + (MASK_ZCMP): Ditto. + (MASK_ZCMT): Ditto. + (TARGET_ZCA): New target. + (TARGET_ZCB): Ditto. + (TARGET_ZCE): Ditto. + (TARGET_ZCF): Ditto. + (TARGET_ZCD): Ditto. + (TARGET_ZCMP): Ditto. + (TARGET_ZCMT): Ditto. + * config/riscv/riscv.opt: New target variable. + +2023-08-14 Juzhe-Zhong + + Revert: + 2023-05-17 Jin Ma + + * genrecog.cc (print_nonbool_test): Fix type error of + switch (SUBREG_BYTE (op))'. + +2023-08-14 Richard Biener + + * tree-cfg.cc (print_loop_info): Dump to 'file', not 'dump_file'. + +2023-08-14 Pan Li + + * config/riscv/riscv-vector-builtins-bases.cc + (class unop_frm): New class for frm. + (vfsqrt_frm_obj): New declaration. + (BASE): Ditto. + * config/riscv/riscv-vector-builtins-bases.h: Ditto. + * config/riscv/riscv-vector-builtins-functions.def + (vfsqrt_frm): New intrinsic function definition. + +2023-08-14 Pan Li + + * config/riscv/riscv-vector-builtins-bases.cc + (class vfwnmsac_frm): New class for frm. + (vfwnmsac_frm_obj): New declaration. + (BASE): Ditto. + * config/riscv/riscv-vector-builtins-bases.h: Ditto. + * config/riscv/riscv-vector-builtins-functions.def + (vfwnmsac_frm): New intrinsic function definition. + +2023-08-14 Pan Li + + * config/riscv/riscv-vector-builtins-bases.cc + (class vfwmsac_frm): New class for frm. + (vfwmsac_frm_obj): New declaration. + (BASE): Ditto. + * config/riscv/riscv-vector-builtins-bases.h: Ditto. + * config/riscv/riscv-vector-builtins-functions.def + (vfwmsac_frm): New intrinsic function definition. + +2023-08-14 Pan Li + + * config/riscv/riscv-vector-builtins-bases.cc + (class vfwnmacc_frm): New class for frm. + (vfwnmacc_frm_obj): New declaration. + (BASE): Ditto. + * config/riscv/riscv-vector-builtins-bases.h: Ditto. + * config/riscv/riscv-vector-builtins-functions.def + (vfwnmacc_frm): New intrinsic function definition. + +2023-08-14 Cui, Lili + + * common/config/i386/cpuinfo.h (get_intel_cpu): Add model value 0xba + to Raptorlake. + +2023-08-14 Hans-Peter Nilsson + + * config/mmix/predicates.md (mmix_address_operand): Use + lra_in_progress, not reload_in_progress. + +2023-08-14 Hans-Peter Nilsson + + * config/mmix/mmix.cc: Re-enable LRA. + +2023-08-14 Hans-Peter Nilsson + + * config/mmix/predicates.md (frame_pointer_operand): Handle FP+offset + when lra_in_progress. + +2023-08-14 Hans-Peter Nilsson + + * config/mmix/mmix.cc: Disable LRA for MMIX. + +2023-08-14 Pan Li + + * config/riscv/riscv-vector-builtins-bases.cc + (class vfwmacc_frm): New class for vfwmacc frm. + (vfwmacc_frm_obj): New declaration. + (BASE): Ditto. + * config/riscv/riscv-vector-builtins-bases.h: Ditto. + * config/riscv/riscv-vector-builtins-functions.def + (vfwmacc_frm): Function definition for vfwmacc. + * config/riscv/riscv-vector-builtins.cc + (function_expander::use_widen_ternop_insn): Add frm support. + +2023-08-14 Pan Li + + * config/riscv/riscv-vector-builtins-bases.cc + (class vfnmsub_frm): New class for vfnmsub frm. + (vfnmsub_frm): New declaration. + (BASE): Ditto. + * config/riscv/riscv-vector-builtins-bases.h: Ditto. + * config/riscv/riscv-vector-builtins-functions.def + (vfnmsub_frm): New function declaration. + +2023-08-14 Vladimir N. Makarov + + * lra-constraints.cc (curr_insn_transform): Set done_p up and + check it on true after processing output stack pointer reload. + +2023-08-12 Jakub Jelinek + + * Makefile.in (USER_H): Add stdckdint.h. + * ginclude/stdckdint.h: New file. + +2023-08-12 Juzhe-Zhong + + PR target/110994 + * config/riscv/riscv-opts.h (TARGET_VECTOR_VLS): Add TARGET_VETOR. + +2023-08-12 Patrick Palka + + * tree-pretty-print.cc (dump_generic_node) : + Delimit output with braces. + +2023-08-12 Juzhe-Zhong + + PR target/110985 + * config/riscv/riscv-v.cc (expand_vec_series): Refactor the expander. + +2023-08-12 Juzhe-Zhong + + * config/riscv/autovec.md: Add VLS CONST_VECTOR. + * config/riscv/riscv.cc (riscv_const_insns): Ditto. + * config/riscv/vector.md: Ditto. + +2023-08-11 David Malcolm + + PR analyzer/105899 + * doc/analyzer.texi (__analyzer_get_strlen): New. + * doc/invoke.texi: Add -Wanalyzer-unterminated-string. + +2023-08-11 Jeff Law + + * config/rx/rx.md (subdi3): Fix test for borrow. + +2023-08-11 Juzhe-Zhong + + PR middle-end/110989 + * tree-vect-stmts.cc (vectorizable_store): Replace iv_type with sizetype. + (vectorizable_load): Ditto. + +2023-08-11 Jose E. Marchesi + + * config/bpf/bpf.md (allocate_stack): Define. + * config/bpf/bpf.h (FIRST_PSEUDO_REGISTER): Make room for fake + stack pointer register. + (FIXED_REGISTERS): Adjust accordingly. + (CALL_USED_REGISTERS): Likewise. + (REG_CLASS_CONTENTS): Likewise. + (REGISTER_NAMES): Likewise. + * config/bpf/bpf.cc (bpf_compute_frame_layout): Do not reserve + space for callee-saved registers. + (bpf_expand_prologue): Do not save callee-saved registers in xbpf. + (bpf_expand_epilogue): Do not restore callee-saved registers in + xbpf. + +2023-08-11 Jose E. Marchesi + + * config/bpf/bpf.cc (bpf_function_arg_advance): Do not complain + about too many arguments if function is always inlined. + +2023-08-11 Patrick Palka + + * tree-pretty-print.cc (dump_generic_node) : + Don't call component_ref_field_offset if the RHS isn't a decl. + +2023-08-11 John David Anglin + + PR bootstrap/110646 + * gensupport.cc(class conlist): Use strtol instead of std::stoi. + +2023-08-11 Vladimir N. Makarov + + * lra-constraints.cc (goal_alt_out_sp_reload_p): New flag. + (process_alt_operands): Set the flag. + (curr_insn_transform): Modify stack pointer offsets if output + stack pointer reload is generated. + +2023-08-11 Joseph Myers + + * configure: Regenerate. + +2023-08-11 Richard Biener + + PR tree-optimization/110979 + * tree-vect-loop.cc (vectorizable_reduction): For + FOLD_LEFT_REDUCTION without target support make sure + we don't need to honor signed zeros and sign dependent rounding. + +2023-08-11 Richard Biener + + * tree-vect-slp.cc (vect_slp_region): Provide opt-info for all SLP + subgraph entries. Dump the used vector size based on the + SLP subgraph entry root vector type. + +2023-08-11 Pan Li + + * config/riscv/riscv-vector-builtins-bases.cc + (class vfmsub_frm): New class for vfmsub frm. + (vfmsub_frm): New declaration. + (BASE): Ditto. + * config/riscv/riscv-vector-builtins-bases.h: Ditto. + * config/riscv/riscv-vector-builtins-functions.def + (vfmsub_frm): New function declaration. + +2023-08-11 Juzhe-Zhong + + * doc/md.texi: Add vec_mask_len_{load_lanes,store_lanes} patterns. + * internal-fn.cc (expand_partial_load_optab_fn): Ditto. + (expand_partial_store_optab_fn): Ditto. + * internal-fn.def (MASK_LEN_LOAD_LANES): Ditto. + (MASK_LEN_STORE_LANES): Ditto. + * optabs.def (OPTAB_CD): Ditto. + +2023-08-11 Pan Li + + * config/riscv/riscv-vector-builtins-bases.cc + (class vfnmadd_frm): New class for vfnmadd frm. + (vfnmadd_frm): New declaration. + (BASE): Ditto. + * config/riscv/riscv-vector-builtins-bases.h: Ditto. + * config/riscv/riscv-vector-builtins-functions.def + (vfnmadd_frm): New function declaration. + +2023-08-11 Drew Ross + Jakub Jelinek + + PR tree-optimization/109938 + * match.pd (((x ^ y) & z) | x -> (z & y) | x): New simplification. + +2023-08-11 Pan Li + + * config/riscv/riscv-vector-builtins-bases.cc + (class vfmadd_frm): New class for vfmadd frm. + (vfmadd_frm_obj): New declaration. + (BASE): Ditto. + * config/riscv/riscv-vector-builtins-bases.h: Ditto. + * config/riscv/riscv-vector-builtins-functions.def + (vfmadd_frm): New function definition. + +2023-08-11 Pan Li + + * config/riscv/riscv-vector-builtins-bases.cc + (class vfnmsac_frm): New class for vfnmsac frm. + (vfnmsac_frm_obj): New declaration. + (BASE): Ditto. + * config/riscv/riscv-vector-builtins-bases.h: Ditto. + * config/riscv/riscv-vector-builtins-functions.def + (vfnmsac_frm): New function definition. + +2023-08-11 Jakub Jelinek + + * doc/extend.texi (Typeof): Document typeof_unqual + and __typeof_unqual__. + +2023-08-11 Andrew Pinski + + PR tree-optimization/110954 + * generic-match-head.cc (bitwise_inverted_equal_p): Add + wascmp argument and set it accordingly. + * gimple-match-head.cc (bitwise_inverted_equal_p): Add + wascmp argument to the macro. + (gimple_bitwise_inverted_equal_p): Add + wascmp argument and set it accordingly. + * match.pd (`a & ~a`, `a ^| ~a`): Update call + to bitwise_inverted_equal_p and handle wascmp case. + (`(~x | y) & x`, `(~x | y) & x`, `a?~t:t`): Update + call to bitwise_inverted_equal_p and check to see + if was !wascmp or if precision was 1. + +2023-08-11 Martin Uecker + + PR c/84510 + * doc/invoke.texi: Update. + +2023-08-11 Pan Li + + * config/riscv/riscv-vector-builtins-bases.cc + (class vfmsac_frm): New class for vfmsac frm. + (vfmsac_frm_obj): New declaration. + (BASE): Ditto. + * config/riscv/riscv-vector-builtins-bases.h: Ditto. + * config/riscv/riscv-vector-builtins-functions.def + (vfmsac_frm): New function definition + +2023-08-10 Jan Hubicka + + PR middle-end/110923 + * tree-ssa-loop-split.cc (split_loop): Watch for division by zero. + +2023-08-10 Patrick O'Neill + + * common/config/riscv/riscv-common.cc: Add Ztso and mark Ztso as + dependent on 'a' extension. + * config/riscv/riscv-opts.h (MASK_ZTSO): New mask. + (TARGET_ZTSO): New target. + * config/riscv/riscv.cc (riscv_memmodel_needs_amo_acquire): Add + Ztso case. + (riscv_memmodel_needs_amo_release): Add Ztso case. + (riscv_print_operand): Add Ztso case for LR/SC annotations. + * config/riscv/riscv.md: Import sync-rvwmo.md and sync-ztso.md. + * config/riscv/riscv.opt: Add Ztso target variable. + * config/riscv/sync.md (mem_thread_fence_1): Expand to RVWMO or + Ztso specific insn. + (atomic_load): Expand to RVWMO or Ztso specific insn. + (atomic_store): Expand to RVWMO or Ztso specific insn. + * config/riscv/sync-rvwmo.md: New file. Seperate out RVWMO + specific load/store/fence mappings. + * config/riscv/sync-ztso.md: New file. Seperate out Ztso + specific load/store/fence mappings. + +2023-08-10 Jan Hubicka + + * cfgloopmanip.cc (duplicate_loop_body_to_header_edge): Special case loops with + 0 iteration count. + +2023-08-10 Jan Hubicka + + * tree-ssa-threadupdate.cc (ssa_fix_duplicate_block_edges): Fix profile update. + +2023-08-10 Jan Hubicka + + * profile-count.cc (profile_count::differs_from_p): Fix overflow and + handling of undefined values. + +2023-08-10 Jakub Jelinek + + PR c/102989 + * tree-ssa-phiopt.cc (single_non_singleton_phi_for_edges): Never + return virtual phis and return NULL if there is a virtual phi + where the arguments from E0 and E1 edges aren't equal. + +2023-08-10 Richard Biener + + * internal-fn.def (VCOND, VCONDU, VCONDEQ, VCOND_MASK, + VEC_SET, VEC_EXTRACT): Make ECF_CONST | ECF_NOTHROW. + +2023-08-10 Juzhe-Zhong + + PR target/110962 + * config/riscv/autovec.md (vec_duplicate): New pattern. + +2023-08-10 Pan Li + + * config/riscv/riscv-vector-builtins-bases.cc + (class vfnmacc_frm): New class for vfnmacc. + (vfnmacc_frm_obj): New declaration. + (BASE): Ditto. + * config/riscv/riscv-vector-builtins-bases.h: Ditto. + * config/riscv/riscv-vector-builtins-functions.def + (vfnmacc_frm): New function definition. + +2023-08-10 Pan Li + + * config/riscv/riscv-vector-builtins-bases.cc + (class vfmacc_frm): New class for vfmacc frm. + (vfmacc_frm_obj): New declaration. + (BASE): Ditto. + * config/riscv/riscv-vector-builtins-bases.h: Ditto. + * config/riscv/riscv-vector-builtins-functions.def + (vfmacc_frm): New function definition. + +2023-08-10 Juzhe-Zhong + + PR target/110964 + * config/riscv/riscv-v.cc (expand_cond_len_ternop): Add integer ternary. + +2023-08-10 Richard Biener + + * tree-vectorizer.h (vectorizable_live_operation): Remove + gimple_stmt_iterator * argument. + * tree-vect-loop.cc (vectorizable_live_operation): Likewise. + Adjust plumbing around vect_get_loop_mask. + (vect_analyze_loop_operations): Adjust. + * tree-vect-slp.cc (vect_slp_analyze_node_operations_1): Likewise. + (vect_bb_slp_mark_live_stmts): Likewise. + (vect_schedule_slp_node): Likewise. + * tree-vect-stmts.cc (can_vectorize_live_stmts): Likewise. + Remove gimple_stmt_iterator * argument. + (vect_transform_stmt): Adjust. + +2023-08-10 Juzhe-Zhong + + * config/riscv/vector-iterators.md: Add missing modes. + +2023-08-10 Jakub Jelinek + + PR c/102989 + * lto-streamer-in.cc (lto_input_tree_1): Assert TYPE_PRECISION + is up to WIDE_INT_MAX_PRECISION rather than MAX_BITSIZE_MODE_ANY_INT. + +2023-08-10 Jakub Jelinek + + PR c/102989 + * expr.cc (expand_expr_real_1) : Add an early return for + EXPAND_WRITE or EXPAND_MEMORY modifiers to avoid testing it multiple + times. + +2023-08-10 liuhongt + + PR target/110832 + * config/i386/mmx.md: (movq__to_sse): Also do not + sanitize upper part of V4HFmode register with + -fno-trapping-math. + (v4hf3): Enable for ix86_partial_vec_fp_math. + (v2hf3): Ditto. + (divv2hf3): Ditto. + (movd_v2hf_to_sse): Do not sanitize upper part of V2HFmode + register with -fno-trapping-math. + +2023-08-10 Pan Li + Kito Cheng + + * config/riscv/riscv-protos.h + (enum floating_point_rounding_mode): Add NONE, DYN_EXIT and DYN_CALL. + (get_frm_mode): New declaration. + * config/riscv/riscv-v.cc (get_frm_mode): New function to get frm mode. + * config/riscv/riscv-vector-builtins.cc + (function_expander::use_ternop_insn): Take care of frm reg. + * config/riscv/riscv.cc (riscv_static_frm_mode_p): Migrate to FRM_XXX. + (riscv_emit_frm_mode_set): Ditto. + (riscv_emit_mode_set): Ditto. + (riscv_frm_adjust_mode_after_call): Ditto. + (riscv_frm_mode_needed): Ditto. + (riscv_frm_mode_after): Ditto. + (riscv_mode_entry): Ditto. + (riscv_mode_exit): Ditto. + * config/riscv/riscv.h (NUM_MODES_FOR_MODE_SWITCHING): Ditto. + * config/riscv/vector.md + (rne,rtz,rdn,rup,rmm,dyn,dyn_exit,dyn_call,none): Removed + (symbol_ref): * config/riscv/vector.md: Set frm_mode attr explicitly. + +2023-08-09 Juzhe-Zhong + + * config/riscv/riscv-vsetvl.cc (anticipatable_occurrence_p): Fix + incorrect anticipate info. + +2023-08-09 Tsukasa OI + + * common/config/riscv/riscv-common.cc (riscv_ext_version_table): + Remove 'Zve32d' from the version list. + +2023-08-09 Jin Ma + + * config/riscv/riscv.cc (riscv_sched_variable_issue): New function. + (TARGET_SCHED_VARIABLE_ISSUE): New macro. + Co-authored-by: Philipp Tomsich + Co-authored-by: Jeff Law + +2023-08-09 Jivan Hakobyan + + * config/riscv/riscv.cc (riscv_legitimize_address): Handle folding. + (mem_shadd_or_shadd_rtx_p): New function. + +2023-08-09 Andrew Pinski + + PR tree-optimization/110937 + PR tree-optimization/100798 + * match.pd (`a ? ~b : b`): Handle this + case. + +2023-08-09 Uros Bizjak + + * config/i386/i386.opt (mpartial-vector-fp-math): Add dot. + +2023-08-09 Richard Ball + + * config/aarch64/aarch64-cores.def (AARCH64_CORE): Add Cortex-A520 CPU. + * config/aarch64/aarch64-tune.md: Regenerate. + * doc/invoke.texi: Document Cortex-A520 CPU. + +2023-08-09 Carl Love + + * config/rs6000/rs6000-builtins.def (vcmpneb, vcmpneh, vcmpnew): + Move definitions to Altivec stanza. + * config/rs6000/altivec.md (vcmpneb, vcmpneh, vcmpnew): New + define_expand. + +2023-08-09 Juzhe-Zhong + + PR target/110950 + * config/riscv/riscv-v.cc (expand_const_vector): Add NPATTERNS = 1 + stepped vector support. + +2023-08-09 liuhongt + + * common/config/i386/cpuinfo.h (get_available_features): + Rename local variable subleaf_level to max_subleaf_level. + +2023-08-09 Richard Biener + + PR rtl-optimization/110587 + * lra-assigns.cc (find_hard_regno_for_1): Re-order checks. + +2023-08-09 Kewen Lin + + PR tree-optimization/110248 + * config/rs6000/rs6000.cc (rs6000_legitimate_address_p): Check if + the given code is for ifn LEN_{LOAD,STORE}, if yes then make it not + legitimate when outer code is PLUS. + +2023-08-09 Kewen Lin + + PR tree-optimization/110248 + * recog.cc (memory_address_addr_space_p): Add one more argument ch of + type code_helper and pass it to targetm.addr_space.legitimate_address_p + instead of ERROR_MARK. + (offsettable_address_addr_space_p): Update one function pointer with + one more argument of type code_helper as its assignees + memory_address_addr_space_p and strict_memory_address_addr_space_p + have been adjusted, and adjust some call sites with ERROR_MARK. + * recog.h (tree.h): New include header file for tree_code ERROR_MARK. + (memory_address_addr_space_p): Adjust with one more unnamed argument + of type code_helper with default ERROR_MARK. + (strict_memory_address_addr_space_p): Likewise. + * reload.cc (strict_memory_address_addr_space_p): Add one unnamed + argument of type code_helper. + * tree-ssa-address.cc (valid_mem_ref_p): Add one more argument ch of + type code_helper and pass it to memory_address_addr_space_p. + * tree-ssa-address.h (valid_mem_ref_p): Adjust the declaration with + one more unnamed argument of type code_helper with default value + ERROR_MARK. + * tree-ssa-loop-ivopts.cc (get_address_cost): Use ERROR_MARK as code + by default, change it with ifn code for USE_PTR_ADDRESS type use, and + pass it to all valid_mem_ref_p calls. + +2023-08-09 Kewen Lin + + PR tree-optimization/110248 + * coretypes.h (class code_helper): Add forward declaration. + * doc/tm.texi: Regenerate. + * lra-constraints.cc (valid_address_p): Call target hook + targetm.addr_space.legitimate_address_p with an extra parameter + ERROR_MARK as its prototype changes. + * recog.cc (memory_address_addr_space_p): Likewise. + * reload.cc (strict_memory_address_addr_space_p): Likewise. + * target.def (legitimate_address_p, addr_space.legitimate_address_p): + Extend with one more argument of type code_helper, update the + documentation accordingly. + * targhooks.cc (default_legitimate_address_p): Adjust for the + new code_helper argument. + (default_addr_space_legitimate_address_p): Likewise. + * targhooks.h (default_legitimate_address_p): Likewise. + (default_addr_space_legitimate_address_p): Likewise. + * config/aarch64/aarch64.cc (aarch64_legitimate_address_hook_p): Adjust + with extra unnamed code_helper argument with default ERROR_MARK. + * config/alpha/alpha.cc (alpha_legitimate_address_p): Likewise. + * config/arc/arc.cc (arc_legitimate_address_p): Likewise. + * config/arm/arm-protos.h (arm_legitimate_address_p): Likewise. + (tree.h): New include for tree_code ERROR_MARK. + * config/arm/arm.cc (arm_legitimate_address_p): Adjust with extra + unnamed code_helper argument with default ERROR_MARK. + * config/avr/avr.cc (avr_addr_space_legitimate_address_p): Likewise. + * config/bfin/bfin.cc (bfin_legitimate_address_p): Likewise. + * config/bpf/bpf.cc (bpf_legitimate_address_p): Likewise. + * config/c6x/c6x.cc (c6x_legitimate_address_p): Likewise. + * config/cris/cris-protos.h (cris_legitimate_address_p): Likewise. + (tree.h): New include for tree_code ERROR_MARK. + * config/cris/cris.cc (cris_legitimate_address_p): Adjust with extra + unnamed code_helper argument with default ERROR_MARK. + * config/csky/csky.cc (csky_legitimate_address_p): Likewise. + * config/epiphany/epiphany.cc (epiphany_legitimate_address_p): + Likewise. + * config/frv/frv.cc (frv_legitimate_address_p): Likewise. + * config/ft32/ft32.cc (ft32_addr_space_legitimate_address_p): Likewise. + * config/gcn/gcn.cc (gcn_addr_space_legitimate_address_p): Likewise. + * config/h8300/h8300.cc (h8300_legitimate_address_p): Likewise. + * config/i386/i386.cc (ix86_legitimate_address_p): Likewise. + * config/ia64/ia64.cc (ia64_legitimate_address_p): Likewise. + * config/iq2000/iq2000.cc (iq2000_legitimate_address_p): Likewise. + * config/lm32/lm32.cc (lm32_legitimate_address_p): Likewise. + * config/loongarch/loongarch.cc (loongarch_legitimate_address_p): + Likewise. + * config/m32c/m32c.cc (m32c_legitimate_address_p): Likewise. + (m32c_addr_space_legitimate_address_p): Likewise. + * config/m32r/m32r.cc (m32r_legitimate_address_p): Likewise. + * config/m68k/m68k.cc (m68k_legitimate_address_p): Likewise. + * config/mcore/mcore.cc (mcore_legitimate_address_p): Likewise. + * config/microblaze/microblaze-protos.h (tree.h): New include for + tree_code ERROR_MARK. + (microblaze_legitimate_address_p): Adjust with extra unnamed + code_helper argument with default ERROR_MARK. + * config/microblaze/microblaze.cc (microblaze_legitimate_address_p): + Likewise. + * config/mips/mips.cc (mips_legitimate_address_p): Likewise. + * config/mmix/mmix.cc (mmix_legitimate_address_p): Likewise. + * config/mn10300/mn10300.cc (mn10300_legitimate_address_p): Likewise. + * config/moxie/moxie.cc (moxie_legitimate_address_p): Likewise. + * config/msp430/msp430.cc (msp430_legitimate_address_p): Likewise. + (msp430_addr_space_legitimate_address_p): Adjust with extra code_helper + argument with default ERROR_MARK and adjust the call to function + msp430_legitimate_address_p. + * config/nds32/nds32.cc (nds32_legitimate_address_p): Adjust with extra + unnamed code_helper argument with default ERROR_MARK. + * config/nios2/nios2.cc (nios2_legitimate_address_p): Likewise. + * config/nvptx/nvptx.cc (nvptx_legitimate_address_p): Likewise. + * config/or1k/or1k.cc (or1k_legitimate_address_p): Likewise. + * config/pa/pa.cc (pa_legitimate_address_p): Likewise. + * config/pdp11/pdp11.cc (pdp11_legitimate_address_p): Likewise. + * config/pru/pru.cc (pru_addr_space_legitimate_address_p): Likewise. + * config/riscv/riscv.cc (riscv_legitimate_address_p): Likewise. + * config/rl78/rl78-protos.h (rl78_as_legitimate_address): Likewise. + (tree.h): New include for tree_code ERROR_MARK. + * config/rl78/rl78.cc (rl78_as_legitimate_address): Adjust with + extra unnamed code_helper argument with default ERROR_MARK. + * config/rs6000/rs6000.cc (rs6000_legitimate_address_p): Likewise. + (rs6000_debug_legitimate_address_p): Adjust with extra code_helper + argument and adjust the call to function rs6000_legitimate_address_p. + * config/rx/rx.cc (rx_is_legitimate_address): Adjust with extra + unnamed code_helper argument with default ERROR_MARK. + * config/s390/s390.cc (s390_legitimate_address_p): Likewise. + * config/sh/sh.cc (sh_legitimate_address_p): Likewise. + * config/sparc/sparc.cc (sparc_legitimate_address_p): Likewise. + * config/v850/v850.cc (v850_legitimate_address_p): Likewise. + * config/vax/vax.cc (vax_legitimate_address_p): Likewise. + * config/visium/visium.cc (visium_legitimate_address_p): Likewise. + * config/xtensa/xtensa.cc (xtensa_legitimate_address_p): Likewise. + * config/stormy16/stormy16-protos.h (xstormy16_legitimate_address_p): + Likewise. + (tree.h): New include for tree_code ERROR_MARK. + * config/stormy16/stormy16.cc (xstormy16_legitimate_address_p): + Adjust with extra unnamed code_helper argument with default + ERROR_MARK. + +2023-08-09 liuhongt + + * common/config/i386/cpuinfo.h (get_available_features): Check + EAX for valid subleaf before use CPUID. + +2023-08-08 Jeff Law + + * config/riscv/riscv.cc (riscv_expand_conditional_move): Use word_mode + for the temporary when canonicalizing the condition. + +2023-08-08 Cupertino Miranda + + * config/bpf/core-builtins.cc: Cleaned include headers. + (struct cr_builtins): Added GTY. + (cr_builtins_ref): Created. + (builtins_data) Changed to GC root. + (allocate_builtin_data): Changed. + Included gt-core-builtins.h. + * config/bpf/coreout.cc: (bpf_core_extra) Added GTY. + (bpf_core_extra_ref): Created. + (bpf_comment_info): Changed to GC root. + (bpf_core_reloc_add, output_btfext_header, btf_ext_init): Changed. + +2023-08-08 Uros Bizjak + + PR target/110832 + * config/i386/i386.opt (mpartial-vector-fp-math): New option. + * config/i386/mmx.md (movq__to_sse): Do not sanitize + upper part of V2SFmode register with -fno-trapping-math. + (v2sf3): Enable for ix86_partial_vec_fp_math. + (divv2sf3): Ditto. + (v2sf3): Ditto. + (sqrtv2sf2): Ditto. + (*mmx_haddv2sf3_low): Ditto. + (*mmx_hsubv2sf3_low): Ditto. + (vec_addsubv2sf3): Ditto. + (vec_cmpv2sfv2si): Ditto. + (vcondv2sf): Ditto. + (fmav2sf4): Ditto. + (fmsv2sf4): Ditto. + (fnmav2sf4): Ditto. + (fnmsv2sf4): Ditto. + (fix_truncv2sfv2si2): Ditto. + (fixuns_truncv2sfv2si2): Ditto. + (floatv2siv2sf2): Ditto. + (floatunsv2siv2sf2): Ditto. + (nearbyintv2sf2): Ditto. + (rintv2sf2): Ditto. + (lrintv2sfv2si2): Ditto. + (ceilv2sf2): Ditto. + (lceilv2sfv2si2): Ditto. + (floorv2sf2): Ditto. + (lfloorv2sfv2si2): Ditto. + (btruncv2sf2): Ditto. + (roundv2sf2): Ditto. + (lroundv2sfv2si2): Ditto. + * doc/invoke.texi (x86 Options): Document + -mpartial-vector-fp-math option. + +2023-08-08 Andrew Pinski + + PR tree-optimization/103281 + PR tree-optimization/28794 + * vr-values.cc (simplify_using_ranges::simplify_cond_using_ranges_1): Split out + majority to ... + (simplify_using_ranges::simplify_compare_using_ranges_1): Here. + (simplify_using_ranges::simplify_casted_cond): Rename to ... + (simplify_using_ranges::simplify_casted_compare): This + and change arguments to take op0 and op1. + (simplify_using_ranges::simplify_compare_assign_using_ranges_1): New method. + (simplify_using_ranges::simplify): For tcc_comparison assignments call + simplify_compare_assign_using_ranges_1. + * vr-values.h (simplify_using_ranges): Add + new methods, simplify_compare_using_ranges_1 and simplify_compare_assign_using_ranges_1. + Rename simplify_casted_cond and simplify_casted_compare and + update argument types. + +2023-08-08 Andrzej Turko + + * genmatch.cc: Log line numbers indirectly. + +2023-08-08 Andrzej Turko + + * genmatch.cc: Make sinfo map ordered. + * Makefile.in: Require the ordered map header for genmatch.o. + +2023-08-08 Andrzej Turko + + * ordered-hash-map.h: Add get_or_insert. + * ordered-hash-map-tests.cc: Use get_or_insert in tests. + +2023-08-08 Juzhe-Zhong + + * config/riscv/autovec.md (cond_): New pattern. + (cond_len_): Ditto. + (cond_fma): Ditto. + (cond_len_fma): Ditto. + (cond_fnma): Ditto. + (cond_len_fnma): Ditto. + (cond_fms): Ditto. + (cond_len_fms): Ditto. + (cond_fnms): Ditto. + (cond_len_fnms): Ditto. + * config/riscv/riscv-protos.h (riscv_get_v_regno_alignment): Export + global. + (enum insn_type): Add new enum type. + (prepare_ternary_operands): New function. + * config/riscv/riscv-v.cc (emit_vlmax_masked_fp_mu_insn): Ditto. + (emit_nonvlmax_tumu_insn): Ditto. + (emit_nonvlmax_fp_tumu_insn): Ditto. + (expand_cond_len_binop): Add condtional operations. + (expand_cond_len_ternop): Ditto. + (prepare_ternary_operands): New function. + * config/riscv/riscv.cc (riscv_memmodel_needs_amo_release): Export + riscv_get_v_regno_alignment as global scope. + * config/riscv/vector.md: Fix ternary bugs. + +2023-08-08 Richard Biener + + PR tree-optimization/49955 + * tree-vectorizer.h (_slp_instance::remain_stmts): New. + (SLP_INSTANCE_REMAIN_STMTS): Likewise. + * tree-vect-slp.cc (vect_free_slp_instance): Release + SLP_INSTANCE_REMAIN_STMTS. + (vect_build_slp_instance): Make the number of lanes of + a BB reduction even. + (vectorize_slp_instance_root_stmt): Handle unvectorized + defs of a BB reduction. + +2023-08-08 Ju-Zhe Zhong + + * internal-fn.cc (get_len_internal_fn): New function. + (DEF_INTERNAL_COND_FN): Ditto. + (DEF_INTERNAL_SIGNED_COND_FN): Ditto. + * internal-fn.h (get_len_internal_fn): Ditto. + * tree-vect-stmts.cc (vectorizable_call): Add CALL auto-vectorization. + +2023-08-08 Richard Biener + + PR tree-optimization/110924 + * tree-ssa-live.h (virtual_operand_live): Update comment. + * tree-ssa-live.cc (virtual_operand_live::get_live_in): Remove + optimization, look at each predecessor. + * tree-ssa-sink.cc (pass_sink_code::execute): Mark backedges. + +2023-08-08 yulong + + * config/riscv/riscv-v.cc (slide1_sew64_helper): Modify. + +2023-08-08 Juzhe-Zhong + + * config/riscv/autovec-vls.md (2): Add VLS neg. + * config/riscv/vector.md: Ditto. + +2023-08-08 Juzhe-Zhong + + * config/riscv/autovec.md: Add VLS shift. + +2023-08-07 Juzhe-Zhong + + * config/riscv/autovec-vls.md (3): Add VLS modes. + * config/riscv/vector-iterators.md: Ditto. + * config/riscv/vector.md: Ditto. + +2023-08-07 Jonathan Wakely + + * config/i386/i386.cc (ix86_invalid_conversion): Fix grammar. + +2023-08-07 Nick Alcock + + * configure: Regenerate. + +2023-08-07 John Ericson + + * configure: Regenerate. + +2023-08-07 Alan Modra + + * configure: Regenerate. + +2023-08-07 Alexander von Gluck IV + + * configure: Regenerate. + +2023-08-07 Nick Alcock + + * configure: Regenerate. + +2023-08-07 Nick Alcock + + * configure: Regenerate. + +2023-08-07 H.J. Lu + + * configure: Regenerate. + +2023-08-07 H.J. Lu + + * configure: Regenerate. + +2023-08-07 Jeff Law + + * config/riscv/riscv.cc (riscv_expand_conditional_move): Allow + VOIDmode operands to conditional before canonicalization. + +2023-08-07 Manolis Tsamis + + * regcprop.cc (maybe_copy_reg_attrs): Remove unnecessary function. + (find_oldest_value_reg): Inline stack_pointer_rtx check. + (copyprop_hardreg_forward_1): Inline stack_pointer_rtx check. + +2023-08-07 Martin Jambor + + PR ipa/110378 + * ipa-param-manipulation.h (class ipa_param_body_adjustments): New + members get_ddef_if_exists_and_is_used and mark_clobbers_dead. + * ipa-sra.cc (isra_track_scalar_value_uses): Ignore clobbers. + (ptr_parm_has_nonarg_uses): Likewise. + * ipa-param-manipulation.cc + (ipa_param_body_adjustments::get_ddef_if_exists_and_is_used): New. + (ipa_param_body_adjustments::mark_dead_statements): Move initial + checks to get_ddef_if_exists_and_is_used. + (ipa_param_body_adjustments::mark_clobbers_dead): New. + (ipa_param_body_adjustments::common_initialization): Call + mark_clobbers_dead when splitting. + +2023-08-07 Raphael Zinsly + + * config/riscv/riscv.cc (riscv_expand_int_scc): Add invert_ptr + as an argument and pass it to riscv_emit_int_order_test. + (riscv_expand_conditional_move): Handle cases where the condition + is not EQ/NE or the second argument to the conditional is not + (const_int 0). + * config/riscv/riscv-protos.h (riscv_expand_int_scc): Update prototype. + Co-authored-by: Jeff Law + +2023-08-07 Andrew Pinski + + PR tree-optimization/109959 + * match.pd (`(a > 1) ? 0 : (cast)a`, `(a <= 1) & (cast)a`): + New patterns. + +2023-08-07 Richard Biener + + * tree-ssa-sink.cc (pass_sink_code::execute): Do not + calculate post-dominators. Calculate RPO on the inverted + graph and process blocks in that order. + +2023-08-07 liuhongt + + PR target/110926 + * config/i386/i386-protos.h + (vpternlog_redundant_operand_mask): Adjust parameter type. + * config/i386/i386.cc (vpternlog_redundant_operand_mask): Use + INTVAL instead of XINT, also adjust parameter type from rtx* + to rtx since the function only needs operands[4] in vpternlog + pattern. + (substitute_vpternlog_operands): Pass operands[4] instead of + operands to vpternlog_redundant_operand_mask. + * config/i386/sse.md: Ditto. + +2023-08-07 Richard Biener + + * tree-vect-slp.cc (vect_slp_region): Save/restore vect_location + around dumping code. + +2023-08-07 liuhongt + + PR target/110762 + * config/i386/mmx.md (3): Changed from define_insn + to define_expand and break into .. + (v4hf3): .. this. + (divv4hf3): .. this. + (v2hf3): .. this. + (divv2hf3): .. this. + (movd_v2hf_to_sse): New define_expand. + (movq__to_sse): Extend to V4HFmode. + (mmxdoublevecmode): Ditto. + (V2FI_V4HF): New mode iterator. + * config/i386/sse.md (*vec_concatv4sf): Extend to hanlde V8HF + by using mode iterator V4SF_V8HF, renamed to .. + (*vec_concat): .. this. + (*vec_concatv4sf_0): Extend to handle V8HF by using mode + iterator V4SF_V8HF, renamed to .. + (*vec_concat_0): .. this. + (*vec_concatv8hf_movss): New define_insn. + (V4SF_V8HF): New mode iterator. + +2023-08-07 Juzhe-Zhong + + * tree-vect-patterns.cc (vect_recog_over_widening_pattern): Add op vectype. + +2023-08-07 Jan Beulich + + * config/i386/mmx.md (*mmx_pinsrd): Drop "prefix_data16". + (*mmx_pinsrb): Likewise. + (*mmx_pextrb): Likewise. + (*mmx_pextrb_zext): Likewise. + (mmx_pshufbv8qi3): Likewise. + (mmx_pshufbv4qi3): Likewise. + (mmx_pswapdv2si2): Likewise. + (*pinsrb): Likewise. + (*pextrb): Likewise. + (*pextrb_zext): Likewise. + * config/i386/sse.md (*sse4_1_mulv2siv2di3): Likewise. + (*sse2_eq3): Likewise. + (*sse2_gt3): Likewise. + (_pinsr): Likewise. + (*vec_extract): Likewise. + (*vec_extract_zext): Likewise. + (*vec_extractv16qi_zext): Likewise. + (ssse3_phwv8hi3): Likewise. + (ssse3_pmaddubsw128): Likewise. + (*_pmulhrsw3): Likewise. + (_pshufb3): Likewise. + (_psign3): Likewise. + (_palignr): Likewise. + (*abs2): Likewise. + (sse4_2_pcmpestr): Likewise. + (sse4_2_pcmpestri): Likewise. + (sse4_2_pcmpestrm): Likewise. + (sse4_2_pcmpestr_cconly): Likewise. + (sse4_2_pcmpistr): Likewise. + (sse4_2_pcmpistri): Likewise. + (sse4_2_pcmpistrm): Likewise. + (sse4_2_pcmpistr_cconly): Likewise. + (vgf2p8affineinvqb_): Likewise. + (vgf2p8affineqb_): Likewise. + (vgf2p8mulb_): Likewise. + (*v8hi3 [smaxmin]): Drop "prefix_data16" and + "prefix_extra". + (*v16qi3 [umaxmin]): Likewise. + +2023-08-07 Jan Beulich + + * config/i386/i386.md (sse4_1_round2): Make + "length_immediate" uniformly 1. + * config/i386/mmx.md (mmx_pblendvb_v8qi): Likewise. + (mmx_pblendvb_): Likewise. + +2023-08-07 Jan Beulich + + * config/i386/sse.md + (__): Add + "prefix" attribute. + (avx512fp16_sh_v8hf): + Likewise. + +2023-08-07 Jan Beulich + + * config/i386/sse.md (xop_phaddbw): Add "prefix", + "prefix_extra", and "mode" attributes. + (xop_phaddbd): Likewise. + (xop_phaddbq): Likewise. + (xop_phaddwd): Likewise. + (xop_phaddwq): Likewise. + (xop_phadddq): Likewise. + (xop_phsubbw): Likewise. + (xop_phsubwd): Likewise. + (xop_phsubdq): Likewise. + (xop_rotl3): Add "prefix" and "prefix_extra" attributes. + (xop_rotr3): Likewise. + (xop_frcz2): Likewise. + (*xop_vmfrcz2): Likewise. + (xop_vrotl3): Add "prefix" attribute. Change + "prefix_extra" to 1. + (xop_sha3): Likewise. + (xop_shl3): Likewise. + +2023-08-07 Jan Beulich + + * config/i386/sse.md + (*_eq3_1): Drop + "prefix_extra". + (avx512dq_vextract64x2_1_mask): Likewise. + (*avx512dq_vextract64x2_1): Likewise. + (avx512f_vextract32x4_1_mask): Likewise. + (*avx512f_vextract32x4_1): Likewise. + (vec_extract_lo__mask [AVX512 forms]): Likewise. + (vec_extract_lo_ [AVX512 forms]): Likewise. + (vec_extract_hi__mask [AVX512 forms]): Likewise. + (vec_extract_hi_ [AVX512 forms]): Likewise. + (@vec_extract_lo_ [AVX512 forms]): Likewise. + (@vec_extract_hi_ [AVX512 forms]): Likewise. + (vec_extract_lo_v64qi): Likewise. + (vec_extract_hi_v64qi): Likewise. + (*vec_widen_umult_even_v16si): Likewise. + (*vec_widen_smult_even_v16si): Likewise. + (*avx512f_3): Likewise. + (*vec_extractv4ti): Likewise. + (avx512bw_v32qiv32hi2): Likewise. + (avx512dq_broadcast_1): Likewise. + Add "length_immediate". + +2023-08-07 Jan Beulich + + * config/i386/i386.md (@rdrand): Add "prefix_0f". Drop + "prefix_extra". + (@rdseed): Likewise. + * config/i386/mmx.md (3 [smaxmin and umaxmin cases]): + Adjust "prefix_extra". + * config/i386/sse.md (@vec_set_0): Likewise. + (*sse4_1_3): Likewise. + (*avx2_eq3): Likewise. + (avx2_gt3): Likewise. + (_pinsr): Likewise. + (*vec_extract): Likewise. + (_movntdqa): Likewise. + +2023-08-07 Jan Beulich + + * config/i386/i386.md (rdbase): Add "prefix_0f" and + "prefix_rep". Drop "prefix_extra". + (wrbase): Likewise. + (ptwrite): Likewise. + +2023-08-07 Jan Beulich + + * config/i386/i386.md (isa): Move up. + (length_immediate): Handle "fma4". + (prefix): Handle "ssemuladd". + * config/i386/sse.md (*fma_fmadd_): Add "prefix" attribute. + (fma_fmadd_): + Likewise. + (_fmadd__mask): Likewise. + (_fmadd__mask3): Likewise. + (fma_fmsub_): + Likewise. + (_fmsub__mask): Likewise. + (_fmsub__mask3): Likewise. + (*fma_fnmadd_): Likewise. + (fma_fnmadd_): + Likewise. + (_fnmadd__mask): Likewise. + (_fnmadd__mask3): Likewise. + (fma_fnmsub_): + Likewise. + (_fnmsub__mask): Likewise. + (_fnmsub__mask3): Likewise. + (fma_fmaddsub_): + Likewise. + (_fmaddsub__mask): Likewise. + (_fmaddsub__mask3): Likewise. + (fma_fmsubadd_): + Likewise. + (_fmsubadd__mask): Likewise. + (_fmsubadd__mask3): Likewise. + (*fmai_fmadd_): Likewise. + (*fmai_fmsub_): Likewise. + (*fmai_fnmadd_): Likewise. + (*fmai_fnmsub_): Likewise. + (avx512f_vmfmadd__mask): Likewise. + (avx512f_vmfmadd__mask3): Likewise. + (avx512f_vmfmadd__maskz_1): Likewise. + (*avx512f_vmfmsub__mask): Likewise. + (avx512f_vmfmsub__mask3): Likewise. + (*avx512f_vmfmsub__maskz_1): Likewise. + (avx512f_vmfnmadd__mask): Likewise. + (avx512f_vmfnmadd__mask3): Likewise. + (avx512f_vmfnmadd__maskz_1): Likewise. + (*avx512f_vmfnmsub__mask): Likewise. + (*avx512f_vmfnmsub__mask3): Likewise. + (*avx512f_vmfnmsub__maskz_1): Likewise. + (*fma4i_vmfmadd_): Likewise. + (*fma4i_vmfmsub_): Likewise. + (*fma4i_vmfnmadd_): Likewise. + (*fma4i_vmfnmsub_): Likewise. + (fma__): Likewise. + (___mask): Likewise. + (avx512fp16_fma_sh_v8hf): + Likewise. + (avx512fp16_sh_v8hf_mask): Likewise. + (xop_p): Likewise. + (xop_pdql): Likewise. + (xop_pdqh): Likewise. + (xop_pwd): Likewise. + (xop_pwd): Likewise. + (fma___pair): Likewise. Add "mode" attribute. + +2023-08-07 Jan Beulich + + * config/i386/i386.md (length_immediate): Handle "sse4arg". + (prefix): Likewise. + (*xop_pcmov_): Add "mode" attribute. + * config/i386/mmx.md (*xop_maskcmp3): Drop "prefix_data16", + "prefix_rep", "prefix_extra", and "length_immediate" attributes. + (*xop_maskcmp_uns3): Likewise. Switch "type" to "sse4arg". + (*xop_pcmov_): Add "mode" attribute. + * config/i386/sse.md (xop_pcmov_): Add "mode" + attribute. + (xop_maskcmp3): Drop "prefix_data16", "prefix_rep", + "prefix_extra", and "length_immediate" attributes. + (xop_maskcmp_uns3): Likewise. Switch "type" to "sse4arg". + (xop_maskcmp_uns23): Drop "prefix_data16", "prefix_extra", + and "length_immediate" attributes. Switch "type" to "sse4arg". + (xop_pcom_tf3): Likewise. + (xop_vpermil23): Drop "length_immediate" attribute. + +2023-08-07 Jan Beulich + + * config/i386/i386.md (prefix_extra): Correct comment. Fold + cases yielding 2 into ones yielding 1. + +2023-08-07 Jan Hubicka + + PR tree-optimization/106293 + * tree-vect-loop-manip.cc (vect_loop_versioning): Fix profile update. + * tree-vect-loop.cc (vect_transform_loop): Likewise. + +2023-08-07 Andrew Pinski + + PR tree-optimization/96695 + * match.pd (min_value, max_value): Extend to + pointer types too. + 2023-08-06 Jan Hubicka * config/i386/cpuid.h (__get_cpuid_count, __get_cpuid_max): Add diff --git a/gcc/DATESTAMP b/gcc/DATESTAMP index b18ce65ab84d..0f5e059744b3 100644 --- a/gcc/DATESTAMP +++ b/gcc/DATESTAMP @@ -1 +1 @@ -20230807 +20230904 diff --git a/gcc/Makefile.in b/gcc/Makefile.in index a0fec5decc09..675b685522b6 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -55,6 +55,7 @@ MAKEOVERRIDES = # ------------------------------- build=@build@ +build_os=@build_os@ host=@host@ host_noncanonical=@host_noncanonical@ host_os=@host_os@ @@ -469,6 +470,7 @@ USER_H = $(srcdir)/ginclude/float.h \ $(srcdir)/ginclude/stdnoreturn.h \ $(srcdir)/ginclude/stdalign.h \ $(srcdir)/ginclude/stdatomic.h \ + $(srcdir)/ginclude/stdckdint.h \ $(EXTRA_HEADERS) USER_H_INC_NEXT_PRE = @user_headers_inc_next_pre@ @@ -895,7 +897,8 @@ OPTIONS_C_EXTRA = $(PRETTY_PRINT_H) BCONFIG_H = bconfig.h $(build_xm_file_list) CONFIG_H = config.h $(host_xm_file_list) TCONFIG_H = tconfig.h $(xm_file_list) -TM_P_H = tm_p.h $(tm_p_file_list) +# Some $(target)-protos.h depends on tree.h +TM_P_H = tm_p.h $(tm_p_file_list) $(TREE_H) TM_D_H = tm_d.h $(tm_d_file_list) TM_RUST_H = tm_rust.h $(tm_rust_file_list) GTM_H = tm.h $(tm_file_list) insn-constants.h @@ -996,7 +999,7 @@ GIMPLE_H = gimple.h gimple.def gsstruct.def $(VEC_H) \ $(GGC_H) $(BASIC_BLOCK_H) $(TREE_H) tree-ssa-operands.h \ tree-ssa-alias.h $(INTERNAL_FN_H) $(HASH_TABLE_H) is-a.h GCOV_IO_H = gcov-io.h version.h auto-host.h gcov-counter.def -RECOG_H = recog.h +RECOG_H = recog.h $(TREE_H) EMIT_RTL_H = emit-rtl.h FLAGS_H = flags.h flag-types.h $(OPTIONS_H) OPTIONS_H = options.h flag-types.h $(OPTIONS_H_EXTRA) @@ -1318,6 +1321,7 @@ ANALYZER_OBJS = \ analyzer/pending-diagnostic.o \ analyzer/program-point.o \ analyzer/program-state.o \ + analyzer/ranges.o \ analyzer/region.o \ analyzer/region-model.o \ analyzer/region-model-asm.o \ @@ -3036,8 +3040,8 @@ build/genhooks.o : genhooks.cc $(TARGET_DEF) $(C_TARGET_DEF) \ $(SYSTEM_H) errors.h build/genmddump.o : genmddump.cc $(RTL_BASE_H) $(BCONFIG_H) $(SYSTEM_H) \ $(CORETYPES_H) $(GTM_H) errors.h $(READ_MD_H) $(GENSUPPORT_H) -build/genmatch.o : genmatch.cc $(BCONFIG_H) $(SYSTEM_H) \ - $(CORETYPES_H) errors.h $(HASH_TABLE_H) hash-map.h $(GGC_H) is-a.h \ +build/genmatch.o : genmatch.cc $(BCONFIG_H) $(SYSTEM_H) $(CORETYPES_H) \ + errors.h $(HASH_TABLE_H) hash-map.h $(GGC_H) is-a.h ordered-hash-map.h \ tree.def builtins.def internal-fn.def case-cfn-macros.h $(CPPLIB_H) build/gencfn-macros.o : gencfn-macros.cc $(BCONFIG_H) $(SYSTEM_H) \ $(CORETYPES_H) errors.h $(HASH_TABLE_H) hash-set.h builtins.def \ @@ -3363,8 +3367,13 @@ stmp-fixinc: gsyslimits.h macro_list fixinc_list \ multi_dir=`echo $${ml} | sed -e 's/^[^;]*;//'`; \ fix_dir=include-fixed$${multi_dir}; \ if ! $(inhibit_libc) && test ! -d ${BUILD_SYSTEM_HEADER_DIR}; then \ - echo The directory that should contain system headers does not exist: >&2 ; \ + echo "The directory (BUILD_SYSTEM_HEADER_DIR) that should contain system headers does not exist:" >&2 ; \ echo " ${BUILD_SYSTEM_HEADER_DIR}" >&2 ; \ + case ${build_os} in \ + darwin*) \ + echo "(on Darwin this usually means you need to pass the --with-sysroot= flag to point to a valid MacOS SDK)" >&2; \ + ;; \ + esac; \ tooldir_sysinc=`echo "${gcc_tooldir}/sys-include" | sed -e :a -e "s,[^/]*/\.\.\/,," -e ta`; \ if test "x${BUILD_SYSTEM_HEADER_DIR}" = "x$${tooldir_sysinc}"; \ then sleep 1; else exit 1; fi; \ diff --git a/gcc/ada/ChangeLog b/gcc/ada/ChangeLog index 5a460e1f9d6b..c10629b1d5a5 100644 --- a/gcc/ada/ChangeLog +++ b/gcc/ada/ChangeLog @@ -1,3 +1,23 @@ +2023-08-07 Sheri Bernstein + + * libgnat/s-parame__qnx.adb: Refactor multiple returns. + +2023-08-07 Piotr Trojanek + + * libgnat/i-cstrin.ads (Value): Extend preconditions; adapt comment for + the package. + +2023-08-07 Yannick Moy + + * sem_res.adb (Resolve_Call): Always call Cannot_Inline so that + subprogram called is marked as not always inlined. + +2023-08-07 Javier Miranda + + * sem_res.adb (Resolve_Type_Conversion): Do not warn on conversion + to class-wide type on internally build helpers of class-wide + preconditions. + 2023-08-03 Sheri Bernstein * libgnat/s-aridou.adb: Add pragma to exempt Improper_Returns. diff --git a/gcc/analyzer/ChangeLog b/gcc/analyzer/ChangeLog index b1970a87a2f4..c9277bf9581b 100644 --- a/gcc/analyzer/ChangeLog +++ b/gcc/analyzer/ChangeLog @@ -1,3 +1,403 @@ +2023-09-01 benjamin priour + + PR analyzer/105948 + PR analyzer/94355 + * analyzer.h (is_placement_new_p): New declaration. + * call-details.cc + (call_details::deref_ptr_arg): New function. + Dereference the argument at given index if possible. + * call-details.h: Declaration of the above function. + * kf-lang-cp.cc (is_placement_new_p): Returns true if the gcall + is recognized as a placement new. + (kf_operator_delete::impl_call_post): Unbinding a region and its + descendents now poisons with POISON_KIND_DELETED. + (register_known_functions_lang_cp): Known function "operator + delete" is now registered only once independently of its number of + arguments. + * region-model.cc (region_model::eval_condition): Now + recursively calls itself if any of the operand is wrapped in a + cast. + * sm-malloc.cc (malloc_state_machine::on_stmt): + Add placement new recognition. + * svalue.cc (poison_kind_to_str): Wording for the new PK. + * svalue.h (enum poison_kind): Add value POISON_KIND_DELETED. + +2023-08-31 Francois-Xavier Coudert + + * kf.cc: Change spelling to macOS. + +2023-08-30 Eric Feng + + PR analyzer/107646 + * engine.cc (impl_region_model_context::warn): New optional + parameter. + * exploded-graph.h (class impl_region_model_context): Likewise. + * region-model.cc (region_model::pop_frame): New callback + feature for region_model::pop_frame. + * region-model.h (struct append_regions_cb_data): Likewise. + (class region_model): Likewise. + (class region_model_context): New optional parameter. + (class region_model_context_decorator): Likewise. + +2023-08-30 Francois-Xavier Coudert + + * region-model.cc: Define INCLUDE_ALGORITHM. + +2023-08-29 David Malcolm + + PR analyzer/99860 + * analyzer-selftests.cc (selftest::run_analyzer_selftests): Call + selftest::analyzer_ranges_cc_tests. + * analyzer-selftests.h (selftest::run_analyzer_selftests): New + decl. + * analyzer.opt (Wanalyzer-overlapping-buffers): New option. + * call-details.cc: Include "analyzer/ranges.h" and "make-unique.h". + (class overlapping_buffers): New. + (call_details::complain_about_overlap): New. + * call-details.h (call_details::complain_about_overlap): New decl. + * kf.cc (kf_memcpy_memmove::impl_call_pre): Call + cd.complain_about_overlap for memcpy and memcpy_chk. + (kf_strcat::impl_call_pre): Call cd.complain_about_overlap. + (kf_strcpy::impl_call_pre): Likewise. + * ranges.cc: New file. + * ranges.h: New file. + +2023-08-29 David Malcolm + + PR analyzer/105899 + * kf.cc (kf_strdup::impl_call_pre): Set size of + dynamically-allocated buffer. Simulate copying the string from + the source region to the new buffer. + +2023-08-27 benjamin priour + + PR analyzer/96395 + * analyzer.h (class known_function): Add virtual casts + to builtin_known_function. + (class builtin_known_function): New subclass of known_function + for builtins. + * kf.cc (class kf_alloca): Now derived from + builtin_known_function. + (class kf_calloc): Likewise. + (class kf_free): Likewise. + (class kf_malloc): Likewise. + (class kf_memcpy_memmove): Likewise. + (class kf_memset): Likewise. + (class kf_realloc): Likewise. + (class kf_strchr): Likewise. + (class kf_sprintf): Likewise. + (class kf_strcat): Likewise. + (class kf_strcpy): Likewise. + (class kf_strdup): Likewise. + (class kf_strlen): Likewise. + (class kf_strndup): Likewise. + (register_known_functions): Builtins are now registered as + known_functions by name rather than by their BUILTIN_CODE. + * known-function-manager.cc (get_normal_builtin): New overload. + * known-function-manager.h: New overload declaration. + * region-model.cc (region_model::get_builtin_kf): New function. + * region-model.h (class region_model): Add declaration of + get_builtin_kf. + * sm-fd.cc: For called recognized as builtins, use the + attributes of that builtin as defined in gcc/builtins.def + rather than the user's. + * sm-malloc.cc (malloc_state_machine::on_stmt): Likewise. + +2023-08-25 David Malcolm + + * access-diagram.cc (class string_region_spatial_item): Remove + assumption that the string is written to the start of the cluster. + +2023-08-24 David Malcolm + + PR analyzer/105899 + * call-details.cc + (call_details::check_for_null_terminated_string_arg): Split into + overloads, one taking just an arg_idx, the other a new + "include_terminator" param. + * call-details.h: Likewise. + * kf.cc (class kf_strcat): New. + (kf_strcpy::impl_call_pre): Update for change to + check_for_null_terminated_string_arg. + (register_known_functions): Register kf_strcat. + * region-model.cc + (region_model::check_for_null_terminated_string_arg): Split into + overloads, one taking just an arg_idx, the other a new + "include_terminator" param. When returning an svalue, handle + "include_terminator" being false by subtracting one. + * region-model.h + (region_model::check_for_null_terminated_string_arg): Split into + overloads, one taking just an arg_idx, the other a new + "include_terminator" param. + +2023-08-24 David Malcolm + + PR analyzer/105899 + * region-model.cc (fragment::has_null_terminator): Handle + SK_BITS_WITHIN. + +2023-08-24 David Malcolm + + PR analyzer/105899 + * region-model-manager.cc + (region_model_manager::get_or_create_initial_value): Simplify + INIT_VAL(ELEMENT_REG(STRING_REG), CONSTANT_SVAL) to + CONSTANT_SVAL(STRING[N]). + +2023-08-24 David Malcolm + + PR analyzer/105899 + * region-model.cc (fragment::has_null_terminator): Move STRING_CST + handling to fragment::string_cst_has_null_terminator; also use it to + handle INIT_VAL(STRING_REG). + (fragment::string_cst_has_null_terminator): New, from above. + +2023-08-24 David Malcolm + + * kf.cc (kf_memcpy_memmove::impl_call_pre): Reimplement using + region_model::copy_bytes. + * region-model.cc (region_model::read_bytes): New. + (region_model::copy_bytes): New. + * region-model.h (region_model::read_bytes): New decl. + (region_model::copy_bytes): New decl. + +2023-08-24 David Malcolm + + PR analyzer/105899 + * region-model.cc (region_model::get_string_size): Delete both. + * region-model.h (region_model::get_string_size): Delete both + decls. + +2023-08-24 David Malcolm + + PR analyzer/105899 + * kf.cc (kf_strcpy::impl_call_pre): Reimplement using + check_for_null_terminated_string_arg. + * region-model.cc (region_model::get_store_bytes): Shortcut + reading all of a string_region. + (region_model::scan_for_null_terminator): Use get_store_value for + the bytes rather than "unknown" when returning an unknown length. + (region_model::write_bytes): New. + * region-model.h (region_model::write_bytes): New decl. + +2023-08-24 David Malcolm + + PR analyzer/105899 + * region-model.cc (iterable_cluster::iterable_cluster): Add + symbolic binding keys to m_symbolic_bindings. + (iterable_cluster::has_symbolic_bindings_p): New. + (iterable_cluster::m_symbolic_bindings): New field. + (region_model::scan_for_null_terminator): Treat clusters with + symbolic bindings as having unknown strlen. + +2023-08-24 David Malcolm + + * engine.cc (impl_path_context::impl_path_context): Add logger + param. + (impl_path_context::bifurcate): Add log message. + (impl_path_context::terminate_path): Likewise. + (impl_path_context::m_logger): New field. + (exploded_graph::process_node): Pass logger to path_ctxt ctor. + +2023-08-22 David Malcolm + + PR analyzer/105899 + * kf-analyzer.cc (class kf_analyzer_get_strlen): Move to kf.cc. + (register_known_analyzer_functions): Use make_kf_strlen. + * kf.cc (class kf_strlen::impl_call_pre): Replace with + implementation of kf_analyzer_get_strlen from kf-analyzer.cc. + Handle "UNKNOWN" return from check_for_null_terminated_string_arg + by falling back to a conjured svalue. + (make_kf_strlen): New. + (register_known_functions): Use make_kf_strlen. + * known-function-manager.h (make_kf_strlen): New decl. + +2023-08-22 David Malcolm + + PR analyzer/105899 + * call-details.cc (call_details::call_details): New ctor. + * call-details.h (call_details::call_details): New ctor decl. + (struct call_arg_details): Move here from region-model.cc. + * region-model.cc (region_model::check_call_format_attr): New. + (region_model::check_call_args): Call it. + (struct call_arg_details): Move it to call-details.h. + * region-model.h (region_model::check_call_format_attr): New decl. + +2023-08-22 David Malcolm + + * kf.cc (class kf_fopen): New. + (register_known_functions): Register it. + +2023-08-22 David Malcolm + + PR analyzer/105899 + * analyzer.opt (Wanalyzer-unterminated-string): Delete. + * call-details.cc + (call_details::check_for_null_terminated_string_arg): Convert + return type from void to const svalue *. Add param "out_sval". + * call-details.h + (call_details::check_for_null_terminated_string_arg): Likewise. + * kf-analyzer.cc (kf_analyzer_get_strlen::impl_call_pre): Wire up + to result of check_for_null_terminated_string_arg. + * region-model.cc (get_strlen): Delete. + (class unterminated_string_arg): Delete. + (struct fragment): New. + (class iterable_cluster): New. + (region_model::get_store_bytes): New. + (get_tree_for_byte_offset): New. + (region_model::scan_for_null_terminator): New. + (region_model::check_for_null_terminated_string_arg): Convert + return type from void to const svalue *. Add param "out_sval". + Reimplement in terms of scan_for_null_terminator, dropping the + special-case for -Wanalyzer-unterminated-string. + * region-model.h (region_model::get_store_bytes): New decl. + (region_model::scan_for_null_terminator): New decl. + (region_model::check_for_null_terminated_string_arg): Convert + return type from void to const svalue *. Add param "out_sval". + * store.cc (concrete_binding::get_byte_range): New. + * store.h (concrete_binding::get_byte_range): New decl. + (store_manager::get_concrete_binding): New overload. + +2023-08-22 David Malcolm + + * region-model.cc (region_model_context_decorator::add_event): + Handle m_inner being NULL. + * region-model.h (class region_model_context_decorator): Likewise. + (annotating_context::warn): Likewise. + +2023-08-22 David Malcolm + + * diagnostic-manager.cc (saved_diagnostic::add_event): New. + (saved_diagnostic::add_any_saved_events): New. + (diagnostic_manager::add_event): New. + (dedupe_winners::emit_best): New. + (diagnostic_manager::emit_saved_diagnostic): Make "sd" param + non-const. Call saved_diagnostic::add_any_saved_events. + * diagnostic-manager.h (saved_diagnostic::add_event): New decl. + (saved_diagnostic::add_any_saved_events): New decl. + (saved_diagnostic::m_saved_events): New field. + (diagnostic_manager::add_event): New decl. + (diagnostic_manager::emit_saved_diagnostic): Make "sd" param + non-const. + * engine.cc (impl_region_model_context::add_event): New. + * exploded-graph.h (impl_region_model_context::add_event): New decl. + * region-model.cc + (noop_region_model_context::add_event): New. + (region_model_context_decorator::add_event): New. + * region-model.h (region_model_context::add_event): New vfunc. + (noop_region_model_context::add_event): New decl. + (region_model_context_decorator::add_event): New decl. + +2023-08-22 David Malcolm + + * region-model.cc + (class check_external_function_for_access_attr::annotating_ctxt): + Convert to an annotating_context. + * region-model.h (class note_adding_context): Rename to... + (class annotating_context): ...this, updating the "warn" method. + (note_adding_context::make_note): Replace with... + (annotating_context::add_annotations): ...this. + +2023-08-14 benjamin priour + + PR analyzer/110543 + * analyzer.opt: Add new option. + * diagnostic-manager.cc + (diagnostic_manager::prune_path): Call prune_system_headers. + (prune_frame): New function that deletes all events in a frame. + (diagnostic_manager::prune_system_headers): New function. + * diagnostic-manager.h: Add prune_system_headers declaration. + +2023-08-11 David Malcolm + + PR analyzer/105899 + * analyzer.opt (Wanalyzer-unterminated-string): New. + * call-details.cc + (call_details::check_for_null_terminated_string_arg): New. + * call-details.h + (call_details::check_for_null_terminated_string_arg): New decl. + * kf-analyzer.cc (class kf_analyzer_get_strlen): New. + (register_known_analyzer_functions): Register it. + * kf.cc (kf_error::impl_call_pre): Check that format arg is a + valid null-terminated string. + (kf_putenv::impl_call_pre): Likewise for the sole param. + (kf_strchr::impl_call_pre): Likewise for the first param. + (kf_strcpy::impl_call_pre): Likewise for the second param. + (kf_strdup::impl_call_pre): Likewise for the sole param. + * region-model.cc (get_strlen): New. + (struct call_arg_details): New. + (inform_about_expected_null_terminated_string_arg): New. + (class unterminated_string_arg): New. + (region_model::check_for_null_terminated_string_arg): New. + * region-model.h + (region_model::check_for_null_terminated_string_arg): New decl. + +2023-08-11 Eric Feng + + PR analyzer/107646 + * call-details.h: New function. + * region-model.cc (region_model::get_or_create_region_for_heap_alloc): + New optional parameters. + * region-model.h (class region_model): New optional parameters. + * sm-malloc.cc (on_realloc_with_move): New function. + (region_model::transition_ptr_sval_non_null): New function. + +2023-08-09 David Malcolm + + * analyzer.h (class pure_known_function_with_default_return): New + subclass. + * call-details.cc (const_fn_p): Move here from region-model.cc. + (maybe_get_const_fn_result): Likewise. + (get_result_size_in_bytes): Likewise. + (call_details::set_any_lhs_with_defaults): New function, based on + code in region_model::on_call_pre. + * call-details.h (call_details::set_any_lhs_with_defaults): New + decl. + * diagnostic-manager.cc + (diagnostic_manager::emit_saved_diagnostic): Log the index of the + saved_diagnostic. + * kf.cc (pure_known_function_with_default_return::impl_call_pre): + New. + (kf_memset::impl_call_pre): Set the LHS to the first param. + (kf_putenv::impl_call_pre): Call cd.set_any_lhs_with_defaults. + (kf_sprintf::impl_call_pre): Call cd.set_any_lhs_with_defaults. + (class kf_stack_restore): Derive from + pure_known_function_with_default_return. + (class kf_stack_save): Likewise. + (kf_strlen::impl_call_pre): Call cd.set_any_lhs_with_defaults. + * region-model-reachability.cc (reachable_regions::handle_sval): + Remove logic for symbolic regions for pointers. + * region-model.cc (region_model::canonicalize): Remove purging of + dynamic extents workaround for surplus values from + region_model::on_call_pre's default LHS code. + (const_fn_p): Move to call-details.cc. + (maybe_get_const_fn_result): Likewise. + (get_result_size_in_bytes): Likewise. + (region_model::update_for_nonzero_return): Call + cd.set_any_lhs_with_defaults. + (region_model::on_call_pre): Remove the assignment to the LHS of a + default return value, instead requiring all known_function + implementations to write to any LHS of the call. Use + cd.set_any_lhs_with_defaults on the non-kf paths. + * sm-fd.cc (kf_socket::outcome_of_socket::update_model): Use + cd.set_any_lhs_with_defaults when failing to get at fd state. + (kf_bind::outcome_of_bind::update_model): Likewise. + (kf_listen::outcome_of_listen::update_model): Likewise. + (kf_accept::outcome_of_accept::update_model): Likewise. + (kf_connect::outcome_of_connect::update_model): Likewise. + (kf_read::impl_call_pre): Use cd.set_any_lhs_with_defaults. + * sm-file.cc (class kf_stdio_output_fn): Derive from + pure_known_function_with_default_return. + (class kf_ferror): Likewise. + (class kf_fileno): Likewise. + (kf_fgets::impl_call_pre): Use cd.set_any_lhs_with_defaults. + (kf_read::impl_call_pre): Likewise. + (class kf_getc): Derive from + pure_known_function_with_default_return. + (class kf_getchar): Likewise. + * varargs.cc (kf_va_arg::impl_call_pre): Use + cd.set_any_lhs_with_defaults. + 2023-08-04 David Malcolm PR analyzer/110426 diff --git a/gcc/analyzer/access-diagram.cc b/gcc/analyzer/access-diagram.cc index d7b669a4e38e..a51d594b5b2c 100644 --- a/gcc/analyzer/access-diagram.cc +++ b/gcc/analyzer/access-diagram.cc @@ -1509,10 +1509,16 @@ public: out.add_all_bytes_in_range (m_actual_bits); else { - byte_range head_of_string (0, m_ellipsis_head_len); + byte_range bytes (0, 0); + bool valid = m_actual_bits.as_concrete_byte_range (&bytes); + gcc_assert (valid); + byte_range head_of_string (bytes.get_start_byte_offset (), + m_ellipsis_head_len); out.add_all_bytes_in_range (head_of_string); byte_range tail_of_string - (TREE_STRING_LENGTH (string_cst) - m_ellipsis_tail_len, + ((bytes.get_start_byte_offset () + + TREE_STRING_LENGTH (string_cst) + - m_ellipsis_tail_len), m_ellipsis_tail_len); out.add_all_bytes_in_range (tail_of_string); /* Adding the above pair of ranges will also effectively add @@ -1535,11 +1541,14 @@ public: tree string_cst = get_string_cst (); if (m_show_full_string) { - for (byte_offset_t byte_idx = bytes.get_start_byte_offset (); - byte_idx < bytes.get_next_byte_offset (); - byte_idx = byte_idx + 1) - add_column_for_byte (t, btm, sm, byte_idx, - byte_idx_table_y, byte_val_table_y); + for (byte_offset_t byte_idx_within_cluster + = bytes.get_start_byte_offset (); + byte_idx_within_cluster < bytes.get_next_byte_offset (); + byte_idx_within_cluster = byte_idx_within_cluster + 1) + add_column_for_byte + (t, btm, sm, byte_idx_within_cluster, + byte_idx_within_cluster - bytes.get_start_byte_offset (), + byte_idx_table_y, byte_val_table_y); if (m_show_utf8) { @@ -1566,10 +1575,13 @@ public: = decoded_char.m_start_byte - TREE_STRING_POINTER (string_cst); byte_size_t size_in_bytes = decoded_char.m_next_byte - decoded_char.m_start_byte; - byte_range bytes (start_byte_idx, size_in_bytes); + byte_range cluster_bytes_for_codepoint + (start_byte_idx + bytes.get_start_byte_offset (), + size_in_bytes); const table::rect_t code_point_table_rect - = btm.get_table_rect (&m_string_reg, bytes, + = btm.get_table_rect (&m_string_reg, + cluster_bytes_for_codepoint, utf8_code_point_table_y, 1); char buf[100]; sprintf (buf, "U+%04x", decoded_char.m_ch); @@ -1579,7 +1591,8 @@ public: if (show_unichars) { const table::rect_t character_table_rect - = btm.get_table_rect (&m_string_reg, bytes, + = btm.get_table_rect (&m_string_reg, + cluster_bytes_for_codepoint, utf8_character_table_y, 1); if (cpp_is_printable_char (decoded_char.m_ch)) t.set_cell_span (character_table_rect, @@ -1598,12 +1611,14 @@ public: { /* Head of string. */ for (int byte_idx = 0; byte_idx < m_ellipsis_head_len; byte_idx++) - add_column_for_byte (t, btm, sm, byte_idx, + add_column_for_byte (t, btm, sm, + byte_idx + bytes.get_start_byte_offset (), + byte_idx, byte_idx_table_y, byte_val_table_y); /* Ellipsis (two rows high). */ const byte_range ellipsis_bytes - (m_ellipsis_head_len, + (m_ellipsis_head_len + bytes.get_start_byte_offset (), TREE_STRING_LENGTH (string_cst) - (m_ellipsis_head_len + m_ellipsis_tail_len)); const table::rect_t table_rect @@ -1616,7 +1631,9 @@ public: = (TREE_STRING_LENGTH (string_cst) - m_ellipsis_tail_len); byte_idx < TREE_STRING_LENGTH (string_cst); byte_idx++) - add_column_for_byte (t, btm, sm, byte_idx, + add_column_for_byte (t, btm, sm, + byte_idx + bytes.get_start_byte_offset (), + byte_idx, byte_idx_table_y, byte_val_table_y); } @@ -1660,25 +1677,27 @@ private: void add_column_for_byte (table &t, const bit_to_table_map &btm, style_manager &sm, - const byte_offset_t byte_idx, + const byte_offset_t byte_idx_within_cluster, + const byte_offset_t byte_idx_within_string, const int byte_idx_table_y, const int byte_val_table_y) const { tree string_cst = get_string_cst (); - gcc_assert (byte_idx >= 0); - gcc_assert (byte_idx < TREE_STRING_LENGTH (string_cst)); + gcc_assert (byte_idx_within_string >= 0); + gcc_assert (byte_idx_within_string < TREE_STRING_LENGTH (string_cst)); - const byte_range bytes (byte_idx, 1); + const byte_range bytes (byte_idx_within_cluster, 1); if (1) // show_byte_indices { const table::rect_t idx_table_rect = btm.get_table_rect (&m_string_reg, bytes, byte_idx_table_y, 1); t.set_cell_span (idx_table_rect, fmt_styled_string (sm, "[%li]", - byte_idx.ulow ())); + byte_idx_within_string.ulow ())); } - char byte_val = TREE_STRING_POINTER (string_cst)[byte_idx.ulow ()]; + char byte_val + = TREE_STRING_POINTER (string_cst)[byte_idx_within_string.ulow ()]; const table::rect_t val_table_rect = btm.get_table_rect (&m_string_reg, bytes, byte_val_table_y, 1); table_cell_content content (make_cell_content_for_byte (sm, byte_val)); diff --git a/gcc/analyzer/analyzer-selftests.cc b/gcc/analyzer/analyzer-selftests.cc index 63b8cdfa1369..d06b4c374430 100644 --- a/gcc/analyzer/analyzer-selftests.cc +++ b/gcc/analyzer/analyzer-selftests.cc @@ -55,6 +55,7 @@ run_analyzer_selftests () analyzer_function_set_cc_tests (); analyzer_program_point_cc_tests (); analyzer_program_state_cc_tests (); + analyzer_ranges_cc_tests (); analyzer_region_model_cc_tests (); analyzer_sm_file_cc_tests (); analyzer_sm_signal_cc_tests (); diff --git a/gcc/analyzer/analyzer-selftests.h b/gcc/analyzer/analyzer-selftests.h index d848ed9bc941..de494bfceae8 100644 --- a/gcc/analyzer/analyzer-selftests.h +++ b/gcc/analyzer/analyzer-selftests.h @@ -38,6 +38,7 @@ extern void analyzer_constraint_manager_cc_tests (); extern void analyzer_function_set_cc_tests (); extern void analyzer_program_point_cc_tests (); extern void analyzer_program_state_cc_tests (); +extern void analyzer_ranges_cc_tests (); extern void analyzer_region_model_cc_tests (); extern void analyzer_sm_file_cc_tests (); extern void analyzer_sm_signal_cc_tests (); diff --git a/gcc/analyzer/analyzer.h b/gcc/analyzer/analyzer.h index 579517c23e61..208b85026fc1 100644 --- a/gcc/analyzer/analyzer.h +++ b/gcc/analyzer/analyzer.h @@ -128,6 +128,10 @@ struct interesting_t; class feasible_node; +class known_function; + class builtin_known_function; + class internal_known_function; + /* Forward decls of functions. */ extern void dump_tree (pretty_printer *pp, tree t); @@ -279,6 +283,24 @@ public: { return; } + + virtual const builtin_known_function * + dyn_cast_builtin_kf () const { return NULL; } +}; + +/* Subclass of known_function for builtin functions. */ + +class builtin_known_function : public known_function +{ +public: + virtual enum built_in_function builtin_code () const = 0; + tree builtin_decl () const { + gcc_assert (builtin_code () < END_BUILTINS); + return builtin_info[builtin_code ()].decl; + } + + const builtin_known_function * + dyn_cast_builtin_kf () const final override { return this; } }; /* Subclass of known_function for IFN_* functions. */ @@ -293,6 +315,16 @@ public: } }; +/* Abstract subclass of known_function that merely sets the return + value of the function (based on function attributes), and assumes + it has no side-effects. */ + +class pure_known_function_with_default_return : public known_function +{ +public: + void impl_call_pre (const call_details &cd) const override; +}; + extern void register_known_functions (known_function_manager &mgr); extern void register_known_analyzer_functions (known_function_manager &kfm); extern void register_known_fd_functions (known_function_manager &kfm); @@ -391,6 +423,7 @@ extern bool is_std_named_call_p (const_tree fndecl, const char *funcname, const gcall *call, unsigned int num_args); extern bool is_setjmp_call_p (const gcall *call); extern bool is_longjmp_call_p (const gcall *call); +extern bool is_placement_new_p (const gcall *call); extern const char *get_user_facing_name (const gcall *call); diff --git a/gcc/analyzer/analyzer.opt b/gcc/analyzer/analyzer.opt index 2760aaa81517..25df89d9c06b 100644 --- a/gcc/analyzer/analyzer.opt +++ b/gcc/analyzer/analyzer.opt @@ -154,6 +154,10 @@ Wanalyzer-out-of-bounds Common Var(warn_analyzer_out_of_bounds) Init(1) Warning Warn about code paths in which a write or read to a buffer is out-of-bounds. +Wanalyzer-overlapping-buffers +Common Var(warn_analyzer_overlapping_buffers) Init(1) Warning +Warn about code paths in which undefined behavior would occur due to overlapping buffers. + Wanalyzer-possible-null-argument Common Var(warn_analyzer_possible_null_argument) Init(1) Warning Warn about code paths in which a possibly-NULL value is passed to a must-not-be-NULL function argument. @@ -290,6 +294,10 @@ fanalyzer-transitivity Common Var(flag_analyzer_transitivity) Init(0) Enable transitivity of constraints during analysis. +fanalyzer-show-events-in-system-headers +Common Var(flag_analyzer_show_events_in_system_headers) Init(0) +Show events within system headers in analyzer execution paths. + fanalyzer-call-summaries Common Var(flag_analyzer_call_summaries) Init(0) Approximate the effect of function calls to simplify analysis. diff --git a/gcc/analyzer/call-details.cc b/gcc/analyzer/call-details.cc index 793317eaa026..9480f037eaac 100644 --- a/gcc/analyzer/call-details.cc +++ b/gcc/analyzer/call-details.cc @@ -34,8 +34,10 @@ along with GCC; see the file COPYING3. If not see #include "gimple-pretty-print.h" #include "analyzer/region-model.h" #include "analyzer/call-details.h" +#include "analyzer/ranges.h" #include "stringpool.h" #include "attribs.h" +#include "make-unique.h" #if ENABLE_ANALYZER @@ -58,6 +60,16 @@ call_details::call_details (const gcall *call, region_model *model, } } +/* call_details's ctor: copy CD, but override the context, + using CTXT instead. */ + +call_details::call_details (const call_details &cd, + region_model_context *ctxt) +{ + *this = cd; + m_ctxt = ctxt; +} + /* Get the manager from m_model. */ region_model_manager * @@ -105,6 +117,135 @@ call_details::maybe_set_lhs (const svalue *result) const return false; } +/* Return true if CD is known to be a call to a function with + __attribute__((const)). */ + +static bool +const_fn_p (const call_details &cd) +{ + tree fndecl = cd.get_fndecl_for_call (); + if (!fndecl) + return false; + gcc_assert (DECL_P (fndecl)); + return TREE_READONLY (fndecl); +} + +/* If this CD is known to be a call to a function with + __attribute__((const)), attempt to get a const_fn_result_svalue + based on the arguments, or return NULL otherwise. */ + +static const svalue * +maybe_get_const_fn_result (const call_details &cd) +{ + if (!const_fn_p (cd)) + return NULL; + + unsigned num_args = cd.num_args (); + if (num_args > const_fn_result_svalue::MAX_INPUTS) + /* Too many arguments. */ + return NULL; + + auto_vec inputs (num_args); + for (unsigned arg_idx = 0; arg_idx < num_args; arg_idx++) + { + const svalue *arg_sval = cd.get_arg_svalue (arg_idx); + if (!arg_sval->can_have_associated_state_p ()) + return NULL; + inputs.quick_push (arg_sval); + } + + region_model_manager *mgr = cd.get_manager (); + const svalue *sval + = mgr->get_or_create_const_fn_result_svalue (cd.get_lhs_type (), + cd.get_fndecl_for_call (), + inputs); + return sval; +} + +/* Look for attribute "alloc_size" on the called function and, if found, + return a symbolic value of type size_type_node for the allocation size + based on the call's parameters. + Otherwise, return null. */ + +static const svalue * +get_result_size_in_bytes (const call_details &cd) +{ + const tree attr = cd.lookup_function_attribute ("alloc_size"); + if (!attr) + return nullptr; + + const tree atval_1 = TREE_VALUE (attr); + if (!atval_1) + return nullptr; + + unsigned argidx1 = TREE_INT_CST_LOW (TREE_VALUE (atval_1)) - 1; + if (cd.num_args () <= argidx1) + return nullptr; + + const svalue *sval_arg1 = cd.get_arg_svalue (argidx1); + + if (const tree atval_2 = TREE_CHAIN (atval_1)) + { + /* Two arguments. */ + unsigned argidx2 = TREE_INT_CST_LOW (TREE_VALUE (atval_2)) - 1; + if (cd.num_args () <= argidx2) + return nullptr; + const svalue *sval_arg2 = cd.get_arg_svalue (argidx2); + /* TODO: ideally we shouldn't need this cast here; + see PR analyzer/110902. */ + return cd.get_manager ()->get_or_create_cast + (size_type_node, + cd.get_manager ()->get_or_create_binop (size_type_node, + MULT_EXPR, + sval_arg1, sval_arg2)); + } + else + /* Single argument. */ + return cd.get_manager ()->get_or_create_cast (size_type_node, sval_arg1); +} + +/* If this call has an LHS, assign a value to it based on attributes + of the function: + - if __attribute__((const)), use a const_fn_result_svalue, + - if __attribute__((malloc)), use a heap-allocated region with + unknown content + - otherwise, use a conjured_svalue. + + If __attribute__((alloc_size), set the dynamic extents on the region + pointed to. */ + +void +call_details::set_any_lhs_with_defaults () const +{ + if (!m_lhs_region) + return; + + const svalue *sval = maybe_get_const_fn_result (*this); + if (!sval) + { + region_model_manager *mgr = get_manager (); + if (lookup_function_attribute ("malloc")) + { + const region *new_reg + = m_model->get_or_create_region_for_heap_alloc (NULL, m_ctxt); + m_model->mark_region_as_unknown (new_reg, NULL); + sval = mgr->get_ptr_svalue (get_lhs_type (), new_reg); + } + else + /* For the common case of functions without __attribute__((const)), + use a conjured value, and purge any prior state involving that + value (in case this is in a loop). */ + sval = get_or_create_conjured_svalue (m_lhs_region); + if (const svalue *size_in_bytes = get_result_size_in_bytes (*this)) + { + const region *reg + = m_model->deref_rvalue (sval, NULL_TREE, m_ctxt, false); + m_model->set_dynamic_extents (reg, size_in_bytes, m_ctxt); + } + } + maybe_set_lhs (sval); +} + /* Return the number of arguments used by the call statement. */ unsigned @@ -154,6 +295,17 @@ call_details::get_arg_svalue (unsigned idx) const return m_model->get_rvalue (arg, m_ctxt); } +/* If argument IDX's svalue at the callsite is of pointer type, + return the region it points to. + Otherwise return NULL. */ + +const region * +call_details::deref_ptr_arg (unsigned idx) const +{ + const svalue *ptr_sval = get_arg_svalue (idx); + return m_model->deref_rvalue (ptr_sval, get_arg_tree (idx), m_ctxt); +} + /* Attempt to get the string literal for argument IDX, or return NULL otherwise. For use when implementing "__analyzer_*" functions that take @@ -247,6 +399,129 @@ call_details::lookup_function_attribute (const char *attr_name) const return lookup_attribute (attr_name, TYPE_ATTRIBUTES (allocfntype)); } +void +call_details::check_for_null_terminated_string_arg (unsigned arg_idx) const +{ + check_for_null_terminated_string_arg (arg_idx, false, nullptr); +} + +const svalue * +call_details:: +check_for_null_terminated_string_arg (unsigned arg_idx, + bool include_terminator, + const svalue **out_sval) const +{ + region_model *model = get_model (); + return model->check_for_null_terminated_string_arg (*this, + arg_idx, + include_terminator, + out_sval); +} + +/* A subclass of pending_diagnostic for complaining about overlapping + buffers. */ + +class overlapping_buffers +: public pending_diagnostic_subclass +{ +public: + overlapping_buffers (tree fndecl) + : m_fndecl (fndecl) + { + } + + const char *get_kind () const final override + { + return "overlapping_buffers"; + } + + bool operator== (const overlapping_buffers &other) const + { + return m_fndecl == other.m_fndecl; + } + + int get_controlling_option () const final override + { + return OPT_Wanalyzer_overlapping_buffers; + } + + bool emit (rich_location *rich_loc, logger *) final override + { + auto_diagnostic_group d; + + bool warned; + warned = warning_at (rich_loc, get_controlling_option (), + "overlapping buffers passed as arguments to %qD", + m_fndecl); + + // TODO: draw a picture? + + if (warned) + inform (DECL_SOURCE_LOCATION (m_fndecl), + "the behavior of %qD is undefined for overlapping buffers", + m_fndecl); + + return warned; + } + + label_text describe_final_event (const evdesc::final_event &ev) final override + { + return ev.formatted_print + ("overlapping buffers passed as arguments to %qD", + m_fndecl); + } + +private: + tree m_fndecl; +}; + + +/* Check if the buffers pointed to by arguments ARG_IDX_A and ARG_IDX_B + (zero-based) overlap, when considering them both to be of size + NUM_BYTES_READ_SVAL. + + If they do overlap, complain to the context. */ + +void +call_details::complain_about_overlap (unsigned arg_idx_a, + unsigned arg_idx_b, + const svalue *num_bytes_read_sval) const +{ + region_model_context *ctxt = get_ctxt (); + if (!ctxt) + return; + + region_model *model = get_model (); + region_model_manager *mgr = model->get_manager (); + + const svalue *arg_a_ptr_sval = get_arg_svalue (arg_idx_a); + if (arg_a_ptr_sval->get_kind () == SK_UNKNOWN) + return; + const region *arg_a_reg = model->deref_rvalue (arg_a_ptr_sval, + get_arg_tree (arg_idx_a), + ctxt); + const svalue *arg_b_ptr_sval = get_arg_svalue (arg_idx_b); + if (arg_b_ptr_sval->get_kind () == SK_UNKNOWN) + return; + const region *arg_b_reg = model->deref_rvalue (arg_b_ptr_sval, + get_arg_tree (arg_idx_b), + ctxt); + if (arg_a_reg->get_base_region () != arg_b_reg->get_base_region ()) + return; + + /* Are they within NUM_BYTES_READ_SVAL of each other? */ + symbolic_byte_range byte_range_a (arg_a_reg->get_offset (mgr), + num_bytes_read_sval, + *mgr); + symbolic_byte_range byte_range_b (arg_b_reg->get_offset (mgr), + num_bytes_read_sval, + *mgr); + if (!byte_range_a.intersection (byte_range_b, *model).is_true ()) + return; + + ctxt->warn (make_unique (get_fndecl_for_call ())); +} + } // namespace ana #endif /* #if ENABLE_ANALYZER */ diff --git a/gcc/analyzer/call-details.h b/gcc/analyzer/call-details.h index 25ea55461825..976517bdab49 100644 --- a/gcc/analyzer/call-details.h +++ b/gcc/analyzer/call-details.h @@ -30,6 +30,7 @@ class call_details public: call_details (const gcall *call, region_model *model, region_model_context *ctxt); + call_details (const call_details &cd, region_model_context *ctxt); region_model *get_model () const { return m_model; } region_model_manager *get_manager () const; @@ -41,6 +42,7 @@ public: const region *get_lhs_region () const { return m_lhs_region; } bool maybe_set_lhs (const svalue *result) const; + void set_any_lhs_with_defaults () const; unsigned num_args () const; bool arg_is_pointer_p (unsigned idx) const @@ -48,6 +50,10 @@ public: return POINTER_TYPE_P (get_arg_type (idx)); } bool arg_is_size_p (unsigned idx) const; + bool arg_is_integral_p (unsigned idx) const + { + return INTEGRAL_TYPE_P (get_arg_type (idx)); + } const gcall *get_call_stmt () const { return m_call; } location_t get_location () const; @@ -55,6 +61,7 @@ public: tree get_arg_tree (unsigned idx) const; tree get_arg_type (unsigned idx) const; const svalue *get_arg_svalue (unsigned idx) const; + const region *deref_ptr_arg (unsigned idx) const; const char *get_arg_string_literal (unsigned idx) const; tree get_fndecl_for_call () const; @@ -66,6 +73,18 @@ public: tree lookup_function_attribute (const char *attr_name) const; + void + check_for_null_terminated_string_arg (unsigned arg_idx) const; + const svalue * + check_for_null_terminated_string_arg (unsigned arg_idx, + bool include_terminator, + const svalue **out_sval) const; + + void + complain_about_overlap (unsigned arg_idx_a, + unsigned arg_idx_b, + const svalue *num_bytes_read_sval) const; + private: const gcall *m_call; region_model *m_model; @@ -74,6 +93,35 @@ private: const region *m_lhs_region; }; +/* A bundle of information about a problematic argument at a callsite + for use by pending_diagnostic subclasses for reporting and + for deduplication. */ + +struct call_arg_details +{ +public: + call_arg_details (const call_details &cd, unsigned arg_idx) + : m_call (cd.get_call_stmt ()), + m_called_fndecl (cd.get_fndecl_for_call ()), + m_arg_idx (arg_idx), + m_arg_expr (cd.get_arg_tree (arg_idx)) + { + } + + bool operator== (const call_arg_details &other) const + { + return (m_call == other.m_call + && m_called_fndecl == other.m_called_fndecl + && m_arg_idx == other.m_arg_idx + && pending_diagnostic::same_tree_p (m_arg_expr, other.m_arg_expr)); + } + + const gcall *m_call; + tree m_called_fndecl; + unsigned m_arg_idx; // 0-based + tree m_arg_expr; +}; + } // namespace ana #endif /* GCC_ANALYZER_CALL_DETAILS_H */ diff --git a/gcc/analyzer/diagnostic-manager.cc b/gcc/analyzer/diagnostic-manager.cc index cfca305d5528..10fea486b8c8 100644 --- a/gcc/analyzer/diagnostic-manager.cc +++ b/gcc/analyzer/diagnostic-manager.cc @@ -23,6 +23,7 @@ along with GCC; see the file COPYING3. If not see #include "system.h" #include "coretypes.h" #include "tree.h" +#include "input.h" #include "pretty-print.h" #include "gcc-rich-location.h" #include "gimple-pretty-print.h" @@ -720,6 +721,15 @@ saved_diagnostic::add_note (std::unique_ptr pn) m_notes.safe_push (pn.release ()); } +/* Add EVENT to this diagnostic. */ + +void +saved_diagnostic::add_event (std::unique_ptr event) +{ + gcc_assert (event); + m_saved_events.safe_push (event.release ()); +} + /* Return a new json::object of the form {"sm": optional str, "enode": int, @@ -889,6 +899,19 @@ saved_diagnostic::supercedes_p (const saved_diagnostic &other) const return m_d->supercedes_p (*other.m_d); } +/* Move any saved checker_events from this saved_diagnostic to + the end of DST_PATH. */ + +void +saved_diagnostic::add_any_saved_events (checker_path &dst_path) +{ + for (auto &event : m_saved_events) + { + dst_path.add_event (std::unique_ptr (event)); + event = nullptr; + } +} + /* Emit any pending notes owned by this diagnostic. */ void @@ -1056,6 +1079,20 @@ diagnostic_manager::add_note (std::unique_ptr pn) sd->add_note (std::move (pn)); } +/* Add EVENT to the most recent saved_diagnostic. */ + +void +diagnostic_manager::add_event (std::unique_ptr event) +{ + LOG_FUNC (get_logger ()); + gcc_assert (event); + + /* Get most recent saved_diagnostic. */ + gcc_assert (m_saved_diagnostics.length () > 0); + saved_diagnostic *sd = m_saved_diagnostics[m_saved_diagnostics.length () - 1]; + sd->add_event (std::move (event)); +} + /* Return a new json::object of the form {"diagnostics" : [obj for saved_diagnostic]}. */ @@ -1307,7 +1344,7 @@ public: { saved_diagnostic **slot = m_map.get (key); gcc_assert (*slot); - const saved_diagnostic *sd = *slot; + saved_diagnostic *sd = *slot; dm->emit_saved_diagnostic (eg, *sd); } } @@ -1369,10 +1406,11 @@ diagnostic_manager::emit_saved_diagnostics (const exploded_graph &eg) void diagnostic_manager::emit_saved_diagnostic (const exploded_graph &eg, - const saved_diagnostic &sd) + saved_diagnostic &sd) { LOG_SCOPE (get_logger ()); - log ("sd: %qs at SN: %i", sd.m_d->get_kind (), sd.m_snode->m_index); + log ("sd[%i]: %qs at SN: %i", + sd.get_index (), sd.m_d->get_kind (), sd.m_snode->m_index); log ("num dupes: %i", sd.get_num_dupes ()); pretty_printer *pp = global_dc->printer->clone (); @@ -1393,6 +1431,11 @@ diagnostic_manager::emit_saved_diagnostic (const exploded_graph &eg, /* Now prune it to just cover the most pertinent events. */ prune_path (&emission_path, sd.m_sm, sd.m_sval, sd.m_state); + /* Add any saved events to the path, giving contextual information + about what the analyzer was simulating as the diagnostic was + generated. These don't get pruned, as they are probably pertinent. */ + sd.add_any_saved_events (emission_path); + /* Add a final event to the path, covering the diagnostic itself. We use the final enode from the epath, which might be different from the sd.m_enode, as the dedupe code doesn't care about enodes, just @@ -2281,6 +2324,8 @@ diagnostic_manager::prune_path (checker_path *path, path->maybe_log (get_logger (), "path"); prune_for_sm_diagnostic (path, sm, sval, state); prune_interproc_events (path); + if (! flag_analyzer_show_events_in_system_headers) + prune_system_headers (path); consolidate_conditions (path); finish_pruning (path); path->maybe_log (get_logger (), "pruned"); @@ -2667,6 +2712,99 @@ diagnostic_manager::prune_interproc_events (checker_path *path) const while (changed); } +/* Remove everything within [call point, IDX]. For consistency, + IDX should represent the return event of the frame to delete, + or if there is none it should be the last event of the frame. + After this function, IDX designates the event prior to calling + this frame. */ + +static void +prune_frame (checker_path *path, int &idx) +{ + gcc_assert (idx >= 0); + int nesting = 1; + if (path->get_checker_event (idx)->is_return_p ()) + nesting = 0; + do + { + if (path->get_checker_event (idx)->is_call_p ()) + nesting--; + else if (path->get_checker_event (idx)->is_return_p ()) + nesting++; + + path->delete_event (idx--); + } while (idx >= 0 && nesting != 0); +} + +/* This function is called when fanalyzer-show-events-in-system-headers + is disabled and will prune the diagnostic of all events within a + system header, only keeping the entry and exit events to the header. + This should be called after diagnostic_manager::prune_interproc_events + so that sucessive events [system header call, system header return] + are preserved thereafter. + + Given a diagnostics path diving into a system header in the form + [ + prefix events..., + system header call, + system header entry, + events within system headers..., + system header return, + suffix events... + ] + + then transforms it into + [ + prefix events..., + system header call, + system header return, + suffix events... + ]. */ + +void +diagnostic_manager::prune_system_headers (checker_path *path) const +{ + int idx = (signed)path->num_events () - 1; + while (idx >= 0) + { + const checker_event *event = path->get_checker_event (idx); + /* Prune everything between + [..., system entry, (...), system return, ...]. */ + if (event->is_return_p () + && in_system_header_at (event->get_location ())) + { + int ret_idx = idx; + prune_frame (path, idx); + + if (get_logger ()) + { + log ("filtering system headers events %i-%i:", + idx, ret_idx); + } + // Delete function entry within system headers. + if (idx >= 0) + { + event = path->get_checker_event (idx); + if (event->is_function_entry_p () + && in_system_header_at (event->get_location ())) + { + if (get_logger ()) + { + label_text desc (event->get_desc (false)); + log ("filtering event %i:" + "system header entry event: %s", + idx, desc.get ()); + } + + path->delete_event (idx); + } + } + } + + idx--; + } +} + /* Return true iff event IDX within PATH is on the same line as REF_EXP_LOC. */ static bool diff --git a/gcc/analyzer/diagnostic-manager.h b/gcc/analyzer/diagnostic-manager.h index 9b3e903fc5d9..413ab0c90b14 100644 --- a/gcc/analyzer/diagnostic-manager.h +++ b/gcc/analyzer/diagnostic-manager.h @@ -42,6 +42,7 @@ public: bool operator== (const saved_diagnostic &other) const; void add_note (std::unique_ptr pn); + void add_event (std::unique_ptr event); json::object *to_json () const; @@ -64,6 +65,8 @@ public: bool supercedes_p (const saved_diagnostic &other) const; + void add_any_saved_events (checker_path &dst_path); + void emit_any_notes () const; //private: @@ -87,6 +90,12 @@ private: auto_vec m_duplicates; auto_delete_vec m_notes; + + /* Optionally: additional context-dependent events to be emitted + immediately before the warning_event, giving more details of what + operation was being simulated when a diagnostic was saved + e.g. "looking for null terminator in param 2 of 'foo'". */ + auto_delete_vec m_saved_events; }; class path_builder; @@ -124,11 +133,12 @@ public: std::unique_ptr d); void add_note (std::unique_ptr pn); + void add_event (std::unique_ptr event); void emit_saved_diagnostics (const exploded_graph &eg); void emit_saved_diagnostic (const exploded_graph &eg, - const saved_diagnostic &sd); + saved_diagnostic &sd); unsigned get_num_diagnostics () const { @@ -180,6 +190,7 @@ private: state_machine::state_t state) const; void update_for_unsuitable_sm_exprs (tree *expr) const; void prune_interproc_events (checker_path *path) const; + void prune_system_headers (checker_path *path) const; void consolidate_conditions (checker_path *path) const; void finish_pruning (checker_path *path) const; diff --git a/gcc/analyzer/engine.cc b/gcc/analyzer/engine.cc index 61685f43fba0..736a41ecdaf8 100644 --- a/gcc/analyzer/engine.cc +++ b/gcc/analyzer/engine.cc @@ -115,10 +115,12 @@ impl_region_model_context (program_state *state, } bool -impl_region_model_context::warn (std::unique_ptr d) +impl_region_model_context::warn (std::unique_ptr d, + const stmt_finder *custom_finder) { LOG_FUNC (get_logger ()); - if (m_stmt == NULL && m_stmt_finder == NULL) + auto curr_stmt_finder = custom_finder ? custom_finder : m_stmt_finder; + if (m_stmt == NULL && curr_stmt_finder == NULL) { if (get_logger ()) get_logger ()->log ("rejecting diagnostic: no stmt"); @@ -129,7 +131,7 @@ impl_region_model_context::warn (std::unique_ptr d) bool terminate_path = d->terminate_path_p (); if (m_eg->get_diagnostic_manager ().add_diagnostic (m_enode_for_diag, m_enode_for_diag->get_supernode (), - m_stmt, m_stmt_finder, std::move (d))) + m_stmt, curr_stmt_finder, std::move (d))) { if (m_path_ctxt && terminate_path @@ -149,6 +151,14 @@ impl_region_model_context::add_note (std::unique_ptr pn) m_eg->get_diagnostic_manager ().add_note (std::move (pn)); } +void +impl_region_model_context::add_event (std::unique_ptr event) +{ + LOG_FUNC (get_logger ()); + if (m_eg) + m_eg->get_diagnostic_manager ().add_event (std::move (event)); +} + void impl_region_model_context::on_svalue_leak (const svalue *sval) @@ -3840,8 +3850,10 @@ exploded_graph::maybe_create_dynamic_call (const gcall *call, class impl_path_context : public path_context { public: - impl_path_context (const program_state *cur_state) + impl_path_context (const program_state *cur_state, + logger *logger) : m_cur_state (cur_state), + m_logger (logger), m_terminate_path (false) { } @@ -3860,6 +3872,9 @@ public: void bifurcate (std::unique_ptr info) final override { + if (m_logger) + m_logger->log ("bifurcating path"); + if (m_state_at_bifurcation) /* Verify that the state at bifurcation is consistent when we split into multiple out-edges. */ @@ -3876,6 +3891,8 @@ public: void terminate_path () final override { + if (m_logger) + m_logger->log ("terminating path"); m_terminate_path = true; } @@ -3892,6 +3909,8 @@ public: private: const program_state *m_cur_state; + logger *m_logger; + /* Lazily-created copy of the state before the split. */ std::unique_ptr m_state_at_bifurcation; @@ -4036,7 +4055,7 @@ exploded_graph::process_node (exploded_node *node) exactly one stmt, the one that caused the change. */ program_state next_state (state); - impl_path_context path_ctxt (&next_state); + impl_path_context path_ctxt (&next_state, logger); uncertainty_t uncertainty; const supernode *snode = point.get_supernode (); diff --git a/gcc/analyzer/exploded-graph.h b/gcc/analyzer/exploded-graph.h index 4a4ef9d12b48..6e9a5ef58c7d 100644 --- a/gcc/analyzer/exploded-graph.h +++ b/gcc/analyzer/exploded-graph.h @@ -56,8 +56,10 @@ class impl_region_model_context : public region_model_context uncertainty_t *uncertainty, logger *logger = NULL); - bool warn (std::unique_ptr d) final override; + bool warn (std::unique_ptr d, + const stmt_finder *custom_finder = NULL) final override; void add_note (std::unique_ptr pn) final override; + void add_event (std::unique_ptr event) final override; void on_svalue_leak (const svalue *) override; void on_liveness_change (const svalue_set &live_svalues, const region_model *model) final override; @@ -106,6 +108,7 @@ class impl_region_model_context : public region_model_context std::unique_ptr *out_sm_context) override; const gimple *get_stmt () const override { return m_stmt; } + const exploded_graph *get_eg () const override { return m_eg; } exploded_graph *m_eg; log_user m_logger; diff --git a/gcc/analyzer/kf-analyzer.cc b/gcc/analyzer/kf-analyzer.cc index 5aed007d6ead..7ae598a89123 100644 --- a/gcc/analyzer/kf-analyzer.cc +++ b/gcc/analyzer/kf-analyzer.cc @@ -379,6 +379,7 @@ register_known_analyzer_functions (known_function_manager &kfm) kfm.add ("__analyzer_eval", make_unique ()); kfm.add ("__analyzer_get_unknown_ptr", make_unique ()); + kfm.add ("__analyzer_get_strlen", make_kf_strlen ()); } } // namespace ana diff --git a/gcc/analyzer/kf-lang-cp.cc b/gcc/analyzer/kf-lang-cp.cc index 393b4f25e793..c7ee622909e6 100644 --- a/gcc/analyzer/kf-lang-cp.cc +++ b/gcc/analyzer/kf-lang-cp.cc @@ -35,6 +35,38 @@ along with GCC; see the file COPYING3. If not see #if ENABLE_ANALYZER +/* Return true if CALL is a non-allocating operator new or operator new [] + that contains no user-defined args, i.e. having any signature of: + + - void* operator new (std::size_t count, void* ptr); + - void* operator new[] (std::size_t count, void* ptr); + + See https://en.cppreference.com/w/cpp/memory/new/operator_new. */ + +bool is_placement_new_p (const gcall *call) +{ + gcc_assert (call); + tree fndecl = gimple_call_fndecl (call); + + if (!fndecl || TREE_CODE (TREE_TYPE (fndecl)) == METHOD_TYPE) + /* Give up on overloaded operator new. */ + return false; + + if (!is_named_call_p (fndecl, "operator new", call, 2) + && !is_named_call_p (fndecl, "operator new []", call, 2)) + return false; + + /* We must distinguish between an allocating non-throwing new + and a non-allocating new. + + The former might have one of the following signatures : + void* operator new (std::size_t count, const std::nothrow_t& tag); + void* operator new[] (std::size_t count, const std::nothrow_t& tag); + Whereas a placement new would take a pointer. */ + tree arg1_type = TREE_CHAIN (TYPE_ARG_TYPES (TREE_TYPE (fndecl))); + return TREE_CODE (TREE_VALUE (arg1_type)) == POINTER_TYPE; +} + namespace ana { /* Implementations of specific functions. */ @@ -46,7 +78,11 @@ class kf_operator_new : public known_function public: bool matches_call_types_p (const call_details &cd) const final override { - return cd.num_args () == 1; + return (cd.num_args () == 1 + && cd.arg_is_size_p (0)) + || (cd.num_args () == 2 + && cd.arg_is_size_p (0) + && POINTER_TYPE_P (cd.get_arg_type (1))); } void impl_call_pre (const call_details &cd) const final override @@ -54,28 +90,74 @@ public: region_model *model = cd.get_model (); region_model_manager *mgr = cd.get_manager (); const svalue *size_sval = cd.get_arg_svalue (0); - const region *new_reg - = model->get_or_create_region_for_heap_alloc (size_sval, cd.get_ctxt ()); - if (cd.get_lhs_type ()) + region_model_context *ctxt = cd.get_ctxt (); + const gcall *call = cd.get_call_stmt (); + + /* If the call was actually a placement new, check that accessing + the buffer lhs is placed into does not result in out-of-bounds. */ + if (is_placement_new_p (call)) { - const svalue *ptr_sval - = mgr->get_ptr_svalue (cd.get_lhs_type (), new_reg); - cd.maybe_set_lhs (ptr_sval); + const region *ptr_reg = cd.deref_ptr_arg (1); + if (ptr_reg && cd.get_lhs_type ()) + { + const svalue *num_bytes_sval = cd.get_arg_svalue (0); + const region *sized_new_reg + = mgr->get_sized_region (ptr_reg, + cd.get_lhs_type (), + num_bytes_sval); + model->check_region_for_write (sized_new_reg, + nullptr, + ctxt); + const svalue *ptr_sval + = mgr->get_ptr_svalue (cd.get_lhs_type (), sized_new_reg); + cd.maybe_set_lhs (ptr_sval); + } + } + /* If the call is an allocating new, then create a heap allocated + region. */ + else + { + const region *new_reg + = model->get_or_create_region_for_heap_alloc (size_sval, ctxt); + if (cd.get_lhs_type ()) + { + const svalue *ptr_sval + = mgr->get_ptr_svalue (cd.get_lhs_type (), new_reg); + cd.maybe_set_lhs (ptr_sval); + } + } + } + + void impl_call_post (const call_details &cd) const final override + { + region_model *model = cd.get_model (); + region_model_manager *mgr = cd.get_manager (); + tree callee_fndecl = cd.get_fndecl_for_call (); + region_model_context *ctxt = cd.get_ctxt (); + + /* If the call is guaranteed to return nonnull + then add a nonnull constraint to the allocated region. */ + if (!TREE_NOTHROW (callee_fndecl) && flag_exceptions) + { + const svalue *null_sval + = mgr->get_or_create_null_ptr (cd.get_lhs_type ()); + const svalue *result + = model->get_store_value (cd.get_lhs_region (), ctxt); + model->add_constraint (result, NE_EXPR, null_sval, ctxt); } } }; -/* Handler for "operator delete", both the sized and unsized variants - (2 arguments and 1 argument respectively), and for "operator delete []" */ +/* Handler for "operator delete" and for "operator delete []", + both the sized and unsized variants + (2 arguments and 1 argument respectively). */ class kf_operator_delete : public known_function { public: - kf_operator_delete (unsigned num_args) : m_num_args (num_args) {} - bool matches_call_types_p (const call_details &cd) const final override { - return cd.num_args () == m_num_args; + return cd.num_args () == 1 or cd.num_args () == 2; } void impl_call_post (const call_details &cd) const final override @@ -86,12 +168,11 @@ public: { /* If the ptr points to an underlying heap region, delete it, poisoning pointers. */ - model->unbind_region_and_descendents (freed_reg, POISON_KIND_FREED); + model->unbind_region_and_descendents (freed_reg, + POISON_KIND_DELETED); } } -private: - unsigned m_num_args; }; /* Populate KFM with instances of known functions relating to C++. */ @@ -101,9 +182,8 @@ register_known_functions_lang_cp (known_function_manager &kfm) { kfm.add ("operator new", make_unique ()); kfm.add ("operator new []", make_unique ()); - kfm.add ("operator delete", make_unique (1)); - kfm.add ("operator delete", make_unique (2)); - kfm.add ("operator delete []", make_unique (1)); + kfm.add ("operator delete", make_unique ()); + kfm.add ("operator delete []", make_unique ()); } } // namespace ana diff --git a/gcc/analyzer/kf.cc b/gcc/analyzer/kf.cc index 3e319a076bbd..e5bd7459f271 100644 --- a/gcc/analyzer/kf.cc +++ b/gcc/analyzer/kf.cc @@ -40,17 +40,30 @@ along with GCC; see the file COPYING3. If not see namespace ana { +/* class pure_known_function_with_default_return : public known_function. */ + +void +pure_known_function_with_default_return:: +impl_call_pre (const call_details &cd) const +{ + cd.set_any_lhs_with_defaults (); +} + /* Implementations of specific functions. */ /* Handler for "alloca". */ -class kf_alloca : public known_function +class kf_alloca : public builtin_known_function { public: bool matches_call_types_p (const call_details &cd) const final override { return cd.num_args () == 1; } + enum built_in_function builtin_code () const final override + { + return BUILT_IN_ALLOCA; + } void impl_call_pre (const call_details &cd) const final override; }; @@ -313,7 +326,7 @@ public: /* Handler for "calloc". */ -class kf_calloc : public known_function +class kf_calloc : public builtin_known_function { public: bool matches_call_types_p (const call_details &cd) const final override @@ -322,6 +335,11 @@ public: && cd.arg_is_size_p (0) && cd.arg_is_size_p (1)); } + enum built_in_function builtin_code () const final override + { + return BUILT_IN_CALLOC; + } + void impl_call_pre (const call_details &cd) const final override; }; @@ -405,8 +423,39 @@ kf_error::impl_call_pre (const call_details &cd) const if (!model->add_constraint (status, EQ_EXPR, integer_zero_node, ctxt)) if (ctxt) ctxt->terminate_path (); + + /* Check "format" arg. */ + const int fmt_arg_idx = (m_min_args == 3) ? 2 : 4; + model->check_for_null_terminated_string_arg (cd, fmt_arg_idx); } +/* Handler for fopen. + FILE *fopen (const char *filename, const char *mode); + See e.g. https://en.cppreference.com/w/c/io/fopen + https://www.man7.org/linux/man-pages/man3/fopen.3.html + https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/fopen-wfopen?view=msvc-170 */ + +class kf_fopen : public known_function +{ +public: + bool matches_call_types_p (const call_details &cd) const final override + { + return (cd.num_args () == 2 + && cd.arg_is_pointer_p (0) + && cd.arg_is_pointer_p (1)); + } + + void impl_call_pre (const call_details &cd) const final override + { + cd.check_for_null_terminated_string_arg (0); + cd.check_for_null_terminated_string_arg (1); + cd.set_any_lhs_with_defaults (); + + /* fopen's mode param is effectively a mini-DSL, but there are various + non-standard extensions, so we don't bother to check it. */ + } +}; + /* Handler for "free", after sm-handling. If the ptr points to an underlying heap region, delete the region, @@ -422,12 +471,16 @@ kf_error::impl_call_pre (const call_details &cd) const all pointers to the region to the "freed" state together, regardless of casts. */ -class kf_free : public known_function +class kf_free : public builtin_known_function { public: bool matches_call_types_p (const call_details &cd) const final override { - return (cd.num_args () == 0 && cd.arg_is_pointer_p (0)); + return (cd.num_args () == 1 && cd.arg_is_pointer_p (0)); + } + enum built_in_function builtin_code () const final override + { + return BUILT_IN_FREE; } void impl_call_post (const call_details &cd) const final override; }; @@ -448,7 +501,7 @@ kf_free::impl_call_post (const call_details &cd) const /* Handle the on_call_pre part of "malloc". */ -class kf_malloc : public known_function +class kf_malloc : public builtin_known_function { public: bool matches_call_types_p (const call_details &cd) const final override @@ -456,6 +509,10 @@ public: return (cd.num_args () == 1 && cd.arg_is_size_p (0)); } + enum built_in_function builtin_code () const final override + { + return BUILT_IN_MALLOC; + } void impl_call_pre (const call_details &cd) const final override; }; @@ -477,12 +534,19 @@ kf_malloc::impl_call_pre (const call_details &cd) const /* Handler for "memcpy" and "__builtin_memcpy", "memmove", and "__builtin_memmove". */ -/* TODO: complain about overlapping src and dest for the memcpy - variants. */ -class kf_memcpy_memmove : public known_function +class kf_memcpy_memmove : public builtin_known_function { public: + enum kf_memcpy_memmove_variant + { + KF_MEMCPY, + KF_MEMCPY_CHK, + KF_MEMMOVE, + KF_MEMMOVE_CHK, + }; + kf_memcpy_memmove (enum kf_memcpy_memmove_variant variant) + : m_variant (variant) {}; bool matches_call_types_p (const call_details &cd) const final override { return (cd.num_args () == 3 @@ -490,7 +554,25 @@ public: && cd.arg_is_pointer_p (1) && cd.arg_is_size_p (2)); } + enum built_in_function builtin_code () const final override + { + switch (m_variant) + { + case KF_MEMCPY: + return BUILT_IN_MEMCPY; + case KF_MEMCPY_CHK: + return BUILT_IN_MEMCPY_CHK; + case KF_MEMMOVE: + return BUILT_IN_MEMMOVE; + case KF_MEMMOVE_CHK: + return BUILT_IN_MEMMOVE_CHK; + default: + gcc_unreachable (); + } + } void impl_call_pre (const call_details &cd) const final override; +private: + const enum kf_memcpy_memmove_variant m_variant; }; void @@ -501,7 +583,6 @@ kf_memcpy_memmove::impl_call_pre (const call_details &cd) const const svalue *num_bytes_sval = cd.get_arg_svalue (2); region_model *model = cd.get_model (); - region_model_manager *mgr = cd.get_manager (); const region *dest_reg = model->deref_rvalue (dest_ptr_sval, cd.get_arg_tree (0), cd.get_ctxt ()); @@ -509,29 +590,45 @@ kf_memcpy_memmove::impl_call_pre (const call_details &cd) const = model->deref_rvalue (src_ptr_sval, cd.get_arg_tree (1), cd.get_ctxt ()); cd.maybe_set_lhs (dest_ptr_sval); + /* Check for overlap. */ + switch (m_variant) + { + case KF_MEMCPY: + case KF_MEMCPY_CHK: + cd.complain_about_overlap (0, 1, num_bytes_sval); + break; - const region *sized_src_reg - = mgr->get_sized_region (src_reg, NULL_TREE, num_bytes_sval); - const region *sized_dest_reg - = mgr->get_sized_region (dest_reg, NULL_TREE, num_bytes_sval); - const svalue *src_contents_sval - = model->get_store_value (sized_src_reg, cd.get_ctxt ()); - model->check_for_poison (src_contents_sval, cd.get_arg_tree (1), - sized_src_reg, cd.get_ctxt ()); - model->set_value (sized_dest_reg, src_contents_sval, cd.get_ctxt ()); + case KF_MEMMOVE: + case KF_MEMMOVE_CHK: + /* It's OK for memmove's arguments to overlap. */ + break; + + default: + gcc_unreachable (); + } + model->copy_bytes (dest_reg, + src_reg, cd.get_arg_tree (1), + num_bytes_sval, + cd.get_ctxt ()); } /* Handler for "memset" and "__builtin_memset". */ -class kf_memset : public known_function +class kf_memset : public builtin_known_function { public: + kf_memset (bool chk_variant) : m_chk_variant (chk_variant) {} bool matches_call_types_p (const call_details &cd) const final override { return (cd.num_args () == 3 && cd.arg_is_pointer_p (0)); } - + enum built_in_function builtin_code () const final override + { + return m_chk_variant ? BUILT_IN_MEMSET_CHK : BUILT_IN_MEMSET; + } void impl_call_pre (const call_details &cd) const final override; +private: + const bool m_chk_variant; }; void @@ -557,6 +654,8 @@ kf_memset::impl_call_pre (const call_details &cd) const nullptr, cd.get_ctxt ()); model->fill_region (sized_dest_reg, fill_value_u8); + + cd.maybe_set_lhs (dest_sval); } /* A subclass of pending_diagnostic for complaining about 'putenv' @@ -663,6 +762,7 @@ public: gcc_assert (fndecl); region_model_context *ctxt = cd.get_ctxt (); region_model *model = cd.get_model (); + model->check_for_null_terminated_string_arg (cd, 0); const svalue *ptr_sval = cd.get_arg_svalue (0); const region *reg = model->deref_rvalue (ptr_sval, cd.get_arg_tree (0), ctxt); @@ -683,6 +783,7 @@ public: ctxt->warn (make_unique (fndecl, reg)); break; } + cd.set_any_lhs_with_defaults (); } }; @@ -709,7 +810,7 @@ public: Each of these has a custom_edge_info subclass, which updates the region_model and sm-state of the destination state. */ -class kf_realloc : public known_function +class kf_realloc : public builtin_known_function { public: bool matches_call_types_p (const call_details &cd) const final override @@ -718,6 +819,12 @@ public: && cd.arg_is_pointer_p (0) && cd.arg_is_size_p (1)); } + + enum built_in_function builtin_code () const final override + { + return BUILT_IN_REALLOC; + } + void impl_call_post (const call_details &cd) const final override; }; @@ -930,13 +1037,22 @@ kf_realloc::impl_call_post (const call_details &cd) const /* Handler for "strchr" and "__builtin_strchr". */ -class kf_strchr : public known_function +class kf_strchr : public builtin_known_function { public: bool matches_call_types_p (const call_details &cd) const final override { return (cd.num_args () == 2 && cd.arg_is_pointer_p (0)); } + void impl_call_pre (const call_details &cd) const final override + { + cd.check_for_null_terminated_string_arg (0); + } + + enum built_in_function builtin_code () const final override + { + return BUILT_IN_STRCHR; + } void impl_call_post (const call_details &cd) const final override; }; @@ -1013,7 +1129,7 @@ kf_strchr::impl_call_post (const call_details &cd) const int sprintf(char *str, const char *format, ...); */ -class kf_sprintf : public known_function +class kf_sprintf : public builtin_known_function { public: bool matches_call_types_p (const call_details &cd) const final override @@ -1023,6 +1139,11 @@ public: && cd.arg_is_pointer_p (1)); } + enum built_in_function builtin_code () const final override + { + return BUILT_IN_SPRINTF; + } + void impl_call_pre (const call_details &cd) const final override { /* For now, merely assume that the destination buffer gets set to a @@ -1034,12 +1155,13 @@ public: = model->deref_rvalue (dst_ptr, cd.get_arg_tree (0), ctxt); const svalue *content = cd.get_or_create_conjured_svalue (dst_reg); model->set_value (dst_reg, content, ctxt); + cd.set_any_lhs_with_defaults (); } }; /* Handler for "__builtin_stack_restore". */ -class kf_stack_restore : public known_function +class kf_stack_restore : public pure_known_function_with_default_return { public: bool matches_call_types_p (const call_details &) const final override @@ -1052,7 +1174,7 @@ public: /* Handler for "__builtin_stack_save". */ -class kf_stack_save : public known_function +class kf_stack_save : public pure_known_function_with_default_return { public: bool matches_call_types_p (const call_details &) const final override @@ -1063,12 +1185,14 @@ public: /* Currently a no-op. */ }; -/* Handler for "strcpy" and "__builtin_strcpy_chk". */ +/* Handler for "strcat" and "__builtin_strcat_chk". */ -class kf_strcpy : public known_function +class kf_strcat : public builtin_known_function { public: - kf_strcpy (unsigned int num_args) : m_num_args (num_args) {} + kf_strcat (unsigned int num_args, bool chk_variant) + : m_num_args (num_args), + m_chk_variant (chk_variant) {} bool matches_call_types_p (const call_details &cd) const final override { return (cd.num_args () == m_num_args @@ -1076,116 +1200,197 @@ public: && cd.arg_is_pointer_p (1)); } + enum built_in_function builtin_code () const final override + { + return m_chk_variant ? BUILT_IN_STRCAT_CHK : BUILT_IN_STRCAT; + } + + void impl_call_pre (const call_details &cd) const final override + { + region_model *model = cd.get_model (); + region_model_manager *mgr = cd.get_manager (); + + const svalue *dest_sval = cd.get_arg_svalue (0); + const region *dest_reg = model->deref_rvalue (dest_sval, cd.get_arg_tree (0), + cd.get_ctxt ()); + + const svalue *dst_strlen_sval + = cd.check_for_null_terminated_string_arg (0, false, nullptr); + if (!dst_strlen_sval) + { + if (cd.get_ctxt ()) + cd.get_ctxt ()->terminate_path (); + return; + } + + const svalue *bytes_to_copy; + const svalue *num_src_bytes_read_sval + = cd.check_for_null_terminated_string_arg (1, true, &bytes_to_copy); + if (!num_src_bytes_read_sval) + { + if (cd.get_ctxt ()) + cd.get_ctxt ()->terminate_path (); + return; + } + + cd.maybe_set_lhs (dest_sval); + cd.complain_about_overlap (0, 1, num_src_bytes_read_sval); + + const region *offset_reg + = mgr->get_offset_region (dest_reg, NULL_TREE, dst_strlen_sval); + model->write_bytes (offset_reg, + num_src_bytes_read_sval, + bytes_to_copy, + cd.get_ctxt ()); + } + +private: + unsigned int m_num_args; + const bool m_chk_variant; +}; + +/* Handler for "strcpy" and "__builtin_strcpy_chk". */ + +class kf_strcpy : public builtin_known_function +{ +public: + kf_strcpy (unsigned int num_args, bool chk_variant) + : m_num_args (num_args), + m_chk_variant (chk_variant) {} + bool matches_call_types_p (const call_details &cd) const final override + { + return (cd.num_args () == m_num_args + && cd.arg_is_pointer_p (0) + && cd.arg_is_pointer_p (1)); + } + enum built_in_function builtin_code () const final override + { + return m_chk_variant ? BUILT_IN_STRCPY_CHK : BUILT_IN_STRCPY; + } void impl_call_pre (const call_details &cd) const final override; private: unsigned int m_num_args; + const bool m_chk_variant; }; void kf_strcpy::impl_call_pre (const call_details &cd) const { region_model *model = cd.get_model (); - region_model_manager *mgr = cd.get_manager (); + region_model_context *ctxt = cd.get_ctxt (); const svalue *dest_sval = cd.get_arg_svalue (0); const region *dest_reg = model->deref_rvalue (dest_sval, cd.get_arg_tree (0), - cd.get_ctxt ()); - const svalue *src_sval = cd.get_arg_svalue (1); - const region *src_reg = model->deref_rvalue (src_sval, cd.get_arg_tree (1), - cd.get_ctxt ()); - const svalue *src_contents_sval = model->get_store_value (src_reg, - cd.get_ctxt ()); - + ctxt); + /* strcpy returns the initial param. */ cd.maybe_set_lhs (dest_sval); - /* Try to get the string size if SRC_REG is a string_region. */ - const svalue *copied_bytes_sval = model->get_string_size (src_reg); - /* Otherwise, check if the contents of SRC_REG is a string. */ - if (copied_bytes_sval->get_kind () == SK_UNKNOWN) - copied_bytes_sval = model->get_string_size (src_contents_sval); - - const region *sized_dest_reg - = mgr->get_sized_region (dest_reg, NULL_TREE, copied_bytes_sval); - model->set_value (sized_dest_reg, src_contents_sval, cd.get_ctxt ()); + const svalue *bytes_to_copy; + if (const svalue *num_bytes_read_sval + = cd.check_for_null_terminated_string_arg (1, true, &bytes_to_copy)) + { + cd.complain_about_overlap (0, 1, num_bytes_read_sval); + model->write_bytes (dest_reg, num_bytes_read_sval, bytes_to_copy, ctxt); + } + else + { + if (cd.get_ctxt ()) + cd.get_ctxt ()->terminate_path (); + } } /* Handler for "strdup" and "__builtin_strdup". */ -class kf_strdup : public known_function +class kf_strdup : public builtin_known_function { public: bool matches_call_types_p (const call_details &cd) const final override { return (cd.num_args () == 1 && cd.arg_is_pointer_p (0)); } + enum built_in_function builtin_code () const final override + { + return BUILT_IN_STRDUP; + } void impl_call_pre (const call_details &cd) const final override { region_model *model = cd.get_model (); + region_model_context *ctxt = cd.get_ctxt (); region_model_manager *mgr = cd.get_manager (); - /* Ideally we'd get the size here, and simulate copying the bytes. */ - const region *new_reg - = model->get_or_create_region_for_heap_alloc (NULL, cd.get_ctxt ()); - model->mark_region_as_unknown (new_reg, NULL); - if (cd.get_lhs_type ()) + const svalue *bytes_to_copy; + if (const svalue *num_bytes_read_sval + = cd.check_for_null_terminated_string_arg (0, true, &bytes_to_copy)) { - const svalue *ptr_sval - = mgr->get_ptr_svalue (cd.get_lhs_type (), new_reg); - cd.maybe_set_lhs (ptr_sval); + const region *new_reg + = model->get_or_create_region_for_heap_alloc (num_bytes_read_sval, + ctxt); + model->write_bytes (new_reg, num_bytes_read_sval, bytes_to_copy, ctxt); + if (cd.get_lhs_type ()) + { + const svalue *ptr_sval + = mgr->get_ptr_svalue (cd.get_lhs_type (), new_reg); + cd.maybe_set_lhs (ptr_sval); + } + } + else + { + if (ctxt) + ctxt->terminate_path (); } } }; -/* Handle the on_call_pre part of "strlen". */ +/* Handler for "strlen" and for "__analyzer_get_strlen". */ -class kf_strlen : public known_function +class kf_strlen : public builtin_known_function { public: bool matches_call_types_p (const call_details &cd) const final override { return (cd.num_args () == 1 && cd.arg_is_pointer_p (0)); } - void impl_call_pre (const call_details &cd) const final override; -}; + enum built_in_function builtin_code () const final override + { + return BUILT_IN_STRLEN; + } -void -kf_strlen::impl_call_pre (const call_details &cd) const -{ - region_model_context *ctxt = cd.get_ctxt (); - region_model *model = cd.get_model (); - region_model_manager *mgr = cd.get_manager (); - - const svalue *arg_sval = cd.get_arg_svalue (0); - const region *buf_reg - = model->deref_rvalue (arg_sval, cd.get_arg_tree (0), ctxt); - if (const string_region *str_reg - = buf_reg->dyn_cast_string_region ()) - { - tree str_cst = str_reg->get_string_cst (); - /* TREE_STRING_LENGTH is sizeof, not strlen. */ - int sizeof_cst = TREE_STRING_LENGTH (str_cst); - int strlen_cst = sizeof_cst - 1; - if (cd.get_lhs_type ()) + void impl_call_pre (const call_details &cd) const final override + { + if (const svalue *strlen_sval + = cd.check_for_null_terminated_string_arg (0, false, nullptr)) + if (strlen_sval->get_kind () != SK_UNKNOWN) { - tree t_cst = build_int_cst (cd.get_lhs_type (), strlen_cst); - const svalue *result_sval - = mgr->get_or_create_constant_svalue (t_cst); - cd.maybe_set_lhs (result_sval); + cd.maybe_set_lhs (strlen_sval); return; } - } - /* Otherwise a conjured value. */ + + /* Use a conjured svalue. */ + cd.set_any_lhs_with_defaults (); + } +}; + +/* Factory function, so that kf-analyzer.cc can use this class. */ + +std::unique_ptr +make_kf_strlen () +{ + return make_unique (); } /* Handler for "strndup" and "__builtin_strndup". */ -class kf_strndup : public known_function +class kf_strndup : public builtin_known_function { public: bool matches_call_types_p (const call_details &cd) const final override { return (cd.num_args () == 2 && cd.arg_is_pointer_p (0)); } + enum built_in_function builtin_code () const final override + { + return BUILT_IN_STRNDUP; + } void impl_call_pre (const call_details &cd) const final override { region_model *model = cd.get_model (); @@ -1358,45 +1563,78 @@ register_known_functions (known_function_manager &kfm) kfm.add (IFN_UBSAN_BOUNDS, make_unique ()); } - /* Built-ins the analyzer has known_functions for. */ + /* GCC built-ins that do not correspond to a function + in the standard library. */ { - kfm.add (BUILT_IN_ALLOCA, make_unique ()); - kfm.add (BUILT_IN_ALLOCA_WITH_ALIGN, make_unique ()); - kfm.add (BUILT_IN_CALLOC, make_unique ()); kfm.add (BUILT_IN_EXPECT, make_unique ()); kfm.add (BUILT_IN_EXPECT_WITH_PROBABILITY, make_unique ()); - kfm.add (BUILT_IN_FREE, make_unique ()); - kfm.add (BUILT_IN_MALLOC, make_unique ()); - kfm.add (BUILT_IN_MEMCPY, make_unique ()); - kfm.add (BUILT_IN_MEMCPY_CHK, make_unique ()); - kfm.add (BUILT_IN_MEMMOVE, make_unique ()); - kfm.add (BUILT_IN_MEMMOVE_CHK, make_unique ()); - kfm.add (BUILT_IN_MEMSET, make_unique ()); - kfm.add (BUILT_IN_MEMSET_CHK, make_unique ()); - kfm.add (BUILT_IN_REALLOC, make_unique ()); - kfm.add (BUILT_IN_SPRINTF, make_unique ()); + kfm.add (BUILT_IN_ALLOCA_WITH_ALIGN, make_unique ()); kfm.add (BUILT_IN_STACK_RESTORE, make_unique ()); kfm.add (BUILT_IN_STACK_SAVE, make_unique ()); - kfm.add (BUILT_IN_STRCHR, make_unique ()); - kfm.add (BUILT_IN_STRCPY, make_unique (2)); - kfm.add (BUILT_IN_STRCPY_CHK, make_unique (3)); - kfm.add (BUILT_IN_STRDUP, make_unique ()); - kfm.add (BUILT_IN_STRNDUP, make_unique ()); - kfm.add (BUILT_IN_STRLEN, make_unique ()); register_atomic_builtins (kfm); register_varargs_builtins (kfm); } - /* Known builtins and C standard library functions. */ + /* Known builtins and C standard library functions + the analyzer has known functions for. */ { - kfm.add ("memset", make_unique ()); + kfm.add ("alloca", make_unique ()); + kfm.add ("__builtin_alloca", make_unique ()); + kfm.add ("calloc", make_unique ()); + kfm.add ("__builtin_calloc", make_unique ()); + kfm.add ("free", make_unique ()); + kfm.add ("__builtin_free", make_unique ()); + kfm.add ("malloc", make_unique ()); + kfm.add ("__builtin_malloc", make_unique ()); + kfm.add ("memcpy", + make_unique (kf_memcpy_memmove::KF_MEMCPY)); + kfm.add ("__builtin_memcpy", + make_unique (kf_memcpy_memmove::KF_MEMCPY)); + kfm.add ("__memcpy_chk", make_unique + (kf_memcpy_memmove::KF_MEMCPY_CHK)); + kfm.add ("__builtin___memcpy_chk", make_unique + (kf_memcpy_memmove::KF_MEMCPY_CHK)); + kfm.add ("memmove", + make_unique (kf_memcpy_memmove::KF_MEMMOVE)); + kfm.add ("__builtin_memmove", + make_unique (kf_memcpy_memmove::KF_MEMMOVE)); + kfm.add ("__memmove_chk", make_unique + (kf_memcpy_memmove::KF_MEMMOVE_CHK)); + kfm.add ("__builtin___memmove_chk", make_unique + (kf_memcpy_memmove::KF_MEMMOVE_CHK)); + kfm.add ("memset", make_unique (false)); + kfm.add ("__builtin_memset", make_unique (false)); + kfm.add ("__memset_chk", make_unique (true)); + kfm.add ("__builtin___memset_chk", make_unique (true)); + kfm.add ("realloc", make_unique ()); + kfm.add ("__builtin_realloc", make_unique ()); + kfm.add ("sprintf", make_unique ()); + kfm.add ("__builtin_sprintf", make_unique ()); + kfm.add ("strchr", make_unique ()); + kfm.add ("__builtin_strchr", make_unique ()); + kfm.add ("strcpy", make_unique (2, false)); + kfm.add ("__builtin_strcpy", make_unique (2, false)); + kfm.add ("__strcpy_chk", make_unique (3, true)); + kfm.add ("__builtin___strcpy_chk", make_unique (3, true)); + kfm.add ("strcat", make_unique (2, false)); + kfm.add ("__builtin_strcat", make_unique (2, false)); + kfm.add ("__strcat_chk", make_unique (3, true)); + kfm.add ("__builtin___strcat_chk", make_unique (3, true)); kfm.add ("strdup", make_unique ()); + kfm.add ("__builtin_strdup", make_unique ()); kfm.add ("strndup", make_unique ()); + kfm.add ("__builtin_strndup", make_unique ()); + kfm.add ("strlen", make_unique ()); + kfm.add ("__builtin_strlen", make_unique ()); + + register_atomic_builtins (kfm); + register_varargs_builtins (kfm); } /* Known POSIX functions, and some non-standard extensions. */ { + kfm.add ("fopen", make_unique ()); kfm.add ("putenv", make_unique ()); register_known_fd_functions (kfm); @@ -1416,7 +1654,7 @@ register_known_functions (known_function_manager &kfm) like this: extern int *___errno(void) __attribute__((__const__)); #define errno (*(___errno())) - and OS X like this: + and macOS like this: extern int * __error(void); #define errno (*__error()) and similarly __errno for newlib. diff --git a/gcc/analyzer/known-function-manager.cc b/gcc/analyzer/known-function-manager.cc index 4a2cf52d0b87..615c495f895d 100644 --- a/gcc/analyzer/known-function-manager.cc +++ b/gcc/analyzer/known-function-manager.cc @@ -137,6 +137,13 @@ known_function_manager::get_normal_builtin (enum built_in_function name) const return m_combined_fns_arr[name]; } +const known_function * +known_function_manager:: +get_normal_builtin (const builtin_known_function *builtin_kf) const +{ + return get_normal_builtin (builtin_kf->builtin_code ()); +} + /* Get any known_function matching IDENTIFIER, without type-checking. Return NULL if there isn't one. */ diff --git a/gcc/analyzer/known-function-manager.h b/gcc/analyzer/known-function-manager.h index 4a76136f2594..04f49ceb768f 100644 --- a/gcc/analyzer/known-function-manager.h +++ b/gcc/analyzer/known-function-manager.h @@ -54,6 +54,8 @@ private: DISABLE_COPY_AND_ASSIGN (known_function_manager); const known_function *get_normal_builtin (enum built_in_function name) const; + const known_function * + get_normal_builtin (const builtin_known_function *builtin_kf) const; const known_function *get_by_identifier (tree identifier) const; /* Map from identifier to known_function instance. @@ -64,6 +66,8 @@ private: known_function *m_combined_fns_arr[CFN_LAST]; }; +extern std::unique_ptr make_kf_strlen (); + } // namespace ana #endif /* GCC_ANALYZER_KNOWN_FUNCTION_MANAGER_H */ diff --git a/gcc/analyzer/ranges.cc b/gcc/analyzer/ranges.cc new file mode 100644 index 000000000000..8b1613e6b204 --- /dev/null +++ b/gcc/analyzer/ranges.cc @@ -0,0 +1,324 @@ +/* Symbolic offsets and ranges. + Copyright (C) 2023 Free Software Foundation, Inc. + Contributed by David Malcolm . + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 3, or (at your option) +any later version. + +GCC is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +. */ + +#include "config.h" +#define INCLUDE_MEMORY +#include "system.h" +#include "coretypes.h" +#include "tree.h" +#include "diagnostic-core.h" +#include "gimple-pretty-print.h" +#include "function.h" +#include "basic-block.h" +#include "gimple.h" +#include "gimple-iterator.h" +#include "diagnostic-core.h" +#include "graphviz.h" +#include "options.h" +#include "cgraph.h" +#include "tree-dfa.h" +#include "stringpool.h" +#include "convert.h" +#include "target.h" +#include "fold-const.h" +#include "tree-pretty-print.h" +#include "bitmap.h" +#include "analyzer/analyzer.h" +#include "analyzer/analyzer-logging.h" +#include "ordered-hash-map.h" +#include "options.h" +#include "analyzer/supergraph.h" +#include "sbitmap.h" +#include "analyzer/call-string.h" +#include "analyzer/program-point.h" +#include "analyzer/store.h" +#include "analyzer/region-model.h" +#include "analyzer/constraint-manager.h" +#include "analyzer/analyzer-selftests.h" +#include "analyzer/ranges.h" + +#if ENABLE_ANALYZER + +namespace ana { + +/* class symbolic_byte_offset. */ + +symbolic_byte_offset::symbolic_byte_offset (int i, region_model_manager &mgr) +: m_num_bytes_sval (mgr.get_or_create_int_cst (size_type_node, i)) +{ +} + +symbolic_byte_offset::symbolic_byte_offset (const svalue *num_bytes_sval) +: m_num_bytes_sval (num_bytes_sval) +{ +} + +symbolic_byte_offset::symbolic_byte_offset (region_offset offset, + region_model_manager &mgr) +{ + if (offset.concrete_p ()) + { + bit_offset_t num_bits = offset.get_bit_offset (); + gcc_assert (num_bits % BITS_PER_UNIT == 0); + byte_offset_t num_bytes = num_bits / BITS_PER_UNIT; + m_num_bytes_sval = mgr.get_or_create_int_cst (size_type_node, num_bytes); + } + else + m_num_bytes_sval = offset.get_symbolic_byte_offset (); +} + +void +symbolic_byte_offset::dump_to_pp (pretty_printer *pp, bool simple) const +{ + pp_string (pp, "byte "); + m_num_bytes_sval->dump_to_pp (pp, simple); +} + +void +symbolic_byte_offset::dump (bool simple) const +{ + pretty_printer pp; + pp_format_decoder (&pp) = default_tree_printer; + pp_show_color (&pp) = pp_show_color (global_dc->printer); + pp.buffer->stream = stderr; + dump_to_pp (&pp, simple); + pp_newline (&pp); + pp_flush (&pp); +} + +tree +symbolic_byte_offset::maybe_get_constant () const +{ + return m_num_bytes_sval->maybe_get_constant (); +} + +/* class symbolic_byte_range. */ + +symbolic_byte_range::symbolic_byte_range (region_offset start, + const svalue *num_bytes, + region_model_manager &mgr) +: m_start (start, mgr), + m_size (num_bytes) +{ +} + +void +symbolic_byte_range::dump_to_pp (pretty_printer *pp, + bool simple, + region_model_manager &mgr) const +{ + if (empty_p ()) + { + pp_string (pp, "empty"); + return; + } + + if (tree size_cst = m_size.maybe_get_constant ()) + if (integer_onep (size_cst)) + { + pp_string (pp, "byte "); + m_start.get_svalue ()->dump_to_pp (pp, simple); + return; + } + + pp_string (pp, "bytes "); + m_start.get_svalue ()->dump_to_pp (pp, simple); + pp_string (pp, " to "); + get_last_byte_offset (mgr).get_svalue ()->dump_to_pp (pp, simple); +} + +void +symbolic_byte_range::dump (bool simple, region_model_manager &mgr) const +{ + pretty_printer pp; + pp_format_decoder (&pp) = default_tree_printer; + pp_show_color (&pp) = pp_show_color (global_dc->printer); + pp.buffer->stream = stderr; + dump_to_pp (&pp, simple, mgr); + pp_newline (&pp); + pp_flush (&pp); +} + +bool +symbolic_byte_range::empty_p () const +{ + tree cst = m_size.maybe_get_constant (); + if (!cst) + return false; + return zerop (cst); +} + +symbolic_byte_offset +symbolic_byte_range::get_last_byte_offset (region_model_manager &mgr) const +{ + gcc_assert (!empty_p ()); + const symbolic_byte_offset one (1, mgr); + return symbolic_byte_offset + (mgr.get_or_create_binop (size_type_node, + MINUS_EXPR, + get_next_byte_offset (mgr).get_svalue (), + one.get_svalue ())); +} + +symbolic_byte_offset +symbolic_byte_range::get_next_byte_offset (region_model_manager &mgr) const +{ + return symbolic_byte_offset (mgr.get_or_create_binop (size_type_node, + PLUS_EXPR, + m_start.get_svalue (), + m_size.get_svalue ())); +} + +/* Attempt to determine if THIS range intersects OTHER, + using constraints from MODEL. */ + +tristate +symbolic_byte_range::intersection (const symbolic_byte_range &other, + const region_model &model) const +{ + /* For brevity, consider THIS to be "range A", and OTHER to be "range B". */ + + region_model_manager *mgr = model.get_manager (); + + const svalue *first_sval_a = m_start.get_svalue (); + const svalue *first_sval_b = other.m_start.get_svalue (); + const svalue *last_sval_a = get_last_byte_offset (*mgr).get_svalue (); + const svalue *last_sval_b = other.get_last_byte_offset (*mgr).get_svalue (); + + if (m_size.get_svalue ()->get_kind () == SK_UNKNOWN + || other.m_size.get_svalue ()->get_kind () == SK_UNKNOWN) + { + if (first_sval_a == first_sval_b) + return tristate::TS_TRUE; + else + return tristate::TS_UNKNOWN; + } + + if (first_sval_a == first_sval_b) + return tristate::TS_TRUE; + + /* Is B fully before A? */ + tristate b_fully_before_a = model.eval_condition (last_sval_b, + LT_EXPR, + first_sval_a); + /* Is B fully after A? */ + tristate b_fully_after_a = model.eval_condition (first_sval_b, + GT_EXPR, + last_sval_a); + + if (b_fully_before_a.is_true () + || b_fully_after_a.is_true ()) + return tristate::TS_FALSE; + + if (b_fully_before_a.is_unknown () + || b_fully_after_a.is_unknown ()) + return tristate::TS_UNKNOWN; + + return tristate::TS_TRUE; +} + +#if CHECKING_P + +namespace selftest { + +static void test_intersects (void) +{ + region_model_manager mgr; + region_model m (&mgr); + + /* Test various concrete ranges. */ + symbolic_byte_offset zero (0, mgr); + symbolic_byte_offset one (1, mgr); + symbolic_byte_offset five (5, mgr); + symbolic_byte_offset nine (9, mgr); + symbolic_byte_offset ten (10, mgr); + + symbolic_byte_range r0_9 (zero, ten); + symbolic_byte_range r0 (zero, one); + symbolic_byte_range r5_9 (five, five); + symbolic_byte_range r9 (nine, one); + symbolic_byte_range r10 (ten, one); + symbolic_byte_range r10_19 (ten, ten); + + ASSERT_EQ (r0_9.get_start_byte_offset (), zero); + ASSERT_EQ (r0_9.get_size_in_bytes (), ten); + ASSERT_EQ (r0_9.get_next_byte_offset (mgr), ten); + ASSERT_EQ (r0_9.get_last_byte_offset (mgr), nine); + + ASSERT_EQ (r0_9.intersection (r0, m), tristate::TS_TRUE); + ASSERT_EQ (r0.intersection (r0_9, m), tristate::TS_TRUE); + ASSERT_EQ (r0_9.intersection (r9, m), tristate::TS_TRUE); + ASSERT_EQ (r9.intersection (r0_9, m), tristate::TS_TRUE); + ASSERT_EQ (r0_9.intersection (r10, m), tristate::TS_FALSE); + ASSERT_EQ (r10.intersection (r0_9, m), tristate::TS_FALSE); + + ASSERT_EQ (r5_9.intersection (r0, m), tristate::TS_FALSE); + ASSERT_EQ (r0.intersection (r5_9, m), tristate::TS_FALSE); + ASSERT_EQ (r9.intersection (r5_9, m), tristate::TS_TRUE); + ASSERT_EQ (r10.intersection (r5_9, m), tristate::TS_FALSE); + + /* Test various symbolic ranges. */ + tree x = build_global_decl ("x", size_type_node); + const svalue *x_init_sval = m.get_rvalue (x, nullptr); + tree y = build_global_decl ("y", size_type_node); + const svalue *y_init_sval = m.get_rvalue (y, nullptr); + + symbolic_byte_range r0_x_minus_1 (zero, x_init_sval); + symbolic_byte_range rx (x_init_sval, one); + symbolic_byte_range r0_y_minus_1 (zero, y_init_sval); + symbolic_byte_range ry (y_init_sval, one); + symbolic_byte_range rx_x_plus_y_minus_1 (x_init_sval, y_init_sval); + + ASSERT_EQ (rx_x_plus_y_minus_1.get_start_byte_offset (), x_init_sval); + ASSERT_EQ (rx_x_plus_y_minus_1.get_size_in_bytes (), y_init_sval); + ASSERT_EQ + (rx_x_plus_y_minus_1.get_next_byte_offset (mgr).get_svalue ()->get_kind (), + SK_BINOP); + ASSERT_EQ + (rx_x_plus_y_minus_1.get_last_byte_offset (mgr).get_svalue ()->get_kind (), + SK_BINOP); + + ASSERT_EQ (rx.intersection (ry, m), tristate::TS_UNKNOWN); + ASSERT_EQ (r0_x_minus_1.intersection (r0, m), tristate::TS_TRUE); +#if 0 + ASSERT_EQ (r0_x_minus_1.intersection (rx, m), tristate::TS_FALSE); + /* Fails (with UNKNOWN): b_fully_after_a is UNKNOWN, when it could + be TRUE: last of A is (x - 1), but it's not necessarily true that + X > (x - 1), for the case where x is (unsigned)0. */ +#endif + ASSERT_EQ (r0_x_minus_1.intersection (r0_y_minus_1, m), tristate::TS_TRUE); + // TODO: etc +} + +/* Run all of the selftests within this file. */ + +void +analyzer_ranges_cc_tests () +{ + test_intersects (); +} + +} // namespace selftest + +#endif /* CHECKING_P */ + +} // namespace ana + +#endif /* #if ENABLE_ANALYZER */ diff --git a/gcc/analyzer/ranges.h b/gcc/analyzer/ranges.h new file mode 100644 index 000000000000..cc72469a9023 --- /dev/null +++ b/gcc/analyzer/ranges.h @@ -0,0 +1,96 @@ +/* Symbolic offsets and ranges. + Copyright (C) 2023 Free Software Foundation, Inc. + Contributed by David Malcolm . + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 3, or (at your option) +any later version. + +GCC is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +. */ + +#ifndef GCC_ANALYZER_RANGES_H +#define GCC_ANALYZER_RANGES_H + +namespace ana { + +/* Wrapper around an svalue for a value measured in bytes. */ + +class symbolic_byte_offset +{ +public: + explicit symbolic_byte_offset (int i, region_model_manager &mgr); + symbolic_byte_offset (const svalue *num_bytes_sval); + explicit symbolic_byte_offset (region_offset offset, + region_model_manager &mgr); + + const svalue *get_svalue () const { return m_num_bytes_sval; } + tree maybe_get_constant () const; + + void dump_to_pp (pretty_printer *pp, bool) const; + void dump (bool) const; + + bool operator== (const symbolic_byte_offset &other) const + { + return m_num_bytes_sval == other.m_num_bytes_sval; + } + +private: + const svalue *m_num_bytes_sval; +}; + +/* A range of byte offsets, where both the start and size of the + range can be symbolic. */ + +class symbolic_byte_range +{ +public: + symbolic_byte_range (symbolic_byte_offset start, + symbolic_byte_offset size) + : m_start (start), + m_size (size) + { + } + + symbolic_byte_range (region_offset start, + const svalue *num_bytes, + region_model_manager &mgr); + + void dump_to_pp (pretty_printer *pp, + bool simple, + region_model_manager &mgr) const; + void dump (bool, region_model_manager &mgr) const; + + bool empty_p () const; + + symbolic_byte_offset get_start_byte_offset () const + { + return m_start; + } + symbolic_byte_offset get_last_byte_offset (region_model_manager &mgr) const; + symbolic_byte_offset get_size_in_bytes () const + { + return m_size; + } + symbolic_byte_offset get_next_byte_offset (region_model_manager &mgr) const; + + tristate intersection (const symbolic_byte_range &other, + const region_model &model) const; + +private: + symbolic_byte_offset m_start; + symbolic_byte_offset m_size; +}; + +} // namespace ana + +#endif /* GCC_ANALYZER_RANGES_H */ diff --git a/gcc/analyzer/region-model-manager.cc b/gcc/analyzer/region-model-manager.cc index 65b719056c84..22246876f8f9 100644 --- a/gcc/analyzer/region-model-manager.cc +++ b/gcc/analyzer/region-model-manager.cc @@ -310,6 +310,25 @@ region_model_manager::get_or_create_initial_value (const region *reg, get_or_create_initial_value (original_reg)); } + /* Simplify: + INIT_VAL(ELEMENT_REG(STRING_REG), CONSTANT_SVAL) + to: + CONSTANT_SVAL(STRING[N]). */ + if (const element_region *element_reg = reg->dyn_cast_element_region ()) + if (tree cst_idx = element_reg->get_index ()->maybe_get_constant ()) + if (const string_region *string_reg + = element_reg->get_parent_region ()->dyn_cast_string_region ()) + if (tree_fits_shwi_p (cst_idx)) + { + HOST_WIDE_INT idx = tree_to_shwi (cst_idx); + tree string_cst = string_reg->get_string_cst (); + if (idx >= 0 && idx <= TREE_STRING_LENGTH (string_cst)) + { + int ch = TREE_STRING_POINTER (string_cst)[idx]; + return get_or_create_int_cst (reg->get_type (), ch); + } + } + /* INIT_VAL (*UNKNOWN_PTR) -> UNKNOWN_VAL. */ if (reg->symbolic_for_unknown_ptr_p ()) return get_or_create_unknown_svalue (reg->get_type ()); diff --git a/gcc/analyzer/region-model-reachability.cc b/gcc/analyzer/region-model-reachability.cc index 1c747e14eabe..a5c12f493460 100644 --- a/gcc/analyzer/region-model-reachability.cc +++ b/gcc/analyzer/region-model-reachability.cc @@ -184,27 +184,6 @@ reachable_regions::handle_sval (const svalue *sval) } add (pointee, ptr_is_mutable); } - else if (sval->get_type () - && TREE_CODE (sval->get_type ()) == POINTER_TYPE - && sval->get_kind () == SK_CONJURED) - { - /* Also add symbolic regions for pointers, but only for conjured svalues - for the LHS of a stmt. Doing it for more leads to state explosions - on chains of calls to external functions, due to each conjured svalue - potentially being modified at each successive call, recursively. */ - const conjured_svalue *conjured_sval = (const conjured_svalue *)sval; - if (conjured_sval->lhs_value_p ()) - { - const region *pointee - = m_model->get_manager ()->get_symbolic_region (sval); - /* Use const-ness of pointer type to affect mutability. */ - bool ptr_is_mutable = true; - if (TYPE_READONLY (TREE_TYPE (sval->get_type ()))) - ptr_is_mutable = false; - add (pointee, ptr_is_mutable); - } - } - /* Treat all svalues within a compound_svalue as reachable. */ if (const compound_svalue *compound_sval = sval->dyn_cast_compound_svalue ()) diff --git a/gcc/analyzer/region-model.cc b/gcc/analyzer/region-model.cc index e92b3f7b074e..82bc3b2c3826 100644 --- a/gcc/analyzer/region-model.cc +++ b/gcc/analyzer/region-model.cc @@ -20,6 +20,7 @@ along with GCC; see the file COPYING3. If not see #include "config.h" #define INCLUDE_MEMORY +#define INCLUDE_ALGORITHM #include "system.h" #include "coretypes.h" #include "make-unique.h" @@ -82,6 +83,8 @@ along with GCC; see the file COPYING3. If not see namespace ana { +auto_vec region_model::pop_frame_callbacks; + /* Dump T to PP in language-independent form, for debugging/logging/dumping purposes. */ @@ -441,29 +444,6 @@ region_model::canonicalize () { m_store.canonicalize (m_mgr->get_store_manager ()); m_constraints->canonicalize (); - - if (!m_dynamic_extents.is_empty ()) - { - /* Purge any dynamic extents for regions that aren't referenced. - Normally these are eliminated when leaks are detected, but we - can also gain stray heap_allocated_regions that aren't seen - by the leak-detection code. This happens when - region_model::on_call_pre provides a default result for a - function with both attributes "malloc" and "alloc_size" that - also has a known_function implementation. - Purge dynamic extent information for such regions. */ - auto_bitmap referenced_base_region_ids; - get_referenced_base_regions (referenced_base_region_ids); - auto_vec purgable_dyn_extents; - for (auto iter : m_dynamic_extents) - { - const region *reg = iter.first; - if (!bitmap_bit_p (referenced_base_region_ids, reg->get_id ())) - purgable_dyn_extents.safe_push (reg); - } - for (auto reg : purgable_dyn_extents) - m_dynamic_extents.remove (reg); - } } /* Return true if this region_model is in canonical form. */ @@ -522,6 +502,7 @@ public: case POISON_KIND_UNINIT: return OPT_Wanalyzer_use_of_uninitialized_value; case POISON_KIND_FREED: + case POISON_KIND_DELETED: return OPT_Wanalyzer_use_after_free; case POISON_KIND_POPPED_STACK: return OPT_Wanalyzer_use_of_pointer_in_stale_stack_frame; @@ -554,6 +535,15 @@ public: m_expr); } break; + case POISON_KIND_DELETED: + { + diagnostic_metadata m; + m.add_cwe (416); /* "CWE-416: Use After Free". */ + return warning_meta (rich_loc, m, get_controlling_option (), + "use after % of %qE", + m_expr); + } + break; case POISON_KIND_POPPED_STACK: { /* TODO: which CWE? */ @@ -578,6 +568,9 @@ public: case POISON_KIND_FREED: return ev.formatted_print ("use after % of %qE here", m_expr); + case POISON_KIND_DELETED: + return ev.formatted_print ("use after % of %qE here", + m_expr); case POISON_KIND_POPPED_STACK: return ev.formatted_print ("dereferencing pointer %qE to within stale stack frame", @@ -1294,59 +1287,108 @@ region_model::on_stmt_pre (const gimple *stmt, } } +/* Given a call CD with function attribute FORMAT_ATTR, check that the + format arg to the call is a valid null-terminated string. */ + +void +region_model::check_call_format_attr (const call_details &cd, + tree format_attr) const +{ + /* We assume that FORMAT_ATTR has already been validated. */ + + /* arg0 of the attribute should be kind of format strings + that this function expects (e.g. "printf"). */ + const tree arg0_tree_list = TREE_VALUE (format_attr); + if (!arg0_tree_list) + return; + + /* arg1 of the attribute should be the 1-based parameter index + to treat as the format string. */ + const tree arg1_tree_list = TREE_CHAIN (arg0_tree_list); + if (!arg1_tree_list) + return; + const tree arg1_value = TREE_VALUE (arg1_tree_list); + if (!arg1_value) + return; + + unsigned format_arg_idx = TREE_INT_CST_LOW (arg1_value) - 1; + if (cd.num_args () <= format_arg_idx) + return; + + /* Subclass of annotating_context that + adds a note about the format attr to any saved diagnostics. */ + class annotating_ctxt : public annotating_context + { + public: + annotating_ctxt (const call_details &cd, + unsigned fmt_param_idx) + : annotating_context (cd.get_ctxt ()), + m_cd (cd), + m_fmt_param_idx (fmt_param_idx) + { + } + void add_annotations () final override + { + class reason_format_attr + : public pending_note_subclass + { + public: + reason_format_attr (const call_arg_details &arg_details) + : m_arg_details (arg_details) + { + } + + const char *get_kind () const final override + { + return "reason_format_attr"; + } + + void emit () const final override + { + inform (DECL_SOURCE_LOCATION (m_arg_details.m_called_fndecl), + "parameter %i of %qD marked as a format string" + " via %qs attribute", + m_arg_details.m_arg_idx + 1, m_arg_details.m_called_fndecl, + "format"); + } + + bool operator== (const reason_format_attr &other) const + { + return m_arg_details == other.m_arg_details; + } + + private: + call_arg_details m_arg_details; + }; + + call_arg_details arg_details (m_cd, m_fmt_param_idx); + add_note (make_unique (arg_details)); + } + private: + const call_details &m_cd; + unsigned m_fmt_param_idx; + }; + + annotating_ctxt my_ctxt (cd, format_arg_idx); + call_details my_cd (cd, &my_ctxt); + my_cd.check_for_null_terminated_string_arg (format_arg_idx); +} + /* Ensure that all arguments at the call described by CD are checked - for poisoned values, by calling get_rvalue on each argument. */ + for poisoned values, by calling get_rvalue on each argument. + + Check that calls to functions with "format" attribute have valid + null-terminated strings for their format argument. */ void region_model::check_call_args (const call_details &cd) const { for (unsigned arg_idx = 0; arg_idx < cd.num_args (); arg_idx++) cd.get_arg_svalue (arg_idx); -} -/* Return true if CD is known to be a call to a function with - __attribute__((const)). */ - -static bool -const_fn_p (const call_details &cd) -{ - tree fndecl = cd.get_fndecl_for_call (); - if (!fndecl) - return false; - gcc_assert (DECL_P (fndecl)); - return TREE_READONLY (fndecl); -} - -/* If this CD is known to be a call to a function with - __attribute__((const)), attempt to get a const_fn_result_svalue - based on the arguments, or return NULL otherwise. */ - -static const svalue * -maybe_get_const_fn_result (const call_details &cd) -{ - if (!const_fn_p (cd)) - return NULL; - - unsigned num_args = cd.num_args (); - if (num_args > const_fn_result_svalue::MAX_INPUTS) - /* Too many arguments. */ - return NULL; - - auto_vec inputs (num_args); - for (unsigned arg_idx = 0; arg_idx < num_args; arg_idx++) - { - const svalue *arg_sval = cd.get_arg_svalue (arg_idx); - if (!arg_sval->can_have_associated_state_p ()) - return NULL; - inputs.quick_push (arg_sval); - } - - region_model_manager *mgr = cd.get_manager (); - const svalue *sval - = mgr->get_or_create_const_fn_result_svalue (cd.get_lhs_type (), - cd.get_fndecl_for_call (), - inputs); - return sval; + /* Handle attribute "format". */ + if (tree format_attr = cd.lookup_function_attribute ("format")) + check_call_format_attr (cd, format_attr); } /* Update this model for an outcome of a call that returns a specific @@ -1381,7 +1423,9 @@ region_model::update_for_zero_return (const call_details &cd, update_for_int_cst_return (cd, 0, unmergeable); } -/* Update this model for an outcome of a call that returns non-zero. */ +/* Update this model for an outcome of a call that returns non-zero. + Specifically, assign an svalue to the LHS, and add a constraint that + that svalue is non-zero. */ void region_model::update_for_nonzero_return (const call_details &cd) @@ -1390,6 +1434,7 @@ region_model::update_for_nonzero_return (const call_details &cd) return; if (TREE_CODE (cd.get_lhs_type ()) != INTEGER_TYPE) return; + cd.set_any_lhs_with_defaults (); const svalue *zero = m_mgr->get_or_create_int_cst (cd.get_lhs_type (), 0); const svalue *result @@ -1485,46 +1530,60 @@ region_model::get_known_function (enum internal_fn ifn) const return known_fn_mgr->get_internal_fn (ifn); } -/* Look for attribute "alloc_size" on the called function and, if found, - return a symbolic value of type size_type_node for the allocation size - based on the call's parameters. - Otherwise, return null. */ +/* Get any builtin_known_function for CALL and emit any warning to CTXT + if not NULL. -static const svalue * -get_result_size_in_bytes (const call_details &cd) + The call must match all assumptions made by the known_function (such as + e.g. "argument 1's type must be a pointer type"). + + Return NULL if no builtin_known_function is found, or it does + not match the assumption(s). + + Internally calls get_known_function to find a known_function and cast it + to a builtin_known_function. + + For instance, calloc is a C builtin, defined in gcc/builtins.def + by the DEF_LIB_BUILTIN macro. Such builtins are recognized by the + analyzer by their name, so that even in C++ or if the user redeclares + them but mismatch their signature, they are still recognized as builtins. + + Cases when a supposed builtin is not flagged as one by the FE: + + The C++ FE does not recognize calloc as a builtin if it has not been + included from a standard header, but the C FE does. Hence in C++ if + CALL comes from a calloc and stdlib is not included, + gcc/tree.h:fndecl_built_in_p (CALL) would be false. + + In C code, a __SIZE_TYPE__ calloc (__SIZE_TYPE__, __SIZE_TYPE__) user + declaration has obviously a mismatching signature from the standard, and + its function_decl tree won't be unified by + gcc/c-decl.cc:match_builtin_function_types. + + Yet in both cases the analyzer should treat the calls as a builtin calloc + so that extra attributes unspecified by the standard but added by GCC + (e.g. sprintf attributes in gcc/builtins.def), useful for the detection of + dangerous behavior, are indeed processed. + + Therefore for those cases when a "builtin flag" is not added by the FE, + builtins' kf are derived from builtin_known_function, whose method + builtin_known_function::builtin_decl returns the builtin's + function_decl tree as defined in gcc/builtins.def, with all the extra + attributes. */ + +const builtin_known_function * +region_model::get_builtin_kf (const gcall *call, + region_model_context *ctxt /* = NULL */) const { - const tree attr = cd.lookup_function_attribute ("alloc_size"); - if (!attr) - return nullptr; + region_model *mut_this = const_cast (this); + tree callee_fndecl = mut_this->get_fndecl_for_call (call, ctxt); + if (! callee_fndecl) + return NULL; - const tree atval_1 = TREE_VALUE (attr); - if (!atval_1) - return nullptr; + call_details cd (call, mut_this, ctxt); + if (const known_function *kf = get_known_function (callee_fndecl, cd)) + return kf->dyn_cast_builtin_kf (); - unsigned argidx1 = TREE_INT_CST_LOW (TREE_VALUE (atval_1)) - 1; - if (cd.num_args () <= argidx1) - return nullptr; - - const svalue *sval_arg1 = cd.get_arg_svalue (argidx1); - - if (const tree atval_2 = TREE_CHAIN (atval_1)) - { - /* Two arguments. */ - unsigned argidx2 = TREE_INT_CST_LOW (TREE_VALUE (atval_2)) - 1; - if (cd.num_args () <= argidx2) - return nullptr; - const svalue *sval_arg2 = cd.get_arg_svalue (argidx2); - /* TODO: ideally we shouldn't need this cast here; - see PR analyzer/110902. */ - return cd.get_manager ()->get_or_create_cast - (size_type_node, - cd.get_manager ()->get_or_create_binop (size_type_node, - MULT_EXPR, - sval_arg1, sval_arg2)); - } - else - /* Single argument. */ - return cd.get_manager ()->get_or_create_cast (size_type_node, sval_arg1); + return NULL; } /* Update this model for the CALL stmt, using CTXT to report any @@ -1562,40 +1621,6 @@ region_model::on_call_pre (const gcall *call, region_model_context *ctxt) tree callee_fndecl = get_fndecl_for_call (call, ctxt); - /* Some of the cases below update the lhs of the call based on the - return value, but not all. Provide a default value, which may - get overwritten below. */ - if (tree lhs = gimple_call_lhs (call)) - { - const region *lhs_region = get_lvalue (lhs, ctxt); - const svalue *sval = maybe_get_const_fn_result (cd); - if (!sval) - { - if (callee_fndecl - && lookup_attribute ("malloc", DECL_ATTRIBUTES (callee_fndecl))) - { - const region *new_reg - = get_or_create_region_for_heap_alloc (NULL, ctxt); - mark_region_as_unknown (new_reg, NULL); - sval = m_mgr->get_ptr_svalue (cd.get_lhs_type (), new_reg); - } - else - /* For the common case of functions without __attribute__((const)), - use a conjured value, and purge any prior state involving that - value (in case this is in a loop). */ - sval = m_mgr->get_or_create_conjured_svalue (TREE_TYPE (lhs), call, - lhs_region, - conjured_purge (this, - ctxt)); - if (const svalue *size_in_bytes = get_result_size_in_bytes (cd)) - { - const region *reg = deref_rvalue (sval, NULL_TREE, ctxt, false); - set_dynamic_extents (reg, size_in_bytes, ctxt); - } - } - set_value (lhs_region, sval, ctxt); - } - if (gimple_call_internal_p (call)) if (const known_function *kf = get_known_function (gimple_call_internal_fn (call))) @@ -1605,7 +1630,10 @@ region_model::on_call_pre (const gcall *call, region_model_context *ctxt) } if (!callee_fndecl) - return true; /* Unknown side effects. */ + { + cd.set_any_lhs_with_defaults (); + return true; /* Unknown side effects. */ + } if (const known_function *kf = get_known_function (callee_fndecl, cd)) { @@ -1613,6 +1641,8 @@ region_model::on_call_pre (const gcall *call, region_model_context *ctxt) return false; /* No further side effects. */ } + cd.set_any_lhs_with_defaults (); + const int callee_fndecl_flags = flags_from_decl_or_type (callee_fndecl); if (callee_fndecl_flags & (ECF_CONST | ECF_PURE)) return false; /* No side effects. */ @@ -1777,23 +1807,23 @@ check_external_function_for_access_attr (const gcall *call, if (access->mode == access_write_only || access->mode == access_read_write) { - /* Subclass of decorated_region_model_context that + /* Subclass of annotating_context that adds a note about the attr access to any saved diagnostics. */ - class annotating_ctxt : public note_adding_context + class annotating_ctxt : public annotating_context { public: annotating_ctxt (tree callee_fndecl, const attr_access &access, region_model_context *ctxt) - : note_adding_context (ctxt), + : annotating_context (ctxt), m_callee_fndecl (callee_fndecl), m_access (access) { } - std::unique_ptr make_note () final override + void add_annotations () final override { - return make_unique - (m_callee_fndecl, m_access); + add_note (make_unique + (m_callee_fndecl, m_access)); } private: tree m_callee_fndecl; @@ -2836,35 +2866,6 @@ region_model::get_capacity (const region *reg) const return m_mgr->get_or_create_unknown_svalue (sizetype); } -/* Return the string size, including the 0-terminator, if SVAL is a - constant_svalue holding a string. Otherwise, return an unknown_svalue. */ - -const svalue * -region_model::get_string_size (const svalue *sval) const -{ - tree cst = sval->maybe_get_constant (); - if (!cst || TREE_CODE (cst) != STRING_CST) - return m_mgr->get_or_create_unknown_svalue (size_type_node); - - tree out = build_int_cst (size_type_node, TREE_STRING_LENGTH (cst)); - return m_mgr->get_or_create_constant_svalue (out); -} - -/* Return the string size, including the 0-terminator, if REG is a - string_region. Otherwise, return an unknown_svalue. */ - -const svalue * -region_model::get_string_size (const region *reg) const -{ - const string_region *str_reg = dyn_cast (reg); - if (!str_reg) - return m_mgr->get_or_create_unknown_svalue (size_type_node); - - tree cst = str_reg->get_string_cst (); - tree out = build_int_cst (size_type_node, TREE_STRING_LENGTH (cst)); - return m_mgr->get_or_create_constant_svalue (out); -} - /* If CTXT is non-NULL, use it to warn about any problems accessing REG, using DIR to determine if this access is a read or write. Return TRUE if an OOB access was detected. @@ -3311,6 +3312,607 @@ region_model::set_value (tree lhs, tree rhs, region_model_context *ctxt) set_value (lhs_reg, rhs_sval, ctxt); } +/* Issue a note specifying that a particular function parameter is expected + to be a valid null-terminated string. */ + +static void +inform_about_expected_null_terminated_string_arg (const call_arg_details &ad) +{ + // TODO: ideally we'd underline the param here + inform (DECL_SOURCE_LOCATION (ad.m_called_fndecl), + "argument %d of %qD must be a pointer to a null-terminated string", + ad.m_arg_idx + 1, ad.m_called_fndecl); +} + +/* A binding of a specific svalue at a concrete byte range. */ + +struct fragment +{ + fragment () + : m_byte_range (0, 0), m_sval (nullptr) + { + } + + fragment (const byte_range &bytes, const svalue *sval) + : m_byte_range (bytes), m_sval (sval) + { + } + + static int cmp_ptrs (const void *p1, const void *p2) + { + const fragment *f1 = (const fragment *)p1; + const fragment *f2 = (const fragment *)p2; + return byte_range::cmp (f1->m_byte_range, f2->m_byte_range); + } + + /* Determine if there is a zero terminator somewhere in the + bytes of this fragment, starting at START_READ_OFFSET (which + is absolute to the start of the cluster as a whole), and stopping + at the end of this fragment. + + Return a tristate: + - true if there definitely is a zero byte, writing to *OUT_BYTES_READ + the number of bytes from that would be read, including the zero byte. + - false if there definitely isn't a zero byte + - unknown if we don't know. */ + tristate has_null_terminator (byte_offset_t start_read_offset, + byte_offset_t *out_bytes_read) const + { + byte_offset_t rel_start_read_offset + = start_read_offset - m_byte_range.get_start_byte_offset (); + gcc_assert (rel_start_read_offset >= 0); + byte_offset_t available_bytes + = (m_byte_range.get_next_byte_offset () - start_read_offset); + gcc_assert (available_bytes >= 0); + + if (rel_start_read_offset > INT_MAX) + return tristate::TS_UNKNOWN; + HOST_WIDE_INT rel_start_read_offset_hwi = rel_start_read_offset.slow (); + + if (available_bytes > INT_MAX) + return tristate::TS_UNKNOWN; + HOST_WIDE_INT available_bytes_hwi = available_bytes.slow (); + + switch (m_sval->get_kind ()) + { + case SK_CONSTANT: + { + tree cst + = as_a (m_sval)->get_constant (); + switch (TREE_CODE (cst)) + { + case STRING_CST: + return string_cst_has_null_terminator (cst, + rel_start_read_offset_hwi, + available_bytes_hwi, + out_bytes_read); + case INTEGER_CST: + if (rel_start_read_offset_hwi == 0 + && integer_onep (TYPE_SIZE_UNIT (TREE_TYPE (cst)))) + { + /* Model accesses to the initial byte of a 1-byte + INTEGER_CST. */ + if (zerop (cst)) + { + *out_bytes_read = 1; + return tristate (true); + } + else + { + *out_bytes_read = available_bytes; + return tristate (false); + } + } + /* Treat any other access to an INTEGER_CST as unknown. */ + return tristate::TS_UNKNOWN; + + default: + gcc_unreachable (); + break; + } + } + break; + + case SK_INITIAL: + { + const initial_svalue *initial_sval = (const initial_svalue *)m_sval; + const region *reg = initial_sval->get_region (); + if (const string_region *string_reg = reg->dyn_cast_string_region ()) + { + tree string_cst = string_reg->get_string_cst (); + return string_cst_has_null_terminator (string_cst, + rel_start_read_offset_hwi, + available_bytes_hwi, + out_bytes_read); + } + return tristate::TS_UNKNOWN; + } + break; + + case SK_BITS_WITHIN: + { + const bits_within_svalue *bits_within_sval + = (const bits_within_svalue *)m_sval; + byte_range bytes (0, 0); + if (bits_within_sval->get_bits ().as_byte_range (&bytes)) + { + const svalue *inner_sval = bits_within_sval->get_inner_svalue (); + fragment f (byte_range + (start_read_offset - bytes.get_start_bit_offset (), + std::max (bytes.m_size_in_bytes, + available_bytes)), + inner_sval); + return f.has_null_terminator (start_read_offset, out_bytes_read); + } + } + break; + + default: + // TODO: it may be possible to handle other cases here. + break; + } + return tristate::TS_UNKNOWN; + } + + static tristate + string_cst_has_null_terminator (tree string_cst, + HOST_WIDE_INT rel_start_read_offset_hwi, + HOST_WIDE_INT available_bytes_hwi, + byte_offset_t *out_bytes_read) + { + /* Look for the first 0 byte within STRING_CST + from START_READ_OFFSET onwards. */ + const HOST_WIDE_INT num_bytes_to_search + = std::min ((TREE_STRING_LENGTH (string_cst) + - rel_start_read_offset_hwi), + available_bytes_hwi); + const char *start = (TREE_STRING_POINTER (string_cst) + + rel_start_read_offset_hwi); + if (num_bytes_to_search >= 0) + if (const void *p = memchr (start, 0, + num_bytes_to_search)) + { + *out_bytes_read = (const char *)p - start + 1; + return tristate (true); + } + + *out_bytes_read = available_bytes_hwi; + return tristate (false); + } + + byte_range m_byte_range; + const svalue *m_sval; +}; + +/* A frozen copy of a single base region's binding_cluster within a store, + optimized for traversal of the concrete parts in byte order. + This only captures concrete bindings, and is an implementation detail + of region_model::scan_for_null_terminator. */ + +class iterable_cluster +{ +public: + iterable_cluster (const binding_cluster *cluster) + { + if (!cluster) + return; + for (auto iter : *cluster) + { + const binding_key *key = iter.first; + const svalue *sval = iter.second; + + if (const concrete_binding *concrete_key + = key->dyn_cast_concrete_binding ()) + { + byte_range fragment_bytes (0, 0); + if (concrete_key->get_byte_range (&fragment_bytes)) + m_fragments.safe_push (fragment (fragment_bytes, sval)); + } + else + m_symbolic_bindings.safe_push (key); + } + m_fragments.qsort (fragment::cmp_ptrs); + } + + bool + get_fragment_for_byte (byte_offset_t byte, fragment *out_frag) const + { + /* TODO: binary search rather than linear. */ + unsigned iter_idx; + for (iter_idx = 0; iter_idx < m_fragments.length (); iter_idx++) + { + if (m_fragments[iter_idx].m_byte_range.contains_p (byte)) + { + *out_frag = m_fragments[iter_idx]; + return true; + } + } + return false; + } + + bool has_symbolic_bindings_p () const + { + return !m_symbolic_bindings.is_empty (); + } + +private: + auto_vec m_fragments; + auto_vec m_symbolic_bindings; +}; + +/* Simulate reading the bytes at BYTES from BASE_REG. + Complain to CTXT about any issues with the read e.g. out-of-bounds. */ + +const svalue * +region_model::get_store_bytes (const region *base_reg, + const byte_range &bytes, + region_model_context *ctxt) const +{ + /* Shortcut reading all of a string_region. */ + if (bytes.get_start_byte_offset () == 0) + if (const string_region *string_reg = base_reg->dyn_cast_string_region ()) + if (bytes.m_size_in_bytes + == TREE_STRING_LENGTH (string_reg->get_string_cst ())) + return m_mgr->get_or_create_initial_value (base_reg); + + const svalue *index_sval + = m_mgr->get_or_create_int_cst (size_type_node, + bytes.get_start_byte_offset ()); + const region *offset_reg = m_mgr->get_offset_region (base_reg, + NULL_TREE, + index_sval); + const svalue *byte_size_sval + = m_mgr->get_or_create_int_cst (size_type_node, bytes.m_size_in_bytes); + const region *read_reg = m_mgr->get_sized_region (offset_reg, + NULL_TREE, + byte_size_sval); + + /* Simulate reading those bytes from the store. */ + const svalue *sval = get_store_value (read_reg, ctxt); + return sval; +} + +static tree +get_tree_for_byte_offset (tree ptr_expr, byte_offset_t byte_offset) +{ + gcc_assert (ptr_expr); + return fold_build2 (MEM_REF, + char_type_node, + ptr_expr, wide_int_to_tree (size_type_node, byte_offset)); +} + +/* Simulate a series of reads of REG until we find a 0 byte + (equivalent to calling strlen). + + Complain to CTXT and return NULL if: + - the buffer pointed to isn't null-terminated + - the buffer pointed to has any uninitalized bytes before any 0-terminator + - any of the reads aren't within the bounds of the underlying base region + + Otherwise, return a svalue for the number of bytes read (strlen + 1), + and, if OUT_SVAL is non-NULL, write to *OUT_SVAL with an svalue + representing the content of REG up to and including the terminator. + + Algorithm + ========= + + Get offset for first byte to read. + Find the binding (if any) that contains it. + Find the size in bits of that binding. + Round to the nearest byte (which way???) + Or maybe give up if we have a partial binding there. + Get the svalue from the binding. + Determine the strlen (if any) of that svalue. + Does it have a 0-terminator within it? + If so, we have a partial read up to and including that terminator + Read those bytes from the store; add to the result in the correct place. + Finish + If not, we have a full read of that svalue + Read those bytes from the store; add to the result in the correct place. + Update read/write offsets + Continue + If unknown: + Result is unknown + Finish +*/ + +const svalue * +region_model::scan_for_null_terminator (const region *reg, + tree expr, + const svalue **out_sval, + region_model_context *ctxt) const +{ + store_manager *store_mgr = m_mgr->get_store_manager (); + + region_offset offset = reg->get_offset (m_mgr); + if (offset.symbolic_p ()) + { + if (out_sval) + *out_sval = get_store_value (reg, nullptr); + return m_mgr->get_or_create_unknown_svalue (size_type_node); + } + byte_offset_t src_byte_offset; + if (!offset.get_concrete_byte_offset (&src_byte_offset)) + { + if (out_sval) + *out_sval = get_store_value (reg, nullptr); + return m_mgr->get_or_create_unknown_svalue (size_type_node); + } + const byte_offset_t initial_src_byte_offset = src_byte_offset; + byte_offset_t dst_byte_offset = 0; + + const region *base_reg = reg->get_base_region (); + + if (const string_region *str_reg = base_reg->dyn_cast_string_region ()) + { + tree string_cst = str_reg->get_string_cst (); + if (const void *p = memchr (TREE_STRING_POINTER (string_cst), + 0, + TREE_STRING_LENGTH (string_cst))) + { + size_t num_bytes_read + = (const char *)p - TREE_STRING_POINTER (string_cst) + 1; + /* Simulate the read. */ + byte_range bytes_to_read (0, num_bytes_read); + const svalue *sval = get_store_bytes (reg, bytes_to_read, ctxt); + if (out_sval) + *out_sval = sval; + return m_mgr->get_or_create_int_cst (size_type_node, + num_bytes_read); + } + } + + const binding_cluster *cluster = m_store.get_cluster (base_reg); + iterable_cluster c (cluster); + binding_map result; + + while (1) + { + fragment f; + if (c.get_fragment_for_byte (src_byte_offset, &f)) + { + byte_offset_t fragment_bytes_read; + tristate is_terminated + = f.has_null_terminator (src_byte_offset, &fragment_bytes_read); + if (is_terminated.is_unknown ()) + { + if (out_sval) + *out_sval = get_store_value (reg, nullptr); + return m_mgr->get_or_create_unknown_svalue (size_type_node); + } + + /* Simulate reading those bytes from the store. */ + byte_range bytes_to_read (src_byte_offset, fragment_bytes_read); + const svalue *sval = get_store_bytes (base_reg, bytes_to_read, ctxt); + check_for_poison (sval, expr, nullptr, ctxt); + + if (out_sval) + { + byte_range bytes_to_write (dst_byte_offset, fragment_bytes_read); + const binding_key *key + = store_mgr->get_concrete_binding (bytes_to_write); + result.put (key, sval); + } + + src_byte_offset += fragment_bytes_read; + dst_byte_offset += fragment_bytes_read; + + if (is_terminated.is_true ()) + { + if (out_sval) + *out_sval = m_mgr->get_or_create_compound_svalue (NULL_TREE, + result); + return m_mgr->get_or_create_int_cst (size_type_node, + dst_byte_offset); + } + } + else + break; + } + + /* No binding for this base_region, or no binding at src_byte_offset + (or a symbolic binding). */ + + if (c.has_symbolic_bindings_p ()) + { + if (out_sval) + *out_sval = get_store_value (reg, nullptr); + return m_mgr->get_or_create_unknown_svalue (size_type_node); + } + + /* TODO: the various special-cases seen in + region_model::get_store_value. */ + + /* Simulate reading from this byte, then give up. */ + byte_range bytes_to_read (src_byte_offset, 1); + const svalue *sval = get_store_bytes (base_reg, bytes_to_read, ctxt); + tree byte_expr + = get_tree_for_byte_offset (expr, + src_byte_offset - initial_src_byte_offset); + check_for_poison (sval, byte_expr, nullptr, ctxt); + if (base_reg->can_have_initial_svalue_p ()) + { + if (out_sval) + *out_sval = get_store_value (reg, nullptr); + return m_mgr->get_or_create_unknown_svalue (size_type_node); + } + else + return nullptr; +} + +/* Check that argument ARG_IDX (0-based) to the call described by CD + is a pointer to a valid null-terminated string. + + Simulate scanning through the buffer, reading until we find a 0 byte + (equivalent to calling strlen). + + Complain and return NULL if: + - the buffer pointed to isn't null-terminated + - the buffer pointed to has any uninitalized bytes before any 0-terminator + - any of the reads aren't within the bounds of the underlying base region + + Otherwise, return a svalue for strlen of the buffer (*not* including + the null terminator). + + TODO: we should also complain if: + - the pointer is NULL (or could be). */ + +void +region_model::check_for_null_terminated_string_arg (const call_details &cd, + unsigned arg_idx) +{ + check_for_null_terminated_string_arg (cd, + arg_idx, + false, /* include_terminator */ + nullptr); // out_sval +} + + +/* Check that argument ARG_IDX (0-based) to the call described by CD + is a pointer to a valid null-terminated string. + + Simulate scanning through the buffer, reading until we find a 0 byte + (equivalent to calling strlen). + + Complain and return NULL if: + - the buffer pointed to isn't null-terminated + - the buffer pointed to has any uninitalized bytes before any 0-terminator + - any of the reads aren't within the bounds of the underlying base region + + Otherwise, return a svalue. This will be the number of bytes read + (including the null terminator) if INCLUDE_TERMINATOR is true, or strlen + of the buffer (not including the null terminator) if it is false. + + Also, when returning an svalue, if OUT_SVAL is non-NULL, write to + *OUT_SVAL with an svalue representing the content of the buffer up to + and including the terminator. + + TODO: we should also complain if: + - the pointer is NULL (or could be). */ + +const svalue * +region_model::check_for_null_terminated_string_arg (const call_details &cd, + unsigned arg_idx, + bool include_terminator, + const svalue **out_sval) +{ + class null_terminator_check_event : public custom_event + { + public: + null_terminator_check_event (const event_loc_info &loc_info, + const call_arg_details &arg_details) + : custom_event (loc_info), + m_arg_details (arg_details) + { + } + + label_text get_desc (bool can_colorize) const final override + { + if (m_arg_details.m_arg_expr) + return make_label_text (can_colorize, + "while looking for null terminator" + " for argument %i (%qE) of %qD...", + m_arg_details.m_arg_idx + 1, + m_arg_details.m_arg_expr, + m_arg_details.m_called_fndecl); + else + return make_label_text (can_colorize, + "while looking for null terminator" + " for argument %i of %qD...", + m_arg_details.m_arg_idx + 1, + m_arg_details.m_called_fndecl); + } + + private: + const call_arg_details m_arg_details; + }; + + class null_terminator_check_decl_note + : public pending_note_subclass + { + public: + null_terminator_check_decl_note (const call_arg_details &arg_details) + : m_arg_details (arg_details) + { + } + + const char *get_kind () const final override + { + return "null_terminator_check_decl_note"; + } + + void emit () const final override + { + inform_about_expected_null_terminated_string_arg (m_arg_details); + } + + bool operator== (const null_terminator_check_decl_note &other) const + { + return m_arg_details == other.m_arg_details; + } + + private: + const call_arg_details m_arg_details; + }; + + /* Subclass of decorated_region_model_context that + adds the above event and note to any saved diagnostics. */ + class annotating_ctxt : public annotating_context + { + public: + annotating_ctxt (const call_details &cd, + unsigned arg_idx) + : annotating_context (cd.get_ctxt ()), + m_cd (cd), + m_arg_idx (arg_idx) + { + } + void add_annotations () final override + { + call_arg_details arg_details (m_cd, m_arg_idx); + event_loc_info loc_info (m_cd.get_location (), + m_cd.get_model ()->get_current_function ()->decl, + m_cd.get_model ()->get_stack_depth ()); + + add_event (make_unique (loc_info, + arg_details)); + add_note (make_unique (arg_details)); + } + private: + const call_details &m_cd; + unsigned m_arg_idx; + }; + + /* Use this ctxt below so that any diagnostics that get added + get annotated. */ + annotating_ctxt my_ctxt (cd, arg_idx); + + const svalue *arg_sval = cd.get_arg_svalue (arg_idx); + const region *buf_reg + = deref_rvalue (arg_sval, cd.get_arg_tree (arg_idx), &my_ctxt); + + if (const svalue *num_bytes_read_sval + = scan_for_null_terminator (buf_reg, + cd.get_arg_tree (arg_idx), + out_sval, + &my_ctxt)) + { + if (include_terminator) + return num_bytes_read_sval; + else + { + /* strlen is (bytes_read - 1). */ + const svalue *one = m_mgr->get_or_create_int_cst (size_type_node, 1); + return m_mgr->get_or_create_binop (size_type_node, + MINUS_EXPR, + num_bytes_read_sval, + one); + } + } + else + return nullptr; +} + /* Remove all bindings overlapping REG within the store. */ void @@ -3343,6 +3945,56 @@ region_model::zero_fill_region (const region *reg) m_store.zero_fill_region (m_mgr->get_store_manager(), reg); } +/* Copy NUM_BYTES_SVAL of SVAL to DEST_REG. + Use CTXT to report any warnings associated with the copy + (e.g. out-of-bounds writes). */ + +void +region_model::write_bytes (const region *dest_reg, + const svalue *num_bytes_sval, + const svalue *sval, + region_model_context *ctxt) +{ + const region *sized_dest_reg + = m_mgr->get_sized_region (dest_reg, NULL_TREE, num_bytes_sval); + set_value (sized_dest_reg, sval, ctxt); +} + +/* Read NUM_BYTES_SVAL from SRC_REG. + Use CTXT to report any warnings associated with the copy + (e.g. out-of-bounds reads, copying of uninitialized values, etc). */ + +const svalue * +region_model::read_bytes (const region *src_reg, + tree src_ptr_expr, + const svalue *num_bytes_sval, + region_model_context *ctxt) const +{ + const region *sized_src_reg + = m_mgr->get_sized_region (src_reg, NULL_TREE, num_bytes_sval); + const svalue *src_contents_sval = get_store_value (sized_src_reg, ctxt); + check_for_poison (src_contents_sval, src_ptr_expr, + sized_src_reg, ctxt); + return src_contents_sval; +} + +/* Copy NUM_BYTES_SVAL bytes from SRC_REG to DEST_REG. + Use CTXT to report any warnings associated with the copy + (e.g. out-of-bounds reads/writes, copying of uninitialized values, + etc). */ + +void +region_model::copy_bytes (const region *dest_reg, + const region *src_reg, + tree src_ptr_expr, + const svalue *num_bytes_sval, + region_model_context *ctxt) +{ + const svalue *data_sval + = read_bytes (src_reg, src_ptr_expr, num_bytes_sval, ctxt); + write_bytes (dest_reg, num_bytes_sval, data_sval, ctxt); +} + /* Mark REG as having unknown content. */ void @@ -3555,6 +4207,29 @@ region_model::eval_condition (const svalue *lhs, } } + /* Attempt to unwrap cast if there is one, and the types match. */ + tree lhs_type = lhs->get_type (); + tree rhs_type = rhs->get_type (); + if (lhs_type && rhs_type) + { + const unaryop_svalue *lhs_un_op = dyn_cast (lhs); + const unaryop_svalue *rhs_un_op = dyn_cast (rhs); + if (lhs_un_op && CONVERT_EXPR_CODE_P (lhs_un_op->get_op ()) + && rhs_un_op && CONVERT_EXPR_CODE_P (rhs_un_op->get_op ()) + && lhs_type == rhs_type) + return eval_condition (lhs_un_op->get_arg (), + op, + rhs_un_op->get_arg ()); + + else if (lhs_un_op && CONVERT_EXPR_CODE_P (lhs_un_op->get_op ()) + && lhs_type == rhs_type) + return eval_condition (lhs_un_op->get_arg (), op, rhs); + + else if (rhs_un_op && CONVERT_EXPR_CODE_P (rhs_un_op->get_op ()) + && lhs_type == rhs_type) + return eval_condition (lhs, op, rhs_un_op->get_arg ()); + } + /* Otherwise, try constraints. Cast to const to ensure we don't change the constraint_manager as we do this (e.g. by creating equivalence classes). */ @@ -4753,6 +5428,7 @@ region_model::pop_frame (tree result_lvalue, { gcc_assert (m_current_frame); + const region_model pre_popped_model = *this; const frame_region *frame_reg = m_current_frame; /* Notify state machines. */ @@ -4786,6 +5462,7 @@ region_model::pop_frame (tree result_lvalue, } unbind_region_and_descendents (frame_reg,POISON_KIND_POPPED_STACK); + notify_on_pop_frame (this, &pre_popped_model, retval, ctxt); } /* Get the number of frames in this region_model's stack. */ @@ -5127,11 +5804,16 @@ region_model::check_dynamic_size_for_floats (const svalue *size_in_bytes, Use CTXT to complain about tainted sizes. Reuse an existing heap_allocated_region if it's not being referenced by - this region_model; otherwise create a new one. */ + this region_model; otherwise create a new one. + + Optionally (update_state_machine) transitions the pointer pointing to the + heap_allocated_region from start to assumed non-null. */ const region * region_model::get_or_create_region_for_heap_alloc (const svalue *size_in_bytes, - region_model_context *ctxt) + region_model_context *ctxt, + bool update_state_machine, + const call_details *cd) { /* Determine which regions are referenced in this region_model, so that we can reuse an existing heap_allocated_region if it's not in use on @@ -5153,6 +5835,14 @@ region_model::get_or_create_region_for_heap_alloc (const svalue *size_in_bytes, if (size_in_bytes) if (compat_types_p (size_in_bytes->get_type (), size_type_node)) set_dynamic_extents (reg, size_in_bytes, ctxt); + + if (update_state_machine && cd) + { + const svalue *ptr_sval + = m_mgr->get_ptr_svalue (cd->get_lhs_type (), reg); + transition_ptr_sval_non_null (ctxt, ptr_sval); + } + return reg; } @@ -5815,6 +6505,11 @@ noop_region_model_context::add_note (std::unique_ptr) { } +void +noop_region_model_context::add_event (std::unique_ptr) +{ +} + void noop_region_model_context::bifurcate (std::unique_ptr) { @@ -5825,6 +6520,15 @@ noop_region_model_context::terminate_path () { } +/* class region_model_context_decorator : public region_model_context. */ + +void +region_model_context_decorator::add_event (std::unique_ptr event) +{ + if (m_inner) + m_inner->add_event (std::move (event)); +} + /* struct model_merger. */ /* Dump a multiline representation of this merger to PP. */ diff --git a/gcc/analyzer/region-model.h b/gcc/analyzer/region-model.h index 0cf38714c969..bb50ff12b12e 100644 --- a/gcc/analyzer/region-model.h +++ b/gcc/analyzer/region-model.h @@ -236,6 +236,11 @@ public: struct append_regions_cb_data; +typedef void (*pop_frame_callback) (const region_model *model, + const region_model *prev_model, + const svalue *retval, + region_model_context *ctxt); + /* A region_model encapsulates a representation of the state of memory, with a tree of regions, along with their associated values. The representation is graph-like because values can be pointers to @@ -367,6 +372,19 @@ class region_model void purge_region (const region *reg); void fill_region (const region *reg, const svalue *sval); void zero_fill_region (const region *reg); + void write_bytes (const region *dest_reg, + const svalue *num_bytes_sval, + const svalue *sval, + region_model_context *ctxt); + const svalue *read_bytes (const region *src_reg, + tree src_ptr_expr, + const svalue *num_bytes_sval, + region_model_context *ctxt) const; + void copy_bytes (const region *dest_reg, + const region *src_reg, + tree src_ptr_expr, + const svalue *num_bytes_sval, + region_model_context *ctxt); void mark_region_as_unknown (const region *reg, uncertainty_t *uncertainty); tristate eval_condition (const svalue *lhs, @@ -387,9 +405,12 @@ class region_model region_model_context *ctxt, rejected_constraint **out); - const region * - get_or_create_region_for_heap_alloc (const svalue *size_in_bytes, - region_model_context *ctxt); + const region * + get_or_create_region_for_heap_alloc (const svalue *size_in_bytes, + region_model_context *ctxt, + bool update_state_machine = false, + const call_details *cd = nullptr); + const region *create_region_for_alloca (const svalue *size_in_bytes, region_model_context *ctxt); void get_referenced_base_regions (auto_bitmap &out_ids) const; @@ -448,6 +469,13 @@ class region_model const svalue *get_store_value (const region *reg, region_model_context *ctxt) const; + const svalue *get_store_bytes (const region *base_reg, + const byte_range &bytes, + region_model_context *ctxt) const; + const svalue *scan_for_null_terminator (const region *reg, + tree expr, + const svalue **out_sval, + region_model_context *ctxt) const; bool region_exists_p (const region *reg) const; @@ -455,9 +483,6 @@ class region_model const svalue *get_capacity (const region *reg) const; - const svalue *get_string_size (const svalue *sval) const; - const svalue *get_string_size (const region *reg) const; - bool replay_call_summary (call_summary_replay &r, const region_model &summary); @@ -476,6 +501,11 @@ class region_model const svalue *old_ptr_sval, const svalue *new_ptr_sval); + /* Implemented in sm-malloc.cc. */ + void + transition_ptr_sval_non_null (region_model_context *ctxt, + const svalue *new_ptr_sval); + /* Implemented in sm-taint.cc. */ void mark_as_tainted (const svalue *sval, region_model_context *ctxt); @@ -494,6 +524,35 @@ class region_model const svalue *sval_hint, region_model_context *ctxt) const; + void + check_for_null_terminated_string_arg (const call_details &cd, + unsigned idx); + const svalue * + check_for_null_terminated_string_arg (const call_details &cd, + unsigned idx, + bool include_terminator, + const svalue **out_sval); + + const builtin_known_function * + get_builtin_kf (const gcall *call, + region_model_context *ctxt = NULL) const; + + static void + register_pop_frame_callback (const pop_frame_callback &callback) + { + pop_frame_callbacks.safe_push (callback); + } + + static void + notify_on_pop_frame (const region_model *model, + const region_model *prev_model, + const svalue *retval, + region_model_context *ctxt) + { + for (auto &callback : pop_frame_callbacks) + callback (model, prev_model, retval, ctxt); + } + private: const region *get_lvalue_1 (path_var pv, region_model_context *ctxt) const; const svalue *get_rvalue_1 (path_var pv, region_model_context *ctxt) const; @@ -577,10 +636,13 @@ private: region_model_context *ctxt) const; void check_call_args (const call_details &cd) const; + void check_call_format_attr (const call_details &cd, + tree format_attr) const; void check_external_function_for_access_attr (const gcall *call, tree callee_fndecl, region_model_context *ctxt) const; + static auto_vec pop_frame_callbacks; /* Storing this here to avoid passing it around everywhere. */ region_model_manager *const m_mgr; @@ -609,13 +671,19 @@ class region_model_context { public: /* Hook for clients to store pending diagnostics. - Return true if the diagnostic was stored, or false if it was deleted. */ - virtual bool warn (std::unique_ptr d) = 0; + Return true if the diagnostic was stored, or false if it was deleted. + Optionally provide a custom stmt_finder. */ + virtual bool warn (std::unique_ptr d, + const stmt_finder *custom_finder = NULL) = 0; /* Hook for clients to add a note to the last previously stored pending diagnostic. */ virtual void add_note (std::unique_ptr pn) = 0; + /* Hook for clients to add an event to the last previously stored + pending diagnostic. */ + virtual void add_event (std::unique_ptr event) = 0; + /* Hook for clients to be notified when an SVAL that was reachable in a previous state is no longer live, so that clients can emit warnings about leaks. */ @@ -713,6 +781,8 @@ class region_model_context /* Get the current statement, if any. */ virtual const gimple *get_stmt () const = 0; + + virtual const exploded_graph *get_eg () const = 0; }; /* A "do nothing" subclass of region_model_context. */ @@ -720,8 +790,10 @@ class region_model_context class noop_region_model_context : public region_model_context { public: - bool warn (std::unique_ptr) override { return false; } + bool warn (std::unique_ptr d, + const stmt_finder *custom_finder) override { return false; } void add_note (std::unique_ptr) override; + void add_event (std::unique_ptr) override; void on_svalue_leak (const svalue *) override {} void on_liveness_change (const svalue_set &, const region_model *) override {} @@ -767,6 +839,7 @@ public: } const gimple *get_stmt () const override { return NULL; } + const exploded_graph *get_eg () const override { return NULL; } }; /* A subclass of region_model_context for determining if operations fail @@ -795,94 +868,121 @@ private: class region_model_context_decorator : public region_model_context { public: - bool warn (std::unique_ptr d) override + bool warn (std::unique_ptr d, + const stmt_finder *custom_finder) { - return m_inner->warn (std::move (d)); + if (m_inner) + return m_inner->warn (std::move (d), custom_finder); + else + return false; } void add_note (std::unique_ptr pn) override { - m_inner->add_note (std::move (pn)); + if (m_inner) + m_inner->add_note (std::move (pn)); } + void add_event (std::unique_ptr event) override; void on_svalue_leak (const svalue *sval) override { - m_inner->on_svalue_leak (sval); + if (m_inner) + m_inner->on_svalue_leak (sval); } void on_liveness_change (const svalue_set &live_svalues, const region_model *model) override { - m_inner->on_liveness_change (live_svalues, model); + if (m_inner) + m_inner->on_liveness_change (live_svalues, model); } logger *get_logger () override { - return m_inner->get_logger (); + if (m_inner) + return m_inner->get_logger (); + else + return nullptr; } void on_condition (const svalue *lhs, enum tree_code op, const svalue *rhs) override { - m_inner->on_condition (lhs, op, rhs); + if (m_inner) + m_inner->on_condition (lhs, op, rhs); } void on_bounded_ranges (const svalue &sval, const bounded_ranges &ranges) override { - m_inner->on_bounded_ranges (sval, ranges); + if (m_inner) + m_inner->on_bounded_ranges (sval, ranges); } void on_pop_frame (const frame_region *frame_reg) override { - m_inner->on_pop_frame (frame_reg); + if (m_inner) + m_inner->on_pop_frame (frame_reg); } void on_unknown_change (const svalue *sval, bool is_mutable) override { - m_inner->on_unknown_change (sval, is_mutable); + if (m_inner) + m_inner->on_unknown_change (sval, is_mutable); } void on_phi (const gphi *phi, tree rhs) override { - m_inner->on_phi (phi, rhs); + if (m_inner) + m_inner->on_phi (phi, rhs); } void on_unexpected_tree_code (tree t, const dump_location_t &loc) override { - m_inner->on_unexpected_tree_code (t, loc); + if (m_inner) + m_inner->on_unexpected_tree_code (t, loc); } void on_escaped_function (tree fndecl) override { - m_inner->on_escaped_function (fndecl); + if (m_inner) + m_inner->on_escaped_function (fndecl); } uncertainty_t *get_uncertainty () override { - return m_inner->get_uncertainty (); + if (m_inner) + return m_inner->get_uncertainty (); + else + return nullptr; } void purge_state_involving (const svalue *sval) override { - m_inner->purge_state_involving (sval); + if (m_inner) + m_inner->purge_state_involving (sval); } void bifurcate (std::unique_ptr info) override { - m_inner->bifurcate (std::move (info)); + if (m_inner) + m_inner->bifurcate (std::move (info)); } void terminate_path () override { - m_inner->terminate_path (); + if (m_inner) + m_inner->terminate_path (); } const extrinsic_state *get_ext_state () const override { - return m_inner->get_ext_state (); + if (m_inner) + return m_inner->get_ext_state (); + else + return nullptr; } bool get_state_map_by_name (const char *name, @@ -892,47 +992,61 @@ class region_model_context_decorator : public region_model_context std::unique_ptr *out_sm_context) override { - return m_inner->get_state_map_by_name (name, out_smap, out_sm, out_sm_idx, - out_sm_context); + if (m_inner) + return m_inner->get_state_map_by_name (name, out_smap, out_sm, out_sm_idx, + out_sm_context); + else + return false; } const gimple *get_stmt () const override { - return m_inner->get_stmt (); + if (m_inner) + return m_inner->get_stmt (); + else + return nullptr; + } + + const exploded_graph *get_eg () const override + { + if (m_inner) + return m_inner->get_eg (); + else + return nullptr; } protected: region_model_context_decorator (region_model_context *inner) : m_inner (inner) { - gcc_assert (m_inner); } region_model_context *m_inner; }; -/* Subclass of region_model_context_decorator that adds a note - when saving diagnostics. */ +/* Subclass of region_model_context_decorator with a hook for adding + notes/events when saving diagnostics. */ -class note_adding_context : public region_model_context_decorator +class annotating_context : public region_model_context_decorator { public: - bool warn (std::unique_ptr d) override + bool warn (std::unique_ptr d, + const stmt_finder *custom_finder) override { - if (m_inner->warn (std::move (d))) - { - add_note (make_note ()); - return true; - } - else - return false; + if (m_inner) + if (m_inner->warn (std::move (d), custom_finder)) + { + add_annotations (); + return true; + } + return false; } - /* Hook to make the new note. */ - virtual std::unique_ptr make_note () = 0; + /* Hook to add new event(s)/note(s) */ + virtual void add_annotations () = 0; protected: - note_adding_context (region_model_context *inner) + annotating_context (region_model_context *inner) : region_model_context_decorator (inner) { } @@ -1082,7 +1196,8 @@ using namespace ::selftest; class test_region_model_context : public noop_region_model_context { public: - bool warn (std::unique_ptr d) final override + bool warn (std::unique_ptr d, + const stmt_finder *custom_finder) final override { m_diagnostics.safe_push (d.release ()); return true; diff --git a/gcc/analyzer/sm-fd.cc b/gcc/analyzer/sm-fd.cc index 03ad3598a3cd..34bbd84f6e7e 100644 --- a/gcc/analyzer/sm-fd.cc +++ b/gcc/analyzer/sm-fd.cc @@ -1294,8 +1294,19 @@ fd_state_machine::check_for_fd_attrs ( const gcall *call, const tree callee_fndecl, const char *attr_name, access_directions fd_attr_access_dir) const { + /* Handle interesting fd attributes of the callee_fndecl, + or prioritize those of the builtin that callee_fndecl is + expected to be. + Might want this to be controlled by a flag. */ + tree fndecl = callee_fndecl; + /* If call is recognized as a builtin known_function, + use that builtin's function_decl. */ + if (const region_model *old_model = sm_ctxt->get_old_region_model ()) + if (const builtin_known_function *builtin_kf + = old_model->get_builtin_kf (call)) + fndecl = builtin_kf->builtin_decl (); - tree attrs = TYPE_ATTRIBUTES (TREE_TYPE (callee_fndecl)); + tree attrs = TYPE_ATTRIBUTES (TREE_TYPE (fndecl)); attrs = lookup_attribute (attr_name, attrs); if (!attrs) return; @@ -1325,13 +1336,15 @@ fd_state_machine::check_for_fd_attrs ( // attributes { + /* Do use the fndecl that caused the warning so that the + misused attributes are printed and the user not confused. */ if (is_closed_fd_p (state)) { sm_ctxt->warn (node, stmt, arg, make_unique (*this, diag_arg, - callee_fndecl, attr_name, + fndecl, attr_name, arg_idx)); continue; } @@ -1343,7 +1356,7 @@ fd_state_machine::check_for_fd_attrs ( sm_ctxt->warn (node, stmt, arg, make_unique (*this, diag_arg, - callee_fndecl, attr_name, + fndecl, attr_name, arg_idx)); continue; } @@ -1361,7 +1374,7 @@ fd_state_machine::check_for_fd_attrs ( node, stmt, arg, make_unique (*this, diag_arg, DIRS_WRITE, - callee_fndecl, + fndecl, attr_name, arg_idx)); } @@ -1375,7 +1388,7 @@ fd_state_machine::check_for_fd_attrs ( node, stmt, arg, make_unique (*this, diag_arg, DIRS_READ, - callee_fndecl, + fndecl, attr_name, arg_idx)); } @@ -2282,10 +2295,16 @@ public: const fd_state_machine *fd_sm; std::unique_ptr sm_ctxt; if (!get_fd_state (ctxt, &smap, &fd_sm, NULL, &sm_ctxt)) - return true; + { + cd.set_any_lhs_with_defaults (); + return true; + } const extrinsic_state *ext_state = ctxt->get_ext_state (); if (!ext_state) - return true; + { + cd.set_any_lhs_with_defaults (); + return true; + } return fd_sm->on_socket (cd, m_success, sm_ctxt.get (), *ext_state); } @@ -2329,10 +2348,16 @@ public: const fd_state_machine *fd_sm; std::unique_ptr sm_ctxt; if (!get_fd_state (ctxt, &smap, &fd_sm, NULL, &sm_ctxt)) - return true; + { + cd.set_any_lhs_with_defaults (); + return true; + } const extrinsic_state *ext_state = ctxt->get_ext_state (); if (!ext_state) - return true; + { + cd.set_any_lhs_with_defaults (); + return true; + } return fd_sm->on_bind (cd, m_success, sm_ctxt.get (), *ext_state); } }; @@ -2374,10 +2399,16 @@ class kf_listen : public known_function const fd_state_machine *fd_sm; std::unique_ptr sm_ctxt; if (!get_fd_state (ctxt, &smap, &fd_sm, NULL, &sm_ctxt)) - return true; + { + cd.set_any_lhs_with_defaults (); + return true; + } const extrinsic_state *ext_state = ctxt->get_ext_state (); if (!ext_state) - return true; + { + cd.set_any_lhs_with_defaults (); + return true; + } return fd_sm->on_listen (cd, m_success, sm_ctxt.get (), *ext_state); } @@ -2420,10 +2451,16 @@ class kf_accept : public known_function const fd_state_machine *fd_sm; std::unique_ptr sm_ctxt; if (!get_fd_state (ctxt, &smap, &fd_sm, NULL, &sm_ctxt)) - return true; + { + cd.set_any_lhs_with_defaults (); + return true; + } const extrinsic_state *ext_state = ctxt->get_ext_state (); if (!ext_state) - return true; + { + cd.set_any_lhs_with_defaults (); + return true; + } return fd_sm->on_accept (cd, m_success, sm_ctxt.get (), *ext_state); } @@ -2469,10 +2506,16 @@ public: const fd_state_machine *fd_sm; std::unique_ptr sm_ctxt; if (!get_fd_state (ctxt, &smap, &fd_sm, NULL, &sm_ctxt)) - return true; + { + cd.set_any_lhs_with_defaults (); + return true; + } const extrinsic_state *ext_state = ctxt->get_ext_state (); if (!ext_state) - return true; + { + cd.set_any_lhs_with_defaults (); + return true; + } return fd_sm->on_connect (cd, m_success, sm_ctxt.get (), *ext_state); } @@ -2687,6 +2730,7 @@ public: const svalue *new_sval = cd.get_or_create_conjured_svalue (base_reg); model->set_value (base_reg, new_sval, cd.get_ctxt ()); } + cd.set_any_lhs_with_defaults (); } }; diff --git a/gcc/analyzer/sm-file.cc b/gcc/analyzer/sm-file.cc index 0cfe68217229..0252b3922d42 100644 --- a/gcc/analyzer/sm-file.cc +++ b/gcc/analyzer/sm-file.cc @@ -494,7 +494,7 @@ make_fileptr_state_machine (logger *logger) effects that are out of scope for the analyzer: we only want to model the effects on the return value. */ -class kf_stdio_output_fn : public known_function +class kf_stdio_output_fn : public pure_known_function_with_default_return { public: bool matches_call_types_p (const call_details &) const final override @@ -507,7 +507,7 @@ public: /* Handler for "ferror"". */ -class kf_ferror : public known_function +class kf_ferror : public pure_known_function_with_default_return { public: bool matches_call_types_p (const call_details &cd) const final override @@ -521,7 +521,7 @@ public: /* Handler for "fileno"". */ -class kf_fileno : public known_function +class kf_fileno : public pure_known_function_with_default_return { public: bool matches_call_types_p (const call_details &cd) const final override @@ -557,6 +557,7 @@ public: const svalue *new_sval = cd.get_or_create_conjured_svalue (base_reg); model->set_value (base_reg, new_sval, cd.get_ctxt ()); } + cd.set_any_lhs_with_defaults (); } }; @@ -592,12 +593,13 @@ public: const svalue *new_sval = cd.get_or_create_conjured_svalue (base_reg); model->set_value (base_reg, new_sval, cd.get_ctxt ()); } + cd.set_any_lhs_with_defaults (); } }; /* Handler for "getc"". */ -class kf_getc : public known_function +class kf_getc : public pure_known_function_with_default_return { public: bool matches_call_types_p (const call_details &cd) const final override @@ -605,13 +607,11 @@ public: return (cd.num_args () == 1 && cd.arg_is_pointer_p (0)); } - - /* No side effects. */ }; /* Handler for "getchar"". */ -class kf_getchar : public known_function +class kf_getchar : public pure_known_function_with_default_return { public: bool matches_call_types_p (const call_details &cd) const final override diff --git a/gcc/analyzer/sm-malloc.cc b/gcc/analyzer/sm-malloc.cc index a8c63eb1ce88..5af654414b49 100644 --- a/gcc/analyzer/sm-malloc.cc +++ b/gcc/analyzer/sm-malloc.cc @@ -434,6 +434,11 @@ public: const svalue *new_ptr_sval, const extrinsic_state &ext_state) const; + void transition_ptr_sval_non_null (region_model *model, + sm_state_map *smap, + const svalue *new_ptr_sval, + const extrinsic_state &ext_state) const; + standard_deallocator_set m_free; standard_deallocator_set m_scalar_delete; standard_deallocator_set m_vector_delete; @@ -754,7 +759,7 @@ public: override { if (change.m_old_state == m_sm.get_start_state () - && unchecked_p (change.m_new_state)) + && (unchecked_p (change.m_new_state) || nonnull_p (change.m_new_state))) // TODO: verify that it's the allocation stmt, not a copy return label_text::borrow ("allocated here"); if (unchecked_p (change.m_old_state) @@ -1174,6 +1179,21 @@ public: { return ev.formatted_print ("dereference of NULL %qE", ev.m_expr); } + + /* Implementation of pending_diagnostic::supercedes_p for + null-deref. + + We want null-deref to supercede use-of-unitialized-value, + so that if we have these at the same stmt, we don't emit + a use-of-uninitialized, just the null-deref. */ + + bool supercedes_p (const pending_diagnostic &other) const final override + { + if (other.use_of_uninit_p ()) + return true; + + return false; + } }; /* Concrete subclass for describing passing a NULL value to a @@ -1910,12 +1930,20 @@ malloc_state_machine::on_stmt (sm_context *sm_ctxt, return true; } - if (is_named_call_p (callee_fndecl, "operator new", call, 1)) - on_allocator_call (sm_ctxt, call, &m_scalar_delete); - else if (is_named_call_p (callee_fndecl, "operator new []", call, 1)) - on_allocator_call (sm_ctxt, call, &m_vector_delete); - else if (is_named_call_p (callee_fndecl, "operator delete", call, 1) - || is_named_call_p (callee_fndecl, "operator delete", call, 2)) + if (!is_placement_new_p (call)) + { + bool returns_nonnull = !TREE_NOTHROW (callee_fndecl) + && flag_exceptions; + if (is_named_call_p (callee_fndecl, "operator new")) + on_allocator_call (sm_ctxt, call, + &m_scalar_delete, returns_nonnull); + else if (is_named_call_p (callee_fndecl, "operator new []")) + on_allocator_call (sm_ctxt, call, + &m_vector_delete, returns_nonnull); + } + + if (is_named_call_p (callee_fndecl, "operator delete", call, 1) + || is_named_call_p (callee_fndecl, "operator delete", call, 2)) { on_deallocator_call (sm_ctxt, node, call, &m_scalar_delete.m_deallocator, 0); @@ -1960,71 +1988,88 @@ malloc_state_machine::on_stmt (sm_context *sm_ctxt, malloc_state_machine *mutable_this = const_cast (this); - /* Handle "__attribute__((malloc(FOO)))". */ - if (const deallocator_set *deallocators + /* Handle interesting attributes of the callee_fndecl, + or prioritize those of the builtin that callee_fndecl is expected + to be. + Might want this to be controlled by a flag. */ + { + tree fndecl = callee_fndecl; + /* If call is recognized as a builtin known_function, use that + builtin's function_decl. */ + if (const region_model *old_model = sm_ctxt->get_old_region_model ()) + if (const builtin_known_function *builtin_kf + = old_model->get_builtin_kf (call)) + fndecl = builtin_kf->builtin_decl (); + + /* Handle "__attribute__((malloc(FOO)))". */ + if (const deallocator_set *deallocators = mutable_this->get_or_create_custom_deallocator_set - (callee_fndecl)) + (fndecl)) + { + tree attrs = TYPE_ATTRIBUTES (TREE_TYPE (fndecl)); + bool returns_nonnull + = lookup_attribute ("returns_nonnull", attrs); + on_allocator_call (sm_ctxt, call, deallocators, returns_nonnull); + } + { - tree attrs = TYPE_ATTRIBUTES (TREE_TYPE (callee_fndecl)); - bool returns_nonnull - = lookup_attribute ("returns_nonnull", attrs); - on_allocator_call (sm_ctxt, call, deallocators, returns_nonnull); + /* Handle "__attribute__((nonnull))". */ + tree fntype = TREE_TYPE (fndecl); + bitmap nonnull_args = get_nonnull_args (fntype); + if (nonnull_args) + { + for (unsigned i = 0; i < gimple_call_num_args (stmt); i++) + { + tree arg = gimple_call_arg (stmt, i); + if (TREE_CODE (TREE_TYPE (arg)) != POINTER_TYPE) + continue; + /* If we have a nonnull-args, and either all pointers, or + just the specified pointers. */ + if (bitmap_empty_p (nonnull_args) + || bitmap_bit_p (nonnull_args, i)) + { + state_t state = sm_ctxt->get_state (stmt, arg); + /* Can't use a switch as the states are non-const. */ + /* Do use the fndecl that caused the warning so that the + misused attributes are printed and the user not + confused. */ + if (unchecked_p (state)) + { + tree diag_arg = sm_ctxt->get_diagnostic_tree (arg); + sm_ctxt->warn (node, stmt, arg, + make_unique + (*this, diag_arg, fndecl, i)); + const allocation_state *astate + = as_a_allocation_state (state); + sm_ctxt->set_next_state (stmt, arg, + astate->get_nonnull ()); + } + else if (state == m_null) + { + tree diag_arg = sm_ctxt->get_diagnostic_tree (arg); + sm_ctxt->warn (node, stmt, arg, + make_unique + (*this, diag_arg, fndecl, i)); + sm_ctxt->set_next_state (stmt, arg, m_stop); + } + else if (state == m_start) + maybe_assume_non_null (sm_ctxt, arg, stmt); + } + } + BITMAP_FREE (nonnull_args); + } } - /* Handle "__attribute__((nonnull))". */ - { - tree fntype = TREE_TYPE (callee_fndecl); - bitmap nonnull_args = get_nonnull_args (fntype); - if (nonnull_args) + /* Check for this after nonnull, so that if we have both + then we transition to "freed", rather than "checked". */ + unsigned dealloc_argno = fndecl_dealloc_argno (fndecl); + if (dealloc_argno != UINT_MAX) { - for (unsigned i = 0; i < gimple_call_num_args (stmt); i++) - { - tree arg = gimple_call_arg (stmt, i); - if (TREE_CODE (TREE_TYPE (arg)) != POINTER_TYPE) - continue; - /* If we have a nonnull-args, and either all pointers, or just - the specified pointers. */ - if (bitmap_empty_p (nonnull_args) - || bitmap_bit_p (nonnull_args, i)) - { - state_t state = sm_ctxt->get_state (stmt, arg); - /* Can't use a switch as the states are non-const. */ - if (unchecked_p (state)) - { - tree diag_arg = sm_ctxt->get_diagnostic_tree (arg); - sm_ctxt->warn (node, stmt, arg, - make_unique - (*this, diag_arg, callee_fndecl, i)); - const allocation_state *astate - = as_a_allocation_state (state); - sm_ctxt->set_next_state (stmt, arg, - astate->get_nonnull ()); - } - else if (state == m_null) - { - tree diag_arg = sm_ctxt->get_diagnostic_tree (arg); - sm_ctxt->warn (node, stmt, arg, - make_unique - (*this, diag_arg, callee_fndecl, i)); - sm_ctxt->set_next_state (stmt, arg, m_stop); - } - else if (state == m_start) - maybe_assume_non_null (sm_ctxt, arg, stmt); - } - } - BITMAP_FREE (nonnull_args); + const deallocator *d + = mutable_this->get_or_create_deallocator (fndecl); + on_deallocator_call (sm_ctxt, node, call, d, dealloc_argno); } } - - /* Check for this after nonnull, so that if we have both - then we transition to "freed", rather than "checked". */ - unsigned dealloc_argno = fndecl_dealloc_argno (callee_fndecl); - if (dealloc_argno != UINT_MAX) - { - const deallocator *d - = mutable_this->get_or_create_deallocator (callee_fndecl); - on_deallocator_call (sm_ctxt, node, call, d, dealloc_argno); - } } /* Look for pointers explicitly being compared against zero @@ -2504,6 +2549,17 @@ on_realloc_with_move (region_model *model, NULL, ext_state); } +/* Hook for get_or_create_region_for_heap_alloc for the case when we want + ptr_sval to mark a newly created region as assumed non null on malloc SM. */ +void +malloc_state_machine::transition_ptr_sval_non_null (region_model *model, + sm_state_map *smap, + const svalue *new_ptr_sval, + const extrinsic_state &ext_state) const +{ + smap->set_state (model, new_ptr_sval, m_free.m_nonnull, NULL, ext_state); +} + } // anonymous namespace /* Internal interface to this file. */ @@ -2548,6 +2604,32 @@ region_model::on_realloc_with_move (const call_details &cd, *ext_state); } +/* Moves ptr_sval from start to assumed non-null, for use by + region_model::get_or_create_region_for_heap_alloc. */ +void +region_model::transition_ptr_sval_non_null (region_model_context *ctxt, +const svalue *ptr_sval) +{ + if (!ctxt) + return; + const extrinsic_state *ext_state = ctxt->get_ext_state (); + if (!ext_state) + return; + + sm_state_map *smap; + const state_machine *sm; + unsigned sm_idx; + if (!ctxt->get_malloc_map (&smap, &sm, &sm_idx)) + return; + + gcc_assert (smap); + gcc_assert (sm); + + const malloc_state_machine &malloc_sm = (const malloc_state_machine &)*sm; + + malloc_sm.transition_ptr_sval_non_null (this, smap, ptr_sval, *ext_state); +} + } // namespace ana #endif /* #if ENABLE_ANALYZER */ diff --git a/gcc/analyzer/store.cc b/gcc/analyzer/store.cc index c7bc4b40f87c..aeea69311378 100644 --- a/gcc/analyzer/store.cc +++ b/gcc/analyzer/store.cc @@ -538,6 +538,15 @@ concrete_binding::overlaps_p (const concrete_binding &other) const return false; } +/* If this is expressible as a concrete byte range, return true + and write it to *OUT. Otherwise return false. */ + +bool +concrete_binding::get_byte_range (byte_range *out) const +{ + return m_bit_range.as_byte_range (out); +} + /* Comparator for use by vec::qsort. */ int diff --git a/gcc/analyzer/store.h b/gcc/analyzer/store.h index af6cc7ed03c7..cf10fa3b0108 100644 --- a/gcc/analyzer/store.h +++ b/gcc/analyzer/store.h @@ -399,6 +399,7 @@ public: { return this; } const bit_range &get_bit_range () const { return m_bit_range; } + bool get_byte_range (byte_range *out) const; bit_offset_t get_start_bit_offset () const { @@ -855,6 +856,12 @@ public: return get_concrete_binding (bits.get_start_bit_offset (), bits.m_size_in_bits); } + const concrete_binding * + get_concrete_binding (const byte_range &bytes) + { + bit_range bits = bytes.as_bit_range (); + return get_concrete_binding (bits); + } const symbolic_binding * get_symbolic_binding (const region *region); diff --git a/gcc/analyzer/svalue.cc b/gcc/analyzer/svalue.cc index 064627f3dcc0..35eb8307b203 100644 --- a/gcc/analyzer/svalue.cc +++ b/gcc/analyzer/svalue.cc @@ -970,6 +970,8 @@ poison_kind_to_str (enum poison_kind kind) return "uninit"; case POISON_KIND_FREED: return "freed"; + case POISON_KIND_DELETED: + return "deleted"; case POISON_KIND_POPPED_STACK: return "popped stack"; } diff --git a/gcc/analyzer/svalue.h b/gcc/analyzer/svalue.h index 5492b1e0b7ca..263a0d7af6f5 100644 --- a/gcc/analyzer/svalue.h +++ b/gcc/analyzer/svalue.h @@ -350,6 +350,9 @@ enum poison_kind /* For use to describe freed memory. */ POISON_KIND_FREED, + /* For use to describe deleted memory. */ + POISON_KIND_DELETED, + /* For use on pointers to regions within popped stack frames. */ POISON_KIND_POPPED_STACK }; diff --git a/gcc/analyzer/varargs.cc b/gcc/analyzer/varargs.cc index 72e1b31601cd..f79b2a7d7b51 100644 --- a/gcc/analyzer/varargs.cc +++ b/gcc/analyzer/varargs.cc @@ -1007,6 +1007,8 @@ kf_va_arg::impl_call_pre (const call_details &cd) const tree va_list_tree = get_va_list_diag_arg (cd.get_arg_tree (0)); ap_sval = model->check_for_poison (ap_sval, va_list_tree, ap_reg, ctxt); + cd.set_any_lhs_with_defaults (); + if (const region *impl_reg = ap_sval->maybe_get_region ()) { const svalue *old_impl_sval = model->get_store_value (impl_reg, ctxt); diff --git a/gcc/auto-profile.cc b/gcc/auto-profile.cc index e3af3555e753..ff3b763945cf 100644 --- a/gcc/auto-profile.cc +++ b/gcc/auto-profile.cc @@ -1578,6 +1578,7 @@ afdo_annotate_cfg (const stmt_set &promoted_stmts) } update_max_bb_count (); profile_status_for_fn (cfun) = PROFILE_READ; + cfun->cfg->full_profile = true; if (flag_value_profile_transformations) { gimple_value_profile_transformations (); diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog index a067b12b0386..3559e4ca089d 100644 --- a/gcc/c-family/ChangeLog +++ b/gcc/c-family/ChangeLog @@ -1,3 +1,62 @@ +2023-09-01 Jakub Jelinek + + PR c++/111069 + * c-opts.cc (c_common_post_options): Change latest_abi_version to 19. + +2023-08-31 Francois-Xavier Coudert + + * c.opt: Change spelling to macOS. + +2023-08-31 Richard Biener + + PR middle-end/111253 + * c-pretty-print.cc (c_pretty_printer::primary_expression): + Only dump gimple_assign_single_p SSA def RHS. + +2023-08-25 Sandra Loosemore + + * c-common.h (c_omp_check_loop_binding_exprs): Declare. + * c-omp.cc: Include tree-iterator.h. + (find_binding_in_body): New. + (check_loop_binding_expr_r): New. + (LOCATION_OR): New. + (check_looop_binding_expr): New. + (c_omp_check_loop_binding_exprs): New. + +2023-08-25 Uros Bizjak + + * c-format.cc (read_any_format_width): + Rename TRUE/FALSE to true/false. + +2023-08-20 Martin Uecker + + * c-format.cc: Fix identation. + +2023-08-20 Tomas Kalibera + + PR c/95130 + * c-format.cc: skip default format for printf symbol if + explicitly declared by prototype. + +2023-08-17 Jose E. Marchesi + + PR c/106537 + * c.opt (Wcompare-distinct-pointer-types): New option. + +2023-08-14 Jason Merrill + + * c-cppbuiltin.cc (c_cpp_builtins): Adjust __cpp_concepts. + +2023-08-11 Jakub Jelinek + + * c-common.cc (c_common_reswords): Add __typeof_unqual + and __typeof_unqual__ spellings of typeof_unqual. + +2023-08-11 Martin Uecker + + PR c/84510 + * c.opt: Enable warning for C and ObjC. + 2023-08-05 Martin Uecker PR c/98536 diff --git a/gcc/c-family/c-common.cc b/gcc/c-family/c-common.cc index 9fbaeb437a12..268462f900e8 100644 --- a/gcc/c-family/c-common.cc +++ b/gcc/c-family/c-common.cc @@ -420,6 +420,8 @@ const struct c_common_resword c_common_reswords[] = { "__transaction_cancel", RID_TRANSACTION_CANCEL, 0 }, { "__typeof", RID_TYPEOF, 0 }, { "__typeof__", RID_TYPEOF, 0 }, + { "__typeof_unqual", RID_TYPEOF_UNQUAL, D_CONLY }, + { "__typeof_unqual__", RID_TYPEOF_UNQUAL, D_CONLY }, { "__volatile", RID_VOLATILE, 0 }, { "__volatile__", RID_VOLATILE, 0 }, { "__GIMPLE", RID_GIMPLE, D_CONLY }, diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h index 78fc5248ba68..732cb4eff642 100644 --- a/gcc/c-family/c-common.h +++ b/gcc/c-family/c-common.h @@ -1299,6 +1299,7 @@ extern tree c_finish_omp_for (location_t, enum tree_code, tree, tree, tree, extern bool c_omp_check_loop_iv (tree, tree, walk_tree_lh); extern bool c_omp_check_loop_iv_exprs (location_t, enum tree_code, tree, int, tree, tree, tree, walk_tree_lh); +extern bool c_omp_check_loop_binding_exprs (tree, vec *); extern tree c_finish_oacc_wait (location_t, tree, tree); extern tree c_oacc_split_loop_clauses (tree, tree *, bool); extern void c_omp_split_clauses (location_t, enum tree_code, omp_clause_mask, diff --git a/gcc/c-family/c-cppbuiltin.cc b/gcc/c-family/c-cppbuiltin.cc index 6bd4c1261a76..f2b12fd63db7 100644 --- a/gcc/c-family/c-cppbuiltin.cc +++ b/gcc/c-family/c-cppbuiltin.cc @@ -1089,7 +1089,7 @@ c_cpp_builtins (cpp_reader *pfile) } if (flag_concepts) { - if (cxx_dialect >= cxx20) + if (cxx_dialect >= cxx20 || !flag_concepts_ts) cpp_define (pfile, "__cpp_concepts=202002L"); else cpp_define (pfile, "__cpp_concepts=201507L"); diff --git a/gcc/c-family/c-format.cc b/gcc/c-family/c-format.cc index b4eeebcb30e1..b9906ecc1711 100644 --- a/gcc/c-family/c-format.cc +++ b/gcc/c-family/c-format.cc @@ -1175,6 +1175,7 @@ check_function_format (const_tree fn, tree attrs, int nargs, tree a; tree atname = get_identifier ("format"); + bool skipped_default_format = false; /* See if this function has any format attributes. */ for (a = attrs; a; a = TREE_CHAIN (a)) @@ -1185,6 +1186,38 @@ check_function_format (const_tree fn, tree attrs, int nargs, function_format_info info; decode_format_attr (fn, atname, TREE_VALUE (a), &info, /*validated=*/true); + + /* Mingw32 targets have traditionally used ms_printf format for the + printf function, and this format is built in GCC. But nowadays, + if mingw-w64 is configured to target UCRT, the printf function + uses the gnu_printf format (specified in the stdio.h header). This + causes GCC to check both formats, which means that GCC would + warn twice about the same issue when both formats are violated, + e.g. for %lu used to print long long unsigned. + + Hence, if there is a built-in attribute specifier and at least + one another, we skip the built-in one. See PR 95130 (but note that + GCC ms_printf already supports %llu) and PR 92292. */ + + if (!skipped_default_format + && fn + && TREE_CODE (fn) == FUNCTION_DECL + && fndecl_built_in_p (fn, BUILT_IN_NORMAL) + && (tree_to_uhwi (TREE_PURPOSE (TREE_VALUE (a))) + & (int) ATTR_FLAG_BUILT_IN)) + { + tree aa; + for (aa = attrs; aa; aa = TREE_CHAIN (aa)) + if (a != aa + && is_attribute_p ("format", get_attribute_name (aa))) + { + skipped_default_format = true; + break; + } + if (skipped_default_format) + continue; + } + if (warn_format) { /* FIXME: Rewrite all the internal functions in this file @@ -2292,13 +2325,13 @@ read_any_format_width (tree ¶ms, { /* Possibly read a numeric width. If the width is zero, we complain if appropriate. */ - int non_zero_width_char = FALSE; - int found_width = FALSE; + int non_zero_width_char = false; + int found_width = false; while (ISDIGIT (*format_chars)) { - found_width = TRUE; + found_width = true; if (*format_chars != '0') - non_zero_width_char = TRUE; + non_zero_width_char = true; ++format_chars; } if (found_width && !non_zero_width_char && @@ -5190,6 +5223,9 @@ handle_format_attribute (tree node[3], tree atname, tree args, if (TREE_CODE (TREE_VALUE (args)) == IDENTIFIER_NODE) TREE_VALUE (args) = canonicalize_attr_name (TREE_VALUE (args)); + /* record the flags for check_function_format */ + TREE_PURPOSE (args) = build_int_cst (unsigned_type_node, flags); + if (!decode_format_attr (fndecl ? fndecl : type, atname, args, &info, /* validated_p = */false)) { diff --git a/gcc/c-family/c-omp.cc b/gcc/c-family/c-omp.cc index 4faddb00bbcb..9b7d7f789e3d 100644 --- a/gcc/c-family/c-omp.cc +++ b/gcc/c-family/c-omp.cc @@ -36,6 +36,7 @@ along with GCC; see the file COPYING3. If not see #include "gimplify.h" #include "langhooks.h" #include "bitmap.h" +#include "tree-iterator.h" /* Complete a #pragma oacc wait construct. LOC is the location of @@ -1728,6 +1729,156 @@ c_omp_check_loop_iv_exprs (location_t stmt_loc, enum tree_code code, return !data.fail; } + +/* Helper function for c_omp_check_loop_binding_exprs: look for a binding + of DECL in BODY. Only traverse things that might be containers for + intervening code in an OMP loop. Returns the BIND_EXPR or DECL_EXPR + if found, otherwise null. */ + +static tree +find_binding_in_body (tree decl, tree body) +{ + if (!body) + return NULL_TREE; + + switch (TREE_CODE (body)) + { + case BIND_EXPR: + for (tree b = BIND_EXPR_VARS (body); b; b = DECL_CHAIN (b)) + if (b == decl) + return body; + return find_binding_in_body (decl, BIND_EXPR_BODY (body)); + + case DECL_EXPR: + if (DECL_EXPR_DECL (body) == decl) + return body; + return NULL_TREE; + + case STATEMENT_LIST: + for (tree_stmt_iterator si = tsi_start (body); !tsi_end_p (si); + tsi_next (&si)) + { + tree b = find_binding_in_body (decl, tsi_stmt (si)); + if (b) + return b; + } + return NULL_TREE; + + case OMP_STRUCTURED_BLOCK: + return find_binding_in_body (decl, OMP_BODY (body)); + + default: + return NULL_TREE; + } +} + +/* Traversal function for check_loop_binding_expr, to diagnose + errors when a binding made in intervening code is referenced outside + of the loop. Returns non-null if such a reference is found. DATA points + to the tree containing the loop body. */ + +static tree +check_loop_binding_expr_r (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED, + void *data) +{ + tree body = *(tree *)data; + + if (DECL_P (*tp) && find_binding_in_body (*tp, body)) + return *tp; + return NULL_TREE; +} + +/* Helper macro used below. */ + +#define LOCATION_OR(loc1, loc2) \ + ((loc1) != UNKNOWN_LOCATION ? (loc1) : (loc2)) + +/* Check a single expression EXPR for references to variables bound in + intervening code in BODY. Return true if ok, otherwise give an error + referencing CONTEXT and return false. Use LOC for the error message + if EXPR doesn't have one. */ +static bool +check_loop_binding_expr (tree expr, tree body, const char *context, + location_t loc) +{ + tree bad = walk_tree (&expr, check_loop_binding_expr_r, (void *)&body, NULL); + + if (bad) + { + location_t eloc = EXPR_LOCATION (expr); + error_at (LOCATION_OR (eloc, loc), + "variable %qD used %s is bound " + "in intervening code", bad, context); + return false; + } + return true; +} + +/* STMT is an OMP_FOR construct. Check all of the iteration variable, + initializer, end condition, and increment for bindings inside the + loop body. If ORIG_INITS is provided, check those elements too. + Return true if OK, false otherwise. */ +bool +c_omp_check_loop_binding_exprs (tree stmt, vec *orig_inits) +{ + bool ok = true; + location_t loc = EXPR_LOCATION (stmt); + tree body = OMP_FOR_BODY (stmt); + int orig_init_length = orig_inits ? orig_inits->length () : 0; + + for (int i = 1; i < TREE_VEC_LENGTH (OMP_FOR_INIT (stmt)); i++) + { + tree init = TREE_VEC_ELT (OMP_FOR_INIT (stmt), i); + tree cond = TREE_VEC_ELT (OMP_FOR_COND (stmt), i); + tree incr = TREE_VEC_ELT (OMP_FOR_INCR (stmt), i); + gcc_assert (TREE_CODE (init) == MODIFY_EXPR); + tree decl = TREE_OPERAND (init, 0); + tree orig_init = i < orig_init_length ? (*orig_inits)[i] : NULL_TREE; + tree e; + location_t eloc; + + e = TREE_OPERAND (init, 1); + eloc = LOCATION_OR (EXPR_LOCATION (init), loc); + if (!check_loop_binding_expr (decl, body, "as loop variable", eloc)) + ok = false; + if (!check_loop_binding_expr (e, body, "in initializer", eloc)) + ok = false; + if (orig_init + && !check_loop_binding_expr (orig_init, body, + "in initializer", eloc)) + ok = false; + + /* INCR and/or COND may be null if this is a template with a + class iterator. */ + if (cond) + { + eloc = LOCATION_OR (EXPR_LOCATION (cond), loc); + if (COMPARISON_CLASS_P (cond) && TREE_OPERAND (cond, 0) == decl) + e = TREE_OPERAND (cond, 1); + else if (COMPARISON_CLASS_P (cond) && TREE_OPERAND (cond, 1) == decl) + e = TREE_OPERAND (cond, 0); + else + e = cond; + if (!check_loop_binding_expr (e, body, "in end test", eloc)) + ok = false; + } + + if (incr) + { + eloc = LOCATION_OR (EXPR_LOCATION (incr), loc); + /* INCR should be either a MODIFY_EXPR or pre/post + increment/decrement. We don't have to check the latter + since there are no operands besides the iteration variable. */ + if (TREE_CODE (incr) == MODIFY_EXPR + && !check_loop_binding_expr (TREE_OPERAND (incr, 1), body, + "in increment expression", eloc)) + ok = false; + } + } + + return ok; +} + /* This function splits clauses for OpenACC combined loop constructs. OpenACC combined loop constructs are: #pragma acc kernels loop diff --git a/gcc/c-family/c-opts.cc b/gcc/c-family/c-opts.cc index 4961af63de82..d9f55f45e030 100644 --- a/gcc/c-family/c-opts.cc +++ b/gcc/c-family/c-opts.cc @@ -974,7 +974,7 @@ c_common_post_options (const char **pfilename) /* Change flag_abi_version to be the actual current ABI level, for the benefit of c_cpp_builtins, and to make comparison simpler. */ - const int latest_abi_version = 18; + const int latest_abi_version = 19; /* Generate compatibility aliases for ABI v13 (8.2) by default. */ const int abi_compat_default = 13; diff --git a/gcc/c-family/c-pretty-print.cc b/gcc/c-family/c-pretty-print.cc index 7536a7c471ff..679aa766fe00 100644 --- a/gcc/c-family/c-pretty-print.cc +++ b/gcc/c-family/c-pretty-print.cc @@ -33,6 +33,9 @@ along with GCC; see the file COPYING3. If not see #include "langhooks.h" #include "options.h" #include "internal-fn.h" +#include "function.h" +#include "basic-block.h" +#include "gimple.h" /* The pretty-printer code is primarily designed to closely follow (GNU) C and C++ grammars. That is to be contrasted with spaghetti @@ -1380,12 +1383,14 @@ c_pretty_printer::primary_expression (tree e) else primary_expression (var); } - else + else if (gimple_assign_single_p (SSA_NAME_DEF_STMT (e))) { /* Print only the right side of the GIMPLE assignment. */ gimple *def_stmt = SSA_NAME_DEF_STMT (e); pp_gimple_stmt_1 (this, def_stmt, 0, TDF_RHS_ONLY); } + else + expression (e); break; default: diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt index 0ed87fcc7be9..7348ad42ee08 100644 --- a/gcc/c-family/c.opt +++ b/gcc/c-family/c.opt @@ -1490,7 +1490,7 @@ C++ ObjC++ Var(warn_zero_as_null_pointer_constant) Warning Warn when a literal '0' is used as null pointer. Wuseless-cast -C++ ObjC++ Var(warn_useless_cast) Warning +C ObjC C++ ObjC++ Var(warn_useless_cast) Warning Warn about useless casts. Wsubobject-linkage @@ -1935,6 +1935,10 @@ Winvalid-imported-macros C++ ObjC++ Var(warn_imported_macros) Warning Warn about macros that have conflicting header units definitions. +Wcompare-distinct-pointer-types +C ObjC Var(warn_compare_distinct_pointer_types) Warning Init(1) +Warn if pointers of distinct types are compared without a cast. + flang-info-include-translate C++ Var(note_include_translate_yes) Note #include directives translated to import declarations. @@ -1984,7 +1988,7 @@ Implement resolution of DR 150 for matching of template template arguments. fnext-runtime ObjC ObjC++ LTO RejectNegative Var(flag_next_runtime) -Generate code for NeXT (Apple Mac OS X) runtime environment. +Generate code for NeXT (Apple macOS) runtime environment. fnil-receivers ObjC ObjC++ Var(flag_nil_receivers) Init(1) diff --git a/gcc/c/ChangeLog b/gcc/c/ChangeLog index 1e850f602f29..d9953c71b3c3 100644 --- a/gcc/c/ChangeLog +++ b/gcc/c/ChangeLog @@ -1,3 +1,57 @@ +2023-08-25 Sandra Loosemore + + * c-parser.cc (struct c_parser): Add omp_for_parse_state field. + (struct omp_for_parse_data): New. + (check_omp_intervening_code): New. + (add_structured_block_stmt): New. + (c_parser_compound_statement_nostart): Recognize intervening code, + nested loops, and other things that need special handling in + OpenMP loop constructs. + (c_parser_while_statement): Error on loop in intervening code. + (c_parser_do_statement): Likewise. + (c_parser_for_statement): Likewise. + (c_parser_postfix_expression_after_primary): Error on calls to + the OpenMP runtime in intervening code. + (c_parser_pragma): Error on OpenMP pragmas in intervening code. + (c_parser_omp_loop_nest): New. + (c_parser_omp_for_loop): Rewrite to use recursive descent, calling + c_parser_omp_loop_nest to do the heavy lifting. + +2023-08-24 Richard Sandiford + + * c-parser.cc (c_parser_std_attribute): Conditionally allow + two colons to be used in place of ::. + (c_parser_std_attribute_list): New function, split out from... + (c_parser_std_attribute_specifier): ...here. Allow the attribute-list + to start with __extension__. When it does, also allow two colons + to be used in place of ::. + +2023-08-22 Tobias Burnus + + * c-parser.cc (c_parser_omp_clause_defaultmap): Parse + 'all' as category. + +2023-08-17 Jose E. Marchesi + + PR c/106537 + * c-typeck.cc (build_binary_op): Warning on comparing distinct + pointer types only when -Wcompare-distinct-pointer-types. + +2023-08-15 Chung-Lin Tang + Thomas Schwinge + + * c-parser.cc (OACC_DATA_CLAUSE_MASK): Add PRAGMA_OACC_CLAUSE_DEFAULT. + +2023-08-11 Jakub Jelinek + + * c-parser.cc (c_parser_typeof_specifier): Handle + __typeof_unqual and __typeof_unqual__ as !is_std. + +2023-08-11 Martin Uecker + + PR c/84510 + * c-typeck.cc (build_c_cast): Add warning. + 2023-08-05 Martin Uecker * c-parser.cc (c_parser_generic_selection): Inhibit evaluation diff --git a/gcc/c/c-parser.cc b/gcc/c/c-parser.cc index 57a01dc2fa38..cae10ba9c80e 100644 --- a/gcc/c/c-parser.cc +++ b/gcc/c/c-parser.cc @@ -249,6 +249,10 @@ struct GTY(()) c_parser { /* Location of the last consumed token. */ location_t last_token_location; + + /* Holds state for parsing collapsed OMP_FOR loops. Managed by + c_parser_omp_for_loop. */ + struct omp_for_parse_data * GTY((skip)) omp_for_parse_state; }; /* Return a pointer to the Nth token in PARSERs tokens_buf. */ @@ -1525,6 +1529,44 @@ struct oacc_routine_data { /* Used for parsing objc foreach statements. */ static tree objc_foreach_break_label, objc_foreach_continue_label; +/* Used for parsing OMP for loops. + + Some notes on flags used for context: + parser->omp_for_parse_state is non-null anywhere inside the OMP FOR + construct, except for the final-loop-body. + The want_nested_loop flag is true if inside a {} sequence where + a loop-nest (or another {} sequence containing a loop-nest) is expected, + but has not yet been seen. It's false when parsing intervening code + statements or their substatements that cannot contain a loop-nest. + The in_intervening_code flag is true when parsing any intervening code, + including substatements, and whether or not want_nested_loop is true. + + And, about error handling: + The saw_intervening_code flag is set if the loop is not perfectly + nested, even in the usual case where this is not an error. + perfect_nesting_fail is set if an error has been diagnosed because an + imperfectly-nested loop was found where a perfectly-nested one is + required (we diagnose this only once). + fail is set if any kind of structural error in the loop nest + has been found and diagnosed. + */ +struct omp_for_parse_data { + enum tree_code code; + tree declv, condv, incrv, initv; + tree pre_body; + tree bindings; + int count; /* Expected nesting depth. */ + int depth; /* Current nesting depth. */ + location_t for_loc; + bool ordered : 1; + bool inscan : 1; + bool want_nested_loop : 1; + bool in_intervening_code : 1; + bool saw_intervening_code: 1; + bool perfect_nesting_fail : 1; + bool fail : 1; +}; + static bool c_parser_nth_token_starts_std_attributes (c_parser *, unsigned int); static tree c_parser_std_attribute_specifier_sequence (c_parser *); @@ -1618,6 +1660,7 @@ static void c_parser_omp_threadprivate (c_parser *); static void c_parser_omp_barrier (c_parser *); static void c_parser_omp_depobj (c_parser *); static void c_parser_omp_flush (c_parser *); +static tree c_parser_omp_loop_nest (c_parser *, bool *); static tree c_parser_omp_for_loop (location_t, c_parser *, enum tree_code, tree, tree *, bool *); static void c_parser_omp_taskwait (c_parser *); @@ -4164,7 +4207,8 @@ c_parser_typeof_specifier (c_parser *parser) { gcc_assert (c_parser_next_token_is_keyword (parser, RID_TYPEOF_UNQUAL)); is_unqual = true; - is_std = true; + tree spelling = c_parser_peek_token (parser)->value; + is_std = strcmp (IDENTIFIER_POINTER (spelling), "typeof_unqual") == 0; } c_parser_consume_token (parser); c_inhibit_evaluation_warnings++; @@ -5389,10 +5433,18 @@ c_parser_balanced_token_sequence (c_parser *parser) ( balanced-token-sequence[opt] ) Keywords are accepted as identifiers for this purpose. -*/ + + As an extension, we permit an attribute-specifier to be: + + [ [ __extension__ attribute-list ] ] + + Two colons are then accepted as a synonym for ::. No attempt is made + to check whether the colons are immediately adjacent. LOOSE_SCOPE_P + indicates whether this relaxation is in effect. */ static tree -c_parser_std_attribute (c_parser *parser, bool for_tm) +c_parser_std_attribute (c_parser *parser, bool for_tm, + bool loose_scope_p = false) { c_token *token = c_parser_peek_token (parser); tree ns, name, attribute; @@ -5405,9 +5457,14 @@ c_parser_std_attribute (c_parser *parser, bool for_tm) } name = canonicalize_attr_name (token->value); c_parser_consume_token (parser); - if (c_parser_next_token_is (parser, CPP_SCOPE)) + if (c_parser_next_token_is (parser, CPP_SCOPE) + || (loose_scope_p + && c_parser_next_token_is (parser, CPP_COLON) + && c_parser_peek_2nd_token (parser)->type == CPP_COLON)) { ns = name; + if (c_parser_next_token_is (parser, CPP_COLON)) + c_parser_consume_token (parser); c_parser_consume_token (parser); token = c_parser_peek_token (parser); if (token->type != CPP_NAME && token->type != CPP_KEYWORD) @@ -5480,19 +5537,9 @@ c_parser_std_attribute (c_parser *parser, bool for_tm) } static tree -c_parser_std_attribute_specifier (c_parser *parser, bool for_tm) +c_parser_std_attribute_list (c_parser *parser, bool for_tm, + bool loose_scope_p = false) { - location_t loc = c_parser_peek_token (parser)->location; - if (!c_parser_require (parser, CPP_OPEN_SQUARE, "expected %<[%>")) - return NULL_TREE; - if (!c_parser_require (parser, CPP_OPEN_SQUARE, "expected %<[%>")) - { - c_parser_skip_until_found (parser, CPP_CLOSE_SQUARE, "expected %<]%>"); - return NULL_TREE; - } - if (!for_tm) - pedwarn_c11 (loc, OPT_Wpedantic, - "ISO C does not support %<[[]]%> attributes before C2X"); tree attributes = NULL_TREE; while (true) { @@ -5504,7 +5551,7 @@ c_parser_std_attribute_specifier (c_parser *parser, bool for_tm) c_parser_consume_token (parser); continue; } - tree attribute = c_parser_std_attribute (parser, for_tm); + tree attribute = c_parser_std_attribute (parser, for_tm, loose_scope_p); if (attribute != error_mark_node) { TREE_CHAIN (attribute) = attributes; @@ -5513,6 +5560,35 @@ c_parser_std_attribute_specifier (c_parser *parser, bool for_tm) if (c_parser_next_token_is_not (parser, CPP_COMMA)) break; } + return attributes; +} + +static tree +c_parser_std_attribute_specifier (c_parser *parser, bool for_tm) +{ + location_t loc = c_parser_peek_token (parser)->location; + if (!c_parser_require (parser, CPP_OPEN_SQUARE, "expected %<[%>")) + return NULL_TREE; + if (!c_parser_require (parser, CPP_OPEN_SQUARE, "expected %<[%>")) + { + c_parser_skip_until_found (parser, CPP_CLOSE_SQUARE, "expected %<]%>"); + return NULL_TREE; + } + tree attributes; + if (c_parser_next_token_is_keyword (parser, RID_EXTENSION)) + { + auto ext = disable_extension_diagnostics (); + c_parser_consume_token (parser); + attributes = c_parser_std_attribute_list (parser, for_tm, true); + restore_extension_diagnostics (ext); + } + else + { + if (!for_tm) + pedwarn_c11 (loc, OPT_Wpedantic, + "ISO C does not support %<[[]]%> attributes before C2X"); + attributes = c_parser_std_attribute_list (parser, for_tm); + } c_parser_skip_until_found (parser, CPP_CLOSE_SQUARE, "expected %<]%>"); c_parser_skip_until_found (parser, CPP_CLOSE_SQUARE, "expected %<]%>"); return nreverse (attributes); @@ -6154,6 +6230,68 @@ c_parser_compound_statement (c_parser *parser, location_t *endlocp) return c_end_compound_stmt (brace_loc, stmt, true); } +/* Diagnose errors related to imperfectly nested loops in an OMP + loop construct. This function is called when such code is seen. + Only issue one such diagnostic no matter how much invalid + intervening code there is in the loop. + FIXME: maybe the location associated with the diagnostic should + be the current parser token instead of the location of the outer loop + nest. */ + +static void +check_omp_intervening_code (c_parser *parser) +{ + struct omp_for_parse_data *omp_for_parse_state = parser->omp_for_parse_state; + gcc_assert (omp_for_parse_state); + + if (!omp_for_parse_state->in_intervening_code) + return; + omp_for_parse_state->saw_intervening_code = true; + + /* Only diagnose errors related to perfect nesting once. */ + if (!omp_for_parse_state->perfect_nesting_fail) + { + + /* OpenACC does not (yet) permit intervening code, in + addition to situations forbidden by the OpenMP spec. */ + if (omp_for_parse_state->code == OACC_LOOP) + { + error_at (omp_for_parse_state->for_loc, + "inner loops must be perfectly nested in " + "%<#pragma acc loop%>"); + omp_for_parse_state->perfect_nesting_fail = true; + } + else if (omp_for_parse_state->ordered) + { + error_at (omp_for_parse_state->for_loc, + "inner loops must be perfectly nested with " + "% clause"); + omp_for_parse_state->perfect_nesting_fail = true; + } + else if (omp_for_parse_state->inscan) + { + error_at (omp_for_parse_state->for_loc, + "inner loops must be perfectly nested with " + "% % clause"); + omp_for_parse_state->perfect_nesting_fail = true; + } + /* TODO: Also reject loops with TILE directive. */ + if (omp_for_parse_state->perfect_nesting_fail) + omp_for_parse_state->fail = true; + } +} + +/* Helper function for below: wrap an OMP_STRUCTURED_BLOCK around SL + and add the statement to the current list. If SL is an empty statement + list, do nothing. */ +static void +add_structured_block_stmt (tree sl) +{ + if (TREE_CODE (sl) != STATEMENT_LIST + || !tsi_end_p (tsi_start (sl))) + add_stmt (build1 (OMP_STRUCTURED_BLOCK, void_type_node, sl)); +} + /* Parse a compound statement except for the opening brace. This is used for parsing both compound statements and statement expressions (which follow different paths to handling the opening). */ @@ -6165,6 +6303,12 @@ c_parser_compound_statement_nostart (c_parser *parser) bool last_label = false; bool save_valid_for_pragma = valid_location_for_stdc_pragma_p (); location_t label_loc = UNKNOWN_LOCATION; /* Quiet warning. */ + struct omp_for_parse_data *omp_for_parse_state + = parser->omp_for_parse_state; + bool in_omp_loop_block + = omp_for_parse_state ? omp_for_parse_state->want_nested_loop : false; + tree sl = NULL_TREE; + if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE)) { location_t endloc = c_parser_peek_token (parser)->location; @@ -6172,12 +6316,20 @@ c_parser_compound_statement_nostart (c_parser *parser) c_parser_consume_token (parser); return endloc; } + + /* If we're parsing a {} sequence in an OMP_FOR body, start a + statement list for intervening code. */ + if (in_omp_loop_block) + sl = push_stmt_list (); + mark_valid_location_for_stdc_pragma (true); if (c_parser_next_token_is_keyword (parser, RID_LABEL)) { /* Read zero or more forward-declarations for labels that nested functions can jump to. */ mark_valid_location_for_stdc_pragma (false); + if (in_omp_loop_block) + check_omp_intervening_code (parser); while (c_parser_next_token_is_keyword (parser, RID_LABEL)) { label_loc = c_parser_peek_token (parser)->location; @@ -6219,6 +6371,76 @@ c_parser_compound_statement_nostart (c_parser *parser) { location_t loc = c_parser_peek_token (parser)->location; loc = expansion_point_location_if_in_system_header (loc); + + bool want_nested_loop = (omp_for_parse_state + ? omp_for_parse_state->want_nested_loop + : false); + + /* First take care of special cases for OpenMP "canonical loop + nest form", that do not allow standard attributes, labels, or + __extension__ before the nested statement. */ + if (in_omp_loop_block && !last_label) + { + if (want_nested_loop + && c_parser_next_token_is_keyword (parser, RID_FOR)) + { + /* Found the next nested loop. If there were intervening + code statements collected before now, wrap them in an + OMP_STRUCTURED_BLOCK node, and start a new structured + block to hold statements that may come after the FOR. */ + gcc_assert (sl); + add_structured_block_stmt (pop_stmt_list (sl)); + omp_for_parse_state->depth++; + add_stmt (c_parser_omp_loop_nest (parser, NULL)); + omp_for_parse_state->depth--; + sl = push_stmt_list (); + parser->error = false; + continue; + } + else if (want_nested_loop + && c_parser_next_token_is (parser, CPP_OPEN_BRACE)) + { + /* If this nested compound statement contains the nested loop, + we need to separate the other statements in the current + statement into separate blocks of intervening code. If + there's no nested loop, it's all part of the same + chunk of intervening code. */ + tree pre_sl = pop_stmt_list (sl); + tree nested_sl = push_stmt_list (); + mark_valid_location_for_stdc_pragma (false); + c_parser_statement_after_labels (parser, NULL); + nested_sl = pop_stmt_list (nested_sl); + if (omp_for_parse_state->want_nested_loop) + { + /* This block didn't contain a loop-nest, so it's + all part of the same chunk of intervening code. */ + check_omp_intervening_code (parser); + sl = push_stmt_list (); + add_stmt (pre_sl); + add_stmt (nested_sl); + } + else + { + /* It contains the nested loop. */ + add_structured_block_stmt (pre_sl); + add_stmt (nested_sl); + sl = push_stmt_list (); + } + parser->error = false; + continue; + } + else if (c_parser_next_token_is (parser, CPP_SEMICOLON)) + { + /* Prior to implementing the OpenMP 5.1 syntax for canonical + loop form, GCC used to accept an empty statements that + would now be flagged as intervening code. Continue to + do that, as an extension. */ + /* FIXME: Maybe issue a warning or something here? */ + c_parser_consume_token (parser); + continue; + } + } + /* Standard attributes may start a label, statement or declaration. */ bool have_std_attrs = c_parser_nth_token_starts_std_attributes (parser, 1); @@ -6237,6 +6459,8 @@ c_parser_compound_statement_nostart (c_parser *parser) last_label = true; last_stmt = false; mark_valid_location_for_stdc_pragma (false); + if (in_omp_loop_block) + check_omp_intervening_code (parser); c_parser_label (parser, std_attrs); } else if (c_parser_next_tokens_start_declaration (parser) @@ -6247,7 +6471,13 @@ c_parser_compound_statement_nostart (c_parser *parser) pedwarn_c11 (c_parser_peek_token (parser)->location, OPT_Wpedantic, "a label can only be part of a statement and " "a declaration is not a statement"); - + /* It's unlikely we'll see a nested loop in a declaration in + intervening code in an OMP loop, but disallow it anyway. */ + if (in_omp_loop_block) + { + check_omp_intervening_code (parser); + omp_for_parse_state->want_nested_loop = false; + } mark_valid_location_for_stdc_pragma (false); bool fallthru_attr_p = false; c_parser_declaration_or_fndef (parser, true, !have_std_attrs, @@ -6255,6 +6485,8 @@ c_parser_compound_statement_nostart (c_parser *parser) NULL, have_std_attrs, std_attrs, NULL, &fallthru_attr_p); + if (in_omp_loop_block) + omp_for_parse_state->want_nested_loop = want_nested_loop; if (last_stmt && !fallthru_attr_p) pedwarn_c90 (loc, OPT_Wdeclaration_after_statement, "ISO C90 forbids mixed declarations and code"); @@ -6282,9 +6514,18 @@ c_parser_compound_statement_nostart (c_parser *parser) ext = disable_extension_diagnostics (); c_parser_consume_token (parser); last_label = false; + /* It's unlikely we'll see a nested loop in a declaration in + intervening code in an OMP loop, but disallow it anyway. */ + if (in_omp_loop_block) + { + check_omp_intervening_code (parser); + omp_for_parse_state->want_nested_loop = false; + } mark_valid_location_for_stdc_pragma (false); c_parser_declaration_or_fndef (parser, true, true, true, true, true); + if (in_omp_loop_block) + omp_for_parse_state->want_nested_loop = want_nested_loop; /* Following the old parser, __extension__ does not disable this diagnostic. */ restore_extension_diagnostics (ext); @@ -6305,10 +6546,19 @@ c_parser_compound_statement_nostart (c_parser *parser) syntactically. This ensures that the user doesn't put them places that would turn into syntax errors if the directive were ignored. */ + if (omp_for_parse_state) + omp_for_parse_state->want_nested_loop = false; if (c_parser_pragma (parser, last_label ? pragma_stmt : pragma_compound, NULL)) - last_label = false, last_stmt = true; + { + last_label = false; + last_stmt = true; + if (omp_for_parse_state) + check_omp_intervening_code (parser); + } + if (omp_for_parse_state) + omp_for_parse_state->want_nested_loop = want_nested_loop; } else if (c_parser_next_token_is (parser, CPP_EOF)) { @@ -6338,7 +6588,20 @@ c_parser_compound_statement_nostart (c_parser *parser) last_label = false; last_stmt = true; mark_valid_location_for_stdc_pragma (false); - c_parser_statement_after_labels (parser, NULL); + if (!omp_for_parse_state) + c_parser_statement_after_labels (parser, NULL); + else + { + /* In canonical loop nest form, nested loops can only appear + directly, or in a directly nested compound statement. We + already took care of those cases above, so now we have + something else. This statement and everything inside + it must be intervening code. */ + omp_for_parse_state->want_nested_loop = false; + check_omp_intervening_code (parser); + c_parser_statement_after_labels (parser, NULL); + omp_for_parse_state->want_nested_loop = want_nested_loop; + } } parser->error = false; @@ -6347,8 +6610,21 @@ c_parser_compound_statement_nostart (c_parser *parser) pedwarn_c11 (label_loc, OPT_Wpedantic, "label at end of compound statement"); location_t endloc = c_parser_peek_token (parser)->location; c_parser_consume_token (parser); + /* Restore the value we started with. */ mark_valid_location_for_stdc_pragma (save_valid_for_pragma); + + /* Package leftover intervening code, or the whole contents of the + compound statement if we were looking for a nested loop in an OMP_FOR + construct and didn't find one. */ + if (sl) + { + sl = pop_stmt_list (sl); + if (omp_for_parse_state->want_nested_loop) + add_stmt (sl); + else + add_structured_block_stmt (sl); + } return endloc; } @@ -7180,6 +7456,14 @@ c_parser_while_statement (c_parser *parser, bool ivdep, unsigned short unroll, gcc_assert (c_parser_next_token_is_keyword (parser, RID_WHILE)); token_indent_info while_tinfo = get_token_indent_info (c_parser_peek_token (parser)); + + if (parser->omp_for_parse_state) + { + error_at (c_parser_peek_token (parser)->location, + "loop not permitted in intervening code in OpenMP loop body"); + parser->omp_for_parse_state->fail = true; + } + c_parser_consume_token (parser); block = c_begin_compound_stmt (flag_isoc99); loc = c_parser_peek_token (parser)->location; @@ -7237,6 +7521,14 @@ c_parser_do_statement (c_parser *parser, bool ivdep, unsigned short unroll, unsigned char save_in_statement; location_t loc; gcc_assert (c_parser_next_token_is_keyword (parser, RID_DO)); + + if (parser->omp_for_parse_state) + { + error_at (c_parser_peek_token (parser)->location, + "loop not permitted in intervening code in OpenMP loop body"); + parser->omp_for_parse_state->fail = true; + } + c_parser_consume_token (parser); if (c_parser_next_token_is (parser, CPP_SEMICOLON)) warning_at (c_parser_peek_token (parser)->location, @@ -7348,6 +7640,14 @@ c_parser_for_statement (c_parser *parser, bool ivdep, unsigned short unroll, gcc_assert (c_parser_next_token_is_keyword (parser, RID_FOR)); token_indent_info for_tinfo = get_token_indent_info (c_parser_peek_token (parser)); + + if (parser->omp_for_parse_state) + { + error_at (for_loc, + "loop not permitted in intervening code in OpenMP loop body"); + parser->omp_for_parse_state->fail = true; + } + c_parser_consume_token (parser); /* Open a compound statement in Objective-C as well, just in case this is as foreach expression. */ @@ -11302,6 +11602,14 @@ c_parser_postfix_expression_after_primary (c_parser *parser, && fndecl_built_in_p (expr.value, BUILT_IN_NORMAL) && vec_safe_length (exprlist) == 1) warn_for_abs (expr_loc, expr.value, (*exprlist)[0]); + if (parser->omp_for_parse_state + && parser->omp_for_parse_state->in_intervening_code + && omp_runtime_api_call (expr.value)) + { + error_at (expr_loc, "calls to the OpenMP runtime API are " + "not permitted in intervening code"); + parser->omp_for_parse_state->fail = true; + } } start = expr.get_start (); @@ -13146,6 +13454,17 @@ c_parser_pragma (c_parser *parser, enum pragma_context context, bool *if_p) input_location = c_parser_peek_token (parser)->location; id = c_parser_peek_token (parser)->pragma_kind; gcc_assert (id != PRAGMA_NONE); + if (parser->omp_for_parse_state + && parser->omp_for_parse_state->in_intervening_code + && id >= PRAGMA_OMP__START_ + && id <= PRAGMA_OMP__LAST_) + { + error_at (input_location, + "intervening code must not contain OpenMP directives"); + parser->omp_for_parse_state->fail = true; + c_parser_skip_until_found (parser, CPP_PRAGMA_EOL, NULL); + return false; + } switch (id) { @@ -15066,8 +15385,8 @@ c_parser_omp_clause_defaultmap (c_parser *parser, tree list) if (!c_parser_next_token_is (parser, CPP_NAME)) { invalid_category: - c_parser_error (parser, "expected %, % or " - "%"); + c_parser_error (parser, "expected %, %, " + "% or %"); goto out_err; } p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); @@ -15076,6 +15395,8 @@ c_parser_omp_clause_defaultmap (c_parser *parser, tree list) case 'a': if (strcmp ("aggregate", p) == 0) category = OMP_CLAUSE_DEFAULTMAP_CATEGORY_AGGREGATE; + else if (strcmp ("all", p) == 0) + category = OMP_CLAUSE_DEFAULTMAP_CATEGORY_ALL; else goto invalid_category; break; @@ -15105,13 +15426,19 @@ c_parser_omp_clause_defaultmap (c_parser *parser, tree list) for (c = list; c ; c = OMP_CLAUSE_CHAIN (c)) if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEFAULTMAP && (category == OMP_CLAUSE_DEFAULTMAP_CATEGORY_UNSPECIFIED + || category == OMP_CLAUSE_DEFAULTMAP_CATEGORY_ALL || OMP_CLAUSE_DEFAULTMAP_CATEGORY (c) == category || (OMP_CLAUSE_DEFAULTMAP_CATEGORY (c) - == OMP_CLAUSE_DEFAULTMAP_CATEGORY_UNSPECIFIED))) + == OMP_CLAUSE_DEFAULTMAP_CATEGORY_UNSPECIFIED) + || (OMP_CLAUSE_DEFAULTMAP_CATEGORY (c) + == OMP_CLAUSE_DEFAULTMAP_CATEGORY_ALL))) { enum omp_clause_defaultmap_kind cat = category; location_t loc = OMP_CLAUSE_LOCATION (c); - if (cat == OMP_CLAUSE_DEFAULTMAP_CATEGORY_UNSPECIFIED) + if (cat == OMP_CLAUSE_DEFAULTMAP_CATEGORY_UNSPECIFIED + || (cat == OMP_CLAUSE_DEFAULTMAP_CATEGORY_ALL + && (OMP_CLAUSE_DEFAULTMAP_CATEGORY (c) + != OMP_CLAUSE_DEFAULTMAP_CATEGORY_UNSPECIFIED))) cat = OMP_CLAUSE_DEFAULTMAP_CATEGORY (c); p = NULL; switch (cat) @@ -15119,6 +15446,9 @@ c_parser_omp_clause_defaultmap (c_parser *parser, tree list) case OMP_CLAUSE_DEFAULTMAP_CATEGORY_UNSPECIFIED: p = NULL; break; + case OMP_CLAUSE_DEFAULTMAP_CATEGORY_ALL: + p = "all"; + break; case OMP_CLAUSE_DEFAULTMAP_CATEGORY_AGGREGATE: p = "aggregate"; break; @@ -18283,6 +18613,7 @@ c_parser_oacc_cache (location_t loc, c_parser *parser) | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_COPYIN) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_COPYOUT) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_CREATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_DEFAULT) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_DEVICEPTR) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_IF) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_NO_CREATE) \ @@ -20349,6 +20680,274 @@ c_parser_omp_scan_loop_body (c_parser *parser, bool open_brace_parsed) "expected %<}%>"); } + +/* This function parses a single level of a loop nest, invoking itself + recursively if necessary. + + loop-nest :: for (...) loop-body + loop-body :: loop-nest + | { [intervening-code] loop-body [intervening-code] } + | final-loop-body + intervening-code :: structured-block-sequence + final-loop-body :: structured-block + + For a collapsed loop nest, only a single OMP_FOR is built, pulling out + all the iterator information from the inner loops into the + parser->omp_for_parse_state structure. + + The iterator decl, init, cond, and incr are stored in vectors. + + Initialization code for iterator variables is collected into + parser->omp_for_parse_state->pre_body and ends up inserted directly + into the OMP_FOR structure. */ + +static tree +c_parser_omp_loop_nest (c_parser *parser, bool *if_p) +{ + tree decl, cond, incr, init; + tree body = NULL_TREE; + matching_parens parens; + bool moreloops; + unsigned char save_in_statement; + tree loop_scope; + location_t loc; + struct omp_for_parse_data *omp_for_parse_state + = parser->omp_for_parse_state; + gcc_assert (omp_for_parse_state); + int depth = omp_for_parse_state->depth; + + /* We have already matched the FOR token but not consumed it yet. */ + loc = c_parser_peek_token (parser)->location; + gcc_assert (c_parser_next_token_is_keyword (parser, RID_FOR)); + c_parser_consume_token (parser); + + /* Forbid break/continue in the loop initializer, condition, and + increment expressions. */ + save_in_statement = in_statement; + in_statement = IN_OMP_BLOCK; + + /* We are not in intervening code now. */ + omp_for_parse_state->in_intervening_code = false; + + if (!parens.require_open (parser)) + { + omp_for_parse_state->fail = true; + return NULL_TREE; + } + + /* An implicit scope block surrounds each level of FOR loop, for + declarations of iteration variables at this loop depth. */ + loop_scope = c_begin_compound_stmt (true); + + /* Parse the initialization declaration or expression. */ + if (c_parser_next_tokens_start_declaration (parser)) + { + /* This is a declaration, which must be added to the pre_body code. */ + tree this_pre_body = push_stmt_list (); + c_in_omp_for = true; + c_parser_declaration_or_fndef (parser, true, true, true, true, true); + c_in_omp_for = false; + this_pre_body = pop_stmt_list (this_pre_body); + append_to_statement_list_force (this_pre_body, + &(omp_for_parse_state->pre_body)); + decl = check_for_loop_decls (omp_for_parse_state->for_loc, flag_isoc99); + if (decl == NULL) + goto error_init; + if (DECL_INITIAL (decl) == error_mark_node) + decl = error_mark_node; + init = decl; + } + else if (c_parser_next_token_is (parser, CPP_NAME) + && c_parser_peek_2nd_token (parser)->type == CPP_EQ) + { + struct c_expr decl_exp; + struct c_expr init_exp; + location_t init_loc; + + decl_exp = c_parser_postfix_expression (parser); + decl = decl_exp.value; + + c_parser_require (parser, CPP_EQ, "expected %<=%>"); + + init_loc = c_parser_peek_token (parser)->location; + init_exp = c_parser_expr_no_commas (parser, NULL); + init_exp = default_function_array_read_conversion (init_loc, + init_exp); + c_in_omp_for = true; + init = build_modify_expr (init_loc, decl, decl_exp.original_type, + NOP_EXPR, init_loc, init_exp.value, + init_exp.original_type); + c_in_omp_for = false; + init = c_process_expr_stmt (init_loc, init); + + c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>"); + } + else + { + error_init: + c_parser_error (parser, + "expected iteration declaration or initialization"); + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, + "expected %<)%>"); + omp_for_parse_state->fail = true; + goto parse_next; + } + + /* Parse the loop condition. */ + cond = NULL_TREE; + if (c_parser_next_token_is_not (parser, CPP_SEMICOLON)) + { + location_t cond_loc = c_parser_peek_token (parser)->location; + c_in_omp_for = true; + struct c_expr cond_expr + = c_parser_binary_expression (parser, NULL, NULL_TREE); + c_in_omp_for = false; + + cond = cond_expr.value; + cond = c_objc_common_truthvalue_conversion (cond_loc, cond); + switch (cond_expr.original_code) + { + case GT_EXPR: + case GE_EXPR: + case LT_EXPR: + case LE_EXPR: + break; + case NE_EXPR: + if (omp_for_parse_state->code != OACC_LOOP) + break; + /* FALLTHRU. */ + default: + /* Can't be cond = error_mark_node, because we want to preserve + the location until c_finish_omp_for. */ + cond = build1 (NOP_EXPR, boolean_type_node, error_mark_node); + break; + } + protected_set_expr_location (cond, cond_loc); + } + c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>"); + + /* Parse the increment expression. */ + incr = NULL_TREE; + if (c_parser_next_token_is_not (parser, CPP_CLOSE_PAREN)) + { + location_t incr_loc = c_parser_peek_token (parser)->location; + + incr = c_process_expr_stmt (incr_loc, + c_parser_expression (parser).value); + } + parens.skip_until_found_close (parser); + + if (decl == NULL || decl == error_mark_node || init == error_mark_node) + omp_for_parse_state->fail = true; + else + { + TREE_VEC_ELT (omp_for_parse_state->declv, depth) = decl; + TREE_VEC_ELT (omp_for_parse_state->initv, depth) = init; + TREE_VEC_ELT (omp_for_parse_state->condv, depth) = cond; + TREE_VEC_ELT (omp_for_parse_state->incrv, depth) = incr; + } + +parse_next: + moreloops = depth < omp_for_parse_state->count - 1; + omp_for_parse_state->want_nested_loop = moreloops; + if (moreloops && c_parser_next_token_is_keyword (parser, RID_FOR)) + { + omp_for_parse_state->depth++; + body = c_parser_omp_loop_nest (parser, if_p); + omp_for_parse_state->depth--; + } + else if (moreloops && c_parser_next_token_is (parser, CPP_OPEN_BRACE)) + { + /* This is the open brace in the loop-body grammar production. Rather + than trying to special-case braces, just parse it as a compound + statement and handle the nested loop-body case there. Note that + when we see a further open brace inside the compound statement + loop-body, we don't know whether it is the start of intervening + code that is a compound statement, or a level of braces + surrounding a nested loop-body. Use the WANT_NESTED_LOOP state + bit to ensure we have only one nested loop at each level. */ + omp_for_parse_state->in_intervening_code = true; + body = c_parser_compound_statement (parser, NULL); + omp_for_parse_state->in_intervening_code = false; + if (omp_for_parse_state->want_nested_loop) + { + /* We have already parsed the whole loop body and not found a + nested loop. */ + error_at (omp_for_parse_state->for_loc, + "not enough nested loops"); + omp_for_parse_state->fail = true; + } + if_p = NULL; + } + else + { + /* This is the final-loop-body case in the grammar: we have + something that is not a FOR and not an open brace. */ + if (moreloops) + { + /* If we were expecting a nested loop, give an error and mark + that parsing has failed, and try to recover by parsing the + body as regular code without further collapsing. */ + error_at (omp_for_parse_state->for_loc, + "not enough nested loops"); + omp_for_parse_state->fail = true; + } + in_statement = IN_OMP_FOR; + parser->omp_for_parse_state = NULL; + body = push_stmt_list (); + if (omp_for_parse_state->inscan) + c_parser_omp_scan_loop_body (parser, false); + else + add_stmt (c_parser_c99_block_statement (parser, if_p)); + body = pop_stmt_list (body); + parser->omp_for_parse_state = omp_for_parse_state; + } + in_statement = save_in_statement; + omp_for_parse_state->want_nested_loop = false; + omp_for_parse_state->in_intervening_code = true; + + /* Pop and return the implicit scope surrounding this level of loop. + If the iteration variable at this depth was bound in the for loop, + pull out and save the binding. Later in c_parser_omp_for_loop, + these bindings will be moved to the scope surrounding the entire + OMP_FOR. That keeps the gimplifier happy later on, and meanwhile + we have already resolved all references to the iteration variable + in its true scope. */ + add_stmt (body); + body = c_end_compound_stmt (loc, loop_scope, true); + if (decl && TREE_CODE (body) == BIND_EXPR) + { + tree t = BIND_EXPR_VARS (body); + tree prev = NULL_TREE, next = NULL_TREE; + while (t) + { + next = DECL_CHAIN (t); + if (t == decl) + { + if (prev) + DECL_CHAIN (prev) = next; + else + { + BIND_EXPR_VARS (body) = next; + BLOCK_VARS (BIND_EXPR_BLOCK (body)) = next; + } + DECL_CHAIN (t) = omp_for_parse_state->bindings; + omp_for_parse_state->bindings = t; + break; + } + else + { + prev = t; + t = next; + } + } + if (BIND_EXPR_VARS (body) == NULL_TREE) + body = BIND_EXPR_BODY (body); + } + + return body; +} + /* Parse the restricted form of loop statements allowed by OpenACC and OpenMP. The real trick here is to determine the loop control variable early so that we can push a new decl if necessary to make it private. @@ -20359,17 +20958,14 @@ static tree c_parser_omp_for_loop (location_t loc, c_parser *parser, enum tree_code code, tree clauses, tree *cclauses, bool *if_p) { - tree decl, cond, incr, body, init, stmt, cl; - unsigned char save_in_statement; - tree declv, condv, incrv, initv, ret = NULL_TREE; - tree pre_body = NULL_TREE, this_pre_body; + tree body, stmt, cl; + tree ret = NULL_TREE; tree ordered_cl = NULL_TREE; - bool fail = false, open_brace_parsed = false; - int i, collapse = 1, ordered = 0, count, nbraces = 0; - location_t for_loc; + int i, collapse = 1, ordered = 0, count; bool tiling = false; bool inscan = false; - vec *for_block = make_tree_vector (); + struct omp_for_parse_data data; + struct omp_for_parse_data *save_data = parser->omp_for_parse_state; for (cl = clauses; cl; cl = OMP_CLAUSE_CHAIN (cl)) if (OMP_CLAUSE_CODE (cl) == OMP_CLAUSE_COLLAPSE) @@ -20402,250 +20998,62 @@ c_parser_omp_for_loop (location_t loc, c_parser *parser, enum tree_code code, gcc_assert (tiling || (collapse >= 1 && ordered >= 0)); count = ordered ? ordered : collapse; - declv = make_tree_vec (count); - initv = make_tree_vec (count); - condv = make_tree_vec (count); - incrv = make_tree_vec (count); - if (!c_parser_next_token_is_keyword (parser, RID_FOR)) { c_parser_error (parser, "for statement expected"); return NULL; } - for_loc = c_parser_peek_token (parser)->location; - c_parser_consume_token (parser); - /* Forbid break/continue in the loop initializer, condition, and - increment expressions. */ - save_in_statement = in_statement; - in_statement = IN_OMP_BLOCK; + /* Initialize parse state for recursive descent. */ + data.declv = make_tree_vec (count); + data.initv = make_tree_vec (count); + data.condv = make_tree_vec (count); + data.incrv = make_tree_vec (count); + data.pre_body = NULL_TREE;; + data.bindings = NULL_TREE; + data.for_loc = c_parser_peek_token (parser)->location; + data.count = count; + data.depth = 0; + data.want_nested_loop = true; + data.ordered = ordered > 0; + data.in_intervening_code = false; + data.perfect_nesting_fail = false; + data.fail = false; + data.inscan = inscan; + data.saw_intervening_code = false; + data.code = code; + parser->omp_for_parse_state = &data; - for (i = 0; i < count; i++) + body = c_parser_omp_loop_nest (parser, if_p); + + /* Add saved bindings for iteration variables that were declared in + the nested for loop to the scope surrounding the entire loop. */ + for (tree t = data.bindings; t; ) { - int bracecount = 0; - - matching_parens parens; - if (!parens.require_open (parser)) - goto pop_scopes; - - /* Parse the initialization declaration or expression. */ - if (c_parser_next_tokens_start_declaration (parser)) - { - if (i > 0) - vec_safe_push (for_block, c_begin_compound_stmt (true)); - this_pre_body = push_stmt_list (); - c_in_omp_for = true; - c_parser_declaration_or_fndef (parser, true, true, true, true, true); - c_in_omp_for = false; - if (this_pre_body) - { - this_pre_body = pop_stmt_list (this_pre_body); - if (pre_body) - { - tree t = pre_body; - pre_body = push_stmt_list (); - add_stmt (t); - add_stmt (this_pre_body); - pre_body = pop_stmt_list (pre_body); - } - else - pre_body = this_pre_body; - } - decl = check_for_loop_decls (for_loc, flag_isoc99); - if (decl == NULL) - goto error_init; - if (DECL_INITIAL (decl) == error_mark_node) - decl = error_mark_node; - init = decl; - } - else if (c_parser_next_token_is (parser, CPP_NAME) - && c_parser_peek_2nd_token (parser)->type == CPP_EQ) - { - struct c_expr decl_exp; - struct c_expr init_exp; - location_t init_loc; - - decl_exp = c_parser_postfix_expression (parser); - decl = decl_exp.value; - - c_parser_require (parser, CPP_EQ, "expected %<=%>"); - - init_loc = c_parser_peek_token (parser)->location; - init_exp = c_parser_expr_no_commas (parser, NULL); - init_exp = default_function_array_read_conversion (init_loc, - init_exp); - c_in_omp_for = true; - init = build_modify_expr (init_loc, decl, decl_exp.original_type, - NOP_EXPR, init_loc, init_exp.value, - init_exp.original_type); - c_in_omp_for = false; - init = c_process_expr_stmt (init_loc, init); - - c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>"); - } - else - { - error_init: - c_parser_error (parser, - "expected iteration declaration or initialization"); - c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, - "expected %<)%>"); - fail = true; - goto parse_next; - } - - /* Parse the loop condition. */ - cond = NULL_TREE; - if (c_parser_next_token_is_not (parser, CPP_SEMICOLON)) - { - location_t cond_loc = c_parser_peek_token (parser)->location; - c_in_omp_for = true; - struct c_expr cond_expr - = c_parser_binary_expression (parser, NULL, NULL_TREE); - c_in_omp_for = false; - - cond = cond_expr.value; - cond = c_objc_common_truthvalue_conversion (cond_loc, cond); - switch (cond_expr.original_code) - { - case GT_EXPR: - case GE_EXPR: - case LT_EXPR: - case LE_EXPR: - break; - case NE_EXPR: - if (code != OACC_LOOP) - break; - /* FALLTHRU. */ - default: - /* Can't be cond = error_mark_node, because we want to preserve - the location until c_finish_omp_for. */ - cond = build1 (NOP_EXPR, boolean_type_node, error_mark_node); - break; - } - protected_set_expr_location (cond, cond_loc); - } - c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>"); - - /* Parse the increment expression. */ - incr = NULL_TREE; - if (c_parser_next_token_is_not (parser, CPP_CLOSE_PAREN)) - { - location_t incr_loc = c_parser_peek_token (parser)->location; - - incr = c_process_expr_stmt (incr_loc, - c_parser_expression (parser).value); - } - parens.skip_until_found_close (parser); - - if (decl == NULL || decl == error_mark_node || init == error_mark_node) - fail = true; - else - { - TREE_VEC_ELT (declv, i) = decl; - TREE_VEC_ELT (initv, i) = init; - TREE_VEC_ELT (condv, i) = cond; - TREE_VEC_ELT (incrv, i) = incr; - } - - parse_next: - if (i == count - 1) - break; - - /* FIXME: OpenMP 3.0 draft isn't very clear on what exactly is allowed - in between the collapsed for loops to be still considered perfectly - nested. Hopefully the final version clarifies this. - For now handle (multiple) {'s and empty statements. */ - do - { - if (c_parser_next_token_is_keyword (parser, RID_FOR)) - { - c_parser_consume_token (parser); - break; - } - else if (c_parser_next_token_is (parser, CPP_OPEN_BRACE)) - { - c_parser_consume_token (parser); - bracecount++; - } - else if (bracecount - && c_parser_next_token_is (parser, CPP_SEMICOLON)) - c_parser_consume_token (parser); - else - { - c_parser_error (parser, "not enough perfectly nested loops"); - if (bracecount) - { - open_brace_parsed = true; - bracecount--; - } - fail = true; - count = 0; - break; - } - } - while (1); - - nbraces += bracecount; - } - - if (nbraces) - if_p = NULL; - - in_statement = IN_OMP_FOR; - body = push_stmt_list (); - - if (inscan) - c_parser_omp_scan_loop_body (parser, open_brace_parsed); - else if (open_brace_parsed) - { - location_t here = c_parser_peek_token (parser)->location; - stmt = c_begin_compound_stmt (true); - c_parser_compound_statement_nostart (parser); - add_stmt (c_end_compound_stmt (here, stmt, true)); - } - else - add_stmt (c_parser_c99_block_statement (parser, if_p)); - - body = pop_stmt_list (body); - in_statement = save_in_statement; - - while (nbraces) - { - if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE)) - { - c_parser_consume_token (parser); - nbraces--; - } - else if (c_parser_next_token_is (parser, CPP_SEMICOLON)) - c_parser_consume_token (parser); - else - { - c_parser_error (parser, "collapsed loops not perfectly nested"); - while (nbraces) - { - location_t here = c_parser_peek_token (parser)->location; - stmt = c_begin_compound_stmt (true); - add_stmt (body); - c_parser_compound_statement_nostart (parser); - body = c_end_compound_stmt (here, stmt, true); - nbraces--; - } - goto pop_scopes; - } + tree n = TREE_CHAIN (t); + TREE_CHAIN (t) = NULL_TREE; + pushdecl (t); + t = n; } /* Only bother calling c_finish_omp_for if we haven't already generated an error from the initialization parsing. */ - if (!fail) + if (!data.fail) { c_in_omp_for = true; - stmt = c_finish_omp_for (loc, code, declv, NULL, initv, condv, - incrv, body, pre_body, true); + stmt = c_finish_omp_for (loc, code, data.declv, NULL, data.initv, + data.condv, data.incrv, + body, data.pre_body, true); c_in_omp_for = false; /* Check for iterators appearing in lb, b or incr expressions. */ - if (stmt && !c_omp_check_loop_iv (stmt, declv, NULL)) + if (stmt && !c_omp_check_loop_iv (stmt, data.declv, NULL)) + stmt = NULL_TREE; + + /* Check for errors involving lb/ub/incr expressions referencing + variables declared in intervening code. */ + if (data.saw_intervening_code + && !c_omp_check_loop_binding_exprs (stmt, NULL)) stmt = NULL_TREE; if (stmt) @@ -20697,7 +21105,7 @@ c_parser_omp_for_loop (location_t loc, c_parser *parser, enum tree_code code, else { for (i = 0; i < count; i++) - if (TREE_VEC_ELT (declv, i) == OMP_CLAUSE_DECL (*c)) + if (TREE_VEC_ELT (data.declv, i) == OMP_CLAUSE_DECL (*c)) break; if (i == count) c = &OMP_CLAUSE_CHAIN (*c); @@ -20710,7 +21118,8 @@ c_parser_omp_for_loop (location_t loc, c_parser *parser, enum tree_code code, } else { - /* Move lastprivate (decl) clause to OMP_FOR_CLAUSES. */ + /* Move lastprivate (decl) clause to + OMP_FOR_CLAUSES. */ tree l = *c; *c = OMP_CLAUSE_CHAIN (*c); if (code == OMP_SIMD) @@ -20731,16 +21140,8 @@ c_parser_omp_for_loop (location_t loc, c_parser *parser, enum tree_code code, } ret = stmt; } -pop_scopes: - while (!for_block->is_empty ()) - { - /* FIXME diagnostics: LOC below should be the actual location of - this particular for block. We need to build a list of - locations to go along with FOR_BLOCK. */ - stmt = c_end_compound_stmt (loc, for_block->pop (), true); - add_stmt (stmt); - } - release_tree_vector (for_block); + + parser->omp_for_parse_state = save_data; return ret; } diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc index 7cf411155c60..e6ddf37d4120 100644 --- a/gcc/c/c-typeck.cc +++ b/gcc/c/c-typeck.cc @@ -6062,9 +6062,13 @@ build_c_cast (location_t loc, tree type, tree expr) if (type == TYPE_MAIN_VARIANT (TREE_TYPE (value))) { - if (RECORD_OR_UNION_TYPE_P (type)) - pedwarn (loc, OPT_Wpedantic, - "ISO C forbids casting nonscalar to the same type"); + if (RECORD_OR_UNION_TYPE_P (type) + && pedwarn (loc, OPT_Wpedantic, + "ISO C forbids casting nonscalar to the same type")) + ; + else if (warn_useless_cast) + warning_at (loc, OPT_Wuseless_cast, + "useless cast to type %qT", type); /* Convert to remove any qualifiers from VALUE's type. */ value = convert (type, value); @@ -12768,7 +12772,7 @@ build_binary_op (location_t location, enum tree_code code, else /* Avoid warning about the volatile ObjC EH puts on decls. */ if (!objc_ok) - pedwarn (location, 0, + pedwarn (location, OPT_Wcompare_distinct_pointer_types, "comparison of distinct pointer types lacks a cast"); if (result_type == NULL_TREE) @@ -12908,8 +12912,8 @@ build_binary_op (location_t location, enum tree_code code, int qual = ENCODE_QUAL_ADDR_SPACE (as_common); result_type = build_pointer_type (build_qualified_type (void_type_node, qual)); - pedwarn (location, 0, - "comparison of distinct pointer types lacks a cast"); + pedwarn (location, OPT_Wcompare_distinct_pointer_types, + "comparison of distinct pointer types lacks a cast"); } } else if (code0 == POINTER_TYPE && null_pointer_constant_p (orig_op1)) diff --git a/gcc/caller-save.cc b/gcc/caller-save.cc index b8915dab1281..9ddf9b70b21a 100644 --- a/gcc/caller-save.cc +++ b/gcc/caller-save.cc @@ -342,7 +342,7 @@ new_saved_hard_reg (int regno, int call_freq) saved_reg->num = saved_regs_num++; saved_reg->hard_regno = regno; saved_reg->call_freq = call_freq; - saved_reg->first_p = FALSE; + saved_reg->first_p = false; saved_reg->next = -1; } @@ -558,7 +558,7 @@ setup_save_areas (void) + saved_reg2->num] = saved_reg_conflicts[saved_reg2->num * saved_regs_num + saved_reg->num] - = TRUE; + = true; } } } @@ -608,7 +608,7 @@ setup_save_areas (void) } if (j == i) { - saved_reg->first_p = TRUE; + saved_reg->first_p = true; for (best_slot_num = -1, j = 0; j < prev_save_slots_num; j++) { slot = prev_save_slots[j]; diff --git a/gcc/cfg.cc b/gcc/cfg.cc index 9eb9916f61aa..bd5287394040 100644 --- a/gcc/cfg.cc +++ b/gcc/cfg.cc @@ -81,6 +81,7 @@ init_flow (struct function *the_fun) = ENTRY_BLOCK_PTR_FOR_FN (the_fun); the_fun->cfg->edge_flags_allocated = EDGE_ALL_FLAGS; the_fun->cfg->bb_flags_allocated = BB_ALL_FLAGS; + the_fun->cfg->full_profile = false; } /* Helper function for remove_edge and free_cffg. Frees edge structure diff --git a/gcc/cfg.h b/gcc/cfg.h index a0e944979c87..4c1948b967d0 100644 --- a/gcc/cfg.h +++ b/gcc/cfg.h @@ -78,6 +78,9 @@ struct GTY(()) control_flow_graph { /* Dynamically allocated edge/bb flags. */ int edge_flags_allocated; int bb_flags_allocated; + + /* Set if the profile is computed on every edge and basic block. */ + bool full_profile; }; diff --git a/gcc/cfgloopmanip.cc b/gcc/cfgloopmanip.cc index b237ad4e8ac2..a2ed54a23bbc 100644 --- a/gcc/cfgloopmanip.cc +++ b/gcc/cfgloopmanip.cc @@ -1296,6 +1296,16 @@ duplicate_loop_body_to_header_edge (class loop *loop, edge e, } profile_probability prob_pass_wont_exit = new_count_le.probability_in (count_in); + /* If profile count is 0, the probability will be uninitialized. + We can set probability to any initialized value to avoid + precision loss. If profile is sane, all counts will be 0 anyway. */ + if (!count_in.nonzero_p ()) + { + prob_pass_thru + = profile_probability::always ().apply_scale (1, 2); + prob_pass_wont_exit + = profile_probability::always ().apply_scale (1, 2); + } scale_step = XNEWVEC (profile_probability, ndupl); @@ -1306,7 +1316,9 @@ duplicate_loop_body_to_header_edge (class loop *loop, edge e, /* Complete peeling is special as the probability of exit in last copy becomes 1. */ - if (flags & DLTHE_FLAG_COMPLETTE_PEEL) + if (!count_in.nonzero_p ()) + ; + else if (flags & DLTHE_FLAG_COMPLETTE_PEEL) { profile_count wanted_count = e->count (); diff --git a/gcc/common.opt b/gcc/common.opt index 0888c15b88f0..3e1939293e8f 100644 --- a/gcc/common.opt +++ b/gcc/common.opt @@ -1010,6 +1010,9 @@ Driver Undocumented ; 18: Corrects errors in mangling of lambdas with additional context. ; Default in G++ 13. ; +; 19: Emits ABI tags if needed in structured binding mangled names. +; Default in G++ 14. +; ; Additional positive integers will be assigned as new versions of ; the ABI become the default version of the ABI. fabi-version= diff --git a/gcc/common/config/i386/cpuinfo.h b/gcc/common/config/i386/cpuinfo.h index 30ef0d334cad..24ae0dbf0ac6 100644 --- a/gcc/common/config/i386/cpuinfo.h +++ b/gcc/common/config/i386/cpuinfo.h @@ -533,10 +533,14 @@ get_intel_cpu (struct __processor_model *cpu_model, cpu_model->__cpu_type = INTEL_COREI7; cpu_model->__cpu_subtype = INTEL_COREI7_TIGERLAKE; break; + + case 0xbe: + /* Alder Lake N, E-core only. */ case 0x97: case 0x9a: /* Alder Lake. */ case 0xb7: + case 0xba: case 0xbf: /* Raptor Lake. */ case 0xaa: @@ -762,7 +766,9 @@ get_available_features (struct __processor_model *cpu_model, /* Get Advanced Features at level 7 (eax = 7, ecx = 0/1). */ if (max_cpuid_level >= 7) { - __cpuid_count (7, 0, eax, ebx, ecx, edx); + unsigned int max_subleaf_level; + + __cpuid_count (7, 0, max_subleaf_level, ebx, ecx, edx); if (ebx & bit_BMI) set_feature (FEATURE_BMI); if (ebx & bit_SGX) @@ -874,45 +880,48 @@ get_available_features (struct __processor_model *cpu_model, set_feature (FEATURE_AVX512FP16); } - __cpuid_count (7, 1, eax, ebx, ecx, edx); - if (eax & bit_HRESET) - set_feature (FEATURE_HRESET); - if (eax & bit_CMPCCXADD) - set_feature(FEATURE_CMPCCXADD); - if (edx & bit_PREFETCHI) - set_feature (FEATURE_PREFETCHI); - if (eax & bit_RAOINT) - set_feature (FEATURE_RAOINT); - if (avx_usable) + if (max_subleaf_level >= 1) { - if (eax & bit_AVXVNNI) - set_feature (FEATURE_AVXVNNI); - if (eax & bit_AVXIFMA) - set_feature (FEATURE_AVXIFMA); - if (edx & bit_AVXVNNIINT8) - set_feature (FEATURE_AVXVNNIINT8); - if (edx & bit_AVXNECONVERT) - set_feature (FEATURE_AVXNECONVERT); - if (edx & bit_AVXVNNIINT16) - set_feature (FEATURE_AVXVNNIINT16); - if (eax & bit_SM3) - set_feature (FEATURE_SM3); - if (eax & bit_SHA512) - set_feature (FEATURE_SHA512); - if (eax & bit_SM4) - set_feature (FEATURE_SM4); - } - if (avx512_usable) - { - if (eax & bit_AVX512BF16) - set_feature (FEATURE_AVX512BF16); - } - if (amx_usable) - { - if (eax & bit_AMX_FP16) - set_feature (FEATURE_AMX_FP16); - if (edx & bit_AMX_COMPLEX) - set_feature (FEATURE_AMX_COMPLEX); + __cpuid_count (7, 1, eax, ebx, ecx, edx); + if (eax & bit_HRESET) + set_feature (FEATURE_HRESET); + if (eax & bit_CMPCCXADD) + set_feature(FEATURE_CMPCCXADD); + if (edx & bit_PREFETCHI) + set_feature (FEATURE_PREFETCHI); + if (eax & bit_RAOINT) + set_feature (FEATURE_RAOINT); + if (avx_usable) + { + if (eax & bit_AVXVNNI) + set_feature (FEATURE_AVXVNNI); + if (eax & bit_AVXIFMA) + set_feature (FEATURE_AVXIFMA); + if (edx & bit_AVXVNNIINT8) + set_feature (FEATURE_AVXVNNIINT8); + if (edx & bit_AVXNECONVERT) + set_feature (FEATURE_AVXNECONVERT); + if (edx & bit_AVXVNNIINT16) + set_feature (FEATURE_AVXVNNIINT16); + if (eax & bit_SM3) + set_feature (FEATURE_SM3); + if (eax & bit_SHA512) + set_feature (FEATURE_SHA512); + if (eax & bit_SM4) + set_feature (FEATURE_SM4); + } + if (avx512_usable) + { + if (eax & bit_AVX512BF16) + set_feature (FEATURE_AVX512BF16); + } + if (amx_usable) + { + if (eax & bit_AMX_FP16) + set_feature (FEATURE_AMX_FP16); + if (edx & bit_AMX_COMPLEX) + set_feature (FEATURE_AMX_COMPLEX); + } } } diff --git a/gcc/common/config/i386/i386-common.cc b/gcc/common/config/i386/i386-common.cc index 260059140792..95468b7c405e 100644 --- a/gcc/common/config/i386/i386-common.cc +++ b/gcc/common/config/i386/i386-common.cc @@ -2044,7 +2044,9 @@ const char *const processor_names[] = "alderlake", "rocketlake", "graniterapids", + "graniterapids-d", "arrowlake", + "arrowlake-s", "intel", "lujiazui", "geode", @@ -2168,13 +2170,14 @@ const pta processor_alias_table[] = M_CPU_SUBTYPE (INTEL_COREI7_ALDERLAKE), P_PROC_AVX2}, {"graniterapids", PROCESSOR_GRANITERAPIDS, CPU_HASWELL, PTA_GRANITERAPIDS, M_CPU_SUBTYPE (INTEL_COREI7_GRANITERAPIDS), P_PROC_AVX512F}, - {"graniterapids-d", PROCESSOR_GRANITERAPIDS, CPU_HASWELL, PTA_GRANITERAPIDS_D, - M_CPU_SUBTYPE (INTEL_COREI7_GRANITERAPIDS_D), P_PROC_AVX512F}, + {"graniterapids-d", PROCESSOR_GRANITERAPIDS_D, CPU_HASWELL, + PTA_GRANITERAPIDS_D, M_CPU_SUBTYPE (INTEL_COREI7_GRANITERAPIDS_D), + P_PROC_AVX512F}, {"arrowlake", PROCESSOR_ARROWLAKE, CPU_HASWELL, PTA_ARROWLAKE, M_CPU_SUBTYPE (INTEL_COREI7_ARROWLAKE), P_PROC_AVX2}, - {"arrowlake-s", PROCESSOR_ARROWLAKE, CPU_HASWELL, PTA_ARROWLAKE_S, + {"arrowlake-s", PROCESSOR_ARROWLAKE_S, CPU_HASWELL, PTA_ARROWLAKE_S, M_CPU_SUBTYPE (INTEL_COREI7_ARROWLAKE_S), P_PROC_AVX2}, - {"lunarlake", PROCESSOR_ARROWLAKE, CPU_HASWELL, PTA_ARROWLAKE_S, + {"lunarlake", PROCESSOR_ARROWLAKE_S, CPU_HASWELL, PTA_ARROWLAKE_S, M_CPU_SUBTYPE (INTEL_COREI7_ARROWLAKE_S), P_PROC_AVX2}, {"bonnell", PROCESSOR_BONNELL, CPU_ATOM, PTA_BONNELL, M_CPU_TYPE (INTEL_BONNELL), P_PROC_SSSE3}, @@ -2190,6 +2193,8 @@ const pta processor_alias_table[] = M_CPU_TYPE (INTEL_GOLDMONT_PLUS), P_PROC_SSE4_2}, {"tremont", PROCESSOR_TREMONT, CPU_HASWELL, PTA_TREMONT, M_CPU_TYPE (INTEL_TREMONT), P_PROC_SSE4_2}, + {"gracemont", PROCESSOR_ALDERLAKE, CPU_HASWELL, PTA_ALDERLAKE, + M_CPU_SUBTYPE (INTEL_COREI7_ALDERLAKE), P_PROC_AVX2}, {"sierraforest", PROCESSOR_SIERRAFOREST, CPU_HASWELL, PTA_SIERRAFOREST, M_CPU_SUBTYPE (INTEL_SIERRAFOREST), P_PROC_AVX2}, {"grandridge", PROCESSOR_GRANDRIDGE, CPU_HASWELL, PTA_GRANDRIDGE, diff --git a/gcc/common/config/loongarch/loongarch-common.cc b/gcc/common/config/loongarch/loongarch-common.cc index fce32fa3f8d3..c5ed37d27a64 100644 --- a/gcc/common/config/loongarch/loongarch-common.cc +++ b/gcc/common/config/loongarch/loongarch-common.cc @@ -35,6 +35,7 @@ static const struct default_options loongarch_option_optimization_table[] = { { OPT_LEVELS_ALL, OPT_fasynchronous_unwind_tables, NULL, 1 }, { OPT_LEVELS_1_PLUS, OPT_fsection_anchors, NULL, 1 }, + { OPT_LEVELS_2_PLUS, OPT_free, NULL, 1 }, { OPT_LEVELS_NONE, 0, NULL, 0 } }; diff --git a/gcc/common/config/riscv/riscv-common.cc b/gcc/common/config/riscv/riscv-common.cc index 2eb8c7cadff0..f142212f2edc 100644 --- a/gcc/common/config/riscv/riscv-common.cc +++ b/gcc/common/config/riscv/riscv-common.cc @@ -71,6 +71,8 @@ static const riscv_implied_info_t riscv_implied_info[] = {"zks", "zksed"}, {"zks", "zksh"}, + {"ztso", "a"}, + {"v", "zvl128b"}, {"v", "zve64d"}, @@ -121,6 +123,9 @@ static const riscv_implied_info_t riscv_implied_info[] = {"zfh", "zfhmin"}, {"zfhmin", "f"}, + + {"zfa", "f"}, + {"zvfhmin", "zve32f"}, {"zvfh", "zve32f"}, {"zvfh", "zfhmin"}, @@ -128,6 +133,25 @@ static const riscv_implied_info_t riscv_implied_info[] = {"zhinx", "zhinxmin"}, {"zhinxmin", "zfinx"}, + {"zce", "zca"}, + {"zce", "zcb"}, + {"zce", "zcmp"}, + {"zce", "zcmt"}, + {"zcf", "zca"}, + {"zcd", "zca"}, + {"zcb", "zca"}, + {"zcmp", "zca"}, + {"zcmt", "zca"}, + {"zcmt", "zicsr"}, + + {"smaia", "ssaia"}, + {"smstateen", "ssstateen"}, + {"smepmp", "zicsr"}, + {"ssaia", "zicsr"}, + {"sscofpmf", "zicsr"}, + {"ssstateen", "zicsr"}, + {"sstc", "zicsr"}, + {NULL, NULL} }; @@ -209,6 +233,7 @@ static const struct riscv_ext_version riscv_ext_version_table[] = {"zkt", ISA_SPEC_CLASS_NONE, 1, 0}, {"zihintntl", ISA_SPEC_CLASS_NONE, 1, 0}, + {"zihintpause", ISA_SPEC_CLASS_NONE, 2, 0}, {"zicboz",ISA_SPEC_CLASS_NONE, 1, 0}, {"zicbom",ISA_SPEC_CLASS_NONE, 1, 0}, @@ -218,9 +243,10 @@ static const struct riscv_ext_version riscv_ext_version_table[] = {"zkn", ISA_SPEC_CLASS_NONE, 1, 0}, {"zks", ISA_SPEC_CLASS_NONE, 1, 0}, + {"ztso", ISA_SPEC_CLASS_NONE, 1, 0}, + {"zve32x", ISA_SPEC_CLASS_NONE, 1, 0}, {"zve32f", ISA_SPEC_CLASS_NONE, 1, 0}, - {"zve32d", ISA_SPEC_CLASS_NONE, 1, 0}, {"zve64x", ISA_SPEC_CLASS_NONE, 1, 0}, {"zve64f", ISA_SPEC_CLASS_NONE, 1, 0}, {"zve64d", ISA_SPEC_CLASS_NONE, 1, 0}, @@ -259,10 +285,30 @@ static const struct riscv_ext_version riscv_ext_version_table[] = {"zvfhmin", ISA_SPEC_CLASS_NONE, 1, 0}, {"zvfh", ISA_SPEC_CLASS_NONE, 1, 0}, + {"zfa", ISA_SPEC_CLASS_NONE, 0, 1}, + {"zmmul", ISA_SPEC_CLASS_NONE, 1, 0}, + {"zca", ISA_SPEC_CLASS_NONE, 1, 0}, + {"zcb", ISA_SPEC_CLASS_NONE, 1, 0}, + {"zce", ISA_SPEC_CLASS_NONE, 1, 0}, + {"zcf", ISA_SPEC_CLASS_NONE, 1, 0}, + {"zcd", ISA_SPEC_CLASS_NONE, 1, 0}, + {"zcmp", ISA_SPEC_CLASS_NONE, 1, 0}, + {"zcmt", ISA_SPEC_CLASS_NONE, 1, 0}, + + {"smaia", ISA_SPEC_CLASS_NONE, 1, 0}, + {"smepmp", ISA_SPEC_CLASS_NONE, 1, 0}, + {"smstateen", ISA_SPEC_CLASS_NONE, 1, 0}, + + {"ssaia", ISA_SPEC_CLASS_NONE, 1, 0}, + {"sscofpmf", ISA_SPEC_CLASS_NONE, 1, 0}, + {"ssstateen", ISA_SPEC_CLASS_NONE, 1, 0}, + {"sstc", ISA_SPEC_CLASS_NONE, 1, 0}, + {"svinval", ISA_SPEC_CLASS_NONE, 1, 0}, {"svnapot", ISA_SPEC_CLASS_NONE, 1, 0}, + {"svpbmt", ISA_SPEC_CLASS_NONE, 1, 0}, {"xtheadba", ISA_SPEC_CLASS_NONE, 1, 0}, {"xtheadbb", ISA_SPEC_CLASS_NONE, 1, 0}, @@ -277,6 +323,8 @@ static const struct riscv_ext_version riscv_ext_version_table[] = {"xtheadmempair", ISA_SPEC_CLASS_NONE, 1, 0}, {"xtheadsync", ISA_SPEC_CLASS_NONE, 1, 0}, + {"xventanacondops", ISA_SPEC_CLASS_NONE, 1, 0}, + /* Terminate the list. */ {NULL, ISA_SPEC_CLASS_NONE, 0, 0} }; @@ -1266,11 +1314,22 @@ riscv_subset_list::parse (const char *arch, location_t loc) subset_list->handle_implied_ext (itr->name.c_str ()); } + /* Zce only implies zcf when RV32 and 'f' extension exist. */ + if (subset_list->lookup ("zce") != NULL + && subset_list->m_xlen == 32 + && subset_list->lookup ("f") != NULL + && subset_list->lookup ("zcf") == NULL) + subset_list->add ("zcf", false); + /* Make sure all implied extensions are included. */ gcc_assert (subset_list->check_implied_ext ()); subset_list->handle_combine_ext (); + if (subset_list->lookup ("zcf") && subset_list->m_xlen == 64) + error_at (loc, "%<-march=%s%>: zcf extension supports in rv32 only" + , arch); + if (subset_list->lookup ("zfinx") && subset_list->lookup ("f")) error_at (loc, "%<-march=%s%>: z*inx conflicts with floating-point " "extensions", arch); @@ -1344,6 +1403,7 @@ static const riscv_ext_flag_table_t riscv_ext_flag_table[] = {"zkt", &gcc_options::x_riscv_zk_subext, MASK_ZKT}, {"zihintntl", &gcc_options::x_riscv_zi_subext, MASK_ZIHINTNTL}, + {"zihintpause", &gcc_options::x_riscv_zi_subext, MASK_ZIHINTPAUSE}, {"zicboz", &gcc_options::x_riscv_zicmo_subext, MASK_ZICBOZ}, {"zicbom", &gcc_options::x_riscv_zicmo_subext, MASK_ZICBOM}, @@ -1402,11 +1462,24 @@ static const riscv_ext_flag_table_t riscv_ext_flag_table[] = {"zvfhmin", &gcc_options::x_riscv_zf_subext, MASK_ZVFHMIN}, {"zvfh", &gcc_options::x_riscv_zf_subext, MASK_ZVFH}, + {"zfa", &gcc_options::x_riscv_zfa_subext, MASK_ZFA}, + {"zmmul", &gcc_options::x_riscv_zm_subext, MASK_ZMMUL}, + /* Code-size reduction extensions. */ + {"zca", &gcc_options::x_riscv_zc_subext, MASK_ZCA}, + {"zcb", &gcc_options::x_riscv_zc_subext, MASK_ZCB}, + {"zce", &gcc_options::x_riscv_zc_subext, MASK_ZCE}, + {"zcf", &gcc_options::x_riscv_zc_subext, MASK_ZCF}, + {"zcd", &gcc_options::x_riscv_zc_subext, MASK_ZCD}, + {"zcmp", &gcc_options::x_riscv_zc_subext, MASK_ZCMP}, + {"zcmt", &gcc_options::x_riscv_zc_subext, MASK_ZCMT}, + {"svinval", &gcc_options::x_riscv_sv_subext, MASK_SVINVAL}, {"svnapot", &gcc_options::x_riscv_sv_subext, MASK_SVNAPOT}, + {"ztso", &gcc_options::x_riscv_ztso_subext, MASK_ZTSO}, + {"xtheadba", &gcc_options::x_riscv_xthead_subext, MASK_XTHEADBA}, {"xtheadbb", &gcc_options::x_riscv_xthead_subext, MASK_XTHEADBB}, {"xtheadbs", &gcc_options::x_riscv_xthead_subext, MASK_XTHEADBS}, @@ -1973,6 +2046,8 @@ riscv_get_valid_option_values (int option_code, static const struct default_options riscv_option_optimization_table[] = { { OPT_LEVELS_1_PLUS, OPT_fsection_anchors, NULL, 1 }, + /* Enable -fsched-pressure starting at -O1. */ + { OPT_LEVELS_1_PLUS, OPT_fsched_pressure, NULL, 1 }, { OPT_LEVELS_2_PLUS, OPT_free, NULL, 1 }, #if TARGET_DEFAULT_ASYNC_UNWIND_TABLES == 1 { OPT_LEVELS_ALL, OPT_fasynchronous_unwind_tables, NULL, 1 }, diff --git a/gcc/config.gcc b/gcc/config.gcc index 9dacec117791..315253cca8c1 100644 --- a/gcc/config.gcc +++ b/gcc/config.gcc @@ -541,7 +541,7 @@ pru-*-*) ;; riscv*) cpu_type=riscv - extra_objs="riscv-builtins.o riscv-c.o riscv-sr.o riscv-shorten-memrefs.o riscv-selftests.o riscv-v.o riscv-vsetvl.o" + extra_objs="riscv-builtins.o riscv-c.o riscv-sr.o riscv-shorten-memrefs.o riscv-selftests.o riscv-v.o riscv-vsetvl.o riscv-vector-costs.o" extra_objs="${extra_objs} riscv-vector-builtins.o riscv-vector-builtins-shapes.o riscv-vector-builtins-bases.o" extra_objs="${extra_objs} thead.o" d_target_objs="riscv-d.o" diff --git a/gcc/config.in b/gcc/config.in index 5cf51bc1b01a..f0071456f03c 100644 --- a/gcc/config.in +++ b/gcc/config.in @@ -622,15 +622,13 @@ #endif -/* Define if your Mac OS X assembler supports -mllvm -x86-pad-for-align=false. - */ +/* Define if your macOS assembler supports -mllvm -x86-pad-for-align=false. */ #ifndef USED_FOR_TARGET #undef HAVE_AS_MLLVM_X86_PAD_FOR_ALIGN #endif -/* Define if your Mac OS X assembler supports the -mmacos-version-min option. - */ +/* Define if your macOS assembler supports the -mmacos-version-min option. */ #ifndef USED_FOR_TARGET #undef HAVE_AS_MMACOSX_VERSION_MIN_OPTION #endif diff --git a/gcc/config/aarch64/aarch64-cores.def b/gcc/config/aarch64/aarch64-cores.def index 2ec88c98400d..73976e9a4c5e 100644 --- a/gcc/config/aarch64/aarch64-cores.def +++ b/gcc/config/aarch64/aarch64-cores.def @@ -170,10 +170,14 @@ AARCH64_CORE("cortex-r82", cortexr82, cortexa53, V8R, (), cortexa53, 0x41, 0xd15 /* Arm ('A') cores. */ AARCH64_CORE("cortex-a510", cortexa510, cortexa55, V9A, (SVE2_BITPERM, MEMTAG, I8MM, BF16), cortexa53, 0x41, 0xd46, -1) +AARCH64_CORE("cortex-a520", cortexa520, cortexa55, V9_2A, (SVE2_BITPERM, MEMTAG), cortexa53, 0x41, 0xd80, -1) + AARCH64_CORE("cortex-a710", cortexa710, cortexa57, V9A, (SVE2_BITPERM, MEMTAG, I8MM, BF16), neoversen2, 0x41, 0xd47, -1) AARCH64_CORE("cortex-a715", cortexa715, cortexa57, V9A, (SVE2_BITPERM, MEMTAG, I8MM, BF16), neoversen2, 0x41, 0xd4d, -1) +AARCH64_CORE("cortex-a720", cortexa720, cortexa57, V9_2A, (SVE2_BITPERM, MEMTAG, PROFILE), neoversen2, 0x41, 0xd81, -1) + AARCH64_CORE("cortex-x2", cortexx2, cortexa57, V9A, (SVE2_BITPERM, MEMTAG, I8MM, BF16), neoversen2, 0x41, 0xd48, -1) AARCH64_CORE("cortex-x3", cortexx3, cortexa57, V9A, (SVE2_BITPERM, MEMTAG, I8MM, BF16), neoversen2, 0x41, 0xd4e, -1) diff --git a/gcc/config/aarch64/aarch64-tune.md b/gcc/config/aarch64/aarch64-tune.md index 4fd35fa48846..12d610f0f658 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,thunderxt88p1,thunderxt88,octeontx,octeontxt81,octeontxt83,thunderxt81,thunderxt83,ampere1,ampere1a,emag,xgene1,falkor,qdf24xx,exynosm1,phecda,thunderx2t99p1,vulcan,thunderx2t99,cortexa55,cortexa75,cortexa76,cortexa76ae,cortexa77,cortexa78,cortexa78ae,cortexa78c,cortexa65,cortexa65ae,cortexx1,cortexx1c,ares,neoversen1,neoversee1,octeontx2,octeontx2t98,octeontx2t96,octeontx2t93,octeontx2f95,octeontx2f95n,octeontx2f95mm,a64fx,tsv110,thunderx3t110,zeus,neoversev1,neoverse512tvb,saphira,cortexa57cortexa53,cortexa72cortexa53,cortexa73cortexa35,cortexa73cortexa53,cortexa75cortexa55,cortexa76cortexa55,cortexr82,cortexa510,cortexa710,cortexa715,cortexx2,cortexx3,neoversen2,demeter,neoversev2" + "cortexa34,cortexa35,cortexa53,cortexa57,cortexa72,cortexa73,thunderx,thunderxt88p1,thunderxt88,octeontx,octeontxt81,octeontxt83,thunderxt81,thunderxt83,ampere1,ampere1a,emag,xgene1,falkor,qdf24xx,exynosm1,phecda,thunderx2t99p1,vulcan,thunderx2t99,cortexa55,cortexa75,cortexa76,cortexa76ae,cortexa77,cortexa78,cortexa78ae,cortexa78c,cortexa65,cortexa65ae,cortexx1,cortexx1c,ares,neoversen1,neoversee1,octeontx2,octeontx2t98,octeontx2t96,octeontx2t93,octeontx2f95,octeontx2f95n,octeontx2f95mm,a64fx,tsv110,thunderx3t110,zeus,neoversev1,neoverse512tvb,saphira,cortexa57cortexa53,cortexa72cortexa53,cortexa73cortexa35,cortexa73cortexa53,cortexa75cortexa55,cortexa76cortexa55,cortexr82,cortexa510,cortexa520,cortexa710,cortexa715,cortexa720,cortexx2,cortexx3,neoversen2,demeter,neoversev2" (const (symbol_ref "((enum attr_tune) aarch64_tune)"))) diff --git a/gcc/config/aarch64/aarch64.cc b/gcc/config/aarch64/aarch64.cc index 7cd230c4602a..37d414021cab 100644 --- a/gcc/config/aarch64/aarch64.cc +++ b/gcc/config/aarch64/aarch64.cc @@ -84,6 +84,7 @@ #include "aarch64-feature-deps.h" #include "config/arm/aarch-common.h" #include "config/arm/aarch-common-protos.h" +#include "ssa.h" /* This file should be included last. */ #include "target-def.h" @@ -11182,7 +11183,8 @@ aarch64_classify_symbolic_expression (rtx x) /* Return TRUE if X is a legitimate address for accessing memory in mode MODE. */ static bool -aarch64_legitimate_address_hook_p (machine_mode mode, rtx x, bool strict_p) +aarch64_legitimate_address_hook_p (machine_mode mode, rtx x, bool strict_p, + code_helper = ERROR_MARK) { struct aarch64_address_info addr; @@ -16410,20 +16412,20 @@ aarch64_multiply_add_p (vec_info *vinfo, stmt_vec_info stmt_info, if (code != PLUS_EXPR && code != MINUS_EXPR) return false; - for (int i = 1; i < 3; ++i) + auto is_mul_result = [&](int i) { tree rhs = gimple_op (assign, i); /* ??? Should we try to check for a single use as well? */ if (TREE_CODE (rhs) != SSA_NAME) - continue; + return false; stmt_vec_info def_stmt_info = vinfo->lookup_def (rhs); if (!def_stmt_info || STMT_VINFO_DEF_TYPE (def_stmt_info) != vect_internal_def) - continue; + return false; gassign *rhs_assign = dyn_cast (def_stmt_info->stmt); if (!rhs_assign || gimple_assign_rhs_code (rhs_assign) != MULT_EXPR) - continue; + return false; if (vec_flags & VEC_ADVSIMD) { @@ -16443,8 +16445,19 @@ aarch64_multiply_add_p (vec_info *vinfo, stmt_vec_info stmt_info, } return true; - } - return false; + }; + + if (code == MINUS_EXPR && (vec_flags & VEC_ADVSIMD)) + /* Advanced SIMD doesn't have FNMADD/FNMSUB/FNMLA/FNMLS, so the + multiplication must be on the second operand (to form an FMLS). + But if both operands are multiplications and the second operand + is used more than once, we'll instead negate the second operand + and use it as an accumulator for the first operand. */ + return (is_mul_result (2) + && (has_single_use (gimple_assign_rhs2 (assign)) + || !is_mul_result (1))); + + return is_mul_result (1) || is_mul_result (2); } /* Return true if STMT_INFO is the second part of a two-statement boolean AND @@ -25665,7 +25678,7 @@ aarch64_asan_shadow_offset (void) static rtx aarch64_gen_ccmp_first (rtx_insn **prep_seq, rtx_insn **gen_seq, - int code, tree treeop0, tree treeop1) + rtx_code code, tree treeop0, tree treeop1) { machine_mode op_mode, cmp_mode, cc_mode = CCmode; rtx op0, op1; @@ -25739,7 +25752,8 @@ aarch64_gen_ccmp_first (rtx_insn **prep_seq, rtx_insn **gen_seq, static rtx aarch64_gen_ccmp_next (rtx_insn **prep_seq, rtx_insn **gen_seq, rtx prev, - int cmp_code, tree treeop0, tree treeop1, int bit_code) + rtx_code cmp_code, tree treeop0, tree treeop1, + rtx_code bit_code) { rtx op0, op1, target; machine_mode op_mode, cmp_mode, cc_mode = CCmode; diff --git a/gcc/config/aarch64/aarch64.md b/gcc/config/aarch64/aarch64.md index 01cf989641fc..6f7827bd8c93 100644 --- a/gcc/config/aarch64/aarch64.md +++ b/gcc/config/aarch64/aarch64.md @@ -1170,9 +1170,27 @@ { int i; + /* Generate a PARALLEL that contains all of the register results. + The offsets are somewhat arbitrary, since we don't know the + actual return type. The main thing we need to avoid is having + overlapping byte ranges, since those might give the impression + that two registers are known to have data in common. */ + rtvec rets = rtvec_alloc (XVECLEN (operands[2], 0)); + poly_int64 offset = 0; + for (i = 0; i < XVECLEN (operands[2], 0); i++) + { + rtx reg = SET_SRC (XVECEXP (operands[2], 0, i)); + gcc_assert (REG_P (reg)); + rtx offset_rtx = gen_int_mode (offset, Pmode); + rtx piece = gen_rtx_EXPR_LIST (VOIDmode, reg, offset_rtx); + RTVEC_ELT (rets, i) = piece; + offset += GET_MODE_SIZE (GET_MODE (reg)); + } + rtx ret = gen_rtx_PARALLEL (VOIDmode, rets); + /* Untyped calls always use the default ABI. It's only possible to use ABI variants if we know the type of the target function. */ - emit_call_insn (gen_call (operands[0], const0_rtx, const0_rtx)); + emit_call_insn (gen_call_value (ret, operands[0], const0_rtx, const0_rtx)); for (i = 0; i < XVECLEN (operands[2], 0); i++) { diff --git a/gcc/config/aarch64/falkor-tag-collision-avoidance.cc b/gcc/config/aarch64/falkor-tag-collision-avoidance.cc index 39e3f5c2d1ba..9b3357f59525 100644 --- a/gcc/config/aarch64/falkor-tag-collision-avoidance.cc +++ b/gcc/config/aarch64/falkor-tag-collision-avoidance.cc @@ -740,7 +740,7 @@ dump_insn_list (const rtx &t, const insn_info_list_t &insn_info, void *unused ATTRIBUTE_UNUSED) { gcc_assert (dump_file); - fprintf (dump_file, "Tag 0x%lx ::\n", INTVAL (t)); + fprintf (dump_file, "Tag 0x" HOST_WIDE_INT_PRINT_HEX_PURE " ::\n", INTVAL (t)); for (unsigned i = 0; i < insn_info.length (); i++) dump_insn_slim (dump_file, insn_info[i]->insn); diff --git a/gcc/config/alpha/alpha.cc b/gcc/config/alpha/alpha.cc index beeab06a1aa5..db6b34be9cb0 100644 --- a/gcc/config/alpha/alpha.cc +++ b/gcc/config/alpha/alpha.cc @@ -844,7 +844,8 @@ alpha_linkage_symbol_p (const char *symname) low-order three bits; this is an "unaligned" access. */ static bool -alpha_legitimate_address_p (machine_mode mode, rtx x, bool strict) +alpha_legitimate_address_p (machine_mode mode, rtx x, bool strict, + code_helper = ERROR_MARK) { /* If this is an ldq_u type address, discard the outer AND. */ if (mode == DImode diff --git a/gcc/config/arc/arc.cc b/gcc/config/arc/arc.cc index fef8a504f771..8ee7387286e3 100644 --- a/gcc/config/arc/arc.cc +++ b/gcc/config/arc/arc.cc @@ -6715,7 +6715,8 @@ arc_legitimate_constant_p (machine_mode mode, rtx x) } static bool -arc_legitimate_address_p (machine_mode mode, rtx x, bool strict) +arc_legitimate_address_p (machine_mode mode, rtx x, bool strict, + code_helper = ERROR_MARK) { if (RTX_OK_FOR_BASE_P (x, strict)) return true; @@ -11646,7 +11647,7 @@ arc_split_mov_const (rtx *operands) } /* 3. Check if we can just shift by 16 to fit into the u6 of LSL16. */ - if (TARGET_BARREL_SHIFTER && TARGET_V2 + if (TARGET_SWAP && TARGET_V2 && ((ival & ~0x3f0000) == 0)) { shimm = (ival >> 16) & 0x3f; diff --git a/gcc/config/arc/arc.md b/gcc/config/arc/arc.md index 1f122d9507f2..a4e77a207bf7 100644 --- a/gcc/config/arc/arc.md +++ b/gcc/config/arc/arc.md @@ -5991,7 +5991,7 @@ archs4x, archs4xd" [(set (match_operand:SI 0 "register_operand" "=r") (ashift:SI (match_operand:SI 1 "nonmemory_operand" "rL") (const_int 16)))] - "TARGET_BARREL_SHIFTER && TARGET_V2" + "TARGET_SWAP && TARGET_V2" "lsl16\\t%0,%1" [(set_attr "type" "shift") (set_attr "iscompact" "false") diff --git a/gcc/config/arm/arm-mve-builtins-base.cc b/gcc/config/arm/arm-mve-builtins-base.cc index e31095ae1121..5478cac8aeb2 100644 --- a/gcc/config/arm/arm-mve-builtins-base.cc +++ b/gcc/config/arm/arm-mve-builtins-base.cc @@ -260,8 +260,8 @@ FUNCTION_PRED_P_S_U (vaddvq, VADDVQ) FUNCTION_PRED_P_S_U (vaddvaq, VADDVAQ) FUNCTION_WITH_RTX_M (vandq, AND, VANDQ) FUNCTION_ONLY_N (vbrsrq, VBRSRQ) -FUNCTION (vcaddq_rot90, unspec_mve_function_exact_insn_rot, (UNSPEC_VCADD90, UNSPEC_VCADD90, UNSPEC_VCADD90, VCADDQ_ROT90_M_S, VCADDQ_ROT90_M_U, VCADDQ_ROT90_M_F)) -FUNCTION (vcaddq_rot270, unspec_mve_function_exact_insn_rot, (UNSPEC_VCADD270, UNSPEC_VCADD270, UNSPEC_VCADD270, VCADDQ_ROT270_M_S, VCADDQ_ROT270_M_U, VCADDQ_ROT270_M_F)) +FUNCTION (vcaddq_rot90, unspec_mve_function_exact_insn_rot, (UNSPEC_VCADD90, UNSPEC_VCADD90, UNSPEC_VCADD90, VCADDQ_ROT90_M, VCADDQ_ROT90_M, VCADDQ_ROT90_M_F)) +FUNCTION (vcaddq_rot270, unspec_mve_function_exact_insn_rot, (UNSPEC_VCADD270, UNSPEC_VCADD270, UNSPEC_VCADD270, VCADDQ_ROT270_M, VCADDQ_ROT270_M, VCADDQ_ROT270_M_F)) FUNCTION (vcmlaq, unspec_mve_function_exact_insn_rot, (-1, -1, UNSPEC_VCMLA, -1, -1, VCMLAQ_M_F)) FUNCTION (vcmlaq_rot90, unspec_mve_function_exact_insn_rot, (-1, -1, UNSPEC_VCMLA90, -1, -1, VCMLAQ_ROT90_M_F)) FUNCTION (vcmlaq_rot180, unspec_mve_function_exact_insn_rot, (-1, -1, UNSPEC_VCMLA180, -1, -1, VCMLAQ_ROT180_M_F)) @@ -329,6 +329,10 @@ FUNCTION_WITHOUT_N_NO_F (vmovltq, VMOVLTQ) FUNCTION_WITHOUT_N_NO_F (vmovnbq, VMOVNBQ) FUNCTION_WITHOUT_N_NO_F (vmovntq, VMOVNTQ) FUNCTION_WITHOUT_N_NO_F (vmulhq, VMULHQ) +FUNCTION (vmullbq_int, unspec_mve_function_exact_insn_vmull, (VMULLBQ_INT_S, VMULLBQ_INT_U, VMULLBQ_INT_M_S, VMULLBQ_INT_M_U)) +FUNCTION (vmulltq_int, unspec_mve_function_exact_insn_vmull, (VMULLTQ_INT_S, VMULLTQ_INT_U, VMULLTQ_INT_M_S, VMULLTQ_INT_M_U)) +FUNCTION (vmullbq_poly, unspec_mve_function_exact_insn_vmull_poly, (VMULLBQ_POLY_P, VMULLBQ_POLY_M_P)) +FUNCTION (vmulltq_poly, unspec_mve_function_exact_insn_vmull_poly, (VMULLTQ_POLY_P, VMULLTQ_POLY_M_P)) FUNCTION_WITH_RTX_M_N (vmulq, MULT, VMULQ) FUNCTION_WITH_RTX_M_N_NO_F (vmvnq, NOT, VMVNQ) FUNCTION (vnegq, unspec_based_mve_function_exact_insn, (NEG, NEG, NEG, -1, -1, -1, VNEGQ_M_S, -1, VNEGQ_M_F, -1, -1, -1)) diff --git a/gcc/config/arm/arm-mve-builtins-base.def b/gcc/config/arm/arm-mve-builtins-base.def index e7d466f2efd8..01dfbdef8a30 100644 --- a/gcc/config/arm/arm-mve-builtins-base.def +++ b/gcc/config/arm/arm-mve-builtins-base.def @@ -78,6 +78,10 @@ DEF_MVE_FUNCTION (vmovltq, unary_widen, integer_8_16, mx_or_none) DEF_MVE_FUNCTION (vmovnbq, binary_move_narrow, integer_16_32, m_or_none) DEF_MVE_FUNCTION (vmovntq, binary_move_narrow, integer_16_32, m_or_none) DEF_MVE_FUNCTION (vmulhq, binary, all_integer, mx_or_none) +DEF_MVE_FUNCTION (vmullbq_int, binary_widen, all_integer, mx_or_none) +DEF_MVE_FUNCTION (vmulltq_int, binary_widen, all_integer, mx_or_none) +DEF_MVE_FUNCTION (vmullbq_poly, binary_widen_poly, poly_8_16, mx_or_none) +DEF_MVE_FUNCTION (vmulltq_poly, binary_widen_poly, poly_8_16, mx_or_none) DEF_MVE_FUNCTION (vmulq, binary_opt_n, all_integer, mx_or_none) DEF_MVE_FUNCTION (vmvnq, mvn, all_integer, mx_or_none) DEF_MVE_FUNCTION (vnegq, unary, all_signed, mx_or_none) diff --git a/gcc/config/arm/arm-mve-builtins-base.h b/gcc/config/arm/arm-mve-builtins-base.h index be3698b4f4cd..c574c32ac53e 100644 --- a/gcc/config/arm/arm-mve-builtins-base.h +++ b/gcc/config/arm/arm-mve-builtins-base.h @@ -102,6 +102,10 @@ extern const function_base *const vmovltq; extern const function_base *const vmovnbq; extern const function_base *const vmovntq; extern const function_base *const vmulhq; +extern const function_base *const vmullbq_int; +extern const function_base *const vmulltq_int; +extern const function_base *const vmullbq_poly; +extern const function_base *const vmulltq_poly; extern const function_base *const vmulq; extern const function_base *const vmvnq; extern const function_base *const vnegq; diff --git a/gcc/config/arm/arm-mve-builtins-functions.h b/gcc/config/arm/arm-mve-builtins-functions.h index a65738443192..eba1f071af0a 100644 --- a/gcc/config/arm/arm-mve-builtins-functions.h +++ b/gcc/config/arm/arm-mve-builtins-functions.h @@ -838,6 +838,134 @@ public: } }; +/* Map the vmull-related function directly to CODE (UNSPEC, UNSPEC, M) + where M is the vector mode associated with type suffix 0. We need + this special case because the builtins have _int in their + names. */ +class unspec_mve_function_exact_insn_vmull : public function_base +{ +public: + CONSTEXPR unspec_mve_function_exact_insn_vmull (int unspec_for_sint, + int unspec_for_uint, + int unspec_for_m_sint, + int unspec_for_m_uint) + : m_unspec_for_sint (unspec_for_sint), + m_unspec_for_uint (unspec_for_uint), + m_unspec_for_m_sint (unspec_for_m_sint), + m_unspec_for_m_uint (unspec_for_m_uint) + {} + + /* The unspec code associated with signed-integer and + unsigned-integer operations respectively. It covers the cases + with and without the _m predicate. */ + int m_unspec_for_sint; + int m_unspec_for_uint; + int m_unspec_for_m_sint; + int m_unspec_for_m_uint; + + rtx + expand (function_expander &e) const override + { + insn_code code; + + if (! e.type_suffix (0).integer_p) + gcc_unreachable (); + + if (e.mode_suffix_id != MODE_none) + gcc_unreachable (); + + switch (e.pred) + { + case PRED_none: + /* No predicate, no suffix. */ + if (e.type_suffix (0).unsigned_p) + code = code_for_mve_q_int (m_unspec_for_uint, m_unspec_for_uint, e.vector_mode (0)); + else + code = code_for_mve_q_int (m_unspec_for_sint, m_unspec_for_sint, e.vector_mode (0)); + + return e.use_exact_insn (code); + + case PRED_m: + /* No suffix, "m" predicate. */ + if (e.type_suffix (0).unsigned_p) + code = code_for_mve_q_int_m (m_unspec_for_m_uint, m_unspec_for_m_uint, e.vector_mode (0)); + else + code = code_for_mve_q_int_m (m_unspec_for_m_sint, m_unspec_for_m_sint, e.vector_mode (0)); + + return e.use_cond_insn (code, 0); + + case PRED_x: + /* No suffix, "x" predicate. */ + if (e.type_suffix (0).unsigned_p) + code = code_for_mve_q_int_m (m_unspec_for_m_uint, m_unspec_for_m_uint, e.vector_mode (0)); + else + code = code_for_mve_q_int_m (m_unspec_for_m_sint, m_unspec_for_m_sint, e.vector_mode (0)); + + return e.use_pred_x_insn (code); + + default: + gcc_unreachable (); + } + + gcc_unreachable (); + } +}; + +/* Map the vmull_poly-related function directly to CODE (UNSPEC, + UNSPEC, M) where M is the vector mode associated with type suffix + 0. We need this special case because the builtins have _poly in + their names, and use the special poly type.. */ +class unspec_mve_function_exact_insn_vmull_poly : public function_base +{ +public: + CONSTEXPR unspec_mve_function_exact_insn_vmull_poly (int unspec_for_poly, + int unspec_for_m_poly) + : m_unspec_for_poly (unspec_for_poly), + m_unspec_for_m_poly (unspec_for_m_poly) + {} + + /* The unspec code associated with signed-integer, unsigned-integer + and poly operations respectively. It covers the cases with and + without the _m predicate. */ + int m_unspec_for_poly; + int m_unspec_for_m_poly; + + rtx + expand (function_expander &e) const override + { + insn_code code; + + if (e.mode_suffix_id != MODE_none) + gcc_unreachable (); + + if (! e.type_suffix (0).poly_p) + gcc_unreachable (); + + switch (e.pred) + { + case PRED_none: + /* No predicate, no suffix. */ + code = code_for_mve_q_poly (m_unspec_for_poly, m_unspec_for_poly, e.vector_mode (0)); + return e.use_exact_insn (code); + + case PRED_m: + /* No suffix, "m" predicate. */ + code = code_for_mve_q_poly_m (m_unspec_for_m_poly, m_unspec_for_m_poly, e.vector_mode (0)); + return e.use_cond_insn (code, 0); + + case PRED_x: + /* No suffix, "x" predicate. */ + code = code_for_mve_q_poly_m (m_unspec_for_m_poly, m_unspec_for_m_poly, e.vector_mode (0)); + return e.use_pred_x_insn (code); + + default: + gcc_unreachable (); + } + + gcc_unreachable (); + } +}; + } /* end namespace arm_mve */ /* Declare the global function base NAME, creating it from an instance diff --git a/gcc/config/arm/arm-mve-builtins-shapes.cc b/gcc/config/arm/arm-mve-builtins-shapes.cc index 1b4960f75cd2..23eb9d0e69be 100644 --- a/gcc/config/arm/arm-mve-builtins-shapes.cc +++ b/gcc/config/arm/arm-mve-builtins-shapes.cc @@ -61,10 +61,12 @@ apply_predication (const function_instance &instance, tree return_type, [01] - the element type in type suffix 0 or 1 of INSTANCE. h - a half-sized version of + p - a poly type with the same width as s - a signed type with the given number of bits s[01] - a signed type with the same width as type suffix 0 or 1 u - an unsigned type with the given number of bits u[01] - an unsigned type with the same width as type suffix 0 or 1 + U - an unsigned type with the double width as w - a double-sized version of x - a type with the given number of bits and same signedness as the next argument. @@ -78,8 +80,7 @@ parse_element_type (const function_instance &instance, const char *&format) if (ch == 's' || ch == 'u') { - type_class_index tclass = (ch == 'f' ? TYPE_float - : ch == 's' ? TYPE_signed + type_class_index tclass = (ch == 's' ? TYPE_signed : TYPE_unsigned); char *end; unsigned int bits = strtol (format, &end, 10); @@ -103,6 +104,20 @@ parse_element_type (const function_instance &instance, const char *&format) type_suffixes[suffix].element_bits * 2); } + if (ch == 'U') + { + type_suffix_index suffix = parse_element_type (instance, format); + return find_type_suffix (TYPE_unsigned, + type_suffixes[suffix].element_bits * 2); + } + + if (ch == 'p') + { + type_suffix_index suffix = parse_element_type (instance, format); + return find_type_suffix (TYPE_poly, + type_suffixes[suffix].element_bits); + } + if (ch == 'x') { const char *next = format; @@ -439,7 +454,7 @@ struct binary_acca_int32_def : public overloaded_base<0> || (type = r.infer_vector_type (1)) == NUM_TYPE_SUFFIXES) return error_mark_node; - unsigned int last_arg = i; + unsigned int last_arg = i + 1; for (i = 1; i < last_arg; i++) if (!r.require_matching_vector_type (i, type)) return error_mark_node; @@ -476,7 +491,7 @@ struct binary_acca_int64_def : public overloaded_base<0> || (type = r.infer_vector_type (1)) == NUM_TYPE_SUFFIXES) return error_mark_node; - unsigned int last_arg = i; + unsigned int last_arg = i + 1; for (i = 1; i < last_arg; i++) if (!r.require_matching_vector_type (i, type)) return error_mark_node; @@ -1130,6 +1145,97 @@ struct binary_rshift_narrow_unsigned_def : public overloaded_base<0> }; SHAPE (binary_rshift_narrow_unsigned) +/* _t vfoo[_t0](_t, _t) + + Example: vmullbq. + int32x4_t [__arm_]vmullbq_int[_s16](int16x8_t a, int16x8_t b) + int32x4_t [__arm_]vmullbq_int_m[_s16](int32x4_t inactive, int16x8_t a, int16x8_t b, mve_pred16_t p) + int32x4_t [__arm_]vmullbq_int_x[_s16](int16x8_t a, int16x8_t b, mve_pred16_t p) */ +struct binary_widen_def : public overloaded_base<0> +{ + void + build (function_builder &b, const function_group_info &group, + bool preserve_user_namespace) const override + { + b.add_overloaded_functions (group, MODE_none, preserve_user_namespace); + build_all (b, "vw0,v0,v0", group, MODE_none, preserve_user_namespace); + } + + tree + resolve (function_resolver &r) const override + { + unsigned int i, nargs; + type_suffix_index type; + if (!r.check_gp_argument (2, i, nargs) + || (type = r.infer_vector_type (i - 1)) == NUM_TYPE_SUFFIXES) + return error_mark_node; + + type_suffix_index wide_suffix + = find_type_suffix (type_suffixes[type].tclass, + type_suffixes[type].element_bits * 2); + + if (!r.require_matching_vector_type (i, type)) + return error_mark_node; + + /* Check the inactive argument has the wide type. */ + if ((r.pred == PRED_m) + && (r.infer_vector_type (0) != wide_suffix)) + return r.report_no_such_form (type); + + return r.resolve_to (r.mode_suffix_id, type); + } +}; +SHAPE (binary_widen) + +/* _t vfoo[_t0](_t, _t) + + Example: vmullbq_poly. + uint32x4_t [__arm_]vmullbq_poly[_p16](uint16x8_t a, uint16x8_t b) + uint32x4_t [__arm_]vmullbq_poly_m[_p16](uint32x4_t inactive, uint16x8_t a, uint16x8_t b, mve_pred16_t p) + uint32x4_t [__arm_]vmullbq_poly_x[_p16](uint16x8_t a, uint16x8_t b, mve_pred16_t p) */ +struct binary_widen_poly_def : public overloaded_base<0> +{ + void + build (function_builder &b, const function_group_info &group, + bool preserve_user_namespace) const override + { + b.add_overloaded_functions (group, MODE_none, preserve_user_namespace); + build_all (b, "vU0,vp0,vp0", group, MODE_none, preserve_user_namespace); + } + + tree + resolve (function_resolver &r) const override + { + unsigned int i, nargs; + type_suffix_index type; + if (!r.check_gp_argument (2, i, nargs) + || (type = r.infer_vector_type (i - 1)) == NUM_TYPE_SUFFIXES) + return error_mark_node; + + /* infer_vector_type found the 'unsigned' version of the 'poly' + type we are looking for, so find the 'poly' type with the same + width. */ + type = find_type_suffix (TYPE_poly, type_suffixes[type].element_bits); + + type_suffix_index wide_suffix + = find_type_suffix (TYPE_unsigned, + type_suffixes[type].element_bits * 2); + + /* Require the 'poly' type, require_matching_vector_type would try + and fail with the 'unsigned' one. */ + if (!r.require_vector_type (i, type_suffixes[type].vector_type)) + return error_mark_node; + + /* Check the inactive argument has the wide type. */ + if ((r.pred == PRED_m) + && (r.infer_vector_type (0) != wide_suffix)) + return r.report_no_such_form (type); + + return r.resolve_to (r.mode_suffix_id, type); + } +}; +SHAPE (binary_widen_poly) + /* _t vfoo[_n_t0](_t, const int) Check that 'imm' is in the [1..#bits] range. diff --git a/gcc/config/arm/arm-mve-builtins-shapes.h b/gcc/config/arm/arm-mve-builtins-shapes.h index a1842f5845cf..a93245321c96 100644 --- a/gcc/config/arm/arm-mve-builtins-shapes.h +++ b/gcc/config/arm/arm-mve-builtins-shapes.h @@ -35,13 +35,13 @@ namespace arm_mve { extern const function_shape *const binary; - extern const function_shape *const binary_lshift; - extern const function_shape *const binary_lshift_r; extern const function_shape *const binary_acc_int32; extern const function_shape *const binary_acc_int64; extern const function_shape *const binary_acca_int32; extern const function_shape *const binary_acca_int64; extern const function_shape *const binary_imm32; + extern const function_shape *const binary_lshift; + extern const function_shape *const binary_lshift_r; extern const function_shape *const binary_lshift_unsigned; extern const function_shape *const binary_maxamina; extern const function_shape *const binary_maxavminav; @@ -54,8 +54,10 @@ namespace arm_mve extern const function_shape *const binary_rshift; extern const function_shape *const binary_rshift_narrow; extern const function_shape *const binary_rshift_narrow_unsigned; + extern const function_shape *const binary_widen; extern const function_shape *const binary_widen_n; extern const function_shape *const binary_widen_opt_n; + extern const function_shape *const binary_widen_poly; extern const function_shape *const cmp; extern const function_shape *const create; extern const function_shape *const inherent; diff --git a/gcc/config/arm/arm-mve-builtins.cc b/gcc/config/arm/arm-mve-builtins.cc index 7eec9d2861c9..02dc8fa9b735 100644 --- a/gcc/config/arm/arm-mve-builtins.cc +++ b/gcc/config/arm/arm-mve-builtins.cc @@ -128,10 +128,11 @@ CONSTEXPR const type_suffix_info type_suffixes[NUM_TYPE_SUFFIXES + 1] = { TYPE_##CLASS == TYPE_signed || TYPE_##CLASS == TYPE_unsigned, \ TYPE_##CLASS == TYPE_unsigned, \ TYPE_##CLASS == TYPE_float, \ + TYPE_##CLASS == TYPE_poly, \ 0, \ MODE }, #include "arm-mve-builtins.def" - { "", NUM_VECTOR_TYPES, TYPE_bool, 0, 0, false, false, false, + { "", NUM_VECTOR_TYPES, TYPE_bool, 0, 0, false, false, false, false, 0, VOIDmode } }; @@ -177,6 +178,10 @@ CONSTEXPR const type_suffix_info type_suffixes[NUM_TYPE_SUFFIXES + 1] = { #define TYPES_all_signed(S, D) \ S (s8), S (s16), S (s32) +/* _p8 _p16. */ +#define TYPES_poly_8_16(S, D) \ + S (p8), S (p16) + /* _u8 _u16 _u32. */ #define TYPES_all_unsigned(S, D) \ S (u8), S (u16), S (u32) @@ -275,6 +280,7 @@ DEF_MVE_TYPES_ARRAY (integer_8); DEF_MVE_TYPES_ARRAY (integer_8_16); DEF_MVE_TYPES_ARRAY (integer_16_32); DEF_MVE_TYPES_ARRAY (integer_32); +DEF_MVE_TYPES_ARRAY (poly_8_16); DEF_MVE_TYPES_ARRAY (signed_16_32); DEF_MVE_TYPES_ARRAY (signed_32); DEF_MVE_TYPES_ARRAY (reinterpret_integer); diff --git a/gcc/config/arm/arm-mve-builtins.def b/gcc/config/arm/arm-mve-builtins.def index e3f378762104..e2cf1baf370d 100644 --- a/gcc/config/arm/arm-mve-builtins.def +++ b/gcc/config/arm/arm-mve-builtins.def @@ -63,6 +63,8 @@ DEF_MVE_TYPE_SUFFIX (u8, uint8x16_t, unsigned, 8, V16QImode) DEF_MVE_TYPE_SUFFIX (u16, uint16x8_t, unsigned, 16, V8HImode) DEF_MVE_TYPE_SUFFIX (u32, uint32x4_t, unsigned, 32, V4SImode) DEF_MVE_TYPE_SUFFIX (u64, uint64x2_t, unsigned, 64, V2DImode) +DEF_MVE_TYPE_SUFFIX (p8, uint8x16_t, poly, 8, V16QImode) +DEF_MVE_TYPE_SUFFIX (p16, uint16x8_t, poly, 16, V8HImode) #undef REQUIRES_FLOAT #define REQUIRES_FLOAT true diff --git a/gcc/config/arm/arm-mve-builtins.h b/gcc/config/arm/arm-mve-builtins.h index c9b51a0c77bc..37b8223dfb27 100644 --- a/gcc/config/arm/arm-mve-builtins.h +++ b/gcc/config/arm/arm-mve-builtins.h @@ -146,6 +146,7 @@ enum type_class_index TYPE_float, TYPE_signed, TYPE_unsigned, + TYPE_poly, NUM_TYPE_CLASSES }; @@ -221,7 +222,9 @@ struct type_suffix_info unsigned int unsigned_p : 1; /* True if the suffix is for a floating-point type. */ unsigned int float_p : 1; - unsigned int spare : 13; + /* True if the suffix is for a polynomial type. */ + unsigned int poly_p : 1; + unsigned int spare : 12; /* The associated vector or predicate mode. */ machine_mode vector_mode : 16; diff --git a/gcc/config/arm/arm-protos.h b/gcc/config/arm/arm-protos.h index 6186921011e5..77e76336e940 100644 --- a/gcc/config/arm/arm-protos.h +++ b/gcc/config/arm/arm-protos.h @@ -23,6 +23,7 @@ #define GCC_ARM_PROTOS_H #include "sbitmap.h" +#include "tree.h" /* For ERROR_MARK. */ rtl_opt_pass *make_pass_insert_bti (gcc::context *ctxt); @@ -83,7 +84,8 @@ extern int arm_split_constant (RTX_CODE, machine_mode, rtx, extern int legitimate_pic_operand_p (rtx); extern rtx legitimize_pic_address (rtx, machine_mode, rtx, rtx, bool); extern rtx legitimize_tls_address (rtx, rtx); -extern bool arm_legitimate_address_p (machine_mode, rtx, bool); +extern bool arm_legitimate_address_p (machine_mode, rtx, bool, + code_helper = ERROR_MARK); extern int arm_legitimate_address_outer_p (machine_mode, rtx, RTX_CODE, int); extern int thumb_legitimate_offset_p (machine_mode, HOST_WIDE_INT); extern int thumb1_legitimate_address_p (machine_mode, rtx, int); diff --git a/gcc/config/arm/arm.cc b/gcc/config/arm/arm.cc index 38f0839de1c7..6e933c801838 100644 --- a/gcc/config/arm/arm.cc +++ b/gcc/config/arm/arm.cc @@ -9171,7 +9171,7 @@ thumb_legitimate_offset_p (machine_mode mode, HOST_WIDE_INT val) } bool -arm_legitimate_address_p (machine_mode mode, rtx x, bool strict_p) +arm_legitimate_address_p (machine_mode mode, rtx x, bool strict_p, code_helper) { if (TARGET_ARM) return arm_legitimate_address_outer_p (mode, x, SET, strict_p); diff --git a/gcc/config/arm/arm_mve.h b/gcc/config/arm/arm_mve.h index 88b2e77ffd9e..b82d94e59bd6 100644 --- a/gcc/config/arm/arm_mve.h +++ b/gcc/config/arm/arm_mve.h @@ -43,19 +43,11 @@ #ifndef __ARM_MVE_PRESERVE_USER_NAMESPACE #define vst4q(__addr, __value) __arm_vst4q(__addr, __value) #define vornq(__a, __b) __arm_vornq(__a, __b) -#define vmulltq_int(__a, __b) __arm_vmulltq_int(__a, __b) -#define vmullbq_int(__a, __b) __arm_vmullbq_int(__a, __b) #define vbicq(__a, __b) __arm_vbicq(__a, __b) -#define vmulltq_poly(__a, __b) __arm_vmulltq_poly(__a, __b) -#define vmullbq_poly(__a, __b) __arm_vmullbq_poly(__a, __b) #define vbicq_m_n(__a, __imm, __p) __arm_vbicq_m_n(__a, __imm, __p) #define vshlcq(__a, __b, __imm) __arm_vshlcq(__a, __b, __imm) #define vbicq_m(__inactive, __a, __b, __p) __arm_vbicq_m(__inactive, __a, __b, __p) -#define vmullbq_int_m(__inactive, __a, __b, __p) __arm_vmullbq_int_m(__inactive, __a, __b, __p) -#define vmulltq_int_m(__inactive, __a, __b, __p) __arm_vmulltq_int_m(__inactive, __a, __b, __p) #define vornq_m(__inactive, __a, __b, __p) __arm_vornq_m(__inactive, __a, __b, __p) -#define vmullbq_poly_m(__inactive, __a, __b, __p) __arm_vmullbq_poly_m(__inactive, __a, __b, __p) -#define vmulltq_poly_m(__inactive, __a, __b, __p) __arm_vmulltq_poly_m(__inactive, __a, __b, __p) #define vstrbq_scatter_offset(__base, __offset, __value) __arm_vstrbq_scatter_offset(__base, __offset, __value) #define vstrbq(__addr, __value) __arm_vstrbq(__addr, __value) #define vstrwq_scatter_base(__addr, __offset, __value) __arm_vstrwq_scatter_base(__addr, __offset, __value) @@ -129,10 +121,6 @@ #define viwdupq_x_u8(__a, __b, __imm, __p) __arm_viwdupq_x_u8(__a, __b, __imm, __p) #define viwdupq_x_u16(__a, __b, __imm, __p) __arm_viwdupq_x_u16(__a, __b, __imm, __p) #define viwdupq_x_u32(__a, __b, __imm, __p) __arm_viwdupq_x_u32(__a, __b, __imm, __p) -#define vmullbq_poly_x(__a, __b, __p) __arm_vmullbq_poly_x(__a, __b, __p) -#define vmullbq_int_x(__a, __b, __p) __arm_vmullbq_int_x(__a, __b, __p) -#define vmulltq_poly_x(__a, __b, __p) __arm_vmulltq_poly_x(__a, __b, __p) -#define vmulltq_int_x(__a, __b, __p) __arm_vmulltq_int_x(__a, __b, __p) #define vbicq_x(__a, __b, __p) __arm_vbicq_x(__a, __b, __p) #define vornq_x(__a, __b, __p) __arm_vornq_x(__a, __b, __p) #define vadciq(__a, __b, __carry_out) __arm_vadciq(__a, __b, __carry_out) @@ -215,37 +203,21 @@ #define vcvtq_n_u16_f16(__a, __imm6) __arm_vcvtq_n_u16_f16(__a, __imm6) #define vcvtq_n_u32_f32(__a, __imm6) __arm_vcvtq_n_u32_f32(__a, __imm6) #define vornq_u8(__a, __b) __arm_vornq_u8(__a, __b) -#define vmulltq_int_u8(__a, __b) __arm_vmulltq_int_u8(__a, __b) -#define vmullbq_int_u8(__a, __b) __arm_vmullbq_int_u8(__a, __b) #define vbicq_u8(__a, __b) __arm_vbicq_u8(__a, __b) #define vornq_s8(__a, __b) __arm_vornq_s8(__a, __b) -#define vmulltq_int_s8(__a, __b) __arm_vmulltq_int_s8(__a, __b) -#define vmullbq_int_s8(__a, __b) __arm_vmullbq_int_s8(__a, __b) #define vbicq_s8(__a, __b) __arm_vbicq_s8(__a, __b) #define vornq_u16(__a, __b) __arm_vornq_u16(__a, __b) -#define vmulltq_int_u16(__a, __b) __arm_vmulltq_int_u16(__a, __b) -#define vmullbq_int_u16(__a, __b) __arm_vmullbq_int_u16(__a, __b) #define vbicq_u16(__a, __b) __arm_vbicq_u16(__a, __b) #define vornq_s16(__a, __b) __arm_vornq_s16(__a, __b) -#define vmulltq_int_s16(__a, __b) __arm_vmulltq_int_s16(__a, __b) -#define vmullbq_int_s16(__a, __b) __arm_vmullbq_int_s16(__a, __b) #define vbicq_s16(__a, __b) __arm_vbicq_s16(__a, __b) #define vornq_u32(__a, __b) __arm_vornq_u32(__a, __b) -#define vmulltq_int_u32(__a, __b) __arm_vmulltq_int_u32(__a, __b) -#define vmullbq_int_u32(__a, __b) __arm_vmullbq_int_u32(__a, __b) #define vbicq_u32(__a, __b) __arm_vbicq_u32(__a, __b) #define vornq_s32(__a, __b) __arm_vornq_s32(__a, __b) -#define vmulltq_int_s32(__a, __b) __arm_vmulltq_int_s32(__a, __b) -#define vmullbq_int_s32(__a, __b) __arm_vmullbq_int_s32(__a, __b) #define vbicq_s32(__a, __b) __arm_vbicq_s32(__a, __b) -#define vmulltq_poly_p8(__a, __b) __arm_vmulltq_poly_p8(__a, __b) -#define vmullbq_poly_p8(__a, __b) __arm_vmullbq_poly_p8(__a, __b) #define vbicq_n_u16(__a, __imm) __arm_vbicq_n_u16(__a, __imm) #define vornq_f16(__a, __b) __arm_vornq_f16(__a, __b) #define vbicq_f16(__a, __b) __arm_vbicq_f16(__a, __b) #define vbicq_n_s16(__a, __imm) __arm_vbicq_n_s16(__a, __imm) -#define vmulltq_poly_p16(__a, __b) __arm_vmulltq_poly_p16(__a, __b) -#define vmullbq_poly_p16(__a, __b) __arm_vmullbq_poly_p16(__a, __b) #define vbicq_n_u32(__a, __imm) __arm_vbicq_n_u32(__a, __imm) #define vornq_f32(__a, __b) __arm_vornq_f32(__a, __b) #define vbicq_f32(__a, __b) __arm_vbicq_f32(__a, __b) @@ -304,28 +276,12 @@ #define vbicq_m_u8(__inactive, __a, __b, __p) __arm_vbicq_m_u8(__inactive, __a, __b, __p) #define vbicq_m_u32(__inactive, __a, __b, __p) __arm_vbicq_m_u32(__inactive, __a, __b, __p) #define vbicq_m_u16(__inactive, __a, __b, __p) __arm_vbicq_m_u16(__inactive, __a, __b, __p) -#define vmullbq_int_m_s8(__inactive, __a, __b, __p) __arm_vmullbq_int_m_s8(__inactive, __a, __b, __p) -#define vmullbq_int_m_s32(__inactive, __a, __b, __p) __arm_vmullbq_int_m_s32(__inactive, __a, __b, __p) -#define vmullbq_int_m_s16(__inactive, __a, __b, __p) __arm_vmullbq_int_m_s16(__inactive, __a, __b, __p) -#define vmullbq_int_m_u8(__inactive, __a, __b, __p) __arm_vmullbq_int_m_u8(__inactive, __a, __b, __p) -#define vmullbq_int_m_u32(__inactive, __a, __b, __p) __arm_vmullbq_int_m_u32(__inactive, __a, __b, __p) -#define vmullbq_int_m_u16(__inactive, __a, __b, __p) __arm_vmullbq_int_m_u16(__inactive, __a, __b, __p) -#define vmulltq_int_m_s8(__inactive, __a, __b, __p) __arm_vmulltq_int_m_s8(__inactive, __a, __b, __p) -#define vmulltq_int_m_s32(__inactive, __a, __b, __p) __arm_vmulltq_int_m_s32(__inactive, __a, __b, __p) -#define vmulltq_int_m_s16(__inactive, __a, __b, __p) __arm_vmulltq_int_m_s16(__inactive, __a, __b, __p) -#define vmulltq_int_m_u8(__inactive, __a, __b, __p) __arm_vmulltq_int_m_u8(__inactive, __a, __b, __p) -#define vmulltq_int_m_u32(__inactive, __a, __b, __p) __arm_vmulltq_int_m_u32(__inactive, __a, __b, __p) -#define vmulltq_int_m_u16(__inactive, __a, __b, __p) __arm_vmulltq_int_m_u16(__inactive, __a, __b, __p) #define vornq_m_s8(__inactive, __a, __b, __p) __arm_vornq_m_s8(__inactive, __a, __b, __p) #define vornq_m_s32(__inactive, __a, __b, __p) __arm_vornq_m_s32(__inactive, __a, __b, __p) #define vornq_m_s16(__inactive, __a, __b, __p) __arm_vornq_m_s16(__inactive, __a, __b, __p) #define vornq_m_u8(__inactive, __a, __b, __p) __arm_vornq_m_u8(__inactive, __a, __b, __p) #define vornq_m_u32(__inactive, __a, __b, __p) __arm_vornq_m_u32(__inactive, __a, __b, __p) #define vornq_m_u16(__inactive, __a, __b, __p) __arm_vornq_m_u16(__inactive, __a, __b, __p) -#define vmullbq_poly_m_p8(__inactive, __a, __b, __p) __arm_vmullbq_poly_m_p8(__inactive, __a, __b, __p) -#define vmullbq_poly_m_p16(__inactive, __a, __b, __p) __arm_vmullbq_poly_m_p16(__inactive, __a, __b, __p) -#define vmulltq_poly_m_p8(__inactive, __a, __b, __p) __arm_vmulltq_poly_m_p8(__inactive, __a, __b, __p) -#define vmulltq_poly_m_p16(__inactive, __a, __b, __p) __arm_vmulltq_poly_m_p16(__inactive, __a, __b, __p) #define vbicq_m_f32(__inactive, __a, __b, __p) __arm_vbicq_m_f32(__inactive, __a, __b, __p) #define vbicq_m_f16(__inactive, __a, __b, __p) __arm_vbicq_m_f16(__inactive, __a, __b, __p) #define vcvtq_m_n_s32_f32(__inactive, __a, __imm6, __p) __arm_vcvtq_m_n_s32_f32(__inactive, __a, __imm6, __p) @@ -632,22 +588,6 @@ #define viwdupq_x_wb_u8(__a, __b, __imm, __p) __arm_viwdupq_x_wb_u8(__a, __b, __imm, __p) #define viwdupq_x_wb_u16(__a, __b, __imm, __p) __arm_viwdupq_x_wb_u16(__a, __b, __imm, __p) #define viwdupq_x_wb_u32(__a, __b, __imm, __p) __arm_viwdupq_x_wb_u32(__a, __b, __imm, __p) -#define vmullbq_poly_x_p8(__a, __b, __p) __arm_vmullbq_poly_x_p8(__a, __b, __p) -#define vmullbq_poly_x_p16(__a, __b, __p) __arm_vmullbq_poly_x_p16(__a, __b, __p) -#define vmullbq_int_x_s8(__a, __b, __p) __arm_vmullbq_int_x_s8(__a, __b, __p) -#define vmullbq_int_x_s16(__a, __b, __p) __arm_vmullbq_int_x_s16(__a, __b, __p) -#define vmullbq_int_x_s32(__a, __b, __p) __arm_vmullbq_int_x_s32(__a, __b, __p) -#define vmullbq_int_x_u8(__a, __b, __p) __arm_vmullbq_int_x_u8(__a, __b, __p) -#define vmullbq_int_x_u16(__a, __b, __p) __arm_vmullbq_int_x_u16(__a, __b, __p) -#define vmullbq_int_x_u32(__a, __b, __p) __arm_vmullbq_int_x_u32(__a, __b, __p) -#define vmulltq_poly_x_p8(__a, __b, __p) __arm_vmulltq_poly_x_p8(__a, __b, __p) -#define vmulltq_poly_x_p16(__a, __b, __p) __arm_vmulltq_poly_x_p16(__a, __b, __p) -#define vmulltq_int_x_s8(__a, __b, __p) __arm_vmulltq_int_x_s8(__a, __b, __p) -#define vmulltq_int_x_s16(__a, __b, __p) __arm_vmulltq_int_x_s16(__a, __b, __p) -#define vmulltq_int_x_s32(__a, __b, __p) __arm_vmulltq_int_x_s32(__a, __b, __p) -#define vmulltq_int_x_u8(__a, __b, __p) __arm_vmulltq_int_x_u8(__a, __b, __p) -#define vmulltq_int_x_u16(__a, __b, __p) __arm_vmulltq_int_x_u16(__a, __b, __p) -#define vmulltq_int_x_u32(__a, __b, __p) __arm_vmulltq_int_x_u32(__a, __b, __p) #define vbicq_x_s8(__a, __b, __p) __arm_vbicq_x_s8(__a, __b, __p) #define vbicq_x_s16(__a, __b, __p) __arm_vbicq_x_s16(__a, __b, __p) #define vbicq_x_s32(__a, __b, __p) __arm_vbicq_x_s32(__a, __b, __p) @@ -906,20 +846,6 @@ __arm_vornq_u8 (uint8x16_t __a, uint8x16_t __b) return __builtin_mve_vornq_uv16qi (__a, __b); } -__extension__ extern __inline uint16x8_t -__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -__arm_vmulltq_int_u8 (uint8x16_t __a, uint8x16_t __b) -{ - return __builtin_mve_vmulltq_int_uv16qi (__a, __b); -} - -__extension__ extern __inline uint16x8_t -__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -__arm_vmullbq_int_u8 (uint8x16_t __a, uint8x16_t __b) -{ - return __builtin_mve_vmullbq_int_uv16qi (__a, __b); -} - __extension__ extern __inline uint8x16_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) __arm_vbicq_u8 (uint8x16_t __a, uint8x16_t __b) @@ -934,20 +860,6 @@ __arm_vornq_s8 (int8x16_t __a, int8x16_t __b) return __builtin_mve_vornq_sv16qi (__a, __b); } -__extension__ extern __inline int16x8_t -__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -__arm_vmulltq_int_s8 (int8x16_t __a, int8x16_t __b) -{ - return __builtin_mve_vmulltq_int_sv16qi (__a, __b); -} - -__extension__ extern __inline int16x8_t -__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -__arm_vmullbq_int_s8 (int8x16_t __a, int8x16_t __b) -{ - return __builtin_mve_vmullbq_int_sv16qi (__a, __b); -} - __extension__ extern __inline int8x16_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) __arm_vbicq_s8 (int8x16_t __a, int8x16_t __b) @@ -962,20 +874,6 @@ __arm_vornq_u16 (uint16x8_t __a, uint16x8_t __b) return __builtin_mve_vornq_uv8hi (__a, __b); } -__extension__ extern __inline uint32x4_t -__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -__arm_vmulltq_int_u16 (uint16x8_t __a, uint16x8_t __b) -{ - return __builtin_mve_vmulltq_int_uv8hi (__a, __b); -} - -__extension__ extern __inline uint32x4_t -__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -__arm_vmullbq_int_u16 (uint16x8_t __a, uint16x8_t __b) -{ - return __builtin_mve_vmullbq_int_uv8hi (__a, __b); -} - __extension__ extern __inline uint16x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) __arm_vbicq_u16 (uint16x8_t __a, uint16x8_t __b) @@ -990,20 +888,6 @@ __arm_vornq_s16 (int16x8_t __a, int16x8_t __b) return __builtin_mve_vornq_sv8hi (__a, __b); } -__extension__ extern __inline int32x4_t -__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -__arm_vmulltq_int_s16 (int16x8_t __a, int16x8_t __b) -{ - return __builtin_mve_vmulltq_int_sv8hi (__a, __b); -} - -__extension__ extern __inline int32x4_t -__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -__arm_vmullbq_int_s16 (int16x8_t __a, int16x8_t __b) -{ - return __builtin_mve_vmullbq_int_sv8hi (__a, __b); -} - __extension__ extern __inline int16x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) __arm_vbicq_s16 (int16x8_t __a, int16x8_t __b) @@ -1018,20 +902,6 @@ __arm_vornq_u32 (uint32x4_t __a, uint32x4_t __b) return __builtin_mve_vornq_uv4si (__a, __b); } -__extension__ extern __inline uint64x2_t -__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -__arm_vmulltq_int_u32 (uint32x4_t __a, uint32x4_t __b) -{ - return __builtin_mve_vmulltq_int_uv4si (__a, __b); -} - -__extension__ extern __inline uint64x2_t -__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -__arm_vmullbq_int_u32 (uint32x4_t __a, uint32x4_t __b) -{ - return __builtin_mve_vmullbq_int_uv4si (__a, __b); -} - __extension__ extern __inline uint32x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) __arm_vbicq_u32 (uint32x4_t __a, uint32x4_t __b) @@ -1046,20 +916,6 @@ __arm_vornq_s32 (int32x4_t __a, int32x4_t __b) return __builtin_mve_vornq_sv4si (__a, __b); } -__extension__ extern __inline int64x2_t -__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -__arm_vmulltq_int_s32 (int32x4_t __a, int32x4_t __b) -{ - return __builtin_mve_vmulltq_int_sv4si (__a, __b); -} - -__extension__ extern __inline int64x2_t -__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -__arm_vmullbq_int_s32 (int32x4_t __a, int32x4_t __b) -{ - return __builtin_mve_vmullbq_int_sv4si (__a, __b); -} - __extension__ extern __inline int32x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) __arm_vbicq_s32 (int32x4_t __a, int32x4_t __b) @@ -1067,20 +923,6 @@ __arm_vbicq_s32 (int32x4_t __a, int32x4_t __b) return __builtin_mve_vbicq_sv4si (__a, __b); } -__extension__ extern __inline uint16x8_t -__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -__arm_vmulltq_poly_p8 (uint8x16_t __a, uint8x16_t __b) -{ - return __builtin_mve_vmulltq_poly_pv16qi (__a, __b); -} - -__extension__ extern __inline uint16x8_t -__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -__arm_vmullbq_poly_p8 (uint8x16_t __a, uint8x16_t __b) -{ - return __builtin_mve_vmullbq_poly_pv16qi (__a, __b); -} - __extension__ extern __inline uint16x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) __arm_vbicq_n_u16 (uint16x8_t __a, const int __imm) @@ -1095,20 +937,6 @@ __arm_vbicq_n_s16 (int16x8_t __a, const int __imm) return __builtin_mve_vbicq_n_sv8hi (__a, __imm); } -__extension__ extern __inline uint32x4_t -__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -__arm_vmulltq_poly_p16 (uint16x8_t __a, uint16x8_t __b) -{ - return __builtin_mve_vmulltq_poly_pv8hi (__a, __b); -} - -__extension__ extern __inline uint32x4_t -__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -__arm_vmullbq_poly_p16 (uint16x8_t __a, uint16x8_t __b) -{ - return __builtin_mve_vmullbq_poly_pv8hi (__a, __b); -} - __extension__ extern __inline uint32x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) __arm_vbicq_n_u32 (uint32x4_t __a, const int __imm) @@ -1275,90 +1103,6 @@ __arm_vbicq_m_u16 (uint16x8_t __inactive, uint16x8_t __a, uint16x8_t __b, mve_pr return __builtin_mve_vbicq_m_uv8hi (__inactive, __a, __b, __p); } -__extension__ extern __inline int16x8_t -__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -__arm_vmullbq_int_m_s8 (int16x8_t __inactive, int8x16_t __a, int8x16_t __b, mve_pred16_t __p) -{ - return __builtin_mve_vmullbq_int_m_sv16qi (__inactive, __a, __b, __p); -} - -__extension__ extern __inline int64x2_t -__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -__arm_vmullbq_int_m_s32 (int64x2_t __inactive, int32x4_t __a, int32x4_t __b, mve_pred16_t __p) -{ - return __builtin_mve_vmullbq_int_m_sv4si (__inactive, __a, __b, __p); -} - -__extension__ extern __inline int32x4_t -__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -__arm_vmullbq_int_m_s16 (int32x4_t __inactive, int16x8_t __a, int16x8_t __b, mve_pred16_t __p) -{ - return __builtin_mve_vmullbq_int_m_sv8hi (__inactive, __a, __b, __p); -} - -__extension__ extern __inline uint16x8_t -__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -__arm_vmullbq_int_m_u8 (uint16x8_t __inactive, uint8x16_t __a, uint8x16_t __b, mve_pred16_t __p) -{ - return __builtin_mve_vmullbq_int_m_uv16qi (__inactive, __a, __b, __p); -} - -__extension__ extern __inline uint64x2_t -__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -__arm_vmullbq_int_m_u32 (uint64x2_t __inactive, uint32x4_t __a, uint32x4_t __b, mve_pred16_t __p) -{ - return __builtin_mve_vmullbq_int_m_uv4si (__inactive, __a, __b, __p); -} - -__extension__ extern __inline uint32x4_t -__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -__arm_vmullbq_int_m_u16 (uint32x4_t __inactive, uint16x8_t __a, uint16x8_t __b, mve_pred16_t __p) -{ - return __builtin_mve_vmullbq_int_m_uv8hi (__inactive, __a, __b, __p); -} - -__extension__ extern __inline int16x8_t -__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -__arm_vmulltq_int_m_s8 (int16x8_t __inactive, int8x16_t __a, int8x16_t __b, mve_pred16_t __p) -{ - return __builtin_mve_vmulltq_int_m_sv16qi (__inactive, __a, __b, __p); -} - -__extension__ extern __inline int64x2_t -__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -__arm_vmulltq_int_m_s32 (int64x2_t __inactive, int32x4_t __a, int32x4_t __b, mve_pred16_t __p) -{ - return __builtin_mve_vmulltq_int_m_sv4si (__inactive, __a, __b, __p); -} - -__extension__ extern __inline int32x4_t -__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -__arm_vmulltq_int_m_s16 (int32x4_t __inactive, int16x8_t __a, int16x8_t __b, mve_pred16_t __p) -{ - return __builtin_mve_vmulltq_int_m_sv8hi (__inactive, __a, __b, __p); -} - -__extension__ extern __inline uint16x8_t -__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -__arm_vmulltq_int_m_u8 (uint16x8_t __inactive, uint8x16_t __a, uint8x16_t __b, mve_pred16_t __p) -{ - return __builtin_mve_vmulltq_int_m_uv16qi (__inactive, __a, __b, __p); -} - -__extension__ extern __inline uint64x2_t -__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -__arm_vmulltq_int_m_u32 (uint64x2_t __inactive, uint32x4_t __a, uint32x4_t __b, mve_pred16_t __p) -{ - return __builtin_mve_vmulltq_int_m_uv4si (__inactive, __a, __b, __p); -} - -__extension__ extern __inline uint32x4_t -__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -__arm_vmulltq_int_m_u16 (uint32x4_t __inactive, uint16x8_t __a, uint16x8_t __b, mve_pred16_t __p) -{ - return __builtin_mve_vmulltq_int_m_uv8hi (__inactive, __a, __b, __p); -} - __extension__ extern __inline int8x16_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) __arm_vornq_m_s8 (int8x16_t __inactive, int8x16_t __a, int8x16_t __b, mve_pred16_t __p) @@ -1401,34 +1145,6 @@ __arm_vornq_m_u16 (uint16x8_t __inactive, uint16x8_t __a, uint16x8_t __b, mve_pr return __builtin_mve_vornq_m_uv8hi (__inactive, __a, __b, __p); } -__extension__ extern __inline uint16x8_t -__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -__arm_vmullbq_poly_m_p8 (uint16x8_t __inactive, uint8x16_t __a, uint8x16_t __b, mve_pred16_t __p) -{ - return __builtin_mve_vmullbq_poly_m_pv16qi (__inactive, __a, __b, __p); -} - -__extension__ extern __inline uint32x4_t -__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -__arm_vmullbq_poly_m_p16 (uint32x4_t __inactive, uint16x8_t __a, uint16x8_t __b, mve_pred16_t __p) -{ - return __builtin_mve_vmullbq_poly_m_pv8hi (__inactive, __a, __b, __p); -} - -__extension__ extern __inline uint16x8_t -__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -__arm_vmulltq_poly_m_p8 (uint16x8_t __inactive, uint8x16_t __a, uint8x16_t __b, mve_pred16_t __p) -{ - return __builtin_mve_vmulltq_poly_m_pv16qi (__inactive, __a, __b, __p); -} - -__extension__ extern __inline uint32x4_t -__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -__arm_vmulltq_poly_m_p16 (uint32x4_t __inactive, uint16x8_t __a, uint16x8_t __b, mve_pred16_t __p) -{ - return __builtin_mve_vmulltq_poly_m_pv8hi (__inactive, __a, __b, __p); -} - __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) __arm_vstrbq_scatter_offset_s8 (int8_t * __base, uint8x16_t __offset, int8x16_t __value) @@ -3340,118 +3056,6 @@ __arm_viwdupq_x_wb_u32 (uint32_t *__a, uint32_t __b, const int __imm, mve_pred16 return __res; } -__extension__ extern __inline uint16x8_t -__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -__arm_vmullbq_poly_x_p8 (uint8x16_t __a, uint8x16_t __b, mve_pred16_t __p) -{ - return __builtin_mve_vmullbq_poly_m_pv16qi (__arm_vuninitializedq_u16 (), __a, __b, __p); -} - -__extension__ extern __inline uint32x4_t -__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -__arm_vmullbq_poly_x_p16 (uint16x8_t __a, uint16x8_t __b, mve_pred16_t __p) -{ - return __builtin_mve_vmullbq_poly_m_pv8hi (__arm_vuninitializedq_u32 (), __a, __b, __p); -} - -__extension__ extern __inline int16x8_t -__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -__arm_vmullbq_int_x_s8 (int8x16_t __a, int8x16_t __b, mve_pred16_t __p) -{ - return __builtin_mve_vmullbq_int_m_sv16qi (__arm_vuninitializedq_s16 (), __a, __b, __p); -} - -__extension__ extern __inline int32x4_t -__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -__arm_vmullbq_int_x_s16 (int16x8_t __a, int16x8_t __b, mve_pred16_t __p) -{ - return __builtin_mve_vmullbq_int_m_sv8hi (__arm_vuninitializedq_s32 (), __a, __b, __p); -} - -__extension__ extern __inline int64x2_t -__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -__arm_vmullbq_int_x_s32 (int32x4_t __a, int32x4_t __b, mve_pred16_t __p) -{ - return __builtin_mve_vmullbq_int_m_sv4si (__arm_vuninitializedq_s64 (), __a, __b, __p); -} - -__extension__ extern __inline uint16x8_t -__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -__arm_vmullbq_int_x_u8 (uint8x16_t __a, uint8x16_t __b, mve_pred16_t __p) -{ - return __builtin_mve_vmullbq_int_m_uv16qi (__arm_vuninitializedq_u16 (), __a, __b, __p); -} - -__extension__ extern __inline uint32x4_t -__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -__arm_vmullbq_int_x_u16 (uint16x8_t __a, uint16x8_t __b, mve_pred16_t __p) -{ - return __builtin_mve_vmullbq_int_m_uv8hi (__arm_vuninitializedq_u32 (), __a, __b, __p); -} - -__extension__ extern __inline uint64x2_t -__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -__arm_vmullbq_int_x_u32 (uint32x4_t __a, uint32x4_t __b, mve_pred16_t __p) -{ - return __builtin_mve_vmullbq_int_m_uv4si (__arm_vuninitializedq_u64 (), __a, __b, __p); -} - -__extension__ extern __inline uint16x8_t -__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -__arm_vmulltq_poly_x_p8 (uint8x16_t __a, uint8x16_t __b, mve_pred16_t __p) -{ - return __builtin_mve_vmulltq_poly_m_pv16qi (__arm_vuninitializedq_u16 (), __a, __b, __p); -} - -__extension__ extern __inline uint32x4_t -__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -__arm_vmulltq_poly_x_p16 (uint16x8_t __a, uint16x8_t __b, mve_pred16_t __p) -{ - return __builtin_mve_vmulltq_poly_m_pv8hi (__arm_vuninitializedq_u32 (), __a, __b, __p); -} - -__extension__ extern __inline int16x8_t -__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -__arm_vmulltq_int_x_s8 (int8x16_t __a, int8x16_t __b, mve_pred16_t __p) -{ - return __builtin_mve_vmulltq_int_m_sv16qi (__arm_vuninitializedq_s16 (), __a, __b, __p); -} - -__extension__ extern __inline int32x4_t -__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -__arm_vmulltq_int_x_s16 (int16x8_t __a, int16x8_t __b, mve_pred16_t __p) -{ - return __builtin_mve_vmulltq_int_m_sv8hi (__arm_vuninitializedq_s32 (), __a, __b, __p); -} - -__extension__ extern __inline int64x2_t -__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -__arm_vmulltq_int_x_s32 (int32x4_t __a, int32x4_t __b, mve_pred16_t __p) -{ - return __builtin_mve_vmulltq_int_m_sv4si (__arm_vuninitializedq_s64 (), __a, __b, __p); -} - -__extension__ extern __inline uint16x8_t -__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -__arm_vmulltq_int_x_u8 (uint8x16_t __a, uint8x16_t __b, mve_pred16_t __p) -{ - return __builtin_mve_vmulltq_int_m_uv16qi (__arm_vuninitializedq_u16 (), __a, __b, __p); -} - -__extension__ extern __inline uint32x4_t -__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -__arm_vmulltq_int_x_u16 (uint16x8_t __a, uint16x8_t __b, mve_pred16_t __p) -{ - return __builtin_mve_vmulltq_int_m_uv8hi (__arm_vuninitializedq_u32 (), __a, __b, __p); -} - -__extension__ extern __inline uint64x2_t -__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -__arm_vmulltq_int_x_u32 (uint32x4_t __a, uint32x4_t __b, mve_pred16_t __p) -{ - return __builtin_mve_vmulltq_int_m_uv4si (__arm_vuninitializedq_u64 (), __a, __b, __p); -} - __extension__ extern __inline int8x16_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) __arm_vbicq_x_s8 (int8x16_t __a, int8x16_t __b, mve_pred16_t __p) @@ -5508,20 +5112,6 @@ __arm_vornq (uint8x16_t __a, uint8x16_t __b) return __arm_vornq_u8 (__a, __b); } -__extension__ extern __inline uint16x8_t -__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -__arm_vmulltq_int (uint8x16_t __a, uint8x16_t __b) -{ - return __arm_vmulltq_int_u8 (__a, __b); -} - -__extension__ extern __inline uint16x8_t -__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -__arm_vmullbq_int (uint8x16_t __a, uint8x16_t __b) -{ - return __arm_vmullbq_int_u8 (__a, __b); -} - __extension__ extern __inline uint8x16_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) __arm_vbicq (uint8x16_t __a, uint8x16_t __b) @@ -5536,20 +5126,6 @@ __arm_vornq (int8x16_t __a, int8x16_t __b) return __arm_vornq_s8 (__a, __b); } -__extension__ extern __inline int16x8_t -__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -__arm_vmulltq_int (int8x16_t __a, int8x16_t __b) -{ - return __arm_vmulltq_int_s8 (__a, __b); -} - -__extension__ extern __inline int16x8_t -__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -__arm_vmullbq_int (int8x16_t __a, int8x16_t __b) -{ - return __arm_vmullbq_int_s8 (__a, __b); -} - __extension__ extern __inline int8x16_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) __arm_vbicq (int8x16_t __a, int8x16_t __b) @@ -5564,20 +5140,6 @@ __arm_vornq (uint16x8_t __a, uint16x8_t __b) return __arm_vornq_u16 (__a, __b); } -__extension__ extern __inline uint32x4_t -__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -__arm_vmulltq_int (uint16x8_t __a, uint16x8_t __b) -{ - return __arm_vmulltq_int_u16 (__a, __b); -} - -__extension__ extern __inline uint32x4_t -__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -__arm_vmullbq_int (uint16x8_t __a, uint16x8_t __b) -{ - return __arm_vmullbq_int_u16 (__a, __b); -} - __extension__ extern __inline uint16x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) __arm_vbicq (uint16x8_t __a, uint16x8_t __b) @@ -5592,20 +5154,6 @@ __arm_vornq (int16x8_t __a, int16x8_t __b) return __arm_vornq_s16 (__a, __b); } -__extension__ extern __inline int32x4_t -__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -__arm_vmulltq_int (int16x8_t __a, int16x8_t __b) -{ - return __arm_vmulltq_int_s16 (__a, __b); -} - -__extension__ extern __inline int32x4_t -__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -__arm_vmullbq_int (int16x8_t __a, int16x8_t __b) -{ - return __arm_vmullbq_int_s16 (__a, __b); -} - __extension__ extern __inline int16x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) __arm_vbicq (int16x8_t __a, int16x8_t __b) @@ -5620,20 +5168,6 @@ __arm_vornq (uint32x4_t __a, uint32x4_t __b) return __arm_vornq_u32 (__a, __b); } -__extension__ extern __inline uint64x2_t -__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -__arm_vmulltq_int (uint32x4_t __a, uint32x4_t __b) -{ - return __arm_vmulltq_int_u32 (__a, __b); -} - -__extension__ extern __inline uint64x2_t -__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -__arm_vmullbq_int (uint32x4_t __a, uint32x4_t __b) -{ - return __arm_vmullbq_int_u32 (__a, __b); -} - __extension__ extern __inline uint32x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) __arm_vbicq (uint32x4_t __a, uint32x4_t __b) @@ -5648,20 +5182,6 @@ __arm_vornq (int32x4_t __a, int32x4_t __b) return __arm_vornq_s32 (__a, __b); } -__extension__ extern __inline int64x2_t -__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -__arm_vmulltq_int (int32x4_t __a, int32x4_t __b) -{ - return __arm_vmulltq_int_s32 (__a, __b); -} - -__extension__ extern __inline int64x2_t -__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -__arm_vmullbq_int (int32x4_t __a, int32x4_t __b) -{ - return __arm_vmullbq_int_s32 (__a, __b); -} - __extension__ extern __inline int32x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) __arm_vbicq (int32x4_t __a, int32x4_t __b) @@ -5669,20 +5189,6 @@ __arm_vbicq (int32x4_t __a, int32x4_t __b) return __arm_vbicq_s32 (__a, __b); } -__extension__ extern __inline uint16x8_t -__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -__arm_vmulltq_poly (uint8x16_t __a, uint8x16_t __b) -{ - return __arm_vmulltq_poly_p8 (__a, __b); -} - -__extension__ extern __inline uint16x8_t -__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -__arm_vmullbq_poly (uint8x16_t __a, uint8x16_t __b) -{ - return __arm_vmullbq_poly_p8 (__a, __b); -} - __extension__ extern __inline uint16x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) __arm_vbicq (uint16x8_t __a, const int __imm) @@ -5697,20 +5203,6 @@ __arm_vbicq (int16x8_t __a, const int __imm) return __arm_vbicq_n_s16 (__a, __imm); } -__extension__ extern __inline uint32x4_t -__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -__arm_vmulltq_poly (uint16x8_t __a, uint16x8_t __b) -{ - return __arm_vmulltq_poly_p16 (__a, __b); -} - -__extension__ extern __inline uint32x4_t -__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -__arm_vmullbq_poly (uint16x8_t __a, uint16x8_t __b) -{ - return __arm_vmullbq_poly_p16 (__a, __b); -} - __extension__ extern __inline uint32x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) __arm_vbicq (uint32x4_t __a, const int __imm) @@ -5837,90 +5329,6 @@ __arm_vbicq_m (uint16x8_t __inactive, uint16x8_t __a, uint16x8_t __b, mve_pred16 return __arm_vbicq_m_u16 (__inactive, __a, __b, __p); } -__extension__ extern __inline int16x8_t -__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -__arm_vmullbq_int_m (int16x8_t __inactive, int8x16_t __a, int8x16_t __b, mve_pred16_t __p) -{ - return __arm_vmullbq_int_m_s8 (__inactive, __a, __b, __p); -} - -__extension__ extern __inline int64x2_t -__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -__arm_vmullbq_int_m (int64x2_t __inactive, int32x4_t __a, int32x4_t __b, mve_pred16_t __p) -{ - return __arm_vmullbq_int_m_s32 (__inactive, __a, __b, __p); -} - -__extension__ extern __inline int32x4_t -__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -__arm_vmullbq_int_m (int32x4_t __inactive, int16x8_t __a, int16x8_t __b, mve_pred16_t __p) -{ - return __arm_vmullbq_int_m_s16 (__inactive, __a, __b, __p); -} - -__extension__ extern __inline uint16x8_t -__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -__arm_vmullbq_int_m (uint16x8_t __inactive, uint8x16_t __a, uint8x16_t __b, mve_pred16_t __p) -{ - return __arm_vmullbq_int_m_u8 (__inactive, __a, __b, __p); -} - -__extension__ extern __inline uint64x2_t -__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -__arm_vmullbq_int_m (uint64x2_t __inactive, uint32x4_t __a, uint32x4_t __b, mve_pred16_t __p) -{ - return __arm_vmullbq_int_m_u32 (__inactive, __a, __b, __p); -} - -__extension__ extern __inline uint32x4_t -__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -__arm_vmullbq_int_m (uint32x4_t __inactive, uint16x8_t __a, uint16x8_t __b, mve_pred16_t __p) -{ - return __arm_vmullbq_int_m_u16 (__inactive, __a, __b, __p); -} - -__extension__ extern __inline int16x8_t -__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -__arm_vmulltq_int_m (int16x8_t __inactive, int8x16_t __a, int8x16_t __b, mve_pred16_t __p) -{ - return __arm_vmulltq_int_m_s8 (__inactive, __a, __b, __p); -} - -__extension__ extern __inline int64x2_t -__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -__arm_vmulltq_int_m (int64x2_t __inactive, int32x4_t __a, int32x4_t __b, mve_pred16_t __p) -{ - return __arm_vmulltq_int_m_s32 (__inactive, __a, __b, __p); -} - -__extension__ extern __inline int32x4_t -__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -__arm_vmulltq_int_m (int32x4_t __inactive, int16x8_t __a, int16x8_t __b, mve_pred16_t __p) -{ - return __arm_vmulltq_int_m_s16 (__inactive, __a, __b, __p); -} - -__extension__ extern __inline uint16x8_t -__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -__arm_vmulltq_int_m (uint16x8_t __inactive, uint8x16_t __a, uint8x16_t __b, mve_pred16_t __p) -{ - return __arm_vmulltq_int_m_u8 (__inactive, __a, __b, __p); -} - -__extension__ extern __inline uint64x2_t -__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -__arm_vmulltq_int_m (uint64x2_t __inactive, uint32x4_t __a, uint32x4_t __b, mve_pred16_t __p) -{ - return __arm_vmulltq_int_m_u32 (__inactive, __a, __b, __p); -} - -__extension__ extern __inline uint32x4_t -__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -__arm_vmulltq_int_m (uint32x4_t __inactive, uint16x8_t __a, uint16x8_t __b, mve_pred16_t __p) -{ - return __arm_vmulltq_int_m_u16 (__inactive, __a, __b, __p); -} - __extension__ extern __inline int8x16_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) __arm_vornq_m (int8x16_t __inactive, int8x16_t __a, int8x16_t __b, mve_pred16_t __p) @@ -5963,34 +5371,6 @@ __arm_vornq_m (uint16x8_t __inactive, uint16x8_t __a, uint16x8_t __b, mve_pred16 return __arm_vornq_m_u16 (__inactive, __a, __b, __p); } -__extension__ extern __inline uint16x8_t -__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -__arm_vmullbq_poly_m (uint16x8_t __inactive, uint8x16_t __a, uint8x16_t __b, mve_pred16_t __p) -{ - return __arm_vmullbq_poly_m_p8 (__inactive, __a, __b, __p); -} - -__extension__ extern __inline uint32x4_t -__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -__arm_vmullbq_poly_m (uint32x4_t __inactive, uint16x8_t __a, uint16x8_t __b, mve_pred16_t __p) -{ - return __arm_vmullbq_poly_m_p16 (__inactive, __a, __b, __p); -} - -__extension__ extern __inline uint16x8_t -__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -__arm_vmulltq_poly_m (uint16x8_t __inactive, uint8x16_t __a, uint8x16_t __b, mve_pred16_t __p) -{ - return __arm_vmulltq_poly_m_p8 (__inactive, __a, __b, __p); -} - -__extension__ extern __inline uint32x4_t -__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -__arm_vmulltq_poly_m (uint32x4_t __inactive, uint16x8_t __a, uint16x8_t __b, mve_pred16_t __p) -{ - return __arm_vmulltq_poly_m_p16 (__inactive, __a, __b, __p); -} - __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) __arm_vstrbq_scatter_offset (int8_t * __base, uint8x16_t __offset, int8x16_t __value) @@ -7475,118 +6855,6 @@ __arm_viwdupq_x_u32 (uint32_t *__a, uint32_t __b, const int __imm, mve_pred16_t return __arm_viwdupq_x_wb_u32 (__a, __b, __imm, __p); } -__extension__ extern __inline uint16x8_t -__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -__arm_vmullbq_poly_x (uint8x16_t __a, uint8x16_t __b, mve_pred16_t __p) -{ - return __arm_vmullbq_poly_x_p8 (__a, __b, __p); -} - -__extension__ extern __inline uint32x4_t -__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -__arm_vmullbq_poly_x (uint16x8_t __a, uint16x8_t __b, mve_pred16_t __p) -{ - return __arm_vmullbq_poly_x_p16 (__a, __b, __p); -} - -__extension__ extern __inline int16x8_t -__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -__arm_vmullbq_int_x (int8x16_t __a, int8x16_t __b, mve_pred16_t __p) -{ - return __arm_vmullbq_int_x_s8 (__a, __b, __p); -} - -__extension__ extern __inline int32x4_t -__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -__arm_vmullbq_int_x (int16x8_t __a, int16x8_t __b, mve_pred16_t __p) -{ - return __arm_vmullbq_int_x_s16 (__a, __b, __p); -} - -__extension__ extern __inline int64x2_t -__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -__arm_vmullbq_int_x (int32x4_t __a, int32x4_t __b, mve_pred16_t __p) -{ - return __arm_vmullbq_int_x_s32 (__a, __b, __p); -} - -__extension__ extern __inline uint16x8_t -__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -__arm_vmullbq_int_x (uint8x16_t __a, uint8x16_t __b, mve_pred16_t __p) -{ - return __arm_vmullbq_int_x_u8 (__a, __b, __p); -} - -__extension__ extern __inline uint32x4_t -__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -__arm_vmullbq_int_x (uint16x8_t __a, uint16x8_t __b, mve_pred16_t __p) -{ - return __arm_vmullbq_int_x_u16 (__a, __b, __p); -} - -__extension__ extern __inline uint64x2_t -__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -__arm_vmullbq_int_x (uint32x4_t __a, uint32x4_t __b, mve_pred16_t __p) -{ - return __arm_vmullbq_int_x_u32 (__a, __b, __p); -} - -__extension__ extern __inline uint16x8_t -__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -__arm_vmulltq_poly_x (uint8x16_t __a, uint8x16_t __b, mve_pred16_t __p) -{ - return __arm_vmulltq_poly_x_p8 (__a, __b, __p); -} - -__extension__ extern __inline uint32x4_t -__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -__arm_vmulltq_poly_x (uint16x8_t __a, uint16x8_t __b, mve_pred16_t __p) -{ - return __arm_vmulltq_poly_x_p16 (__a, __b, __p); -} - -__extension__ extern __inline int16x8_t -__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -__arm_vmulltq_int_x (int8x16_t __a, int8x16_t __b, mve_pred16_t __p) -{ - return __arm_vmulltq_int_x_s8 (__a, __b, __p); -} - -__extension__ extern __inline int32x4_t -__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -__arm_vmulltq_int_x (int16x8_t __a, int16x8_t __b, mve_pred16_t __p) -{ - return __arm_vmulltq_int_x_s16 (__a, __b, __p); -} - -__extension__ extern __inline int64x2_t -__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -__arm_vmulltq_int_x (int32x4_t __a, int32x4_t __b, mve_pred16_t __p) -{ - return __arm_vmulltq_int_x_s32 (__a, __b, __p); -} - -__extension__ extern __inline uint16x8_t -__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -__arm_vmulltq_int_x (uint8x16_t __a, uint8x16_t __b, mve_pred16_t __p) -{ - return __arm_vmulltq_int_x_u8 (__a, __b, __p); -} - -__extension__ extern __inline uint32x4_t -__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -__arm_vmulltq_int_x (uint16x8_t __a, uint16x8_t __b, mve_pred16_t __p) -{ - return __arm_vmulltq_int_x_u16 (__a, __b, __p); -} - -__extension__ extern __inline uint64x2_t -__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) -__arm_vmulltq_int_x (uint32x4_t __a, uint32x4_t __b, mve_pred16_t __p) -{ - return __arm_vmulltq_int_x_u32 (__a, __b, __p); -} - __extension__ extern __inline int8x16_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) __arm_vbicq_x (int8x16_t __a, int8x16_t __b, mve_pred16_t __p) @@ -9292,38 +8560,6 @@ extern void *__ARM_undef; int (*)[__ARM_mve_type_float16x8_t][__ARM_mve_type_float16x8_t]: __arm_vornq_f16 (__ARM_mve_coerce(__p0, float16x8_t), __ARM_mve_coerce(__p1, float16x8_t)), \ int (*)[__ARM_mve_type_float32x4_t][__ARM_mve_type_float32x4_t]: __arm_vornq_f32 (__ARM_mve_coerce(__p0, float32x4_t), __ARM_mve_coerce(__p1, float32x4_t)));}) -#define __arm_vmulltq_poly(p0,p1) ({ __typeof(p0) __p0 = (p0); \ - __typeof(p1) __p1 = (p1); \ - _Generic( (int (*)[__ARM_mve_typeid(__p0)][__ARM_mve_typeid(__p1)])0, \ - int (*)[__ARM_mve_type_uint8x16_t][__ARM_mve_type_uint8x16_t]: __arm_vmulltq_poly_p8 (__ARM_mve_coerce(__p0, uint8x16_t), __ARM_mve_coerce(__p1, uint8x16_t)), \ - int (*)[__ARM_mve_type_uint16x8_t][__ARM_mve_type_uint16x8_t]: __arm_vmulltq_poly_p16 (__ARM_mve_coerce(__p0, uint16x8_t), __ARM_mve_coerce(__p1, uint16x8_t)));}) - -#define __arm_vmullbq_poly(p0,p1) ({ __typeof(p0) __p0 = (p0); \ - __typeof(p1) __p1 = (p1); \ - _Generic( (int (*)[__ARM_mve_typeid(__p0)][__ARM_mve_typeid(__p1)])0, \ - int (*)[__ARM_mve_type_uint8x16_t][__ARM_mve_type_uint8x16_t]: __arm_vmullbq_poly_p8 (__ARM_mve_coerce(__p0, uint8x16_t), __ARM_mve_coerce(__p1, uint8x16_t)), \ - int (*)[__ARM_mve_type_uint16x8_t][__ARM_mve_type_uint16x8_t]: __arm_vmullbq_poly_p16 (__ARM_mve_coerce(__p0, uint16x8_t), __ARM_mve_coerce(__p1, uint16x8_t)));}) - -#define __arm_vmulltq_int(p0,p1) ({ __typeof(p0) __p0 = (p0); \ - __typeof(p1) __p1 = (p1); \ - _Generic( (int (*)[__ARM_mve_typeid(__p0)][__ARM_mve_typeid(__p1)])0, \ - int (*)[__ARM_mve_type_int8x16_t][__ARM_mve_type_int8x16_t]: __arm_vmulltq_int_s8 (__ARM_mve_coerce(__p0, int8x16_t), __ARM_mve_coerce(__p1, int8x16_t)), \ - int (*)[__ARM_mve_type_int16x8_t][__ARM_mve_type_int16x8_t]: __arm_vmulltq_int_s16 (__ARM_mve_coerce(__p0, int16x8_t), __ARM_mve_coerce(__p1, int16x8_t)), \ - int (*)[__ARM_mve_type_int32x4_t][__ARM_mve_type_int32x4_t]: __arm_vmulltq_int_s32 (__ARM_mve_coerce(__p0, int32x4_t), __ARM_mve_coerce(__p1, int32x4_t)), \ - int (*)[__ARM_mve_type_uint8x16_t][__ARM_mve_type_uint8x16_t]: __arm_vmulltq_int_u8 (__ARM_mve_coerce(__p0, uint8x16_t), __ARM_mve_coerce(__p1, uint8x16_t)), \ - int (*)[__ARM_mve_type_uint16x8_t][__ARM_mve_type_uint16x8_t]: __arm_vmulltq_int_u16 (__ARM_mve_coerce(__p0, uint16x8_t), __ARM_mve_coerce(__p1, uint16x8_t)), \ - int (*)[__ARM_mve_type_uint32x4_t][__ARM_mve_type_uint32x4_t]: __arm_vmulltq_int_u32 (__ARM_mve_coerce(__p0, uint32x4_t), __ARM_mve_coerce(__p1, uint32x4_t)));}) - -#define __arm_vmullbq_int(p0,p1) ({ __typeof(p0) __p0 = (p0); \ - __typeof(p1) __p1 = (p1); \ - _Generic( (int (*)[__ARM_mve_typeid(__p0)][__ARM_mve_typeid(__p1)])0, \ - int (*)[__ARM_mve_type_int8x16_t][__ARM_mve_type_int8x16_t]: __arm_vmullbq_int_s8 (__ARM_mve_coerce(__p0, int8x16_t), __ARM_mve_coerce(__p1, int8x16_t)), \ - int (*)[__ARM_mve_type_int16x8_t][__ARM_mve_type_int16x8_t]: __arm_vmullbq_int_s16 (__ARM_mve_coerce(__p0, int16x8_t), __ARM_mve_coerce(__p1, int16x8_t)), \ - int (*)[__ARM_mve_type_int32x4_t][__ARM_mve_type_int32x4_t]: __arm_vmullbq_int_s32 (__ARM_mve_coerce(__p0, int32x4_t), __ARM_mve_coerce(__p1, int32x4_t)), \ - int (*)[__ARM_mve_type_uint8x16_t][__ARM_mve_type_uint8x16_t]: __arm_vmullbq_int_u8 (__ARM_mve_coerce(__p0, uint8x16_t), __ARM_mve_coerce(__p1, uint8x16_t)), \ - int (*)[__ARM_mve_type_uint16x8_t][__ARM_mve_type_uint16x8_t]: __arm_vmullbq_int_u16 (__ARM_mve_coerce(__p0, uint16x8_t), __ARM_mve_coerce(__p1, uint16x8_t)), \ - int (*)[__ARM_mve_type_uint32x4_t][__ARM_mve_type_uint32x4_t]: __arm_vmullbq_int_u32 (__ARM_mve_coerce(__p0, uint32x4_t), __ARM_mve_coerce(__p1, uint32x4_t)));}) - #define __arm_vbicq_m_n(p0,p1,p2) ({ __typeof(p0) __p0 = (p0); \ _Generic( (int (*)[__ARM_mve_typeid(__p0)])0, \ int (*)[__ARM_mve_type_int16x8_t]: __arm_vbicq_m_n_s16 (__ARM_mve_coerce(__p0, int16x8_t), p1, p2), \ @@ -9842,26 +9078,6 @@ extern void *__ARM_undef; int (*)[__ARM_mve_type_uint16x8_t][__ARM_mve_type_uint16x8_t]: __arm_vornq_u16 (__ARM_mve_coerce(__p0, uint16x8_t), __ARM_mve_coerce(__p1, uint16x8_t)), \ int (*)[__ARM_mve_type_uint32x4_t][__ARM_mve_type_uint32x4_t]: __arm_vornq_u32 (__ARM_mve_coerce(__p0, uint32x4_t), __ARM_mve_coerce(__p1, uint32x4_t)));}) -#define __arm_vmulltq_int(p0,p1) ({ __typeof(p0) __p0 = (p0); \ - __typeof(p1) __p1 = (p1); \ - _Generic( (int (*)[__ARM_mve_typeid(__p0)][__ARM_mve_typeid(__p1)])0, \ - int (*)[__ARM_mve_type_int8x16_t][__ARM_mve_type_int8x16_t]: __arm_vmulltq_int_s8 (__ARM_mve_coerce(__p0, int8x16_t), __ARM_mve_coerce(__p1, int8x16_t)), \ - int (*)[__ARM_mve_type_int16x8_t][__ARM_mve_type_int16x8_t]: __arm_vmulltq_int_s16 (__ARM_mve_coerce(__p0, int16x8_t), __ARM_mve_coerce(__p1, int16x8_t)), \ - int (*)[__ARM_mve_type_int32x4_t][__ARM_mve_type_int32x4_t]: __arm_vmulltq_int_s32 (__ARM_mve_coerce(__p0, int32x4_t), __ARM_mve_coerce(__p1, int32x4_t)), \ - int (*)[__ARM_mve_type_uint8x16_t][__ARM_mve_type_uint8x16_t]: __arm_vmulltq_int_u8 (__ARM_mve_coerce(__p0, uint8x16_t), __ARM_mve_coerce(__p1, uint8x16_t)), \ - int (*)[__ARM_mve_type_uint16x8_t][__ARM_mve_type_uint16x8_t]: __arm_vmulltq_int_u16 (__ARM_mve_coerce(__p0, uint16x8_t), __ARM_mve_coerce(__p1, uint16x8_t)), \ - int (*)[__ARM_mve_type_uint32x4_t][__ARM_mve_type_uint32x4_t]: __arm_vmulltq_int_u32 (__ARM_mve_coerce(__p0, uint32x4_t), __ARM_mve_coerce(__p1, uint32x4_t)));}) - -#define __arm_vmullbq_int(p0,p1) ({ __typeof(p0) __p0 = (p0); \ - __typeof(p1) __p1 = (p1); \ - _Generic( (int (*)[__ARM_mve_typeid(__p0)][__ARM_mve_typeid(__p1)])0, \ - int (*)[__ARM_mve_type_int8x16_t][__ARM_mve_type_int8x16_t]: __arm_vmullbq_int_s8 (__ARM_mve_coerce(__p0, int8x16_t), __ARM_mve_coerce(__p1, int8x16_t)), \ - int (*)[__ARM_mve_type_int16x8_t][__ARM_mve_type_int16x8_t]: __arm_vmullbq_int_s16 (__ARM_mve_coerce(__p0, int16x8_t), __ARM_mve_coerce(__p1, int16x8_t)), \ - int (*)[__ARM_mve_type_int32x4_t][__ARM_mve_type_int32x4_t]: __arm_vmullbq_int_s32 (__ARM_mve_coerce(__p0, int32x4_t), __ARM_mve_coerce(__p1, int32x4_t)), \ - int (*)[__ARM_mve_type_uint8x16_t][__ARM_mve_type_uint8x16_t]: __arm_vmullbq_int_u8 (__ARM_mve_coerce(__p0, uint8x16_t), __ARM_mve_coerce(__p1, uint8x16_t)), \ - int (*)[__ARM_mve_type_uint16x8_t][__ARM_mve_type_uint16x8_t]: __arm_vmullbq_int_u16 (__ARM_mve_coerce(__p0, uint16x8_t), __ARM_mve_coerce(__p1, uint16x8_t)), \ - int (*)[__ARM_mve_type_uint32x4_t][__ARM_mve_type_uint32x4_t]: __arm_vmullbq_int_u32 (__ARM_mve_coerce(__p0, uint32x4_t), __ARM_mve_coerce(__p1, uint32x4_t)));}) - #define __arm_vbicq(p0,p1) ({ __typeof(p0) __p0 = (p0); \ __typeof(p1) __p1 = (p1); \ _Generic( (int (*)[__ARM_mve_typeid(__p0)][__ARM_mve_typeid(__p1)])0, \ @@ -9876,18 +9092,6 @@ extern void *__ARM_undef; int (*)[__ARM_mve_type_uint16x8_t][__ARM_mve_type_uint16x8_t]: __arm_vbicq_u16 (__ARM_mve_coerce(__p0, uint16x8_t), __ARM_mve_coerce(__p1, uint16x8_t)), \ int (*)[__ARM_mve_type_uint32x4_t][__ARM_mve_type_uint32x4_t]: __arm_vbicq_u32 (__ARM_mve_coerce(__p0, uint32x4_t), __ARM_mve_coerce(__p1, uint32x4_t)));}) -#define __arm_vmulltq_poly(p0,p1) ({ __typeof(p0) __p0 = (p0); \ - __typeof(p1) __p1 = (p1); \ - _Generic( (int (*)[__ARM_mve_typeid(__p0)][__ARM_mve_typeid(__p1)])0, \ - int (*)[__ARM_mve_type_uint8x16_t][__ARM_mve_type_uint8x16_t]: __arm_vmulltq_poly_p8 (__ARM_mve_coerce(__p0, uint8x16_t), __ARM_mve_coerce(__p1, uint8x16_t)), \ - int (*)[__ARM_mve_type_uint16x8_t][__ARM_mve_type_uint16x8_t]: __arm_vmulltq_poly_p16 (__ARM_mve_coerce(__p0, uint16x8_t), __ARM_mve_coerce(__p1, uint16x8_t)));}) - -#define __arm_vmullbq_poly(p0,p1) ({ __typeof(p0) __p0 = (p0); \ - __typeof(p1) __p1 = (p1); \ - _Generic( (int (*)[__ARM_mve_typeid(__p0)][__ARM_mve_typeid(__p1)])0, \ - int (*)[__ARM_mve_type_uint8x16_t][__ARM_mve_type_uint8x16_t]: __arm_vmullbq_poly_p8 (__ARM_mve_coerce(__p0, uint8x16_t), __ARM_mve_coerce(__p1, uint8x16_t)), \ - int (*)[__ARM_mve_type_uint16x8_t][__ARM_mve_type_uint16x8_t]: __arm_vmullbq_poly_p16 (__ARM_mve_coerce(__p0, uint16x8_t), __ARM_mve_coerce(__p1, uint16x8_t)));}) - #define __arm_vshlcq(p0,p1,p2) ({ __typeof(p0) __p0 = (p0); \ _Generic( (int (*)[__ARM_mve_typeid(__p0)])0, \ int (*)[__ARM_mve_type_int8x16_t]: __arm_vshlcq_s8 (__ARM_mve_coerce(__p0, int8x16_t), p1, p2), \ @@ -10163,38 +9367,6 @@ extern void *__ARM_undef; int (*)[__ARM_mve_type_uint32x4_t]: __arm_vuninitializedq_u32 (), \ int (*)[__ARM_mve_type_uint64x2_t]: __arm_vuninitializedq_u64 ());}) -#define __arm_vmullbq_int_x(p1,p2,p3) ({ __typeof(p1) __p1 = (p1); \ - __typeof(p2) __p2 = (p2); \ - _Generic( (int (*)[__ARM_mve_typeid(__p1)][__ARM_mve_typeid(__p2)])0, \ - int (*)[__ARM_mve_type_int8x16_t][__ARM_mve_type_int8x16_t]: __arm_vmullbq_int_x_s8 (__ARM_mve_coerce(__p1, int8x16_t), __ARM_mve_coerce(__p2, int8x16_t), p3), \ - int (*)[__ARM_mve_type_int16x8_t][__ARM_mve_type_int16x8_t]: __arm_vmullbq_int_x_s16 (__ARM_mve_coerce(__p1, int16x8_t), __ARM_mve_coerce(__p2, int16x8_t), p3), \ - int (*)[__ARM_mve_type_int32x4_t][__ARM_mve_type_int32x4_t]: __arm_vmullbq_int_x_s32 (__ARM_mve_coerce(__p1, int32x4_t), __ARM_mve_coerce(__p2, int32x4_t), p3), \ - int (*)[__ARM_mve_type_uint8x16_t][__ARM_mve_type_uint8x16_t]: __arm_vmullbq_int_x_u8( __ARM_mve_coerce(__p1, uint8x16_t), __ARM_mve_coerce(__p2, uint8x16_t), p3), \ - int (*)[__ARM_mve_type_uint16x8_t][__ARM_mve_type_uint16x8_t]: __arm_vmullbq_int_x_u16( __ARM_mve_coerce(__p1, uint16x8_t), __ARM_mve_coerce(__p2, uint16x8_t), p3), \ - int (*)[__ARM_mve_type_uint32x4_t][__ARM_mve_type_uint32x4_t]: __arm_vmullbq_int_x_u32( __ARM_mve_coerce(__p1, uint32x4_t), __ARM_mve_coerce(__p2, uint32x4_t), p3));}) - -#define __arm_vmullbq_poly_x(p1,p2,p3) ({ __typeof(p1) __p1 = (p1); \ - __typeof(p2) __p2 = (p2); \ - _Generic( (int (*)[__ARM_mve_typeid(__p1)][__ARM_mve_typeid(__p2)])0, \ - int (*)[__ARM_mve_type_uint8x16_t][__ARM_mve_type_uint8x16_t]: __arm_vmullbq_poly_x_p8 (__ARM_mve_coerce(__p1, uint8x16_t), __ARM_mve_coerce(__p2, uint8x16_t), p3), \ - int (*)[__ARM_mve_type_uint16x8_t][__ARM_mve_type_uint16x8_t]: __arm_vmullbq_poly_x_p16 (__ARM_mve_coerce(__p1, uint16x8_t), __ARM_mve_coerce(__p2, uint16x8_t), p3));}) - -#define __arm_vmulltq_int_x(p1,p2,p3) ({ __typeof(p1) __p1 = (p1); \ - __typeof(p2) __p2 = (p2); \ - _Generic( (int (*)[__ARM_mve_typeid(__p1)][__ARM_mve_typeid(__p2)])0, \ - int (*)[__ARM_mve_type_int8x16_t][__ARM_mve_type_int8x16_t]: __arm_vmulltq_int_x_s8 (__ARM_mve_coerce(__p1, int8x16_t), __ARM_mve_coerce(__p2, int8x16_t), p3), \ - int (*)[__ARM_mve_type_int16x8_t][__ARM_mve_type_int16x8_t]: __arm_vmulltq_int_x_s16 (__ARM_mve_coerce(__p1, int16x8_t), __ARM_mve_coerce(__p2, int16x8_t), p3), \ - int (*)[__ARM_mve_type_int32x4_t][__ARM_mve_type_int32x4_t]: __arm_vmulltq_int_x_s32 (__ARM_mve_coerce(__p1, int32x4_t), __ARM_mve_coerce(__p2, int32x4_t), p3), \ - int (*)[__ARM_mve_type_uint8x16_t][__ARM_mve_type_uint8x16_t]: __arm_vmulltq_int_x_u8( __ARM_mve_coerce(__p1, uint8x16_t), __ARM_mve_coerce(__p2, uint8x16_t), p3), \ - int (*)[__ARM_mve_type_uint16x8_t][__ARM_mve_type_uint16x8_t]: __arm_vmulltq_int_x_u16( __ARM_mve_coerce(__p1, uint16x8_t), __ARM_mve_coerce(__p2, uint16x8_t), p3), \ - int (*)[__ARM_mve_type_uint32x4_t][__ARM_mve_type_uint32x4_t]: __arm_vmulltq_int_x_u32( __ARM_mve_coerce(__p1, uint32x4_t), __ARM_mve_coerce(__p2, uint32x4_t), p3));}) - -#define __arm_vmulltq_poly_x(p1,p2,p3) ({ __typeof(p1) __p1 = (p1); \ - __typeof(p2) __p2 = (p2); \ - _Generic( (int (*)[__ARM_mve_typeid(__p1)][__ARM_mve_typeid(__p2)])0, \ - int (*)[__ARM_mve_type_uint8x16_t][__ARM_mve_type_uint8x16_t]: __arm_vmulltq_poly_x_p8 (__ARM_mve_coerce(__p1, uint8x16_t), __ARM_mve_coerce(__p2, uint8x16_t), p3), \ - int (*)[__ARM_mve_type_uint16x8_t][__ARM_mve_type_uint16x8_t]: __arm_vmulltq_poly_x_p16 (__ARM_mve_coerce(__p1, uint16x8_t), __ARM_mve_coerce(__p2, uint16x8_t), p3));}) - #define __arm_vornq_x(p1,p2,p3) ({ __typeof(p1) __p1 = (p1); \ __typeof(p2) __p2 = (p2); \ _Generic( (int (*)[__ARM_mve_typeid(__p1)][__ARM_mve_typeid(__p2)])0, \ @@ -10420,42 +9592,6 @@ extern void *__ARM_undef; int (*)[__ARM_mve_type_uint8_t_ptr][__ARM_mve_type_uint16x8_t]: __arm_vldrbq_gather_offset_z_u16 (__ARM_mve_coerce_u8_ptr(p0, uint8_t *), __ARM_mve_coerce(__p1, uint16x8_t), p2), \ int (*)[__ARM_mve_type_uint8_t_ptr][__ARM_mve_type_uint32x4_t]: __arm_vldrbq_gather_offset_z_u32 (__ARM_mve_coerce_u8_ptr(p0, uint8_t *), __ARM_mve_coerce(__p1, uint32x4_t), p2));}) -#define __arm_vmullbq_int_m(p0,p1,p2,p3) ({ __typeof(p0) __p0 = (p0); \ - __typeof(p1) __p1 = (p1); \ - __typeof(p2) __p2 = (p2); \ - _Generic( (int (*)[__ARM_mve_typeid(__p0)][__ARM_mve_typeid(__p1)][__ARM_mve_typeid(__p2)])0, \ - int (*)[__ARM_mve_type_int16x8_t][__ARM_mve_type_int8x16_t][__ARM_mve_type_int8x16_t]: __arm_vmullbq_int_m_s8 (__ARM_mve_coerce(__p0, int16x8_t), __ARM_mve_coerce(__p1, int8x16_t), __ARM_mve_coerce(__p2, int8x16_t), p3), \ - int (*)[__ARM_mve_type_int32x4_t][__ARM_mve_type_int16x8_t][__ARM_mve_type_int16x8_t]: __arm_vmullbq_int_m_s16 (__ARM_mve_coerce(__p0, int32x4_t), __ARM_mve_coerce(__p1, int16x8_t), __ARM_mve_coerce(__p2, int16x8_t), p3), \ - int (*)[__ARM_mve_type_int64x2_t][__ARM_mve_type_int32x4_t][__ARM_mve_type_int32x4_t]: __arm_vmullbq_int_m_s32 (__ARM_mve_coerce(__p0, int64x2_t), __ARM_mve_coerce(__p1, int32x4_t), __ARM_mve_coerce(__p2, int32x4_t), p3), \ - int (*)[__ARM_mve_type_uint16x8_t][__ARM_mve_type_uint8x16_t][__ARM_mve_type_uint8x16_t]: __arm_vmullbq_int_m_u8 (__ARM_mve_coerce(__p0, uint16x8_t), __ARM_mve_coerce(__p1, uint8x16_t), __ARM_mve_coerce(__p2, uint8x16_t), p3), \ - int (*)[__ARM_mve_type_uint32x4_t][__ARM_mve_type_uint16x8_t][__ARM_mve_type_uint16x8_t]: __arm_vmullbq_int_m_u16 (__ARM_mve_coerce(__p0, uint32x4_t), __ARM_mve_coerce(__p1, uint16x8_t), __ARM_mve_coerce(__p2, uint16x8_t), p3), \ - int (*)[__ARM_mve_type_uint64x2_t][__ARM_mve_type_uint32x4_t][__ARM_mve_type_uint32x4_t]: __arm_vmullbq_int_m_u32 (__ARM_mve_coerce(__p0, uint64x2_t), __ARM_mve_coerce(__p1, uint32x4_t), __ARM_mve_coerce(__p2, uint32x4_t), p3));}) - -#define __arm_vmulltq_int_m(p0,p1,p2,p3) ({ __typeof(p0) __p0 = (p0); \ - __typeof(p1) __p1 = (p1); \ - __typeof(p2) __p2 = (p2); \ - _Generic( (int (*)[__ARM_mve_typeid(__p0)][__ARM_mve_typeid(__p1)][__ARM_mve_typeid(__p2)])0, \ - int (*)[__ARM_mve_type_int16x8_t][__ARM_mve_type_int8x16_t][__ARM_mve_type_int8x16_t]: __arm_vmulltq_int_m_s8 (__ARM_mve_coerce(__p0, int16x8_t), __ARM_mve_coerce(__p1, int8x16_t), __ARM_mve_coerce(__p2, int8x16_t), p3), \ - int (*)[__ARM_mve_type_int32x4_t][__ARM_mve_type_int16x8_t][__ARM_mve_type_int16x8_t]: __arm_vmulltq_int_m_s16 (__ARM_mve_coerce(__p0, int32x4_t), __ARM_mve_coerce(__p1, int16x8_t), __ARM_mve_coerce(__p2, int16x8_t), p3), \ - int (*)[__ARM_mve_type_int64x2_t][__ARM_mve_type_int32x4_t][__ARM_mve_type_int32x4_t]: __arm_vmulltq_int_m_s32 (__ARM_mve_coerce(__p0, int64x2_t), __ARM_mve_coerce(__p1, int32x4_t), __ARM_mve_coerce(__p2, int32x4_t), p3), \ - int (*)[__ARM_mve_type_uint16x8_t][__ARM_mve_type_uint8x16_t][__ARM_mve_type_uint8x16_t]: __arm_vmulltq_int_m_u8 (__ARM_mve_coerce(__p0, uint16x8_t), __ARM_mve_coerce(__p1, uint8x16_t), __ARM_mve_coerce(__p2, uint8x16_t), p3), \ - int (*)[__ARM_mve_type_uint32x4_t][__ARM_mve_type_uint16x8_t][__ARM_mve_type_uint16x8_t]: __arm_vmulltq_int_m_u16 (__ARM_mve_coerce(__p0, uint32x4_t), __ARM_mve_coerce(__p1, uint16x8_t), __ARM_mve_coerce(__p2, uint16x8_t), p3), \ - int (*)[__ARM_mve_type_uint64x2_t][__ARM_mve_type_uint32x4_t][__ARM_mve_type_uint32x4_t]: __arm_vmulltq_int_m_u32 (__ARM_mve_coerce(__p0, uint64x2_t), __ARM_mve_coerce(__p1, uint32x4_t), __ARM_mve_coerce(__p2, uint32x4_t), p3));}) - -#define __arm_vmulltq_poly_m(p0,p1,p2,p3) ({ __typeof(p0) __p0 = (p0); \ - __typeof(p1) __p1 = (p1); \ - __typeof(p2) __p2 = (p2); \ - _Generic( (int (*)[__ARM_mve_typeid(__p0)][__ARM_mve_typeid(__p1)][__ARM_mve_typeid(__p2)])0, \ - int (*)[__ARM_mve_type_uint16x8_t][__ARM_mve_type_uint8x16_t][__ARM_mve_type_uint8x16_t]: __arm_vmulltq_poly_m_p8 (__ARM_mve_coerce(__p0, uint16x8_t), __ARM_mve_coerce(__p1, uint8x16_t), __ARM_mve_coerce(__p2, uint8x16_t), p3), \ - int (*)[__ARM_mve_type_uint32x4_t][__ARM_mve_type_uint16x8_t][__ARM_mve_type_uint16x8_t]: __arm_vmulltq_poly_m_p16 (__ARM_mve_coerce(__p0, uint32x4_t), __ARM_mve_coerce(__p1, uint16x8_t), __ARM_mve_coerce(__p2, uint16x8_t), p3));}) - -#define __arm_vmullbq_poly_m(p0,p1,p2,p3) ({ __typeof(p0) __p0 = (p0); \ - __typeof(p1) __p1 = (p1); \ - __typeof(p2) __p2 = (p2); \ - _Generic( (int (*)[__ARM_mve_typeid(__p0)][__ARM_mve_typeid(__p1)][__ARM_mve_typeid(__p2)])0, \ - int (*)[__ARM_mve_type_uint16x8_t][__ARM_mve_type_uint8x16_t][__ARM_mve_type_uint8x16_t]: __arm_vmullbq_poly_m_p8 (__ARM_mve_coerce(__p0, uint16x8_t), __ARM_mve_coerce(__p1, uint8x16_t), __ARM_mve_coerce(__p2, uint8x16_t), p3), \ - int (*)[__ARM_mve_type_uint32x4_t][__ARM_mve_type_uint16x8_t][__ARM_mve_type_uint16x8_t]: __arm_vmullbq_poly_m_p16 (__ARM_mve_coerce(__p0, uint32x4_t), __ARM_mve_coerce(__p1, uint16x8_t), __ARM_mve_coerce(__p2, uint16x8_t), p3));}) - #define __arm_vldrbq_gather_offset(p0,p1) ({ __typeof(p1) __p1 = (p1); \ _Generic( (int (*)[__ARM_mve_typeid(p0)][__ARM_mve_typeid(__p1)])0, \ int (*)[__ARM_mve_type_int8_t_ptr][__ARM_mve_type_uint8x16_t]: __arm_vldrbq_gather_offset_s8(__ARM_mve_coerce_s8_ptr(p0, int8_t *), __ARM_mve_coerce(__p1, uint8x16_t)), \ @@ -10574,38 +9710,6 @@ extern void *__ARM_undef; int (*)[__ARM_mve_type_uint16x8_t]: __arm_vshlcq_m_u16 (__ARM_mve_coerce(__p0, uint16x8_t), p1, p2, p3), \ int (*)[__ARM_mve_type_uint32x4_t]: __arm_vshlcq_m_u32 (__ARM_mve_coerce(__p0, uint32x4_t), p1, p2, p3));}) -#define __arm_vmullbq_int_x(p1,p2,p3) ({ __typeof(p1) __p1 = (p1); \ - __typeof(p2) __p2 = (p2); \ - _Generic( (int (*)[__ARM_mve_typeid(__p1)][__ARM_mve_typeid(__p2)])0, \ - int (*)[__ARM_mve_type_int8x16_t][__ARM_mve_type_int8x16_t]: __arm_vmullbq_int_x_s8 (__ARM_mve_coerce(__p1, int8x16_t), __ARM_mve_coerce(__p2, int8x16_t), p3), \ - int (*)[__ARM_mve_type_int16x8_t][__ARM_mve_type_int16x8_t]: __arm_vmullbq_int_x_s16 (__ARM_mve_coerce(__p1, int16x8_t), __ARM_mve_coerce(__p2, int16x8_t), p3), \ - int (*)[__ARM_mve_type_int32x4_t][__ARM_mve_type_int32x4_t]: __arm_vmullbq_int_x_s32 (__ARM_mve_coerce(__p1, int32x4_t), __ARM_mve_coerce(__p2, int32x4_t), p3), \ - int (*)[__ARM_mve_type_uint8x16_t][__ARM_mve_type_uint8x16_t]: __arm_vmullbq_int_x_u8( __ARM_mve_coerce(__p1, uint8x16_t), __ARM_mve_coerce(__p2, uint8x16_t), p3), \ - int (*)[__ARM_mve_type_uint16x8_t][__ARM_mve_type_uint16x8_t]: __arm_vmullbq_int_x_u16( __ARM_mve_coerce(__p1, uint16x8_t), __ARM_mve_coerce(__p2, uint16x8_t), p3), \ - int (*)[__ARM_mve_type_uint32x4_t][__ARM_mve_type_uint32x4_t]: __arm_vmullbq_int_x_u32( __ARM_mve_coerce(__p1, uint32x4_t), __ARM_mve_coerce(__p2, uint32x4_t), p3));}) - -#define __arm_vmullbq_poly_x(p1,p2,p3) ({ __typeof(p1) __p1 = (p1); \ - __typeof(p2) __p2 = (p2); \ - _Generic( (int (*)[__ARM_mve_typeid(__p1)][__ARM_mve_typeid(__p2)])0, \ - int (*)[__ARM_mve_type_uint8x16_t][__ARM_mve_type_uint8x16_t]: __arm_vmullbq_poly_x_p8 (__ARM_mve_coerce(__p1, uint8x16_t), __ARM_mve_coerce(__p2, uint8x16_t), p3), \ - int (*)[__ARM_mve_type_uint16x8_t][__ARM_mve_type_uint16x8_t]: __arm_vmullbq_poly_x_p16 (__ARM_mve_coerce(__p1, uint16x8_t), __ARM_mve_coerce(__p2, uint16x8_t), p3));}) - -#define __arm_vmulltq_int_x(p1,p2,p3) ({ __typeof(p1) __p1 = (p1); \ - __typeof(p2) __p2 = (p2); \ - _Generic( (int (*)[__ARM_mve_typeid(__p1)][__ARM_mve_typeid(__p2)])0, \ - int (*)[__ARM_mve_type_int8x16_t][__ARM_mve_type_int8x16_t]: __arm_vmulltq_int_x_s8 (__ARM_mve_coerce(__p1, int8x16_t), __ARM_mve_coerce(__p2, int8x16_t), p3), \ - int (*)[__ARM_mve_type_int16x8_t][__ARM_mve_type_int16x8_t]: __arm_vmulltq_int_x_s16 (__ARM_mve_coerce(__p1, int16x8_t), __ARM_mve_coerce(__p2, int16x8_t), p3), \ - int (*)[__ARM_mve_type_int32x4_t][__ARM_mve_type_int32x4_t]: __arm_vmulltq_int_x_s32 (__ARM_mve_coerce(__p1, int32x4_t), __ARM_mve_coerce(__p2, int32x4_t), p3), \ - int (*)[__ARM_mve_type_uint8x16_t][__ARM_mve_type_uint8x16_t]: __arm_vmulltq_int_x_u8( __ARM_mve_coerce(__p1, uint8x16_t), __ARM_mve_coerce(__p2, uint8x16_t), p3), \ - int (*)[__ARM_mve_type_uint16x8_t][__ARM_mve_type_uint16x8_t]: __arm_vmulltq_int_x_u16( __ARM_mve_coerce(__p1, uint16x8_t), __ARM_mve_coerce(__p2, uint16x8_t), p3), \ - int (*)[__ARM_mve_type_uint32x4_t][__ARM_mve_type_uint32x4_t]: __arm_vmulltq_int_x_u32( __ARM_mve_coerce(__p1, uint32x4_t), __ARM_mve_coerce(__p2, uint32x4_t), p3));}) - -#define __arm_vmulltq_poly_x(p1,p2,p3) ({ __typeof(p1) __p1 = (p1); \ - __typeof(p2) __p2 = (p2); \ - _Generic( (int (*)[__ARM_mve_typeid(__p1)][__ARM_mve_typeid(__p2)])0, \ - int (*)[__ARM_mve_type_uint8x16_t][__ARM_mve_type_uint8x16_t]: __arm_vmulltq_poly_x_p8 (__ARM_mve_coerce(__p1, uint8x16_t), __ARM_mve_coerce(__p2, uint8x16_t), p3), \ - int (*)[__ARM_mve_type_uint16x8_t][__ARM_mve_type_uint16x8_t]: __arm_vmulltq_poly_x_p16 (__ARM_mve_coerce(__p1, uint16x8_t), __ARM_mve_coerce(__p2, uint16x8_t), p3));}) - #define __arm_vstrbq(p0,p1) ({ __typeof(p1) __p1 = (p1); \ _Generic( (int (*)[__ARM_mve_typeid(p0)][__ARM_mve_typeid(__p1)])0, \ int (*)[__ARM_mve_type_int8_t_ptr][__ARM_mve_type_int8x16_t]: __arm_vstrbq_s8 (__ARM_mve_coerce_s8_ptr(p0, int8_t *), __ARM_mve_coerce(__p1, int8x16_t)), \ diff --git a/gcc/config/arm/arm_mve_builtins.def b/gcc/config/arm/arm_mve_builtins.def index 43dacc3dda13..6ac1812c6971 100644 --- a/gcc/config/arm/arm_mve_builtins.def +++ b/gcc/config/arm/arm_mve_builtins.def @@ -523,8 +523,8 @@ VAR3 (QUADOP_UNONE_UNONE_UNONE_UNONE_PRED, vhsubq_m_n_u, v16qi, v8hi, v4si) VAR3 (QUADOP_UNONE_UNONE_UNONE_UNONE_PRED, vhaddq_m_u, v16qi, v8hi, v4si) VAR3 (QUADOP_UNONE_UNONE_UNONE_UNONE_PRED, vhaddq_m_n_u, v16qi, v8hi, v4si) VAR3 (QUADOP_UNONE_UNONE_UNONE_UNONE_PRED, veorq_m_u, v16qi, v8hi, v4si) -VAR3 (QUADOP_UNONE_UNONE_UNONE_UNONE_PRED, vcaddq_rot90_m_u, v16qi, v8hi, v4si) -VAR3 (QUADOP_UNONE_UNONE_UNONE_UNONE_PRED, vcaddq_rot270_m_u, v16qi, v8hi, v4si) +VAR3 (QUADOP_UNONE_UNONE_UNONE_UNONE_PRED, vcaddq_rot90_m_, v16qi, v8hi, v4si) +VAR3 (QUADOP_UNONE_UNONE_UNONE_UNONE_PRED, vcaddq_rot270_m_, v16qi, v8hi, v4si) VAR3 (QUADOP_UNONE_UNONE_UNONE_UNONE_PRED, vbicq_m_u, v16qi, v8hi, v4si) VAR3 (QUADOP_UNONE_UNONE_UNONE_UNONE_PRED, vandq_m_u, v16qi, v8hi, v4si) VAR3 (QUADOP_UNONE_UNONE_UNONE_UNONE_PRED, vaddq_m_u, v16qi, v8hi, v4si) @@ -587,8 +587,6 @@ VAR3 (QUADOP_NONE_NONE_NONE_NONE_PRED, vhcaddq_rot270_m_s, v16qi, v8hi, v4si) VAR3 (QUADOP_NONE_NONE_NONE_NONE_PRED, vhaddq_m_s, v16qi, v8hi, v4si) VAR3 (QUADOP_NONE_NONE_NONE_NONE_PRED, vhaddq_m_n_s, v16qi, v8hi, v4si) VAR3 (QUADOP_NONE_NONE_NONE_NONE_PRED, veorq_m_s, v16qi, v8hi, v4si) -VAR3 (QUADOP_NONE_NONE_NONE_NONE_PRED, vcaddq_rot90_m_s, v16qi, v8hi, v4si) -VAR3 (QUADOP_NONE_NONE_NONE_NONE_PRED, vcaddq_rot270_m_s, v16qi, v8hi, v4si) VAR3 (QUADOP_NONE_NONE_NONE_NONE_PRED, vbrsrq_m_n_s, v16qi, v8hi, v4si) VAR3 (QUADOP_NONE_NONE_NONE_NONE_PRED, vbicq_m_s, v16qi, v8hi, v4si) VAR3 (QUADOP_NONE_NONE_NONE_NONE_PRED, vandq_m_s, v16qi, v8hi, v4si) diff --git a/gcc/config/arm/iterators.md b/gcc/config/arm/iterators.md index b13ff53d36f5..a98035381016 100644 --- a/gcc/config/arm/iterators.md +++ b/gcc/config/arm/iterators.md @@ -917,6 +917,7 @@ (define_int_attr mve_insn [ (UNSPEC_VCADD90 "vcadd") (UNSPEC_VCADD270 "vcadd") + (UNSPEC_VCMLA "vcmla") (UNSPEC_VCMLA90 "vcmla") (UNSPEC_VCMLA180 "vcmla") (UNSPEC_VCMLA270 "vcmla") (UNSPEC_VCMUL "vcmul") (UNSPEC_VCMUL90 "vcmul") (UNSPEC_VCMUL180 "vcmul") (UNSPEC_VCMUL270 "vcmul") (VABAVQ_P_S "vabav") (VABAVQ_P_U "vabav") (VABAVQ_S "vabav") (VABAVQ_U "vabav") @@ -941,8 +942,8 @@ (VBICQ_N_S "vbic") (VBICQ_N_U "vbic") (VBRSRQ_M_N_S "vbrsr") (VBRSRQ_M_N_U "vbrsr") (VBRSRQ_M_N_F "vbrsr") (VBRSRQ_N_S "vbrsr") (VBRSRQ_N_U "vbrsr") (VBRSRQ_N_F "vbrsr") - (VCADDQ_ROT270_M_U "vcadd") (VCADDQ_ROT270_M_S "vcadd") (VCADDQ_ROT270_M_F "vcadd") - (VCADDQ_ROT90_M_U "vcadd") (VCADDQ_ROT90_M_S "vcadd") (VCADDQ_ROT90_M_F "vcadd") + (VCADDQ_ROT270_M "vcadd") (VCADDQ_ROT270_M_F "vcadd") + (VCADDQ_ROT90_M "vcadd") (VCADDQ_ROT90_M_F "vcadd") (VCLSQ_M_S "vcls") (VCLSQ_S "vcls") (VCLZQ_M_S "vclz") (VCLZQ_M_U "vclz") @@ -1044,6 +1045,13 @@ (VMOVNTQ_S "vmovnt") (VMOVNTQ_U "vmovnt") (VMULHQ_M_S "vmulh") (VMULHQ_M_U "vmulh") (VMULHQ_S "vmulh") (VMULHQ_U "vmulh") + (VMULLBQ_INT_M_S "vmullb") (VMULLBQ_INT_M_U "vmullb") + (VMULLBQ_INT_S "vmullb") (VMULLBQ_INT_U "vmullb") + (VMULLBQ_POLY_M_P "vmullb") (VMULLTQ_POLY_M_P "vmullt") + (VMULLBQ_POLY_P "vmullb") + (VMULLTQ_INT_M_S "vmullt") (VMULLTQ_INT_M_U "vmullt") + (VMULLTQ_INT_S "vmullt") (VMULLTQ_INT_U "vmullt") + (VMULLTQ_POLY_P "vmullt") (VMULQ_M_N_S "vmul") (VMULQ_M_N_U "vmul") (VMULQ_M_N_F "vmul") (VMULQ_M_S "vmul") (VMULQ_M_U "vmul") (VMULQ_M_F "vmul") (VMULQ_N_S "vmul") (VMULQ_N_U "vmul") (VMULQ_N_F "vmul") @@ -1209,14 +1217,13 @@ (VSUBQ_M_N_S "vsub") (VSUBQ_M_N_U "vsub") (VSUBQ_M_N_F "vsub") (VSUBQ_M_S "vsub") (VSUBQ_M_U "vsub") (VSUBQ_M_F "vsub") (VSUBQ_N_S "vsub") (VSUBQ_N_U "vsub") (VSUBQ_N_F "vsub") - (UNSPEC_VCMLA "vcmla") (UNSPEC_VCMLA90 "vcmla") (UNSPEC_VCMLA180 "vcmla") (UNSPEC_VCMLA270 "vcmla") ]) (define_int_attr isu [ (UNSPEC_VCADD90 "i") (UNSPEC_VCADD270 "i") (VABSQ_M_S "s") - (VCADDQ_ROT270_M_U "i") (VCADDQ_ROT270_M_S "i") - (VCADDQ_ROT90_M_U "i") (VCADDQ_ROT90_M_S "i") + (VCADDQ_ROT270_M "i") + (VCADDQ_ROT90_M "i") (VCLSQ_M_S "s") (VCLZQ_M_S "i") (VCLZQ_M_U "i") @@ -1246,6 +1253,8 @@ (VMOVNBQ_S "i") (VMOVNBQ_U "i") (VMOVNTQ_M_S "i") (VMOVNTQ_M_U "i") (VMOVNTQ_S "i") (VMOVNTQ_U "i") + (VMULLBQ_INT_S "s") (VMULLBQ_INT_U "u") + (VMULLTQ_INT_S "s") (VMULLTQ_INT_U "u") (VNEGQ_M_S "s") (VQABSQ_M_S "s") (VQMOVNBQ_M_S "s") (VQMOVNBQ_M_U "u") @@ -2184,11 +2193,9 @@ (define_int_attr rot [(UNSPEC_VCADD90 "90") (UNSPEC_VCADD270 "270") (VCADDQ_ROT90_M_F "90") - (VCADDQ_ROT90_M_S "90") - (VCADDQ_ROT90_M_U "90") + (VCADDQ_ROT90_M "90") (VCADDQ_ROT270_M_F "270") - (VCADDQ_ROT270_M_S "270") - (VCADDQ_ROT270_M_U "270") + (VCADDQ_ROT270_M "270") (VHCADDQ_ROT90_S "90") (VHCADDQ_ROT270_S "270") (VHCADDQ_ROT90_M_S "90") @@ -2241,11 +2248,9 @@ (define_int_attr mve_rot [(UNSPEC_VCADD90 "_rot90") (UNSPEC_VCADD270 "_rot270") (VCADDQ_ROT90_M_F "_rot90") - (VCADDQ_ROT90_M_S "_rot90") - (VCADDQ_ROT90_M_U "_rot90") + (VCADDQ_ROT90_M "_rot90") (VCADDQ_ROT270_M_F "_rot270") - (VCADDQ_ROT270_M_S "_rot270") - (VCADDQ_ROT270_M_U "_rot270") + (VCADDQ_ROT270_M "_rot270") (VHCADDQ_ROT90_S "_rot90") (VHCADDQ_ROT270_S "_rot270") (VHCADDQ_ROT90_M_S "_rot90") @@ -2330,6 +2335,10 @@ (VMLADAVQ_U "u") (VMULHQ_S "s") (VMULHQ_U "u") (VMULLBQ_INT_S "s") (VMULLBQ_INT_U "u") (VQADDQ_S "s") (VMULLTQ_INT_S "s") (VMULLTQ_INT_U "u") (VQADDQ_U "u") + (VMULLBQ_POLY_P "p") + (VMULLTQ_POLY_P "p") + (VMULLBQ_POLY_M_P "p") + (VMULLTQ_POLY_M_P "p") (VMULQ_N_S "s") (VMULQ_N_U "u") (VMULQ_S "s") (VMULQ_U "u") (VQADDQ_N_S "s") (VQADDQ_N_U "u") @@ -2403,7 +2412,7 @@ (VCVTQ_M_N_TO_F_U "u") (VADDQ_M_N_U "u") (VSHLQ_M_N_S "s") (VMAXQ_M_U "u") (VHSUBQ_M_N_U "u") (VMULQ_M_N_S "s") (VQSHLQ_M_U "u") (VRHADDQ_M_S "s") - (VEORQ_M_U "u") (VSHRQ_M_N_U "u") (VCADDQ_ROT90_M_U "u") + (VEORQ_M_U "u") (VSHRQ_M_N_U "u") (VMLADAVAQ_P_U "u") (VEORQ_M_S "s") (VBRSRQ_M_N_S "s") (VMULQ_M_U "u") (VQRDMLAHQ_M_N_S "s") (VHSUBQ_M_N_S "s") (VQRSHLQ_M_S "s") (VMULQ_M_N_U "u") @@ -2412,17 +2421,17 @@ (VMULLBQ_INT_M_U "u") (VSHLQ_M_N_U "u") (VQSUBQ_M_U "u") (VQDMLASHQ_M_N_S "s") (VQRDMLASHQ_M_N_U "u") (VRSHRQ_M_N_S "s") - (VORNQ_M_S "s") (VCADDQ_ROT270_M_S "s") (VRHADDQ_M_U "u") + (VORNQ_M_S "s") (VCADDQ_ROT270_M "") (VRHADDQ_M_U "u") (VRSHRQ_M_N_U "u") (VMLASQ_M_N_U "u") (VHSUBQ_M_U "u") (VQSUBQ_M_N_S "s") (VMULLTQ_INT_M_S "s") (VORRQ_M_S "s") (VQDMLAHQ_M_N_U "u") (VRSHLQ_M_S "s") (VHADDQ_M_U "u") (VHADDQ_M_N_S "s") (VMULLTQ_INT_M_U "u") (VORRQ_M_U "u") (VHADDQ_M_S "s") (VHADDQ_M_N_U "u") (VQDMLAHQ_M_N_S "s") (VMAXQ_M_S "s") (VORNQ_M_U "u") - (VCADDQ_ROT270_M_U "u") (VQADDQ_M_U "u") + (VQADDQ_M_U "u") (VQRDMLASHQ_M_N_S "s") (VBICQ_M_U "u") (VMINQ_M_U "u") (VSUBQ_M_N_S "s") (VMULLBQ_INT_M_S "s") (VQSUBQ_M_S "s") - (VCADDQ_ROT90_M_S "s") (VRMULHQ_M_S "s") (VANDQ_M_U "u") + (VCADDQ_ROT90_M "") (VRMULHQ_M_S "s") (VANDQ_M_U "u") (VMULHQ_M_S "s") (VADDQ_M_S "s") (VQRDMLAHQ_M_N_U "u") (VMLASQ_M_N_S "s") (VHSUBQ_M_S "s") (VRMULHQ_M_U "u") (VQADDQ_M_N_S "s") (VSHRQ_M_N_S "s") (VANDQ_M_S "s") @@ -2713,8 +2722,8 @@ (define_int_iterator VMINVQ [VMINVQ_U VMINVQ_S]) (define_int_iterator VMLADAVQ [VMLADAVQ_U VMLADAVQ_S]) (define_int_iterator VMULHQ [VMULHQ_S VMULHQ_U]) -(define_int_iterator VMULLBQ_INT [VMULLBQ_INT_U VMULLBQ_INT_S]) -(define_int_iterator VMULLTQ_INT [VMULLTQ_INT_U VMULLTQ_INT_S]) +(define_int_iterator VMULLxQ_INT [VMULLBQ_INT_U VMULLBQ_INT_S VMULLTQ_INT_U VMULLTQ_INT_S]) +(define_int_iterator VMULLxQ_POLY [VMULLBQ_POLY_P VMULLTQ_POLY_P]) (define_int_iterator VMULQ [VMULQ_U VMULQ_S]) (define_int_iterator VMULQ_N [VMULQ_N_U VMULQ_N_S]) (define_int_iterator VQADDQ [VQADDQ_U VQADDQ_S]) @@ -2815,7 +2824,8 @@ (define_int_iterator VSLIQ_M_N [VSLIQ_M_N_U VSLIQ_M_N_S]) (define_int_iterator VRSHLQ_M [VRSHLQ_M_S VRSHLQ_M_U]) (define_int_iterator VMINQ_M [VMINQ_M_S VMINQ_M_U]) -(define_int_iterator VMULLBQ_INT_M [VMULLBQ_INT_M_U VMULLBQ_INT_M_S]) +(define_int_iterator VMULLxQ_INT_M [VMULLBQ_INT_M_U VMULLBQ_INT_M_S VMULLTQ_INT_M_U VMULLTQ_INT_M_S]) +(define_int_iterator VMULLxQ_POLY_M [VMULLBQ_POLY_M_P VMULLTQ_POLY_M_P]) (define_int_iterator VMULHQ_M [VMULHQ_M_S VMULHQ_M_U]) (define_int_iterator VMULQ_M [VMULQ_M_S VMULQ_M_U]) (define_int_iterator VHSUBQ_M_N [VHSUBQ_M_N_S VHSUBQ_M_N_U]) @@ -2834,7 +2844,7 @@ (define_int_iterator VSHLQ_M_N [VSHLQ_M_N_S VSHLQ_M_N_U]) (define_int_iterator VCADDQ_M_F [VCADDQ_ROT90_M_F VCADDQ_ROT270_M_F]) (define_int_iterator VxCADDQ [UNSPEC_VCADD90 UNSPEC_VCADD270 VHCADDQ_ROT90_S VHCADDQ_ROT270_S]) -(define_int_iterator VxCADDQ_M [VHCADDQ_ROT90_M_S VHCADDQ_ROT270_M_S VCADDQ_ROT90_M_U VCADDQ_ROT90_M_S VCADDQ_ROT270_M_U VCADDQ_ROT270_M_S]) +(define_int_iterator VxCADDQ_M [VHCADDQ_ROT90_M_S VHCADDQ_ROT270_M_S VCADDQ_ROT90_M VCADDQ_ROT270_M]) (define_int_iterator VQRSHLQ_M [VQRSHLQ_M_U VQRSHLQ_M_S]) (define_int_iterator VQADDQ_M_N [VQADDQ_M_N_U VQADDQ_M_N_S]) (define_int_iterator VADDQ_M_N [VADDQ_M_N_S VADDQ_M_N_U]) @@ -2844,7 +2854,6 @@ (define_int_iterator VMLADAVAQ_P [VMLADAVAQ_P_U VMLADAVAQ_P_S]) (define_int_iterator VBRSRQ_M_N [VBRSRQ_M_N_U VBRSRQ_M_N_S]) (define_int_iterator VMULQ_M_N [VMULQ_M_N_U VMULQ_M_N_S]) -(define_int_iterator VMULLTQ_INT_M [VMULLTQ_INT_M_S VMULLTQ_INT_M_U]) (define_int_iterator VEORQ_M [VEORQ_M_S VEORQ_M_U]) (define_int_iterator VSHRQ_M_N [VSHRQ_M_N_S VSHRQ_M_N_U]) (define_int_iterator VSUBQ_M_N [VSUBQ_M_N_S VSUBQ_M_N_U]) diff --git a/gcc/config/arm/mve.md b/gcc/config/arm/mve.md index a2cbcff1a6fc..366cec0812a9 100644 --- a/gcc/config/arm/mve.md +++ b/gcc/config/arm/mve.md @@ -839,8 +839,8 @@ ]) ;; -;; [vcaddq_rot90_s, vcadd_rot90_u] -;; [vcaddq_rot270_s, vcadd_rot270_u] +;; [vcaddq_rot90_s, vcaddq_rot90_u] +;; [vcaddq_rot270_s, vcaddq_rot270_u] ;; [vhcaddq_rot90_s] ;; [vhcaddq_rot270_s] ;; @@ -976,32 +976,18 @@ ]) ;; -;; [vmullbq_int_u, vmullbq_int_s]) +;; [vmullbq_int_u, vmullbq_int_s] +;; [vmulltq_int_u, vmulltq_int_s] ;; -(define_insn "mve_vmullbq_int_" +(define_insn "@mve_q_int_" [ (set (match_operand: 0 "s_register_operand" "") (unspec: [(match_operand:MVE_2 1 "s_register_operand" "w") (match_operand:MVE_2 2 "s_register_operand" "w")] - VMULLBQ_INT)) + VMULLxQ_INT)) ] "TARGET_HAVE_MVE" - "vmullb.%#\t%q0, %q1, %q2" - [(set_attr "type" "mve_move") -]) - -;; -;; [vmulltq_int_u, vmulltq_int_s]) -;; -(define_insn "mve_vmulltq_int_" - [ - (set (match_operand: 0 "s_register_operand" "") - (unspec: [(match_operand:MVE_2 1 "s_register_operand" "w") - (match_operand:MVE_2 2 "s_register_operand" "w")] - VMULLTQ_INT)) - ] - "TARGET_HAVE_MVE" - "vmullt.%#\t%q0, %q1, %q2" + ".%#\t%q0, %q1, %q2" [(set_attr "type" "mve_move") ]) @@ -1528,32 +1514,18 @@ ]) ;; -;; [vmulltq_poly_p]) +;; [vmulltq_poly_p] +;; [vmullbq_poly_p] ;; -(define_insn "mve_vmulltq_poly_p" +(define_insn "@mve_q_poly_" [ (set (match_operand: 0 "s_register_operand" "=w") (unspec: [(match_operand:MVE_3 1 "s_register_operand" "w") (match_operand:MVE_3 2 "s_register_operand" "w")] - VMULLTQ_POLY_P)) + VMULLxQ_POLY)) ] "TARGET_HAVE_MVE" - "vmullt.p%#\t%q0, %q1, %q2" - [(set_attr "type" "mve_move") -]) - -;; -;; [vmullbq_poly_p]) -;; -(define_insn "mve_vmullbq_poly_p" - [ - (set (match_operand: 0 "s_register_operand" "=w") - (unspec: [(match_operand:MVE_3 1 "s_register_operand" "w") - (match_operand:MVE_3 2 "s_register_operand" "w")] - VMULLBQ_POLY_P)) - ] - "TARGET_HAVE_MVE" - "vmullb.p%#\t%q0, %q1, %q2" + ".%#\t%q0, %q1, %q2" [(set_attr "type" "mve_move") ]) @@ -2816,36 +2788,20 @@ (set_attr "length""8")]) ;; -;; [vmullbq_int_m_u, vmullbq_int_m_s]) +;; [vmullbq_int_m_u, vmullbq_int_m_s] +;; [vmulltq_int_m_s, vmulltq_int_m_u] ;; -(define_insn "mve_vmullbq_int_m_" +(define_insn "@mve_q_int_m_" [ (set (match_operand: 0 "s_register_operand" "") (unspec: [(match_operand: 1 "s_register_operand" "0") (match_operand:MVE_2 2 "s_register_operand" "w") (match_operand:MVE_2 3 "s_register_operand" "w") (match_operand: 4 "vpr_register_operand" "Up")] - VMULLBQ_INT_M)) + VMULLxQ_INT_M)) ] "TARGET_HAVE_MVE" - "vpst\;vmullbt.%# %q0, %q2, %q3" - [(set_attr "type" "mve_move") - (set_attr "length""8")]) - -;; -;; [vmulltq_int_m_s, vmulltq_int_m_u]) -;; -(define_insn "mve_vmulltq_int_m_" - [ - (set (match_operand: 0 "s_register_operand" "") - (unspec: [(match_operand: 1 "s_register_operand" "0") - (match_operand:MVE_2 2 "s_register_operand" "w") - (match_operand:MVE_2 3 "s_register_operand" "w") - (match_operand: 4 "vpr_register_operand" "Up")] - VMULLTQ_INT_M)) - ] - "TARGET_HAVE_MVE" - "vpst\;vmulltt.%# %q0, %q2, %q3" + "vpst\;t.%#\t%q0, %q2, %q3" [(set_attr "type" "mve_move") (set_attr "length""8")]) @@ -3006,36 +2962,20 @@ (set_attr "length""8")]) ;; -;; [vmullbq_poly_m_p]) +;; [vmullbq_poly_m_p] +;; [vmulltq_poly_m_p] ;; -(define_insn "mve_vmullbq_poly_m_p" +(define_insn "@mve_q_poly_m_" [ (set (match_operand: 0 "s_register_operand" "=w") (unspec: [(match_operand: 1 "s_register_operand" "0") (match_operand:MVE_3 2 "s_register_operand" "w") (match_operand:MVE_3 3 "s_register_operand" "w") (match_operand: 4 "vpr_register_operand" "Up")] - VMULLBQ_POLY_M_P)) + VMULLxQ_POLY_M)) ] "TARGET_HAVE_MVE" - "vpst\;vmullbt.p%#\t%q0, %q2, %q3" - [(set_attr "type" "mve_move") - (set_attr "length""8")]) - -;; -;; [vmulltq_poly_m_p]) -;; -(define_insn "mve_vmulltq_poly_m_p" - [ - (set (match_operand: 0 "s_register_operand" "=w") - (unspec: [(match_operand: 1 "s_register_operand" "0") - (match_operand:MVE_3 2 "s_register_operand" "w") - (match_operand:MVE_3 3 "s_register_operand" "w") - (match_operand: 4 "vpr_register_operand" "Up")] - VMULLTQ_POLY_M_P)) - ] - "TARGET_HAVE_MVE" - "vpst\;vmulltt.p%#\t%q0, %q2, %q3" + "vpst\;t.%#\t%q0, %q2, %q3" [(set_attr "type" "mve_move") (set_attr "length""8")]) diff --git a/gcc/config/arm/unspecs.md b/gcc/config/arm/unspecs.md index dccda2835732..6a5b1f8f623b 100644 --- a/gcc/config/arm/unspecs.md +++ b/gcc/config/arm/unspecs.md @@ -995,8 +995,7 @@ VMAXQ_M_U VQRDMLAHQ_M_N_U VCADDQ_ROT270_M_F - VCADDQ_ROT270_M_U - VCADDQ_ROT270_M_S + VCADDQ_ROT270_M VQRSHLQ_M_S VMULQ_M_F VRHADDQ_M_U @@ -1050,8 +1049,7 @@ VSLIQ_M_N_S VQSHLQ_M_U VQSHLQ_M_S - VCADDQ_ROT90_M_U - VCADDQ_ROT90_M_S + VCADDQ_ROT90_M VORNQ_M_U VORNQ_M_S VQSHLQ_M_N_S diff --git a/gcc/config/avr/avr.cc b/gcc/config/avr/avr.cc index 25f3f4c22e08..5e0217de36fc 100644 --- a/gcc/config/avr/avr.cc +++ b/gcc/config/avr/avr.cc @@ -13433,8 +13433,8 @@ avr_reg_ok_for_pgm_addr (rtx reg, bool strict) /* Implement `TARGET_ADDR_SPACE_LEGITIMATE_ADDRESS_P'. */ static bool -avr_addr_space_legitimate_address_p (machine_mode mode, rtx x, - bool strict, addr_space_t as) +avr_addr_space_legitimate_address_p (machine_mode mode, rtx x, bool strict, + addr_space_t as, code_helper = ERROR_MARK) { bool ok = false; diff --git a/gcc/config/bfin/bfin.cc b/gcc/config/bfin/bfin.cc index 4320ec267226..5718babb6b2c 100644 --- a/gcc/config/bfin/bfin.cc +++ b/gcc/config/bfin/bfin.cc @@ -2718,7 +2718,8 @@ bfin_valid_reg_p (unsigned int regno, int strict, machine_mode mode, */ static bool -bfin_legitimate_address_p (machine_mode mode, rtx x, bool strict) +bfin_legitimate_address_p (machine_mode mode, rtx x, bool strict, + code_helper = ERROR_MARK) { switch (GET_CODE (x)) { case REG: diff --git a/gcc/config/bpf/bpf.cc b/gcc/config/bpf/bpf.cc index 4873475e73bd..437bd652de3e 100644 --- a/gcc/config/bpf/bpf.cc +++ b/gcc/config/bpf/bpf.cc @@ -76,10 +76,6 @@ struct GTY(()) machine_function { /* Number of bytes saved on the stack for local variables. */ int local_vars_size; - - /* Number of bytes saved on the stack for callee-saved - registers. */ - int callee_saved_reg_size; }; /* Handle an attribute requiring a FUNCTION_DECL; @@ -158,6 +154,10 @@ static const struct attribute_spec bpf_attribute_table[] = { "preserve_access_index", 0, -1, false, true, false, true, bpf_handle_preserve_access_index_attribute, NULL }, + /* Support for `naked' function attribute. */ + { "naked", 0, 1, false, false, false, false, + bpf_handle_fndecl_attribute, NULL }, + /* The last attribute spec is set to be NULL. */ { NULL, 0, 0, false, false, false, false, NULL, NULL } }; @@ -339,6 +339,21 @@ bpf_function_value_regno_p (const unsigned int regno) #undef TARGET_FUNCTION_VALUE_REGNO_P #define TARGET_FUNCTION_VALUE_REGNO_P bpf_function_value_regno_p + +/* Determine whether to warn about lack of return statement in a + function. */ + +static bool +bpf_warn_func_return (tree decl) +{ + /* Naked functions are implemented entirely in assembly, including + the return instructions. */ + return lookup_attribute ("naked", DECL_ATTRIBUTES (decl)) == NULL_TREE; +} + +#undef TARGET_WARN_FUNC_RETURN +#define TARGET_WARN_FUNC_RETURN bpf_warn_func_return + /* Compute the size of the function's stack frame, including the local area and the register-save area. */ @@ -346,7 +361,7 @@ static void bpf_compute_frame_layout (void) { int stack_alignment = STACK_BOUNDARY / BITS_PER_UNIT; - int padding_locals, regno; + int padding_locals; /* Set the space used in the stack by local variables. This is rounded up to respect the minimum stack alignment. */ @@ -358,23 +373,9 @@ bpf_compute_frame_layout (void) cfun->machine->local_vars_size += padding_locals; - if (TARGET_XBPF) - { - /* Set the space used in the stack by callee-saved used - registers in the current function. There is no need to round - up, since the registers are all 8 bytes wide. */ - for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++) - if ((df_regs_ever_live_p (regno) - && !call_used_or_fixed_reg_p (regno)) - || (cfun->calls_alloca - && regno == STACK_POINTER_REGNUM)) - cfun->machine->callee_saved_reg_size += 8; - } - /* Check that the total size of the frame doesn't exceed the limit imposed by eBPF. */ - if ((cfun->machine->local_vars_size - + cfun->machine->callee_saved_reg_size) > bpf_frame_limit) + if (cfun->machine->local_vars_size > bpf_frame_limit) { static int stack_limit_exceeded = 0; @@ -393,69 +394,22 @@ bpf_compute_frame_layout (void) void bpf_expand_prologue (void) { - HOST_WIDE_INT size; - - size = (cfun->machine->local_vars_size - + cfun->machine->callee_saved_reg_size); - /* The BPF "hardware" provides a fresh new set of registers for each called function, some of which are initialized to the values of the arguments passed in the first five registers. In doing so, - it saves the values of the registers of the caller, and restored + it saves the values of the registers of the caller, and restores them upon returning. Therefore, there is no need to save the - callee-saved registers here. What is worse, the kernel - implementation refuses to run programs in which registers are - referred before being initialized. */ - if (TARGET_XBPF) - { - int regno; - int fp_offset = -cfun->machine->local_vars_size; + callee-saved registers here. In fact, the kernel implementation + refuses to run programs in which registers are referred before + being initialized. */ - /* Save callee-saved hard registes. The register-save-area - starts right after the local variables. */ - for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++) - { - if ((df_regs_ever_live_p (regno) - && !call_used_or_fixed_reg_p (regno)) - || (cfun->calls_alloca - && regno == STACK_POINTER_REGNUM)) - { - rtx mem; + /* BPF does not support functions that allocate stack space + dynamically. This should have been checked already and an error + emitted. */ + gcc_assert (!cfun->calls_alloca); - if (!IN_RANGE (fp_offset, -1 - 0x7fff, 0x7fff)) - /* This has been already reported as an error in - bpf_compute_frame_layout. */ - break; - else - { - mem = gen_frame_mem (DImode, - plus_constant (DImode, - hard_frame_pointer_rtx, - fp_offset - 8)); - emit_move_insn (mem, gen_rtx_REG (DImode, regno)); - fp_offset -= 8; - } - } - } - } - - /* Set the stack pointer, if the function allocates space - dynamically. Note that the value of %sp should be directly - derived from %fp, for the kernel verifier to track it as a stack - accessor. */ - if (cfun->calls_alloca) - { - emit_move_insn (stack_pointer_rtx, - hard_frame_pointer_rtx); - - if (size > 0) - { - emit_insn (gen_rtx_SET (stack_pointer_rtx, - gen_rtx_PLUS (Pmode, - stack_pointer_rtx, - GEN_INT (-size)))); - } - } + /* If we ever need to have a proper prologue here, please mind the + `naked' function attribute. */ } /* Expand to the instructions in a function epilogue. This function @@ -466,37 +420,9 @@ bpf_expand_epilogue (void) { /* See note in bpf_expand_prologue for an explanation on why we are not restoring callee-saved registers in BPF. */ - if (TARGET_XBPF) - { - int regno; - int fp_offset = -cfun->machine->local_vars_size; - /* Restore callee-saved hard registes from the stack. */ - for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++) - { - if ((df_regs_ever_live_p (regno) - && !call_used_or_fixed_reg_p (regno)) - || (cfun->calls_alloca - && regno == STACK_POINTER_REGNUM)) - { - rtx mem; - - if (!IN_RANGE (fp_offset, -1 - 0x7fff, 0x7fff)) - /* This has been already reported as an error in - bpf_compute_frame_layout. */ - break; - else - { - mem = gen_frame_mem (DImode, - plus_constant (DImode, - hard_frame_pointer_rtx, - fp_offset - 8)); - emit_move_insn (gen_rtx_REG (DImode, regno), mem); - fp_offset -= 8; - } - } - } - } + /* If we ever need to do anything else than just generating a return + instruction here, please mind the `naked' function attribute. */ emit_jump_insn (gen_exit ()); } @@ -543,11 +469,10 @@ bpf_initial_elimination_offset (int from, int to) { HOST_WIDE_INT ret; - if (from == ARG_POINTER_REGNUM && to == STACK_POINTER_REGNUM) - ret = (cfun->machine->local_vars_size - + cfun->machine->callee_saved_reg_size); - else if (from == ARG_POINTER_REGNUM && to == FRAME_POINTER_REGNUM) + if (from == ARG_POINTER_REGNUM && to == FRAME_POINTER_REGNUM) ret = 0; + else if (from == STACK_POINTER_REGNUM && to == FRAME_POINTER_REGNUM) + ret = -(cfun->machine->local_vars_size); else gcc_unreachable (); @@ -625,7 +550,8 @@ bpf_address_base_p (rtx x, bool strict) static bool bpf_legitimate_address_p (machine_mode mode, rtx x, - bool strict) + bool strict, + code_helper = ERROR_MARK) { switch (GET_CODE (x)) { @@ -731,7 +657,14 @@ bpf_function_arg_advance (cumulative_args_t ca, unsigned num_words = CEIL (num_bytes, UNITS_PER_WORD); if (*cum <= 5 && *cum + num_words > 5) - error ("too many function arguments for eBPF"); + { + /* Too many arguments for BPF. However, if the function is + gonna be inline for sure, we let it pass. Otherwise, issue + an error. */ + if (!lookup_attribute ("always_inline", + DECL_ATTRIBUTES (cfun->decl))) + error ("too many function arguments for eBPF"); + } *cum += num_words; } @@ -845,7 +778,7 @@ bpf_print_register (FILE *file, rtx op, int code) fprintf (file, "%s", reg_names[REGNO (op)]); else { - if (code == 'w' && GET_MODE (op) == SImode) + if (code == 'w' && GET_MODE_SIZE (GET_MODE (op)) <= 4) { if (REGNO (op) == BPF_FP) fprintf (file, "w10"); diff --git a/gcc/config/bpf/bpf.h b/gcc/config/bpf/bpf.h index ccba7f8b3334..82702aa7b6ba 100644 --- a/gcc/config/bpf/bpf.h +++ b/gcc/config/bpf/bpf.h @@ -153,24 +153,27 @@ #define BPF_R7 7 #define BPF_R8 8 #define BPF_R9 9 -#define BPF_SP BPF_R9 #define BPF_R10 10 #define BPF_FP BPF_R10 +#define BPF_R11 11 +#define BPF_R12 12 +#define BPF_SP BPF_R12 + /* 11 is not a real eBPF hard register and is eliminated or not used in the final assembler. See below. */ -#define FIRST_PSEUDO_REGISTER 12 +#define FIRST_PSEUDO_REGISTER 13 /* The registers %r0..%r8 are available for general allocation. - %r9 is the pseudo-stack pointer. %r10 is the stack frame, which is read-only. - %r11 (__arg__) is a fake register that always gets eliminated. */ + %r11 (__arg__) is a fake register that always gets eliminated. + %r12 is the pseudo-stack pointer that always gets eliminated. */ #define FIXED_REGISTERS \ - {0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1} + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1} /* %r0..%r5 are clobbered by function calls. */ #define CALL_USED_REGISTERS \ - {1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1} + {1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1} /**** Register Classes. */ @@ -206,7 +209,7 @@ enum reg_class { \ 0x00000000, /* NO_REGS */ \ 0x00000001, /* R0 */ \ - 0x00000fff, /* ALL_REGS */ \ + 0x00001fff, /* ALL_REGS */ \ } /* A C expression whose value is a register class containing hard @@ -260,15 +263,15 @@ enum reg_class /*** Registers That Address the Stack Frame. */ #define FRAME_POINTER_REGNUM 10 -#define STACK_POINTER_REGNUM 9 #define ARG_POINTER_REGNUM 11 +#define STACK_POINTER_REGNUM 12 #define STATIC_CHAIN_REGNUM 8 /*** Registers elimination. */ #define ELIMINABLE_REGS \ {{ ARG_POINTER_REGNUM, FRAME_POINTER_REGNUM }, \ - { ARG_POINTER_REGNUM, STACK_POINTER_REGNUM }} + { STACK_POINTER_REGNUM, FRAME_POINTER_REGNUM }} /* Define the offset between two registers, one to be eliminated, and the other its replacement, at the start of a routine. */ @@ -444,7 +447,7 @@ enum reg_class #define REGISTER_NAMES \ { "%r0", "%r1", "%r2", "%r3", "%r4", "%r5", "%r6", "%r7", \ - "%r8", "%r9", "%fp", "__arg__" } + "%r8", "%r9", "%fp", "__arg__", "__sp__" } #define ADDITIONAL_REGISTER_NAMES \ { { "%a", 0 }, { "%ctx", 6 }, { "%r10" , 10 } } diff --git a/gcc/config/bpf/bpf.md b/gcc/config/bpf/bpf.md index e9c00e445af3..e87d72182bb8 100644 --- a/gcc/config/bpf/bpf.md +++ b/gcc/config/bpf/bpf.md @@ -115,6 +115,19 @@ "{ja\t0|goto 0}" [(set_attr "type" "alu")]) +;;;; Stack usage + +(define_expand "allocate_stack" + [(match_operand:DI 0 "general_operand" "") + (match_operand:DI 1 "general_operand" "")] + "" + " +{ + error (\"BPF does not support dynamic stack allocation\"); + emit_insn (gen_nop ()); + DONE; +}") + ;;;; Arithmetic/Logical ;; The arithmetic and logic operations below are defined for SI and DI @@ -150,8 +163,8 @@ ;;; Negation (define_insn "neg2" - [(set (match_operand:AM 0 "register_operand" "=r,r") - (neg:AM (match_operand:AM 1 "reg_or_imm_operand" " 0,I")))] + [(set (match_operand:AM 0 "register_operand" "=r") + (neg:AM (match_operand:AM 1 "register_operand" " 0")))] "" "{neg\t%0|%w0 = -%w1}" [(set_attr "type" "")]) @@ -337,13 +350,6 @@ {ldxsb\t%0,%1|%0 = *(s8 *) (%1)}" [(set_attr "type" "alu,ldx")]) -(define_insn "extendsisi2" - [(set (match_operand:SI 0 "register_operand" "=r") - (sign_extend:SI (match_operand:SI 1 "register_operand" "r")))] - "bpf_has_smov" - "{movs32\t%0,%1,32|%w0 = (s32) %w1}" - [(set_attr "type" "alu")]) - (define_insn "extendhisi2" [(set (match_operand:SI 0 "register_operand" "=r") (sign_extend:SI (match_operand:HI 1 "register_operand" "r")))] diff --git a/gcc/config/bpf/bpf.opt b/gcc/config/bpf/bpf.opt index 8e240d397e4c..efa0380ee3f6 100644 --- a/gcc/config/bpf/bpf.opt +++ b/gcc/config/bpf/bpf.opt @@ -38,7 +38,7 @@ Target RejectNegative InverseMask(BIG_ENDIAN) Generate little-endian eBPF. mframe-limit= -Target Joined RejectNegative UInteger IntegerRange(0, 32767) Var(bpf_frame_limit) Init(512) +Target Joined RejectNegative UInteger IntegerRange(0, 32767) Var(bpf_frame_limit) Init(32767) Set a hard limit for the size of each stack frame, in bytes. mco-re diff --git a/gcc/config/bpf/core-builtins.cc b/gcc/config/bpf/core-builtins.cc index 575e63d8ea77..60d21a8ae739 100644 --- a/gcc/config/bpf/core-builtins.cc +++ b/gcc/config/bpf/core-builtins.cc @@ -22,52 +22,23 @@ along with GCC; see the file COPYING3. If not see #include "config.h" #include "system.h" #include "coretypes.h" -#include "tm.h" +#include "target.h" #include "rtl.h" -#include "regs.h" -#include "insn-config.h" -#include "insn-attr.h" -#include "recog.h" #include "output.h" -#include "alias.h" #include "tree.h" #include "stringpool.h" #include "attribs.h" -#include "varasm.h" -#include "stor-layout.h" -#include "calls.h" #include "function.h" -#include "explow.h" #include "memmodel.h" #include "emit-rtl.h" -#include "reload.h" -#include "tm_p.h" -#include "target.h" -#include "basic-block.h" #include "expr.h" -#include "optabs.h" -#include "bitmap.h" -#include "df.h" -#include "c-family/c-common.h" #include "diagnostic.h" -#include "builtins.h" -#include "predict.h" #include "langhooks.h" -#include "flags.h" - -#include "cfg.h" +#include "basic-block.h" #include "gimple.h" #include "gimple-iterator.h" #include "gimple-walk.h" #include "tree-pass.h" -#include "tree-iterator.h" - -#include "context.h" -#include "pass_manager.h" - -#include "gimplify.h" -#include "gimplify-me.h" - #include "plugin.h" #include "ctfc.h" @@ -159,37 +130,41 @@ along with GCC; see the file COPYING3. If not see as a builtin. */ -struct cr_builtins +struct GTY(()) cr_builtins { tree type; tree expr; tree default_value; rtx rtx_default_value; - enum btf_core_reloc_kind kind; /* Recovered from proper argument. */ + enum btf_core_reloc_kind kind; enum bpf_builtins orig_builtin_code; tree orig_arg_expr; }; +typedef struct cr_builtins *cr_builtins_ref; #define CORE_BUILTINS_DATA_EMPTY \ { NULL_TREE, NULL_TREE, NULL_TREE, NULL_RTX, BPF_RELO_INVALID, \ BPF_BUILTIN_UNUSED, NULL } /* Vector definition and its access function. */ -vec builtins_data; +static GTY(()) vec *builtins_data = NULL; static inline int allocate_builtin_data () { - struct cr_builtins data = CORE_BUILTINS_DATA_EMPTY; - int ret = builtins_data.length (); - builtins_data.safe_push (data); + if (builtins_data == NULL) + vec_alloc (builtins_data, 1); + + cr_builtins_ref data = ggc_cleared_alloc (); + int ret = builtins_data->length (); + vec_safe_push (builtins_data, data); return ret; } static inline struct cr_builtins * get_builtin_data (int index) { - return &builtins_data[index]; + return (*builtins_data)[index]; } typedef bool @@ -200,11 +175,12 @@ search_builtin_data (builtin_local_data_compare_fn callback, struct cr_builtins *elem) { unsigned int i; - for (i = 0; i < builtins_data.length (); i++) - if ((callback != NULL && (callback) (elem, &builtins_data[i])) - || (callback == NULL - && (builtins_data[i].orig_arg_expr == elem->orig_arg_expr))) - return (int) i; + if (builtins_data != NULL) + for (i = 0; i < builtins_data->length (); i++) + if ((callback != NULL && (callback) (elem, (*builtins_data)[i])) + || (callback == NULL + && ((*builtins_data)[i]->orig_arg_expr == elem->orig_arg_expr))) + return (int) i; return -1; } @@ -1392,3 +1368,5 @@ bpf_replace_core_move_operands (rtx *operands) } } } + +#include "gt-core-builtins.h" diff --git a/gcc/config/bpf/coreout.cc b/gcc/config/bpf/coreout.cc index b84585fb104e..0c5d166298fb 100644 --- a/gcc/config/bpf/coreout.cc +++ b/gcc/config/bpf/coreout.cc @@ -147,11 +147,12 @@ static char btf_ext_info_section_label[MAX_BTF_EXT_LABEL_BYTES]; static GTY (()) vec *bpf_core_sections; -struct bpf_core_extra { +struct GTY(()) bpf_core_extra { const char *accessor_str; tree type; }; -static hash_map bpf_comment_info; +typedef struct bpf_core_extra *bpf_core_extra_ref; +static GTY(()) hash_map *bpf_comment_info; /* Create a new BPF CO-RE relocation record, and add it to the appropriate CO-RE section. */ @@ -162,7 +163,7 @@ bpf_core_reloc_add (const tree type, const char * section_name, enum btf_core_reloc_kind kind) { bpf_core_reloc_ref bpfcr = ggc_cleared_alloc (); - struct bpf_core_extra *info = ggc_cleared_alloc (); + bpf_core_extra_ref info = ggc_cleared_alloc (); ctf_container_ref ctfc = ctf_get_tu_ctfc (); /* Buffer the access string in the auxiliary strtab. */ @@ -173,7 +174,7 @@ bpf_core_reloc_add (const tree type, const char * section_name, info->accessor_str = accessor; info->type = type; - bpf_comment_info.put (bpfcr, info); + bpf_comment_info->put (bpfcr, info); /* Add the CO-RE reloc to the appropriate section. */ bpf_core_section_ref sec; @@ -288,7 +289,7 @@ output_btfext_header (void) static void output_asm_btfext_core_reloc (bpf_core_reloc_ref bpfcr) { - struct bpf_core_extra **info = bpf_comment_info.get (bpfcr); + bpf_core_extra_ref *info = bpf_comment_info->get (bpfcr); gcc_assert (info != NULL); bpfcr->bpfcr_astr_off += ctfc_get_strtab_len (ctf_get_tu_ctfc (), @@ -365,6 +366,7 @@ btf_ext_init (void) btf_ext_label_num++); vec_alloc (bpf_core_sections, 1); + bpf_comment_info = hash_map::create_ggc (); } /* Output the entire .BTF.ext section. */ diff --git a/gcc/config/c6x/c6x.cc b/gcc/config/c6x/c6x.cc index 0c9cb821f28c..72e8b4c5345a 100644 --- a/gcc/config/c6x/c6x.cc +++ b/gcc/config/c6x/c6x.cc @@ -2444,7 +2444,8 @@ c6x_legitimate_address_p_1 (machine_mode mode, rtx x, bool strict, } static bool -c6x_legitimate_address_p (machine_mode mode, rtx x, bool strict) +c6x_legitimate_address_p (machine_mode mode, rtx x, bool strict, + code_helper = ERROR_MARK) { return c6x_legitimate_address_p_1 (mode, x, strict, false); } diff --git a/gcc/config/cris/cris.cc b/gcc/config/cris/cris.cc index f04f501326e7..8b0f82e98107 100644 --- a/gcc/config/cris/cris.cc +++ b/gcc/config/cris/cris.cc @@ -168,6 +168,8 @@ static unsigned int cris_hard_regno_nregs (unsigned int, machine_mode); static bool cris_hard_regno_mode_ok (unsigned int, machine_mode); static HOST_WIDE_INT cris_static_rtx_alignment (machine_mode); static HOST_WIDE_INT cris_constant_alignment (const_tree, HOST_WIDE_INT); +static bool cris_legitimate_address_p_hook (machine_mode, rtx, bool, + code_helper); /* This is the parsed result of the "-max-stack-stackframe=" option. If it (still) is zero, then there was no such option given. */ @@ -217,7 +219,7 @@ int cris_cpu_version = CRIS_DEFAULT_CPU_VERSION; #define TARGET_INIT_LIBFUNCS cris_init_libfuncs #undef TARGET_LEGITIMATE_ADDRESS_P -#define TARGET_LEGITIMATE_ADDRESS_P cris_legitimate_address_p +#define TARGET_LEGITIMATE_ADDRESS_P cris_legitimate_address_p_hook #undef TARGET_PREFERRED_RELOAD_CLASS #define TARGET_PREFERRED_RELOAD_CLASS cris_preferred_reload_class @@ -1536,6 +1538,13 @@ cris_biap_index_p (const_rtx x, bool strict) /* Worker function for TARGET_LEGITIMATE_ADDRESS_P. */ +static bool +cris_legitimate_address_p_hook (machine_mode mode, rtx x, bool strict, + code_helper) +{ + return cris_legitimate_address_p (mode, x, strict); +} + bool cris_legitimate_address_p (machine_mode mode, rtx x, bool strict) { diff --git a/gcc/config/csky/csky.cc b/gcc/config/csky/csky.cc index b4ee3b273a45..731f47cb2c0b 100644 --- a/gcc/config/csky/csky.cc +++ b/gcc/config/csky/csky.cc @@ -3186,7 +3186,8 @@ csky_legitimate_index_p (machine_mode mode, rtx index, int strict_p) be recognized. */ static bool -csky_legitimate_address_p (machine_mode mode, rtx addr, bool strict_p) +csky_legitimate_address_p (machine_mode mode, rtx addr, bool strict_p, + code_helper = ERROR_MARK) { enum rtx_code code = GET_CODE (addr); diff --git a/gcc/config/darwin-c.cc b/gcc/config/darwin-c.cc index ded0cd46c762..4be1d5ce51b0 100644 --- a/gcc/config/darwin-c.cc +++ b/gcc/config/darwin-c.cc @@ -555,7 +555,7 @@ find_subframework_header (cpp_reader *pfile, const char *header, cpp_dir **dirp) return 0; } -/* Given an OS X version VERSION_STR, return it as a statically-allocated array +/* Given an macOS version VERSION_STR, return it as a statically-allocated array of three integers. If VERSION_STR is invalid, return NULL. VERSION_STR must consist of one, two, or three tokens, each separated by @@ -612,7 +612,7 @@ parse_version (const char *version_str) return version_array; } -/* Given VERSION -- a three-component OS X version represented as an array of +/* Given VERSION -- a three-component macOS version represented as an array of non-negative integers -- return a statically-allocated string suitable for the legacy __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ macro. If VERSION is invalid and cannot be coerced into a valid form, return NULL. @@ -645,7 +645,7 @@ version_as_legacy_macro (const unsigned long *version) return result; } -/* Given VERSION -- a three-component OS X version represented as an array of +/* Given VERSION -- a three-component macOS version represented as an array of non-negative integers -- return a statically-allocated string suitable for the modern __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ macro. If VERSION is invalid, return NULL. @@ -675,7 +675,7 @@ version_as_modern_macro (const unsigned long *version) /* Return the value of darwin_macosx_version_min, suitably formatted for the __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ macro. Values representing - OS X 10.9 and earlier are encoded using the legacy four-character format, + macOS 10.9 and earlier are encoded using the legacy four-character format, while 10.10 and later use a modern six-character format. (For example, "10.9" produces "1090", and "10.10.1" produces "101001".) If darwin_macosx_version_min is invalid and cannot be coerced into a valid diff --git a/gcc/config/darwin-driver.cc b/gcc/config/darwin-driver.cc index 9c1dcc3d7949..1028e152a182 100644 --- a/gcc/config/darwin-driver.cc +++ b/gcc/config/darwin-driver.cc @@ -440,7 +440,7 @@ darwin_driver_init (unsigned int *decoded_options_count, } } - /* We will need to know the OS X version we're trying to build for here + /* We will need to know the macOS version we're trying to build for here so that we can figure out the mechanism and source for the sysroot to be used. */ if (!seen_version_min) diff --git a/gcc/config/darwin-sections.def b/gcc/config/darwin-sections.def index 62a51b9761cc..7e1b4710bd68 100644 --- a/gcc/config/darwin-sections.def +++ b/gcc/config/darwin-sections.def @@ -98,6 +98,8 @@ DEF_SECTION (mod_init_section, 0, ".mod_init_func", 0) DEF_SECTION (mod_term_section, 0, ".mod_term_func", 0) DEF_SECTION (constructor_section, 0, ".constructor", 0) DEF_SECTION (destructor_section, 0, ".destructor", 0) +DEF_SECTION (static_init_section, SECTION_CODE, + ".section\t__TEXT,__StaticInit,regular,pure_instructions", 0) /* Objective-C ABI=0 (Original version) sections. */ DEF_SECTION (objc_class_section, 0, ".objc_class", 1) @@ -157,7 +159,7 @@ DEF_SECTION (machopic_picsymbol_stub3_section, SECTION_NO_ANCHOR, /* Exception-related. */ DEF_SECTION (darwin_exception_section, SECTION_NO_ANCHOR, - ".section __DATA,__gcc_except_tab", 0) + ".section __TEXT,__gcc_except_tab", 0) DEF_SECTION (darwin_eh_frame_section, SECTION_NO_ANCHOR, ".section " EH_FRAME_SECTION_NAME ",__eh_frame" EH_FRAME_SECTION_ATTR, 0) diff --git a/gcc/config/darwin.cc b/gcc/config/darwin.cc index efbcb3856ca6..95d6194cf22d 100644 --- a/gcc/config/darwin.cc +++ b/gcc/config/darwin.cc @@ -258,6 +258,45 @@ name_needs_quotes (const char *name) return 0; } +DEBUG_FUNCTION void +dump_machopic_symref_flags (FILE *dump, rtx sym_ref) +{ + unsigned long flags = SYMBOL_REF_FLAGS (sym_ref); + + fprintf (dump, "flags: %08lx %c%c%c%c%c%c%c", + flags, + (MACHO_SYMBOL_STATIC_P (sym_ref) ? 's' : '-'), + (MACHO_SYMBOL_INDIRECTION_P (sym_ref) ? 'I' : '-'), + (MACHO_SYMBOL_LINKER_VIS_P (sym_ref) ? 'l' : '-'), + (MACHO_SYMBOL_HIDDEN_VIS_P (sym_ref) ? 'h' : '-'), + (MACHO_SYMBOL_DEFINED_P (sym_ref) ? 'd' : '-'), + (MACHO_SYMBOL_MUST_INDIRECT_P (sym_ref) ? 'i' : '-'), + (MACHO_SYMBOL_VARIABLE_P (sym_ref) ? 'v' : '-')); + +#if (DARWIN_X86) + fprintf (dump, "%c%c%c%c", + (SYMBOL_REF_STUBVAR_P (sym_ref) ? 'S' : '-'), + (SYMBOL_REF_DLLEXPORT_P (sym_ref) ? 'X' : '-'), + (SYMBOL_REF_DLLIMPORT_P (sym_ref) ? 'I' : '-'), + (SYMBOL_REF_FAR_ADDR_P (sym_ref) ? 'F' : '-')); +#endif + + fprintf (dump, "%c%c%c%03u%c%c%c\n", + (SYMBOL_REF_ANCHOR_P (sym_ref) ? 'a' : '-'), + (SYMBOL_REF_HAS_BLOCK_INFO_P (sym_ref) ? 'b' : '-'), + (SYMBOL_REF_EXTERNAL_P (sym_ref) ? 'e' : '-'), + (unsigned)SYMBOL_REF_TLS_MODEL (sym_ref), + (SYMBOL_REF_SMALL_P (sym_ref) ? 'm' : '-'), + (SYMBOL_REF_LOCAL_P (sym_ref) ? 'l' : '-'), + (SYMBOL_REF_FUNCTION_P (sym_ref) ? 'f' : '-')); +} + +DEBUG_FUNCTION void +debug_machopic_symref_flags (rtx sym_ref) +{ + dump_machopic_symref_flags (stderr, sym_ref); +} + /* Return true if SYM_REF can be used without an indirection. */ int machopic_symbol_defined_p (rtx sym_ref) @@ -2232,6 +2271,7 @@ darwin_emit_except_table_label (FILE *file) { char section_start_label[30]; + fputs ("\t.p2align\t2\n", file); ASM_GENERATE_INTERNAL_LABEL (section_start_label, "GCC_except_table", except_table_label_num++); ASM_OUTPUT_LABEL (file, section_start_label); @@ -3853,6 +3893,14 @@ darwin_function_section (tree decl, enum node_frequency freq, if (decl && DECL_SECTION_NAME (decl) != NULL) return get_named_section (decl, NULL, 0); + /* Intercept functions in global init; these are placed in separate sections. + FIXME: there should be some neater way to do this. */ + if (DECL_NAME (decl) + && (startswith (IDENTIFIER_POINTER (DECL_NAME (decl)), "_GLOBAL__sub_I") + || startswith (IDENTIFIER_POINTER (DECL_NAME (decl)), + "__static_initialization_and_destruction"))) + return darwin_sections[static_init_section]; + /* We always put unlikely executed stuff in the cold section. */ if (freq == NODE_FREQUENCY_UNLIKELY_EXECUTED) return (use_coal) ? darwin_sections[text_cold_coal_section] diff --git a/gcc/config/darwin.h b/gcc/config/darwin.h index e0e8672a455b..b7cfab607dbb 100644 --- a/gcc/config/darwin.h +++ b/gcc/config/darwin.h @@ -1,4 +1,4 @@ -/* Target definitions for Darwin (Mac OS X) systems. +/* Target definitions for Darwin (macOS) systems. Copyright (C) 1989-2023 Free Software Foundation, Inc. Contributed by Apple Computer Inc. @@ -27,7 +27,7 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see #define CONFIG_DARWIN_H /* The definitions in this file are common to all processor types - running Darwin, which is the kernel for Mac OS X. Darwin is + running Darwin, which is the kernel for macOS. Darwin is basically a BSD user layer laid over a Mach kernel, then evolved for many years (at NeXT) in parallel with other Unix systems. So while the runtime is a somewhat idiosyncratic Mach-based thing, @@ -1089,7 +1089,7 @@ enum machopic_addr_class { #undef ASM_PREFERRED_EH_DATA_FORMAT #define ASM_PREFERRED_EH_DATA_FORMAT(CODE,GLOBAL) \ - (((CODE) == 2 && (GLOBAL) == 1) \ + (((CODE) == 2 && (GLOBAL) == 1) || ((CODE) == 0 && (GLOBAL) == 1) \ ? (DW_EH_PE_pcrel | DW_EH_PE_indirect | DW_EH_PE_sdata4) : \ ((CODE) == 1 || (GLOBAL) == 0) ? DW_EH_PE_pcrel : DW_EH_PE_absptr) diff --git a/gcc/config/epiphany/epiphany.cc b/gcc/config/epiphany/epiphany.cc index 60a2845d6d15..a5460dbf97f5 100644 --- a/gcc/config/epiphany/epiphany.cc +++ b/gcc/config/epiphany/epiphany.cc @@ -2053,7 +2053,8 @@ epiphany_adjust_cost (rtx_insn *insn, int dep_type, rtx_insn *dep_insn, || RTX_OK_FOR_OFFSET_P (MODE, XEXP (X, 1)))) static bool -epiphany_legitimate_address_p (machine_mode mode, rtx x, bool strict) +epiphany_legitimate_address_p (machine_mode mode, rtx x, bool strict, + code_helper = ERROR_MARK) { #define REG_OK_FOR_BASE_P(X) \ (strict ? GPR_P (REGNO (X)) : GPR_AP_OR_PSEUDO_P (REGNO (X))) diff --git a/gcc/config/frv/frv.cc b/gcc/config/frv/frv.cc index 2dbaa75f3dc5..03976ba7b715 100644 --- a/gcc/config/frv/frv.cc +++ b/gcc/config/frv/frv.cc @@ -261,7 +261,8 @@ static frv_stack_t *frv_stack_cache = (frv_stack_t *)0; /* Forward references */ static void frv_option_override (void); -static bool frv_legitimate_address_p (machine_mode, rtx, bool); +static bool frv_legitimate_address_p (machine_mode, rtx, bool, + code_helper = ERROR_MARK); static int frv_default_flags_for_cpu (void); static FRV_INLINE bool frv_small_data_reloc_p (rtx, int); static void frv_print_operand (FILE *, rtx, int); @@ -3396,7 +3397,7 @@ frv_legitimate_address_p_1 (machine_mode mode, } bool -frv_legitimate_address_p (machine_mode mode, rtx x, bool strict_p) +frv_legitimate_address_p (machine_mode mode, rtx x, bool strict_p, code_helper) { return frv_legitimate_address_p_1 (mode, x, strict_p, FALSE, FALSE); } diff --git a/gcc/config/ft32/ft32.cc b/gcc/config/ft32/ft32.cc index 806ab769f795..059243d2a3df 100644 --- a/gcc/config/ft32/ft32.cc +++ b/gcc/config/ft32/ft32.cc @@ -856,7 +856,8 @@ reg_ok_for_base_p (rtx r, bool strict) static bool ft32_addr_space_legitimate_address_p (machine_mode mode, rtx x, bool strict, - addr_space_t as ATTRIBUTE_UNUSED) + addr_space_t as ATTRIBUTE_UNUSED, + code_helper = ERROR_MARK) { int max_offset = TARGET_FT32B ? 16384 : 128; diff --git a/gcc/config/gcn/gcn.cc b/gcc/config/gcn/gcn.cc index 02f4dedec421..f6cff6597031 100644 --- a/gcc/config/gcn/gcn.cc +++ b/gcc/config/gcn/gcn.cc @@ -1654,7 +1654,7 @@ gcn_global_address_p (rtx addr) static bool gcn_addr_space_legitimate_address_p (machine_mode mode, rtx x, bool strict, - addr_space_t as) + addr_space_t as, code_helper = ERROR_MARK) { /* All vector instructions need to work on addresses in registers. */ if (!TARGET_GCN5_PLUS && (vgpr_vector_mode_p (mode) && !REG_P (x))) diff --git a/gcc/config/h8300/h8300.cc b/gcc/config/h8300/h8300.cc index cdf74c1acbd1..4bbb1b711e8c 100644 --- a/gcc/config/h8300/h8300.cc +++ b/gcc/config/h8300/h8300.cc @@ -5312,7 +5312,8 @@ h8300_rtx_ok_for_base_p (rtx x, int strict) CONSTANT_ADDRESS. */ static bool -h8300_legitimate_address_p (machine_mode mode, rtx x, bool strict) +h8300_legitimate_address_p (machine_mode mode, rtx x, bool strict, + code_helper = ERROR_MARK) { /* The register indirect addresses like @er0 is always valid. */ if (h8300_rtx_ok_for_base_p (x, strict)) diff --git a/gcc/config/i386/i386-builtins.cc b/gcc/config/i386/i386-builtins.cc index 356b6dfd5fb9..8a0b8dfe0735 100644 --- a/gcc/config/i386/i386-builtins.cc +++ b/gcc/config/i386/i386-builtins.cc @@ -1657,7 +1657,7 @@ ix86_vectorize_builtin_gather (const_tree mem_vectype, ? !TARGET_USE_GATHER_2PARTS : (known_eq (TYPE_VECTOR_SUBPARTS (mem_vectype), 4u) ? !TARGET_USE_GATHER_4PARTS - : !TARGET_USE_GATHER))) + : !TARGET_USE_GATHER_8PARTS))) return NULL_TREE; if ((TREE_CODE (index_type) != INTEGER_TYPE diff --git a/gcc/config/i386/i386-c.cc b/gcc/config/i386/i386-c.cc index 257950582c28..47768fa09405 100644 --- a/gcc/config/i386/i386-c.cc +++ b/gcc/config/i386/i386-c.cc @@ -258,6 +258,10 @@ ix86_target_macros_internal (HOST_WIDE_INT isa_flag, def_or_undef (parse_in, "__graniterapids"); def_or_undef (parse_in, "__graniterapids__"); break; + case PROCESSOR_GRANITERAPIDS_D: + def_or_undef (parse_in, "__graniterapids_d"); + def_or_undef (parse_in, "__graniterapids_d__"); + break; case PROCESSOR_ALDERLAKE: def_or_undef (parse_in, "__alderlake"); def_or_undef (parse_in, "__alderlake__"); @@ -270,6 +274,11 @@ ix86_target_macros_internal (HOST_WIDE_INT isa_flag, def_or_undef (parse_in, "__arrowlake"); def_or_undef (parse_in, "__arrowlake__"); break; + case PROCESSOR_ARROWLAKE_S: + def_or_undef (parse_in, "__arrowlake_s"); + def_or_undef (parse_in, "__arrowlake_s__"); + break; + /* use PROCESSOR_max to not set/unset the arch macro. */ case PROCESSOR_max: break; @@ -451,9 +460,15 @@ ix86_target_macros_internal (HOST_WIDE_INT isa_flag, case PROCESSOR_GRANITERAPIDS: def_or_undef (parse_in, "__tune_graniterapids__"); break; + case PROCESSOR_GRANITERAPIDS_D: + def_or_undef (parse_in, "__tune_graniterapids_d__"); + break; case PROCESSOR_ARROWLAKE: def_or_undef (parse_in, "__tune_arrowlake__"); break; + case PROCESSOR_ARROWLAKE_S: + def_or_undef (parse_in, "__tune_arrowlake_s__"); + break; case PROCESSOR_INTEL: case PROCESSOR_GENERIC: break; diff --git a/gcc/config/i386/i386-expand.cc b/gcc/config/i386/i386-expand.cc index e9dc0bc2e9d7..cbd51a0f362f 100644 --- a/gcc/config/i386/i386-expand.cc +++ b/gcc/config/i386/i386-expand.cc @@ -1124,8 +1124,9 @@ ix86_split_mmx_punpck (rtx operands[], bool high_p) switch (mode) { - case E_V4QImode: case E_V8QImode: + case E_V4QImode: + case E_V2QImode: sse_mode = V16QImode; double_sse_mode = V32QImode; mask = gen_rtx_PARALLEL (VOIDmode, @@ -5636,7 +5637,43 @@ ix86_expand_vec_perm (rtx operands[]) } } -/* Unpack OP[1] into the next wider integer vector type. UNSIGNED_P is +/* Extend SRC into next wider integer vector type. UNSIGNED_P is + true if we should do zero extension, else sign extension. */ + +void +ix86_expand_sse_extend (rtx dest, rtx src, bool unsigned_p) +{ + machine_mode imode = GET_MODE (src); + rtx ops[3]; + + switch (imode) + { + case E_V8QImode: + case E_V4QImode: + case E_V2QImode: + case E_V4HImode: + case E_V2HImode: + case E_V2SImode: + break; + default: + gcc_unreachable (); + } + + ops[0] = gen_reg_rtx (imode); + + ops[1] = force_reg (imode, src); + + if (unsigned_p) + ops[2] = force_reg (imode, CONST0_RTX (imode)); + else + ops[2] = ix86_expand_sse_cmp (gen_reg_rtx (imode), GT, CONST0_RTX (imode), + ops[1], pc_rtx, pc_rtx); + + ix86_split_mmx_punpck (ops, false); + emit_move_insn (dest, lowpart_subreg (GET_MODE (dest), ops[0], imode)); +} + +/* Unpack SRC into the next wider integer vector type. UNSIGNED_P is true if we should do zero extension, else sign extension. HIGH_P is true if we want the N/2 high elements, else the low elements. */ diff --git a/gcc/config/i386/i386-options.cc b/gcc/config/i386/i386-options.cc index 127ee24203cd..e47f9ed5d5f3 100644 --- a/gcc/config/i386/i386-options.cc +++ b/gcc/config/i386/i386-options.cc @@ -127,10 +127,11 @@ along with GCC; see the file COPYING3. If not see #define m_ALDERLAKE (HOST_WIDE_INT_1U<: %s", - clear ? curr_feature_string - 1 : curr_feature_string); + + if (!strcmp (curr_feature_string, "use_gather")) + { + ix86_tune_features[X86_TUNE_USE_GATHER_2PARTS] = !clear; + ix86_tune_features[X86_TUNE_USE_GATHER_4PARTS] = !clear; + ix86_tune_features[X86_TUNE_USE_GATHER_8PARTS] = !clear; + if (dump) + fprintf (stderr, "Explicitly %s features use_gather_2parts," + " use_gather_4parts, use_gather_8parts\n", + clear ? "clear" : "set"); + + } + else if (!strcmp (curr_feature_string, "use_scatter")) + { + ix86_tune_features[X86_TUNE_USE_SCATTER_2PARTS] = !clear; + ix86_tune_features[X86_TUNE_USE_SCATTER_4PARTS] = !clear; + ix86_tune_features[X86_TUNE_USE_SCATTER_8PARTS] = !clear; + if (dump) + fprintf (stderr, "Explicitly %s features use_scatter_2parts," + " use_scatter_4parts, use_scatter_8parts\n", + clear ? "clear" : "set"); + } + else + { + for (i = 0; i < X86_TUNE_LAST; i++) + { + if (!strcmp (curr_feature_string, ix86_tune_feature_names[i])) + { + ix86_tune_features[i] = !clear; + if (dump) + fprintf (stderr, "Explicitly %s feature %s\n", + clear ? "clear" : "set", ix86_tune_feature_names[i]); + break; + } + } + + if (i == X86_TUNE_LAST) + error ("unknown parameter to option %<-mtune-ctrl%>: %s", + clear ? curr_feature_string - 1 : curr_feature_string); + } curr_feature_string = next_feature_string; } while (curr_feature_string); diff --git a/gcc/config/i386/i386-protos.h b/gcc/config/i386/i386-protos.h index fc2f1f13b78f..9ffb125fc2b1 100644 --- a/gcc/config/i386/i386-protos.h +++ b/gcc/config/i386/i386-protos.h @@ -155,6 +155,7 @@ extern bool ix86_expand_mask_vec_cmp (rtx, enum rtx_code, rtx, rtx); extern bool ix86_expand_int_vec_cmp (rtx[]); extern bool ix86_expand_fp_vec_cmp (rtx[]); extern void ix86_expand_sse_movcc (rtx, rtx, rtx, rtx); +extern void ix86_expand_sse_extend (rtx, rtx, bool); extern void ix86_expand_sse_unpack (rtx, rtx, bool, bool); extern void ix86_expand_fp_spaceship (rtx, rtx, rtx); extern bool ix86_expand_int_addcc (rtx[]); diff --git a/gcc/config/i386/i386.cc b/gcc/config/i386/i386.cc index 50860050049f..1bc3f11ff078 100644 --- a/gcc/config/i386/i386.cc +++ b/gcc/config/i386/i386.cc @@ -11040,7 +11040,8 @@ ix86_validate_address_register (rtx op) be recognized. */ static bool -ix86_legitimate_address_p (machine_mode, rtx addr, bool strict) +ix86_legitimate_address_p (machine_mode, rtx addr, bool strict, + code_helper = ERROR_MARK) { struct ix86_address parts; rtx base, index, disp; @@ -19192,7 +19193,7 @@ ix86_vectorize_builtin_scatter (const_tree vectype, ? !TARGET_USE_SCATTER_2PARTS : (known_eq (TYPE_VECTOR_SUBPARTS (vectype), 4u) ? !TARGET_USE_SCATTER_4PARTS - : !TARGET_USE_SCATTER)) + : !TARGET_USE_SCATTER_8PARTS)) return NULL_TREE; if ((TREE_CODE (index_type) != INTEGER_TYPE @@ -22888,9 +22889,9 @@ ix86_invalid_conversion (const_tree fromtype, const_tree totype) || (TYPE_MODE (totype) == BFmode && TYPE_MODE (fromtype) == HImode)) warning (0, "%<__bfloat16%> is redefined from typedef % " - "to real %<__bf16%> since GCC V13, be careful of " + "to real %<__bf16%> since GCC 13.1, be careful of " "implicit conversion between %<__bf16%> and %; " - "a explicit bitcast may be needed here"); + "an explicit bitcast may be needed here"); } /* Conversion allowed. */ diff --git a/gcc/config/i386/i386.h b/gcc/config/i386/i386.h index ef342fcee9b3..3e8488f2ae8b 100644 --- a/gcc/config/i386/i386.h +++ b/gcc/config/i386/i386.h @@ -403,10 +403,10 @@ extern unsigned char ix86_tune_features[X86_TUNE_LAST]; ix86_tune_features[X86_TUNE_USE_GATHER_4PARTS] #define TARGET_USE_SCATTER_4PARTS \ ix86_tune_features[X86_TUNE_USE_SCATTER_4PARTS] -#define TARGET_USE_GATHER \ - ix86_tune_features[X86_TUNE_USE_GATHER] -#define TARGET_USE_SCATTER \ - ix86_tune_features[X86_TUNE_USE_SCATTER] +#define TARGET_USE_GATHER_8PARTS \ + ix86_tune_features[X86_TUNE_USE_GATHER_8PARTS] +#define TARGET_USE_SCATTER_8PARTS \ + ix86_tune_features[X86_TUNE_USE_SCATTER_8PARTS] #define TARGET_FUSE_CMP_AND_BRANCH_32 \ ix86_tune_features[X86_TUNE_FUSE_CMP_AND_BRANCH_32] #define TARGET_FUSE_CMP_AND_BRANCH_64 \ @@ -2200,7 +2200,7 @@ extern int const svr4_debugger_register_map[FIRST_PSEUDO_REGISTER]; #define DEFAULT_LARGE_SECTION_THRESHOLD 65536 /* Which processor to tune code generation for. These must be in sync - with processor_target_table in i386.cc. */ + with processor_cost_table in i386-options.cc. */ enum processor_type { @@ -2237,7 +2237,9 @@ enum processor_type PROCESSOR_ALDERLAKE, PROCESSOR_ROCKETLAKE, PROCESSOR_GRANITERAPIDS, + PROCESSOR_GRANITERAPIDS_D, PROCESSOR_ARROWLAKE, + PROCESSOR_ARROWLAKE_S, PROCESSOR_INTEL, PROCESSOR_LUJIAZUI, PROCESSOR_GEODE, diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md index c906d75b13e9..eef8a0e01ebf 100644 --- a/gcc/config/i386/i386.md +++ b/gcc/config/i386/i386.md @@ -2961,8 +2961,12 @@ ] (const_string "TI")) (eq_attr "alternative" "12") - (cond [(match_test "TARGET_AVX512FP16") + (cond [(match_test "TARGET_AVX512VL") + (const_string "TI") + (match_test "TARGET_AVX512FP16") (const_string "HF") + (match_test "TARGET_AVX512F") + (const_string "SF") (match_test "TARGET_AVX") (const_string "TI") (ior (not (match_test "TARGET_SSE2")) @@ -4099,8 +4103,12 @@ /* movaps is one byte shorter for non-AVX targets. */ (eq_attr "alternative" "13,17") - (cond [(match_test "TARGET_AVX") + (cond [(match_test "TARGET_AVX512VL") + (const_string "V2DF") + (match_test "TARGET_AVX512F") (const_string "DF") + (match_test "TARGET_AVX") + (const_string "V2DF") (ior (not (match_test "TARGET_SSE2")) (match_test "optimize_function_for_size_p (cfun)")) (const_string "V4SF") @@ -4380,8 +4388,14 @@ (const_string "HI") (const_string "TI")) (eq_attr "alternative" "5") - (cond [(match_test "TARGET_AVX512FP16") + (cond [(match_test "TARGET_AVX512VL") + (const_string "V4SF") + (match_test "TARGET_AVX512FP16") (const_string "HF") + (match_test "TARGET_AVX512F") + (const_string "SF") + (match_test "TARGET_AVX") + (const_string "V4SF") (ior (match_test "TARGET_SSE_PARTIAL_REG_DEPENDENCY") (match_test "TARGET_SSE_SPLIT_REGS")) (const_string "V4SF") @@ -12416,17 +12430,16 @@ DONE; }) -(define_insn_and_split "*concatditi3_3" - [(set (match_operand:TI 0 "nonimmediate_operand" "=ro,r,r,&r,x") - (any_or_plus:TI - (ashift:TI - (zero_extend:TI - (match_operand:DI 1 "nonimmediate_operand" "r,m,r,m,x")) +(define_insn_and_split "*concat3_3" + [(set (match_operand: 0 "nonimmediate_operand" "=ro,r,r,&r,x") + (any_or_plus: + (ashift: + (zero_extend: + (match_operand:DWIH 1 "nonimmediate_operand" "r,m,r,m,x")) (match_operand:QI 2 "const_int_operand")) - (zero_extend:TI - (match_operand:DI 3 "nonimmediate_operand" "r,r,m,m,0"))))] - "TARGET_64BIT - && INTVAL (operands[2]) == 64" + (zero_extend: + (match_operand:DWIH 3 "nonimmediate_operand" "r,r,m,m,0"))))] + "INTVAL (operands[2]) == * BITS_PER_UNIT" "#" "&& reload_completed" [(const_int 0)] @@ -12437,28 +12450,10 @@ emit_insn (gen_vec_concatv2di (tmp, operands[3], operands[1])); } else - split_double_concat (TImode, operands[0], operands[3], operands[1]); + split_double_concat (mode, operands[0], operands[3], operands[1]); DONE; -}) - -(define_insn_and_split "*concatsidi3_3" - [(set (match_operand:DI 0 "nonimmediate_operand" "=ro,r,r,&r") - (any_or_plus:DI - (ashift:DI - (zero_extend:DI - (match_operand:SI 1 "nonimmediate_operand" "r,m,r,m")) - (match_operand:QI 2 "const_int_operand")) - (zero_extend:DI - (match_operand:SI 3 "nonimmediate_operand" "r,r,m,m"))))] - "!TARGET_64BIT - && INTVAL (operands[2]) == 32" - "#" - "&& reload_completed" - [(const_int 0)] -{ - split_double_concat (DImode, operands[0], operands[3], operands[1]); - DONE; -}) +} + [(set_attr "isa" "*,*,*,x64,x64")]) (define_insn_and_split "*concat3_4" [(set (match_operand: 0 "nonimmediate_operand" "=ro,r,r,&r") @@ -12476,7 +12471,8 @@ { split_double_concat (mode, operands[0], operands[1], operands[2]); DONE; -}) +} + [(set_attr "isa" "*,*,*,x64")]) (define_insn_and_split "*concat3_5" [(set (match_operand:DWI 0 "nonimmediate_operand" "=r,o,o") diff --git a/gcc/config/i386/i386.opt b/gcc/config/i386/i386.opt index 1cc8563477a9..78b499304a4d 100644 --- a/gcc/config/i386/i386.opt +++ b/gcc/config/i386/i386.opt @@ -632,6 +632,10 @@ Enum(prefer_vector_width) String(256) Value(PVW_AVX256) EnumValue Enum(prefer_vector_width) String(512) Value(PVW_AVX512) +mpartial-vector-fp-math +Target Var(ix86_partial_vec_fp_math) Init(1) +Enable floating-point status flags setting SSE vector operations on partial vectors. + mmove-max= Target RejectNegative Joined Var(ix86_move_max) Enum(prefer_vector_width) Init(PVW_NONE) Save Maximum number of bits that can be moved from memory to memory efficiently. @@ -1298,3 +1302,11 @@ msm4 Target Mask(ISA2_SM4) Var(ix86_isa_flags2) Save Support MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, AVX and SM4 built-in functions and code generation. + +mgather +Target Alias(mtune-ctrl=, use_gather, ^use_gather) +Enable vectorization for gather instruction. + +mscatter +Target Alias(mtune-ctrl=, use_scatter, ^use_scatter) +Enable vectorization for scatter instruction. diff --git a/gcc/config/i386/mmx.md b/gcc/config/i386/mmx.md index b49554e9b8f6..ef5782229451 100644 --- a/gcc/config/i386/mmx.md +++ b/gcc/config/i386/mmx.md @@ -595,7 +595,18 @@ (match_operand:V2FI_V4HF 1 "nonimmediate_operand") (match_dup 2)))] "TARGET_SSE2" - "operands[2] = CONST0_RTX (mode);") +{ + if (mode != V2SImode + && !flag_trapping_math) + { + rtx op1 = force_reg (mode, operands[1]); + emit_move_insn (operands[0], lowpart_subreg (mode, + op1, mode)); + DONE; + } + + operands[2] = CONST0_RTX (mode); +}) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; @@ -648,7 +659,7 @@ (plusminusmult:V2SF (match_operand:V2SF 1 "nonimmediate_operand") (match_operand:V2SF 2 "nonimmediate_operand")))] - "TARGET_MMX_WITH_SSE" + "TARGET_MMX_WITH_SSE && ix86_partial_vec_fp_math" { rtx op2 = gen_reg_rtx (V4SFmode); rtx op1 = gen_reg_rtx (V4SFmode); @@ -726,7 +737,7 @@ [(set (match_operand:V2SF 0 "register_operand") (div:V2SF (match_operand:V2SF 1 "register_operand") (match_operand:V2SF 2 "register_operand")))] - "TARGET_MMX_WITH_SSE" + "TARGET_MMX_WITH_SSE && ix86_partial_vec_fp_math" { rtx op2 = gen_reg_rtx (V4SFmode); rtx op1 = gen_reg_rtx (V4SFmode); @@ -748,7 +759,7 @@ (smaxmin:V2SF (match_operand:V2SF 1 "register_operand") (match_operand:V2SF 2 "register_operand")))] - "TARGET_MMX_WITH_SSE" + "TARGET_MMX_WITH_SSE && ix86_partial_vec_fp_math" { rtx op2 = gen_reg_rtx (V4SFmode); rtx op1 = gen_reg_rtx (V4SFmode); @@ -850,7 +861,7 @@ (define_expand "sqrtv2sf2" [(set (match_operand:V2SF 0 "register_operand") (sqrt:V2SF (match_operand:V2SF 1 "nonimmediate_operand")))] - "TARGET_MMX_WITH_SSE" + "TARGET_MMX_WITH_SSE && ix86_partial_vec_fp_math" { rtx op1 = gen_reg_rtx (V4SFmode); rtx op0 = gen_reg_rtx (V4SFmode); @@ -931,7 +942,7 @@ (vec_select:SF (match_dup 1) (parallel [(match_operand:SI 3 "const_0_to_1_operand")]))))] - "TARGET_SSE3 && TARGET_MMX_WITH_SSE + "TARGET_SSE3 && TARGET_MMX_WITH_SSE && ix86_partial_vec_fp_math && INTVAL (operands[2]) != INTVAL (operands[3]) && ix86_pre_reload_split ()" "#" @@ -977,7 +988,7 @@ (vec_select:SF (match_dup 1) (parallel [(const_int 1)]))))] - "TARGET_SSE3 && TARGET_MMX_WITH_SSE + "TARGET_SSE3 && TARGET_MMX_WITH_SSE && ix86_partial_vec_fp_math && ix86_pre_reload_split ()" "#" "&& 1" @@ -1039,7 +1050,7 @@ (match_operand:V2SF 2 "nonimmediate_operand")) (plus:V2SF (match_dup 1) (match_dup 2)) (const_int 1)))] - "TARGET_SSE3 && TARGET_MMX_WITH_SSE" + "TARGET_SSE3 && TARGET_MMX_WITH_SSE && ix86_partial_vec_fp_math" { rtx op2 = gen_reg_rtx (V4SFmode); rtx op1 = gen_reg_rtx (V4SFmode); @@ -1102,7 +1113,7 @@ (match_operator:V2SI 1 "" [(match_operand:V2SF 2 "nonimmediate_operand") (match_operand:V2SF 3 "nonimmediate_operand")]))] - "TARGET_MMX_WITH_SSE" + "TARGET_MMX_WITH_SSE && ix86_partial_vec_fp_math" { rtx ops[4]; ops[3] = gen_reg_rtx (V4SFmode); @@ -1128,7 +1139,7 @@ (match_operand:V2SF 5 "nonimmediate_operand")]) (match_operand:V2FI 1 "general_operand") (match_operand:V2FI 2 "general_operand")))] - "TARGET_MMX_WITH_SSE" + "TARGET_MMX_WITH_SSE && ix86_partial_vec_fp_math" { rtx ops[6]; ops[5] = gen_reg_rtx (V4SFmode); @@ -1318,7 +1329,7 @@ (match_operand:V2SF 2 "nonimmediate_operand") (match_operand:V2SF 3 "nonimmediate_operand")))] "(TARGET_FMA || TARGET_FMA4 || TARGET_AVX512VL) - && TARGET_MMX_WITH_SSE" + && TARGET_MMX_WITH_SSE && ix86_partial_vec_fp_math" { rtx op3 = gen_reg_rtx (V4SFmode); rtx op2 = gen_reg_rtx (V4SFmode); @@ -1343,7 +1354,7 @@ (neg:V2SF (match_operand:V2SF 3 "nonimmediate_operand"))))] "(TARGET_FMA || TARGET_FMA4 || TARGET_AVX512VL) - && TARGET_MMX_WITH_SSE" + && TARGET_MMX_WITH_SSE && ix86_partial_vec_fp_math" { rtx op3 = gen_reg_rtx (V4SFmode); rtx op2 = gen_reg_rtx (V4SFmode); @@ -1368,7 +1379,7 @@ (match_operand:V2SF 2 "nonimmediate_operand") (match_operand:V2SF 3 "nonimmediate_operand")))] "(TARGET_FMA || TARGET_FMA4 || TARGET_AVX512VL) - && TARGET_MMX_WITH_SSE" + && TARGET_MMX_WITH_SSE && ix86_partial_vec_fp_math" { rtx op3 = gen_reg_rtx (V4SFmode); rtx op2 = gen_reg_rtx (V4SFmode); @@ -1394,7 +1405,7 @@ (neg:V2SF (match_operand:V2SF 3 "nonimmediate_operand"))))] "(TARGET_FMA || TARGET_FMA4 || TARGET_AVX512VL) - && TARGET_MMX_WITH_SSE" + && TARGET_MMX_WITH_SSE && ix86_partial_vec_fp_math" { rtx op3 = gen_reg_rtx (V4SFmode); rtx op2 = gen_reg_rtx (V4SFmode); @@ -1420,7 +1431,7 @@ (define_expand "fix_truncv2sfv2si2" [(set (match_operand:V2SI 0 "register_operand") (fix:V2SI (match_operand:V2SF 1 "nonimmediate_operand")))] - "TARGET_MMX_WITH_SSE" + "TARGET_MMX_WITH_SSE && ix86_partial_vec_fp_math" { rtx op1 = gen_reg_rtx (V4SFmode); rtx op0 = gen_reg_rtx (V4SImode); @@ -1436,7 +1447,7 @@ (define_expand "fixuns_truncv2sfv2si2" [(set (match_operand:V2SI 0 "register_operand") (unsigned_fix:V2SI (match_operand:V2SF 1 "nonimmediate_operand")))] - "TARGET_AVX512VL && TARGET_MMX_WITH_SSE" + "TARGET_AVX512VL && TARGET_MMX_WITH_SSE && ix86_partial_vec_fp_math" { rtx op1 = gen_reg_rtx (V4SFmode); rtx op0 = gen_reg_rtx (V4SImode); @@ -1461,7 +1472,7 @@ (define_expand "floatv2siv2sf2" [(set (match_operand:V2SF 0 "register_operand") (float:V2SF (match_operand:V2SI 1 "nonimmediate_operand")))] - "TARGET_MMX_WITH_SSE" + "TARGET_MMX_WITH_SSE && ix86_partial_vec_fp_math" { rtx op1 = gen_reg_rtx (V4SImode); rtx op0 = gen_reg_rtx (V4SFmode); @@ -1477,7 +1488,7 @@ (define_expand "floatunsv2siv2sf2" [(set (match_operand:V2SF 0 "register_operand") (unsigned_float:V2SF (match_operand:V2SI 1 "nonimmediate_operand")))] - "TARGET_AVX512VL && TARGET_MMX_WITH_SSE" + "TARGET_AVX512VL && TARGET_MMX_WITH_SSE && ix86_partial_vec_fp_math" { rtx op1 = gen_reg_rtx (V4SImode); rtx op0 = gen_reg_rtx (V4SFmode); @@ -1754,7 +1765,7 @@ (define_expand "nearbyintv2sf2" [(match_operand:V2SF 0 "register_operand") (match_operand:V2SF 1 "nonimmediate_operand")] - "TARGET_SSE4_1 && TARGET_MMX_WITH_SSE" + "TARGET_SSE4_1 && TARGET_MMX_WITH_SSE && ix86_partial_vec_fp_math" { rtx op1 = gen_reg_rtx (V4SFmode); rtx op0 = gen_reg_rtx (V4SFmode); @@ -1770,7 +1781,7 @@ (define_expand "rintv2sf2" [(match_operand:V2SF 0 "register_operand") (match_operand:V2SF 1 "nonimmediate_operand")] - "TARGET_SSE4_1 && TARGET_MMX_WITH_SSE" + "TARGET_SSE4_1 && TARGET_MMX_WITH_SSE && ix86_partial_vec_fp_math" { rtx op1 = gen_reg_rtx (V4SFmode); rtx op0 = gen_reg_rtx (V4SFmode); @@ -1786,8 +1797,8 @@ (define_expand "lrintv2sfv2si2" [(match_operand:V2SI 0 "register_operand") (match_operand:V2SF 1 "nonimmediate_operand")] - "TARGET_SSE4_1 && !flag_trapping_math - && TARGET_MMX_WITH_SSE" + "TARGET_SSE4_1 && !flag_trapping_math + && TARGET_MMX_WITH_SSE && ix86_partial_vec_fp_math" { rtx op1 = gen_reg_rtx (V4SFmode); rtx op0 = gen_reg_rtx (V4SImode); @@ -1804,7 +1815,7 @@ [(match_operand:V2SF 0 "register_operand") (match_operand:V2SF 1 "nonimmediate_operand")] "TARGET_SSE4_1 && !flag_trapping_math - && TARGET_MMX_WITH_SSE" + && TARGET_MMX_WITH_SSE && ix86_partial_vec_fp_math" { rtx op1 = gen_reg_rtx (V4SFmode); rtx op0 = gen_reg_rtx (V4SFmode); @@ -1820,8 +1831,8 @@ (define_expand "lceilv2sfv2si2" [(match_operand:V2SI 0 "register_operand") (match_operand:V2SF 1 "nonimmediate_operand")] - "TARGET_SSE4_1 && !flag_trapping_math - && TARGET_MMX_WITH_SSE" + "TARGET_SSE4_1 && !flag_trapping_math + && TARGET_MMX_WITH_SSE && ix86_partial_vec_fp_math" { rtx op1 = gen_reg_rtx (V4SFmode); rtx op0 = gen_reg_rtx (V4SImode); @@ -1838,7 +1849,7 @@ [(match_operand:V2SF 0 "register_operand") (match_operand:V2SF 1 "nonimmediate_operand")] "TARGET_SSE4_1 && !flag_trapping_math - && TARGET_MMX_WITH_SSE" + && TARGET_MMX_WITH_SSE && ix86_partial_vec_fp_math" { rtx op1 = gen_reg_rtx (V4SFmode); rtx op0 = gen_reg_rtx (V4SFmode); @@ -1854,8 +1865,8 @@ (define_expand "lfloorv2sfv2si2" [(match_operand:V2SI 0 "register_operand") (match_operand:V2SF 1 "nonimmediate_operand")] - "TARGET_SSE4_1 && !flag_trapping_math - && TARGET_MMX_WITH_SSE" + "TARGET_SSE4_1 && !flag_trapping_math + && TARGET_MMX_WITH_SSE && ix86_partial_vec_fp_math" { rtx op1 = gen_reg_rtx (V4SFmode); rtx op0 = gen_reg_rtx (V4SImode); @@ -1872,7 +1883,7 @@ [(match_operand:V2SF 0 "register_operand") (match_operand:V2SF 1 "nonimmediate_operand")] "TARGET_SSE4_1 && !flag_trapping_math - && TARGET_MMX_WITH_SSE" + && TARGET_MMX_WITH_SSE && ix86_partial_vec_fp_math" { rtx op1 = gen_reg_rtx (V4SFmode); rtx op0 = gen_reg_rtx (V4SFmode); @@ -1889,7 +1900,7 @@ [(match_operand:V2SF 0 "register_operand") (match_operand:V2SF 1 "nonimmediate_operand")] "TARGET_SSE4_1 && !flag_trapping_math - && TARGET_MMX_WITH_SSE" + && TARGET_MMX_WITH_SSE && ix86_partial_vec_fp_math" { rtx op1 = gen_reg_rtx (V4SFmode); rtx op0 = gen_reg_rtx (V4SFmode); @@ -1905,8 +1916,8 @@ (define_expand "lroundv2sfv2si2" [(match_operand:V2SI 0 "register_operand") (match_operand:V2SF 1 "nonimmediate_operand")] - "TARGET_SSE4_1 && !flag_trapping_math - && TARGET_MMX_WITH_SSE" + "TARGET_SSE4_1 && !flag_trapping_math + && TARGET_MMX_WITH_SSE && ix86_partial_vec_fp_math" { rtx op1 = gen_reg_rtx (V4SFmode); rtx op0 = gen_reg_rtx (V4SImode); @@ -1930,7 +1941,7 @@ (plusminusmult:V4HF (match_operand:V4HF 1 "nonimmediate_operand") (match_operand:V4HF 2 "nonimmediate_operand")))] - "TARGET_AVX512FP16 && TARGET_AVX512VL" + "TARGET_AVX512FP16 && TARGET_AVX512VL && ix86_partial_vec_fp_math" { rtx op2 = gen_reg_rtx (V8HFmode); rtx op1 = gen_reg_rtx (V8HFmode); @@ -1950,7 +1961,7 @@ (div:V4HF (match_operand:V4HF 1 "nonimmediate_operand") (match_operand:V4HF 2 "nonimmediate_operand")))] - "TARGET_AVX512FP16 && TARGET_AVX512VL" + "TARGET_AVX512FP16 && TARGET_AVX512VL && ix86_partial_vec_fp_math" { rtx op2 = gen_reg_rtx (V8HFmode); rtx op1 = gen_reg_rtx (V8HFmode); @@ -1972,14 +1983,22 @@ (match_operand:V2HF 1 "nonimmediate_operand")) (match_operand:V8HF 2 "reg_or_0_operand") (const_int 3)))] - "TARGET_SSE") + "TARGET_SSE" +{ + if (!flag_trapping_math && operands[2] == CONST0_RTX (V8HFmode)) + { + rtx op1 = force_reg (V2HFmode, operands[1]); + emit_move_insn (operands[0], lowpart_subreg (V8HFmode, op1, V2HFmode)); + DONE; + } +}) (define_expand "v2hf3" [(set (match_operand:V2HF 0 "register_operand") (plusminusmult:V2HF (match_operand:V2HF 1 "nonimmediate_operand") (match_operand:V2HF 2 "nonimmediate_operand")))] - "TARGET_AVX512FP16 && TARGET_AVX512VL" + "TARGET_AVX512FP16 && TARGET_AVX512VL && ix86_partial_vec_fp_math" { rtx op2 = gen_reg_rtx (V8HFmode); rtx op1 = gen_reg_rtx (V8HFmode); @@ -1998,7 +2017,7 @@ (div:V2HF (match_operand:V2HF 1 "nonimmediate_operand") (match_operand:V2HF 2 "nonimmediate_operand")))] - "TARGET_AVX512FP16 && TARGET_AVX512VL" + "TARGET_AVX512FP16 && TARGET_AVX512VL && ix86_partial_vec_fp_math" { rtx op2 = gen_reg_rtx (V8HFmode); rtx op1 = gen_reg_rtx (V8HFmode); @@ -3725,8 +3744,14 @@ [(set (match_operand:V4HI 0 "register_operand") (any_extend:V4HI (match_operand:V4QI 1 "register_operand")))] - "TARGET_SSE4_1 && TARGET_MMX_WITH_SSE" + "TARGET_MMX_WITH_SSE" { + if (!TARGET_SSE4_1) + { + ix86_expand_sse_extend (operands[0], operands[1], ); + DONE; + } + rtx op1 = force_reg (V4QImode, operands[1]); op1 = lowpart_subreg (V8QImode, op1, V4QImode); emit_insn (gen_sse4_1_v4qiv4hi2 (operands[0], op1)); @@ -3751,8 +3776,14 @@ [(set (match_operand:V2SI 0 "register_operand") (any_extend:V2SI (match_operand:V2HI 1 "register_operand")))] - "TARGET_SSE4_1 && TARGET_MMX_WITH_SSE" + "TARGET_MMX_WITH_SSE" { + if (!TARGET_SSE4_1) + { + ix86_expand_sse_extend (operands[0], operands[1], ); + DONE; + } + rtx op1 = force_reg (V2HImode, operands[1]); op1 = lowpart_subreg (V4HImode, op1, V2HImode); emit_insn (gen_sse4_1_v2hiv2si2 (operands[0], op1)); @@ -3803,8 +3834,14 @@ [(set (match_operand:V2HI 0 "register_operand") (any_extend:V2HI (match_operand:V2QI 1 "register_operand")))] - "TARGET_SSE4_1" + "TARGET_SSE2" { + if (!TARGET_SSE4_1) + { + ix86_expand_sse_extend (operands[0], operands[1], ); + DONE; + } + rtx op1 = force_reg (V2QImode, operands[1]); op1 = lowpart_subreg (V4QImode, op1, V2QImode); emit_insn (gen_sse4_1_v2qiv2hi2 (operands[0], op1)); diff --git a/gcc/config/i386/sse.md b/gcc/config/i386/sse.md index 2c698af46642..e282d978a01e 100644 --- a/gcc/config/i386/sse.md +++ b/gcc/config/i386/sse.md @@ -312,17 +312,10 @@ ;; All 128bit vector modes (define_mode_iterator V_128 - [V16QI V8HI V4SI V2DI V4SF (V2DF "TARGET_SSE2")]) - -(define_mode_iterator V_128H [V16QI V8HI V8HF V8BF V4SI V2DI V4SF (V2DF "TARGET_SSE2")]) ;; All 256bit vector modes (define_mode_iterator V_256 - [V32QI V16HI V8SI V4DI V8SF V4DF]) - -;; All 256bit vector modes including HF/BF vector modes -(define_mode_iterator V_256H [V32QI V16HI V8SI V4DI V8SF V4DF V16HF V16BF]) ;; All 128bit and 256bit vector modes @@ -331,7 +324,7 @@ V16HF V8HF V8SF V4SF V4DF V2DF]) ;; All 512bit vector modes -(define_mode_iterator V_512 [V64QI V32HI V16SI V8DI V16SF V8DF]) +(define_mode_iterator V_512 [V64QI V32HI V16SI V8DI V16SF V8DF V32HF V32BF]) ;; All 256bit and 512bit vector modes (define_mode_iterator V_256_512 @@ -466,18 +459,10 @@ (define_mode_iterator VF1_AVX512VL [V16SF (V8SF "TARGET_AVX512VL") (V4SF "TARGET_AVX512VL")]) -(define_mode_iterator VF_AVX512FP16 - [V32HF V16HF V8HF]) +(define_mode_iterator VHFBF + [V32HF V16HF V8HF V32BF V16BF V8BF]) -(define_mode_iterator VF_AVX512HFBF16 - [(V32HF "TARGET_AVX512FP16") (V16HF "TARGET_AVX512FP16") - (V8HF "TARGET_AVX512FP16") V32BF V16BF V8BF]) - -(define_mode_iterator VF_AVX512HFBFVL - [V32HF (V16HF "TARGET_AVX512VL") (V8HF "TARGET_AVX512VL") - V32BF (V16BF "TARGET_AVX512VL") (V8BF "TARGET_AVX512VL")]) - -(define_mode_iterator VF_AVX512FP16VL +(define_mode_iterator VHF_AVX512VL [V32HF (V16HF "TARGET_AVX512VL") (V8HF "TARGET_AVX512VL")]) ;; All vector integer modes @@ -700,11 +685,12 @@ [ (V64QI "TARGET_AVX512F") (V32QI "TARGET_AVX") V16QI (V32HI "TARGET_AVX512F") (V16HI "TARGET_AVX") V8HI]) -(define_mode_iterator V48_AVX2 +(define_mode_iterator V48_128_256 [V4SF V2DF + V4DI V2DI V8SF V4DF - (V4SI "TARGET_AVX2") (V2DI "TARGET_AVX2") - (V8SI "TARGET_AVX2") (V4DI "TARGET_AVX2")]) + V8SI V4SI]) + (define_mode_iterator VF4_128_8_256 [V4DF V4SF]) @@ -1630,29 +1616,15 @@ (set_attr "mode" "")]) (define_insn "_blendm" - [(set (match_operand:VI12_AVX512VL 0 "register_operand" "=v,v") - (vec_merge:VI12_AVX512VL - (match_operand:VI12_AVX512VL 2 "nonimmediate_operand" "vm,vm") - (match_operand:VI12_AVX512VL 1 "nonimm_or_0_operand" "0C,v") + [(set (match_operand:VI12HFBF_AVX512VL 0 "register_operand" "=v,v") + (vec_merge:VI12HFBF_AVX512VL + (match_operand:VI12HFBF_AVX512VL 2 "nonimmediate_operand" "vm,vm") + (match_operand:VI12HFBF_AVX512VL 1 "nonimm_or_0_operand" "0C,v") (match_operand: 3 "register_operand" "Yk,Yk")))] "TARGET_AVX512BW" "@ vmovdqu\t{%2, %0%{%3%}%N1|%0%{%3%}%N1, %2} - vpblendm\t{%2, %1, %0%{%3%}|%0%{%3%}, %1, %2}" - [(set_attr "type" "ssemov") - (set_attr "prefix" "evex") - (set_attr "mode" "")]) - -(define_insn "_blendm" - [(set (match_operand:VF_AVX512HFBFVL 0 "register_operand" "=v,v") - (vec_merge:VF_AVX512HFBFVL - (match_operand:VF_AVX512HFBFVL 2 "nonimmediate_operand" "vm,vm") - (match_operand:VF_AVX512HFBFVL 1 "nonimm_or_0_operand" "0C,v") - (match_operand: 3 "register_operand" "Yk,Yk")))] - "TARGET_AVX512BW" - "@ - vmovdqu\t{%2, %0%{%3%}%N1|%0%{%3%}%N1, %2} - vpblendmw\t{%2, %1, %0%{%3%}|%0%{%3%}, %1, %2}" + vpblendm\t{%2, %1, %0%{%3%}|%0%{%3%}, %1, %2}" [(set_attr "type" "ssemov") (set_attr "prefix" "evex") (set_attr "mode" "")]) @@ -1720,6 +1692,18 @@ (set_attr "prefix" "maybe_vex") (set_attr "mode" "TI")]) +(define_insn "*sse2_movq128__1" + [(set (match_operand:VI8F_128 0 "register_operand" "=v") + (vec_merge:VI8F_128 + (match_operand:VI8F_128 1 "nonimmediate_operand" "vm") + (match_operand:VI8F_128 2 "const0_operand") + (const_int 1)))] + "TARGET_SSE2" + "%vmovq\t{%1, %0|%0, %q1}" + [(set_attr "type" "ssemov") + (set_attr "prefix" "maybe_vex") + (set_attr "mode" "TI")]) + ;; Move a DI from a 32-bit register pair (e.g. %edx:%eax) to an xmm. ;; We'd rather avoid this entirely; if the 32-bit reg pair was loaded ;; from memory, we'd prefer to load the memory directly into the %xmm @@ -2442,10 +2426,10 @@ "TARGET_SSE2") (define_expand "div3" - [(set (match_operand:VF_AVX512FP16VL 0 "register_operand") - (div:VF_AVX512FP16VL - (match_operand:VF_AVX512FP16VL 1 "register_operand") - (match_operand:VF_AVX512FP16VL 2 "vector_operand")))] + [(set (match_operand:VHF_AVX512VL 0 "register_operand") + (div:VHF_AVX512VL + (match_operand:VHF_AVX512VL 1 "register_operand") + (match_operand:VHF_AVX512VL 2 "vector_operand")))] "TARGET_AVX512FP16" { /* Transform HF vector div to vector mul/rcp. */ @@ -2562,9 +2546,9 @@ (set_attr "mode" "SF")]) (define_insn "avx512fp16_rcp2" - [(set (match_operand:VF_AVX512FP16VL 0 "register_operand" "=v") - (unspec:VF_AVX512FP16VL - [(match_operand:VF_AVX512FP16VL 1 "nonimmediate_operand" "vm")] + [(set (match_operand:VHF_AVX512VL 0 "register_operand" "=v") + (unspec:VHF_AVX512VL + [(match_operand:VHF_AVX512VL 1 "nonimmediate_operand" "vm")] UNSPEC_RCP))] "TARGET_AVX512FP16" "vrcpph\t{%1, %0|%0, %1}" @@ -2725,9 +2709,9 @@ }) (define_expand "rsqrt2" - [(set (match_operand:VF_AVX512FP16VL 0 "register_operand") - (unspec:VF_AVX512FP16VL - [(match_operand:VF_AVX512FP16VL 1 "vector_operand")] + [(set (match_operand:VHF_AVX512VL 0 "register_operand") + (unspec:VHF_AVX512VL + [(match_operand:VHF_AVX512VL 1 "vector_operand")] UNSPEC_RSQRT))] "TARGET_AVX512FP16") @@ -2742,9 +2726,9 @@ (set_attr "mode" "")]) (define_insn "_rsqrt2" - [(set (match_operand:VF_AVX512FP16VL 0 "register_operand" "=v") - (unspec:VF_AVX512FP16VL - [(match_operand:VF_AVX512FP16VL 1 "vector_operand" "vBm")] UNSPEC_RSQRT))] + [(set (match_operand:VHF_AVX512VL 0 "register_operand" "=v") + (unspec:VHF_AVX512VL + [(match_operand:VHF_AVX512VL 1 "vector_operand" "vBm")] UNSPEC_RSQRT))] "TARGET_AVX512FP16" "vrsqrtph\t{%1, %0|%0, %1}" [(set_attr "type" "sse") @@ -3903,8 +3887,8 @@ [(set (match_operand: 0 "register_operand") (not: (unspec: - [(match_operand:V48_AVX512VL 1 "register_operand") - (match_operand:V48_AVX512VL 2 "nonimmediate_operand") + [(match_operand:V48H_AVX512VL 1 "register_operand") + (match_operand:V48H_AVX512VL 2 "nonimmediate_operand") (match_operand:SI 3 "" "n")] UNSPEC_PCMP)))] "TARGET_AVX512F && ix86_pre_reload_split ()" @@ -4588,13 +4572,13 @@ }) (define_expand "vcond" - [(set (match_operand:VF_AVX512FP16VL 0 "register_operand") - (if_then_else:VF_AVX512FP16VL + [(set (match_operand:VHF_AVX512VL 0 "register_operand") + (if_then_else:VHF_AVX512VL (match_operator 3 "" - [(match_operand:VF_AVX512FP16VL 4 "vector_operand") - (match_operand:VF_AVX512FP16VL 5 "vector_operand")]) - (match_operand:VF_AVX512FP16VL 1 "general_operand") - (match_operand:VF_AVX512FP16VL 2 "general_operand")))] + [(match_operand:VHF_AVX512VL 4 "vector_operand") + (match_operand:VHF_AVX512VL 5 "vector_operand")]) + (match_operand:VHF_AVX512VL 1 "general_operand") + (match_operand:VHF_AVX512VL 2 "general_operand")))] "TARGET_AVX512FP16" { bool ok = ix86_expand_fp_vcond (operands); @@ -4602,27 +4586,12 @@ DONE; }) -(define_expand "vcond" - [(set (match_operand:VF_AVX512HFBFVL 0 "register_operand") - (if_then_else:VF_AVX512HFBFVL - (match_operator 3 "" - [(match_operand: 4 "vector_operand") - (match_operand: 5 "vector_operand")]) - (match_operand:VF_AVX512HFBFVL 1 "general_operand") - (match_operand:VF_AVX512HFBFVL 2 "general_operand")))] - "TARGET_AVX512FP16" -{ - bool ok = ix86_expand_int_vcond (operands); - gcc_assert (ok); - DONE; -}) - (define_expand "vcond" [(set (match_operand: 0 "register_operand") (if_then_else: (match_operator 3 "" - [(match_operand:VF_AVX512FP16VL 4 "vector_operand") - (match_operand:VF_AVX512FP16VL 5 "vector_operand")]) + [(match_operand:VHF_AVX512VL 4 "vector_operand") + (match_operand:VHF_AVX512VL 5 "vector_operand")]) (match_operand: 1 "general_operand") (match_operand: 2 "general_operand")))] "TARGET_AVX512FP16" @@ -6522,10 +6491,10 @@ (V8HF "avx512vl_loadv4sf")]) (define_expand "_fmaddc__mask1" - [(match_operand:VF_AVX512FP16VL 0 "register_operand") - (match_operand:VF_AVX512FP16VL 1 "") - (match_operand:VF_AVX512FP16VL 2 "") - (match_operand:VF_AVX512FP16VL 3 "") + [(match_operand:VHF_AVX512VL 0 "register_operand") + (match_operand:VHF_AVX512VL 1 "") + (match_operand:VHF_AVX512VL 2 "") + (match_operand:VHF_AVX512VL 3 "") (match_operand: 4 "register_operand")] "TARGET_AVX512FP16 && " { @@ -6552,10 +6521,10 @@ }) (define_expand "_fmaddc__maskz" - [(match_operand:VF_AVX512FP16VL 0 "register_operand") - (match_operand:VF_AVX512FP16VL 1 "") - (match_operand:VF_AVX512FP16VL 2 "") - (match_operand:VF_AVX512FP16VL 3 "") + [(match_operand:VHF_AVX512VL 0 "register_operand") + (match_operand:VHF_AVX512VL 1 "") + (match_operand:VHF_AVX512VL 2 "") + (match_operand:VHF_AVX512VL 3 "") (match_operand: 4 "register_operand")] "TARGET_AVX512FP16 && " { @@ -6566,10 +6535,10 @@ }) (define_expand "_fcmaddc__mask1" - [(match_operand:VF_AVX512FP16VL 0 "register_operand") - (match_operand:VF_AVX512FP16VL 1 "") - (match_operand:VF_AVX512FP16VL 2 "") - (match_operand:VF_AVX512FP16VL 3 "") + [(match_operand:VHF_AVX512VL 0 "register_operand") + (match_operand:VHF_AVX512VL 1 "") + (match_operand:VHF_AVX512VL 2 "") + (match_operand:VHF_AVX512VL 3 "") (match_operand: 4 "register_operand")] "TARGET_AVX512FP16 && " { @@ -6598,10 +6567,10 @@ }) (define_expand "_fcmaddc__maskz" - [(match_operand:VF_AVX512FP16VL 0 "register_operand") - (match_operand:VF_AVX512FP16VL 1 "") - (match_operand:VF_AVX512FP16VL 2 "") - (match_operand:VF_AVX512FP16VL 3 "") + [(match_operand:VHF_AVX512VL 0 "register_operand") + (match_operand:VHF_AVX512VL 1 "") + (match_operand:VHF_AVX512VL 2 "") + (match_operand:VHF_AVX512VL 3 "") (match_operand: 4 "register_operand")] "TARGET_AVX512FP16 && " { @@ -6612,20 +6581,20 @@ }) (define_expand "cmla4" - [(set (match_operand:VF_AVX512FP16VL 0 "register_operand") - (unspec:VF_AVX512FP16VL - [(match_operand:VF_AVX512FP16VL 1 "vector_operand") - (match_operand:VF_AVX512FP16VL 2 "vector_operand") - (match_operand:VF_AVX512FP16VL 3 "vector_operand")] + [(set (match_operand:VHF_AVX512VL 0 "register_operand") + (unspec:VHF_AVX512VL + [(match_operand:VHF_AVX512VL 1 "vector_operand") + (match_operand:VHF_AVX512VL 2 "vector_operand") + (match_operand:VHF_AVX512VL 3 "vector_operand")] UNSPEC_COMPLEX_F_C_MA))] "TARGET_AVX512FP16") (define_insn "fma__" - [(set (match_operand:VF_AVX512FP16VL 0 "register_operand" "=&v") - (unspec:VF_AVX512FP16VL - [(match_operand:VF_AVX512FP16VL 1 "" "%v") - (match_operand:VF_AVX512FP16VL 2 "" "") - (match_operand:VF_AVX512FP16VL 3 "" "0")] + [(set (match_operand:VHF_AVX512VL 0 "register_operand" "=&v") + (unspec:VHF_AVX512VL + [(match_operand:VHF_AVX512VL 1 "" "%v") + (match_operand:VHF_AVX512VL 2 "" "") + (match_operand:VHF_AVX512VL 3 "" "0")] UNSPEC_COMPLEX_F_C_MA))] "TARGET_AVX512FP16 && && " "v\t{%2, %1, %0|%0, %1, %2}" @@ -6634,54 +6603,54 @@ (set_attr "mode" "")]) (define_insn_and_split "fma__fadd_fmul" - [(set (match_operand:VF_AVX512FP16VL 0 "register_operand") - (plus:VF_AVX512FP16VL - (unspec:VF_AVX512FP16VL - [(match_operand:VF_AVX512FP16VL 1 "vector_operand") - (match_operand:VF_AVX512FP16VL 2 "vector_operand")] + [(set (match_operand:VHF_AVX512VL 0 "register_operand") + (plus:VHF_AVX512VL + (unspec:VHF_AVX512VL + [(match_operand:VHF_AVX512VL 1 "vector_operand") + (match_operand:VHF_AVX512VL 2 "vector_operand")] UNSPEC_COMPLEX_FMUL) - (match_operand:VF_AVX512FP16VL 3 "vector_operand")))] + (match_operand:VHF_AVX512VL 3 "vector_operand")))] "TARGET_AVX512FP16 && flag_unsafe_math_optimizations && ix86_pre_reload_split ()" "#" "&& 1" [(set (match_dup 0) - (unspec:VF_AVX512FP16VL + (unspec:VHF_AVX512VL [(match_dup 1) (match_dup 2) (match_dup 3)] UNSPEC_COMPLEX_FMA))]) (define_insn_and_split "fma__fadd_fcmul" - [(set (match_operand:VF_AVX512FP16VL 0 "register_operand") - (plus:VF_AVX512FP16VL - (unspec:VF_AVX512FP16VL - [(match_operand:VF_AVX512FP16VL 1 "vector_operand") - (match_operand:VF_AVX512FP16VL 2 "vector_operand")] + [(set (match_operand:VHF_AVX512VL 0 "register_operand") + (plus:VHF_AVX512VL + (unspec:VHF_AVX512VL + [(match_operand:VHF_AVX512VL 1 "vector_operand") + (match_operand:VHF_AVX512VL 2 "vector_operand")] UNSPEC_COMPLEX_FCMUL) - (match_operand:VF_AVX512FP16VL 3 "vector_operand")))] + (match_operand:VHF_AVX512VL 3 "vector_operand")))] "TARGET_AVX512FP16 && flag_unsafe_math_optimizations && ix86_pre_reload_split ()" "#" "&& 1" [(set (match_dup 0) - (unspec:VF_AVX512FP16VL + (unspec:VHF_AVX512VL [(match_dup 1) (match_dup 2) (match_dup 3)] UNSPEC_COMPLEX_FCMA))]) (define_insn_and_split "fma___fma_zero" - [(set (match_operand:VF_AVX512FP16VL 0 "register_operand") - (plus:VF_AVX512FP16VL - (unspec:VF_AVX512FP16VL - [(match_operand:VF_AVX512FP16VL 1 "vector_operand") - (match_operand:VF_AVX512FP16VL 2 "vector_operand") - (match_operand:VF_AVX512FP16VL 3 "const0_operand")] + [(set (match_operand:VHF_AVX512VL 0 "register_operand") + (plus:VHF_AVX512VL + (unspec:VHF_AVX512VL + [(match_operand:VHF_AVX512VL 1 "vector_operand") + (match_operand:VHF_AVX512VL 2 "vector_operand") + (match_operand:VHF_AVX512VL 3 "const0_operand")] UNSPEC_COMPLEX_F_C_MA) - (match_operand:VF_AVX512FP16VL 4 "vector_operand")))] + (match_operand:VHF_AVX512VL 4 "vector_operand")))] "TARGET_AVX512FP16 && flag_unsafe_math_optimizations && ix86_pre_reload_split ()" "#" "&& 1" [(set (match_dup 0) - (unspec:VF_AVX512FP16VL + (unspec:VHF_AVX512VL [(match_dup 1) (match_dup 2) (match_dup 4)] UNSPEC_COMPLEX_F_C_MA))]) @@ -6699,12 +6668,12 @@ (set_attr "mode" "")]) (define_insn_and_split "fma__fmaddc_bcst" - [(set (match_operand:VF_AVX512FP16VL 0 "register_operand") - (unspec:VF_AVX512FP16VL - [(match_operand:VF_AVX512FP16VL 1 "vector_operand") - (subreg:VF_AVX512FP16VL + [(set (match_operand:VHF_AVX512VL 0 "register_operand") + (unspec:VHF_AVX512VL + [(match_operand:VHF_AVX512VL 1 "vector_operand") + (subreg:VHF_AVX512VL (match_operand: 2 "bcst_vector_operand") 0) - (match_operand:VF_AVX512FP16VL 3 "vector_operand")] + (match_operand:VHF_AVX512VL 3 "vector_operand")] UNSPEC_COMPLEX_FMA))] "TARGET_AVX512FP16 && ix86_pre_reload_split ()" "#" @@ -6726,12 +6695,12 @@ }) (define_insn_and_split "fma__fcmaddc_bcst" - [(set (match_operand:VF_AVX512FP16VL 0 "register_operand") - (unspec:VF_AVX512FP16VL - [(match_operand:VF_AVX512FP16VL 1 "vector_operand") - (subreg:VF_AVX512FP16VL + [(set (match_operand:VHF_AVX512VL 0 "register_operand") + (unspec:VHF_AVX512VL + [(match_operand:VHF_AVX512VL 1 "vector_operand") + (subreg:VHF_AVX512VL (match_operand: 2 "bcst_vector_operand") 0) - (match_operand:VF_AVX512FP16VL 3 "vector_operand")] + (match_operand:VHF_AVX512VL 3 "vector_operand")] UNSPEC_COMPLEX_FCMA))] "TARGET_AVX512FP16 && ix86_pre_reload_split ()" "#" @@ -6754,12 +6723,12 @@ }) (define_insn "___mask" - [(set (match_operand:VF_AVX512FP16VL 0 "register_operand" "=&v") - (vec_merge:VF_AVX512FP16VL - (unspec:VF_AVX512FP16VL - [(match_operand:VF_AVX512FP16VL 1 "nonimmediate_operand" "%v") - (match_operand:VF_AVX512FP16VL 2 "nonimmediate_operand" "") - (match_operand:VF_AVX512FP16VL 3 "register_operand" "0")] + [(set (match_operand:VHF_AVX512VL 0 "register_operand" "=&v") + (vec_merge:VHF_AVX512VL + (unspec:VHF_AVX512VL + [(match_operand:VHF_AVX512VL 1 "nonimmediate_operand" "%v") + (match_operand:VHF_AVX512VL 2 "nonimmediate_operand" "") + (match_operand:VHF_AVX512VL 3 "register_operand" "0")] UNSPEC_COMPLEX_F_C_MA) (match_dup 1) (unspec: @@ -6772,18 +6741,18 @@ (set_attr "mode" "")]) (define_expand "cmul3" - [(set (match_operand:VF_AVX512FP16VL 0 "register_operand") - (unspec:VF_AVX512FP16VL - [(match_operand:VF_AVX512FP16VL 1 "vector_operand") - (match_operand:VF_AVX512FP16VL 2 "vector_operand")] + [(set (match_operand:VHF_AVX512VL 0 "register_operand") + (unspec:VHF_AVX512VL + [(match_operand:VHF_AVX512VL 1 "vector_operand") + (match_operand:VHF_AVX512VL 2 "vector_operand")] UNSPEC_COMPLEX_F_C_MUL))] "TARGET_AVX512FP16") (define_insn "__" - [(set (match_operand:VF_AVX512FP16VL 0 "register_operand" "=&v") - (unspec:VF_AVX512FP16VL - [(match_operand:VF_AVX512FP16VL 1 "nonimmediate_operand" "%v") - (match_operand:VF_AVX512FP16VL 2 "nonimmediate_operand" "")] + [(set (match_operand:VHF_AVX512VL 0 "register_operand" "=&v") + (unspec:VHF_AVX512VL + [(match_operand:VHF_AVX512VL 1 "nonimmediate_operand" "%v") + (match_operand:VHF_AVX512VL 2 "nonimmediate_operand" "")] UNSPEC_COMPLEX_F_C_MUL))] "TARGET_AVX512FP16 && " { @@ -7025,7 +6994,7 @@ (define_expand "vec_unpacks_lo_" [(match_operand: 0 "register_operand") - (match_operand:VF_AVX512FP16VL 1 "register_operand")] + (match_operand:VHF_AVX512VL 1 "register_operand")] "TARGET_AVX512FP16" { rtx tem = operands[1]; @@ -7046,7 +7015,7 @@ (define_expand "vec_unpacks_hi_" [(match_operand: 0 "register_operand") - (match_operand:VF_AVX512FP16VL 1 "register_operand")] + (match_operand:VHF_AVX512VL 1 "register_operand")] "TARGET_AVX512FP16" { rtx tem = operands[1]; @@ -8997,7 +8966,7 @@ (define_expand "vec_unpack_fix_trunc_lo_" [(match_operand: 0 "register_operand") (any_fix: - (match_operand:VF_AVX512FP16VL 1 "register_operand"))] + (match_operand:VHF_AVX512VL 1 "register_operand"))] "TARGET_AVX512FP16" { rtx tem = operands[1]; @@ -9019,7 +8988,7 @@ (define_expand "vec_unpack_fix_trunc_hi_" [(match_operand: 0 "register_operand") (any_fix: - (match_operand:VF_AVX512FP16VL 1 "register_operand"))] + (match_operand:VHF_AVX512VL 1 "register_operand"))] "TARGET_AVX512FP16" { rtx tem = operands[1]; @@ -11356,20 +11325,6 @@ DONE; }) -(define_expand "vec_set" - [(match_operand:V8BFH_128 0 "register_operand") - (match_operand: 1 "register_operand") - (match_operand 2 "vec_setm_sse41_operand")] - "TARGET_SSE" -{ - if (CONST_INT_P (operands[2])) - ix86_expand_vector_set (false, operands[0], operands[1], - INTVAL (operands[2])); - else - ix86_expand_vector_set_var (operands[0], operands[1], operands[2]); - DONE; -}) - (define_expand "vec_set" [(match_operand:V_256_512 0 "register_operand") (match_operand: 1 "register_operand") @@ -11823,7 +11778,7 @@ (define_expand "avx_vextractf128" [(match_operand: 0 "nonimmediate_operand") - (match_operand:V_256H 1 "register_operand") + (match_operand:V_256 1 "register_operand") (match_operand:SI 2 "const_0_to_1_operand")] "TARGET_AVX" { @@ -12285,7 +12240,7 @@ (define_insn_and_split "*vec_extract_0" [(set (match_operand: 0 "nonimmediate_operand" "=v,m,r") (vec_select: - (match_operand:VF_AVX512HFBF16 1 "nonimmediate_operand" "vm,v,m") + (match_operand:VHFBF 1 "nonimmediate_operand" "vm,v,m") (parallel [(const_int 0)])))] "TARGET_AVX512F && !(MEM_P (operands[0]) && MEM_P (operands[1]))" "#" @@ -17270,21 +17225,6 @@ DONE; }) -(define_expand "vcondu" - [(set (match_operand:VF_AVX512FP16VL 0 "register_operand") - (if_then_else:VF_AVX512FP16VL - (match_operator 3 "" - [(match_operand: 4 "vector_operand") - (match_operand: 5 "vector_operand")]) - (match_operand:VF_AVX512FP16VL 1 "general_operand") - (match_operand:VF_AVX512FP16VL 2 "general_operand")))] - "TARGET_AVX512FP16" -{ - bool ok = ix86_expand_int_vcond (operands); - gcc_assert (ok); - DONE; -}) - (define_expand "vcondeqv2di" [(set (match_operand:VI8F_128 0 "register_operand") (if_then_else:VI8F_128 @@ -22288,7 +22228,8 @@ (set_attr "mode" "")]) (define_mode_attr ssefltmodesuffix - [(V2DI "pd") (V4DI "pd") (V4SI "ps") (V8SI "ps")]) + [(V2DI "pd") (V4DI "pd") (V4SI "ps") (V8SI "ps") + (V2DF "pd") (V4DF "pd") (V4SF "ps") (V8SF "ps")]) (define_mode_attr ssefltvecmode [(V2DI "V2DF") (V4DI "V4DF") (V4SI "V4SF") (V8SI "V8SF")]) @@ -22862,8 +22803,14 @@ [(set (match_operand:V8HI 0 "register_operand") (any_extend:V8HI (match_operand:V8QI 1 "nonimmediate_operand")))] - "TARGET_SSE4_1" + "TARGET_SSE4_1 || TARGET_MMX_WITH_SSE" { + if (!TARGET_SSE4_1) + { + ix86_expand_sse_extend (operands[0], operands[1], ); + DONE; + } + if (!MEM_P (operands[1])) { rtx op1 = force_reg (V8QImode, operands[1]); @@ -23172,8 +23119,14 @@ [(set (match_operand:V4SI 0 "register_operand") (any_extend:V4SI (match_operand:V4HI 1 "nonimmediate_operand")))] - "TARGET_SSE4_1" + "TARGET_SSE4_1 || TARGET_MMX_WITH_SSE" { + if (!TARGET_SSE4_1) + { + ix86_expand_sse_extend (operands[0], operands[1], ); + DONE; + } + if (!MEM_P (operands[1])) { rtx op1 = force_reg (V4HImode, operands[1]); @@ -23771,8 +23724,14 @@ [(set (match_operand:V2DI 0 "register_operand") (any_extend:V2DI (match_operand:V2SI 1 "nonimmediate_operand")))] - "TARGET_SSE4_1" + "TARGET_SSE4_1 || TARGET_MMX_WITH_SSE" { + if (!TARGET_SSE4_1) + { + ix86_expand_sse_extend (operands[0], operands[1], ); + DONE; + } + if (!MEM_P (operands[1])) { rtx op1 = force_reg (V2SImode, operands[1]); @@ -26804,8 +26763,8 @@ "operands[2] = gen_lowpart (mode, operands[0]);") (define_insn "avx_vbroadcastf128_" - [(set (match_operand:V_256H 0 "register_operand" "=x,x,x,v,v,v,v") - (vec_concat:V_256H + [(set (match_operand:V_256 0 "register_operand" "=x,x,x,v,v,v,v") + (vec_concat:V_256 (match_operand: 1 "nonimmediate_operand" "m,0,?x,m,0,m,0") (match_dup 1)))] "TARGET_AVX" @@ -27125,9 +27084,9 @@ (set_attr "mode" "")]) (define_insn "*ssse3_palignr_perm" - [(set (match_operand:V_128H 0 "register_operand" "=x,Yw") - (vec_select:V_128H - (match_operand:V_128H 1 "register_operand" "0,Yw") + [(set (match_operand:V_128 0 "register_operand" "=x,Yw") + (vec_select:V_128 + (match_operand:V_128 1 "register_operand" "0,Yw") (match_parallel 2 "palignr_operand" [(match_operand 3 "const_int_operand")])))] "TARGET_SSSE3" @@ -27381,13 +27340,18 @@ (set_attr "mode" "OI")]) (define_insn "_maskload" - [(set (match_operand:V48_AVX2 0 "register_operand" "=x") - (unspec:V48_AVX2 + [(set (match_operand:V48_128_256 0 "register_operand" "=x") + (unspec:V48_128_256 [(match_operand: 2 "register_operand" "x") - (match_operand:V48_AVX2 1 "memory_operand" "m")] + (match_operand:V48_128_256 1 "memory_operand" "m")] UNSPEC_MASKMOV))] "TARGET_AVX" - "vmaskmov\t{%1, %2, %0|%0, %2, %1}" +{ + if (TARGET_AVX2) + return "vmaskmov\t{%1, %2, %0|%0, %2, %1}"; + else + return "vmaskmov\t{%1, %2, %0|%0, %2, %1}"; +} [(set_attr "type" "sselog1") (set_attr "prefix_extra" "1") (set_attr "prefix" "vex") @@ -27395,14 +27359,19 @@ (set_attr "mode" "")]) (define_insn "_maskstore" - [(set (match_operand:V48_AVX2 0 "memory_operand" "+m") - (unspec:V48_AVX2 + [(set (match_operand:V48_128_256 0 "memory_operand" "+m") + (unspec:V48_128_256 [(match_operand: 1 "register_operand" "x") - (match_operand:V48_AVX2 2 "register_operand" "x") + (match_operand:V48_128_256 2 "register_operand" "x") (match_dup 0)] UNSPEC_MASKMOV))] "TARGET_AVX" - "vmaskmov\t{%2, %1, %0|%0, %1, %2}" +{ + if (TARGET_AVX2) + return "vmaskmov\t{%2, %1, %0|%0, %1, %2}"; + else + return "vmaskmov\t{%2, %1, %0|%0, %1, %2}"; +} [(set_attr "type" "sselog1") (set_attr "prefix_extra" "1") (set_attr "prefix" "vex") @@ -27410,10 +27379,10 @@ (set_attr "mode" "")]) (define_expand "maskload" - [(set (match_operand:V48_AVX2 0 "register_operand") - (unspec:V48_AVX2 + [(set (match_operand:V48_128_256 0 "register_operand") + (unspec:V48_128_256 [(match_operand: 2 "register_operand") - (match_operand:V48_AVX2 1 "memory_operand")] + (match_operand:V48_128_256 1 "memory_operand")] UNSPEC_MASKMOV))] "TARGET_AVX") @@ -27438,10 +27407,10 @@ "TARGET_AVX512BW") (define_expand "maskstore" - [(set (match_operand:V48_AVX2 0 "memory_operand") - (unspec:V48_AVX2 + [(set (match_operand:V48_128_256 0 "memory_operand") + (unspec:V48_128_256 [(match_operand: 2 "register_operand") - (match_operand:V48_AVX2 1 "register_operand") + (match_operand:V48_128_256 1 "register_operand") (match_dup 0)] UNSPEC_MASKMOV))] "TARGET_AVX") @@ -29925,8 +29894,8 @@ (match_operand: 3 "register_operand")] "TARGET_AVX512BF16" { - emit_insn (gen_avx512f_cvtne2ps2bf16__mask(operands[0], operands[2], - operands[1], CONST0_RTX(mode), operands[3])); + emit_insn (gen_avx512f_cvtne2ps2bf16__mask(operands[0], operands[1], + operands[2], CONST0_RTX(mode), operands[3])); DONE; }) diff --git a/gcc/config/i386/x86-tune.def b/gcc/config/i386/x86-tune.def index 40e04ecddbf8..4b2c5d59a95d 100644 --- a/gcc/config/i386/x86-tune.def +++ b/gcc/config/i386/x86-tune.def @@ -43,7 +43,7 @@ DEF_TUNE (X86_TUNE_SCHEDULE, "schedule", m_PENT | m_LAKEMONT | m_PPRO | m_CORE_ALL | m_BONNELL | m_SILVERMONT | m_INTEL | m_KNL | m_KNM | m_K6_GEODE | m_AMD_MULTIPLE | m_LUJIAZUI | m_GOLDMONT | m_GOLDMONT_PLUS | m_TREMONT | m_ALDERLAKE | m_ARROWLAKE - | m_CORE_ATOM | m_GENERIC) + | m_ARROWLAKE_S | m_CORE_ATOM | m_GENERIC) /* X86_TUNE_PARTIAL_REG_DEPENDENCY: Enable more register renaming on modern chips. Prefer stores affecting whole integer register @@ -53,7 +53,7 @@ DEF_TUNE (X86_TUNE_PARTIAL_REG_DEPENDENCY, "partial_reg_dependency", m_P4_NOCONA | m_CORE2 | m_NEHALEM | m_SANDYBRIDGE | m_CORE_AVX2 | m_BONNELL | m_SILVERMONT | m_GOLDMONT | m_GOLDMONT_PLUS | m_INTEL | m_KNL | m_KNM | m_AMD_MULTIPLE | m_LUJIAZUI | m_TREMONT - | m_ALDERLAKE | m_ARROWLAKE | m_CORE_ATOM | m_GENERIC) + | m_ALDERLAKE | m_ARROWLAKE | m_ARROWLAKE_S | m_CORE_ATOM | m_GENERIC) /* X86_TUNE_SSE_PARTIAL_REG_DEPENDENCY: This knob promotes all store destinations to be 128bit to allow register renaming on 128bit SSE units, @@ -64,7 +64,7 @@ DEF_TUNE (X86_TUNE_PARTIAL_REG_DEPENDENCY, "partial_reg_dependency", DEF_TUNE (X86_TUNE_SSE_PARTIAL_REG_DEPENDENCY, "sse_partial_reg_dependency", m_PPRO | m_P4_NOCONA | m_CORE_ALL | m_BONNELL | m_AMDFAM10 | m_BDVER | m_ZNVER | m_LUJIAZUI | m_TREMONT | m_ALDERLAKE - | m_ARROWLAKE | m_CORE_ATOM | m_GENERIC) + | m_ARROWLAKE | m_ARROWLAKE_S | m_CORE_ATOM | m_GENERIC) /* X86_TUNE_SSE_PARTIAL_REG_FP_CONVERTS_DEPENDENCY: This knob avoids partial write to the destination in scalar SSE conversion from FP @@ -73,7 +73,7 @@ DEF_TUNE (X86_TUNE_SSE_PARTIAL_REG_FP_CONVERTS_DEPENDENCY, "sse_partial_reg_fp_converts_dependency", m_PPRO | m_P4_NOCONA | m_CORE_ALL | m_BONNELL | m_AMDFAM10 | m_BDVER | m_ZNVER | m_LUJIAZUI | m_ALDERLAKE | m_ARROWLAKE - | m_CORE_ATOM | m_GENERIC) + | m_ARROWLAKE_S | m_CORE_ATOM | m_GENERIC) /* X86_TUNE_SSE_PARTIAL_REG_CONVERTS_DEPENDENCY: This knob avoids partial write to the destination in scalar SSE conversion from integer to FP. */ @@ -81,14 +81,14 @@ DEF_TUNE (X86_TUNE_SSE_PARTIAL_REG_CONVERTS_DEPENDENCY, "sse_partial_reg_converts_dependency", m_PPRO | m_P4_NOCONA | m_CORE_ALL | m_BONNELL | m_AMDFAM10 | m_BDVER | m_ZNVER | m_LUJIAZUI | m_ALDERLAKE | m_ARROWLAKE - | m_CORE_ATOM | m_GENERIC) + | m_ARROWLAKE_S | m_CORE_ATOM | m_GENERIC) /* X86_TUNE_DEST_FALSE_DEP_FOR_GLC: This knob inserts zero-idiom before several insns to break false dependency on the dest register for GLC micro-architecture. */ DEF_TUNE (X86_TUNE_DEST_FALSE_DEP_FOR_GLC, "dest_false_dep_for_glc", m_SAPPHIRERAPIDS | m_ALDERLAKE | m_ARROWLAKE - | m_CORE_ATOM) + | m_ARROWLAKE_S | m_CORE_ATOM) /* X86_TUNE_SSE_SPLIT_REGS: Set for machines where the type and dependencies are resolved on SSE register parts instead of whole registers, so we may @@ -115,14 +115,14 @@ DEF_TUNE (X86_TUNE_MOVX, "movx", | m_BONNELL | m_SILVERMONT | m_GOLDMONT | m_KNL | m_KNM | m_INTEL | m_GOLDMONT_PLUS | m_GEODE | m_AMD_MULTIPLE | m_LUJIAZUI | m_CORE_AVX2 | m_TREMONT | m_ALDERLAKE | m_ARROWLAKE - | m_CORE_ATOM | m_GENERIC) + | m_ARROWLAKE_S | m_CORE_ATOM | m_GENERIC) /* X86_TUNE_MEMORY_MISMATCH_STALL: Avoid partial stores that are followed by full sized loads. */ DEF_TUNE (X86_TUNE_MEMORY_MISMATCH_STALL, "memory_mismatch_stall", m_P4_NOCONA | m_CORE_ALL | m_BONNELL | m_SILVERMONT | m_INTEL | m_KNL | m_KNM | m_GOLDMONT | m_GOLDMONT_PLUS | m_AMD_MULTIPLE - | m_LUJIAZUI | m_TREMONT | m_ALDERLAKE | m_ARROWLAKE + | m_LUJIAZUI | m_TREMONT | m_ALDERLAKE | m_ARROWLAKE | m_ARROWLAKE_S | m_CORE_ATOM | m_GENERIC) /* X86_TUNE_FUSE_CMP_AND_BRANCH_32: Fuse compare with a subsequent @@ -179,14 +179,15 @@ DEF_TUNE (X86_TUNE_EPILOGUE_USING_MOVE, "epilogue_using_move", /* X86_TUNE_USE_LEAVE: Use "leave" instruction in epilogues where it fits. */ DEF_TUNE (X86_TUNE_USE_LEAVE, "use_leave", m_386 | m_CORE_ALL | m_K6_GEODE | m_AMD_MULTIPLE | m_LUJIAZUI - | m_TREMONT | m_ALDERLAKE | m_ARROWLAKE | m_CORE_ATOM | m_GENERIC) + | m_TREMONT | m_ALDERLAKE | m_ARROWLAKE | m_ARROWLAKE_S + | m_CORE_ATOM | m_GENERIC) /* X86_TUNE_PUSH_MEMORY: Enable generation of "push mem" instructions. Some chips, like 486 and Pentium works faster with separate load and push instructions. */ DEF_TUNE (X86_TUNE_PUSH_MEMORY, "push_memory", m_386 | m_P4_NOCONA | m_CORE_ALL | m_K6_GEODE | m_AMD_MULTIPLE - | m_LUJIAZUI | m_TREMONT | m_ALDERLAKE | m_ARROWLAKE + | m_LUJIAZUI | m_TREMONT | m_ALDERLAKE | m_ARROWLAKE | m_ARROWLAKE_S | m_CORE_ATOM | m_GENERIC) /* X86_TUNE_SINGLE_PUSH: Enable if single push insn is preferred @@ -258,7 +259,7 @@ DEF_TUNE (X86_TUNE_USE_INCDEC, "use_incdec", ~(m_P4_NOCONA | m_CORE2 | m_NEHALEM | m_SANDYBRIDGE | m_BONNELL | m_SILVERMONT | m_INTEL | m_KNL | m_KNM | m_GOLDMONT | m_GOLDMONT_PLUS | m_TREMONT | m_ALDERLAKE | m_ARROWLAKE - | m_CORE_ATOM | m_LUJIAZUI | m_GENERIC)) + | m_ARROWLAKE_S | m_CORE_ATOM | m_LUJIAZUI | m_GENERIC)) /* X86_TUNE_INTEGER_DFMODE_MOVES: Enable if integer moves are preferred for DFmode copies */ @@ -266,7 +267,7 @@ DEF_TUNE (X86_TUNE_INTEGER_DFMODE_MOVES, "integer_dfmode_moves", ~(m_PPRO | m_P4_NOCONA | m_CORE_ALL | m_BONNELL | m_SILVERMONT | m_KNL | m_KNM | m_INTEL | m_GEODE | m_AMD_MULTIPLE | m_LUJIAZUI | m_GOLDMONT | m_GOLDMONT_PLUS | m_TREMONT | m_ALDERLAKE - | m_ARROWLAKE | m_CORE_ATOM | m_GENERIC)) + | m_ARROWLAKE | m_ARROWLAKE_S | m_CORE_ATOM | m_GENERIC)) /* X86_TUNE_OPT_AGU: Optimize for Address Generation Unit. This flag will impact LEA instruction selection. */ @@ -304,7 +305,7 @@ DEF_TUNE (X86_TUNE_SINGLE_STRINGOP, "single_stringop", m_386 | m_P4_NOCONA) move/set sequences of bytes with known size. */ DEF_TUNE (X86_TUNE_PREFER_KNOWN_REP_MOVSB_STOSB, "prefer_known_rep_movsb_stosb", - m_SKYLAKE | m_ALDERLAKE | m_ARROWLAKE | m_CORE_ATOM + m_SKYLAKE | m_ALDERLAKE | m_ARROWLAKE | m_ARROWLAKE_S | m_CORE_ATOM | m_TREMONT | m_CORE_AVX512 | m_LUJIAZUI) /* X86_TUNE_MISALIGNED_MOVE_STRING_PRO_EPILOGUES: Enable generation of @@ -315,14 +316,14 @@ DEF_TUNE (X86_TUNE_PREFER_KNOWN_REP_MOVSB_STOSB, DEF_TUNE (X86_TUNE_MISALIGNED_MOVE_STRING_PRO_EPILOGUES, "misaligned_move_string_pro_epilogues", m_386 | m_486 | m_CORE_ALL | m_AMD_MULTIPLE | m_LUJIAZUI | m_TREMONT - | m_ALDERLAKE | m_ARROWLAKE | m_CORE_ATOM | m_GENERIC) + | m_ALDERLAKE | m_ARROWLAKE | m_ARROWLAKE_S | m_CORE_ATOM | m_GENERIC) /* X86_TUNE_USE_SAHF: Controls use of SAHF. */ DEF_TUNE (X86_TUNE_USE_SAHF, "use_sahf", m_PPRO | m_P4_NOCONA | m_CORE_ALL | m_BONNELL | m_SILVERMONT | m_KNL | m_KNM | m_INTEL | m_K6_GEODE | m_K8 | m_AMDFAM10 | m_BDVER | m_BTVER | m_ZNVER | m_LUJIAZUI | m_GOLDMONT | m_GOLDMONT_PLUS - | m_TREMONT | m_ALDERLAKE | m_ARROWLAKE | m_CORE_ATOM + | m_TREMONT | m_ALDERLAKE | m_ARROWLAKE | m_ARROWLAKE_S| m_CORE_ATOM | m_GENERIC) /* X86_TUNE_USE_CLTD: Controls use of CLTD and CTQO instructions. */ @@ -335,7 +336,7 @@ DEF_TUNE (X86_TUNE_USE_BT, "use_bt", m_CORE_ALL | m_BONNELL | m_SILVERMONT | m_KNL | m_KNM | m_INTEL | m_LAKEMONT | m_AMD_MULTIPLE | m_LUJIAZUI | m_GOLDMONT | m_GOLDMONT_PLUS | m_TREMONT | m_ALDERLAKE | m_ARROWLAKE - | m_CORE_ATOM | m_GENERIC) + | m_ARROWLAKE_S | m_CORE_ATOM | m_GENERIC) /* X86_TUNE_AVOID_FALSE_DEP_FOR_BMI: Avoid false dependency for bit-manipulation instructions. */ @@ -355,12 +356,12 @@ DEF_TUNE (X86_TUNE_ADJUST_UNROLL, "adjust_unroll_factor", m_BDVER3 | m_BDVER4) DEF_TUNE (X86_TUNE_ONE_IF_CONV_INSN, "one_if_conv_insn", m_SILVERMONT | m_KNL | m_KNM | m_INTEL | m_CORE_ALL | m_GOLDMONT | m_GOLDMONT_PLUS | m_TREMONT | m_ALDERLAKE | m_ARROWLAKE - | m_CORE_ATOM | m_LUJIAZUI | m_GENERIC) + | m_ARROWLAKE_S | m_CORE_ATOM | m_LUJIAZUI | m_GENERIC) /* X86_TUNE_AVOID_MFENCE: Use lock prefixed instructions instead of mfence. */ DEF_TUNE (X86_TUNE_AVOID_MFENCE, "avoid_mfence", m_CORE_ALL | m_BDVER | m_ZNVER | m_LUJIAZUI | m_TREMONT | m_ALDERLAKE - | m_ARROWLAKE | m_CORE_ATOM | m_GENERIC) + | m_ARROWLAKE | m_ARROWLAKE_S | m_CORE_ATOM | m_GENERIC) /* X86_TUNE_EXPAND_ABS: This enables a new abs pattern by generating instructions for abs (x) = (((signed) x >> (W-1) ^ x) - @@ -385,7 +386,7 @@ DEF_TUNE (X86_TUNE_USE_SIMODE_FIOP, "use_simode_fiop", ~(m_PENT | m_LAKEMONT | m_PPRO | m_CORE_ALL | m_BONNELL | m_SILVERMONT | m_KNL | m_KNM | m_INTEL | m_AMD_MULTIPLE | m_LUJIAZUI | m_GOLDMONT | m_GOLDMONT_PLUS | m_TREMONT - | m_ALDERLAKE | m_ARROWLAKE | m_CORE_ATOM + | m_ALDERLAKE | m_ARROWLAKE | m_ARROWLAKE_S | m_CORE_ATOM | m_GENERIC)) /* X86_TUNE_USE_FFREEP: Use freep instruction instead of fstp. */ @@ -396,7 +397,7 @@ DEF_TUNE (X86_TUNE_EXT_80387_CONSTANTS, "ext_80387_constants", m_PPRO | m_P4_NOCONA | m_CORE_ALL | m_BONNELL | m_SILVERMONT | m_KNL | m_KNM | m_INTEL | m_K6_GEODE | m_ATHLON_K8 | m_LUJIAZUI | m_GOLDMONT | m_GOLDMONT_PLUS | m_TREMONT | m_ALDERLAKE | m_ARROWLAKE - | m_CORE_ATOM | m_GENERIC) + | m_ARROWLAKE_S | m_CORE_ATOM | m_GENERIC) /*****************************************************************************/ /* SSE instruction selection tuning */ @@ -412,7 +413,7 @@ DEF_TUNE (X86_TUNE_GENERAL_REGS_SSE_SPILL, "general_regs_sse_spill", DEF_TUNE (X86_TUNE_SSE_UNALIGNED_LOAD_OPTIMAL, "sse_unaligned_load_optimal", m_NEHALEM | m_SANDYBRIDGE | m_CORE_AVX2 | m_SILVERMONT | m_KNL | m_KNM | m_INTEL | m_GOLDMONT | m_GOLDMONT_PLUS | m_TREMONT | m_ALDERLAKE - | m_ARROWLAKE | m_CORE_ATOM | m_AMDFAM10 | m_BDVER + | m_ARROWLAKE | m_ARROWLAKE_S | m_CORE_ATOM | m_AMDFAM10 | m_BDVER | m_BTVER | m_ZNVER | m_LUJIAZUI | m_GENERIC) /* X86_TUNE_SSE_UNALIGNED_STORE_OPTIMAL: Use movups for misaligned stores @@ -420,7 +421,7 @@ DEF_TUNE (X86_TUNE_SSE_UNALIGNED_LOAD_OPTIMAL, "sse_unaligned_load_optimal", DEF_TUNE (X86_TUNE_SSE_UNALIGNED_STORE_OPTIMAL, "sse_unaligned_store_optimal", m_NEHALEM | m_SANDYBRIDGE | m_CORE_AVX2 | m_SILVERMONT | m_KNL | m_KNM | m_INTEL | m_GOLDMONT | m_GOLDMONT_PLUS | m_TREMONT | m_ALDERLAKE - | m_ARROWLAKE | m_CORE_ATOM | m_BDVER | m_ZNVER + | m_ARROWLAKE | m_ARROWLAKE_S| m_CORE_ATOM | m_BDVER | m_ZNVER | m_LUJIAZUI | m_GENERIC) /* X86_TUNE_SSE_PACKED_SINGLE_INSN_OPTIMAL: Use packed single @@ -431,13 +432,13 @@ DEF_TUNE (X86_TUNE_SSE_PACKED_SINGLE_INSN_OPTIMAL, "sse_packed_single_insn_optim /* X86_TUNE_SSE_TYPELESS_STORES: Always movaps/movups for 128bit stores. */ DEF_TUNE (X86_TUNE_SSE_TYPELESS_STORES, "sse_typeless_stores", m_AMD_MULTIPLE | m_LUJIAZUI | m_CORE_ALL | m_TREMONT | m_ALDERLAKE - | m_ARROWLAKE | m_CORE_ATOM | m_GENERIC) + | m_ARROWLAKE | m_ARROWLAKE_S | m_CORE_ATOM | m_GENERIC) /* X86_TUNE_SSE_LOAD0_BY_PXOR: Always use pxor to load0 as opposed to xorps/xorpd and other variants. */ DEF_TUNE (X86_TUNE_SSE_LOAD0_BY_PXOR, "sse_load0_by_pxor", m_PPRO | m_P4_NOCONA | m_CORE_ALL | m_BDVER | m_BTVER | m_ZNVER - | m_LUJIAZUI | m_TREMONT | m_ALDERLAKE | m_ARROWLAKE + | m_LUJIAZUI | m_TREMONT | m_ALDERLAKE | m_ARROWLAKE | m_ARROWLAKE_S | m_CORE_ATOM | m_GENERIC) /* X86_TUNE_INTER_UNIT_MOVES_TO_VEC: Enable moves in from integer @@ -485,13 +486,13 @@ DEF_TUNE (X86_TUNE_SLOW_PSHUFB, "slow_pshufb", /* X86_TUNE_AVOID_4BYTE_PREFIXES: Avoid instructions requiring 4+ bytes of prefixes. */ DEF_TUNE (X86_TUNE_AVOID_4BYTE_PREFIXES, "avoid_4byte_prefixes", m_SILVERMONT | m_GOLDMONT | m_GOLDMONT_PLUS | m_TREMONT | m_ALDERLAKE - | m_ARROWLAKE | m_CORE_ATOM | m_INTEL) + | m_ARROWLAKE | m_ARROWLAKE_S | m_CORE_ATOM | m_INTEL) /* X86_TUNE_USE_GATHER_2PARTS: Use gather instructions for vectors with 2 elements. */ DEF_TUNE (X86_TUNE_USE_GATHER_2PARTS, "use_gather_2parts", ~(m_ZNVER1 | m_ZNVER2 | m_ZNVER3 | m_ZNVER4 | m_ALDERLAKE - | m_ARROWLAKE | m_CORE_ATOM | m_GENERIC)) + | m_ARROWLAKE | m_ARROWLAKE_S | m_CORE_ATOM | m_GENERIC | m_GDS)) /* X86_TUNE_USE_SCATTER_2PARTS: Use scater instructions for vectors with 2 elements. */ @@ -502,7 +503,7 @@ DEF_TUNE (X86_TUNE_USE_SCATTER_2PARTS, "use_scatter_2parts", elements. */ DEF_TUNE (X86_TUNE_USE_GATHER_4PARTS, "use_gather_4parts", ~(m_ZNVER1 | m_ZNVER2 | m_ZNVER3 | m_ZNVER4 | m_ALDERLAKE - | m_ARROWLAKE | m_CORE_ATOM | m_GENERIC)) + | m_ARROWLAKE | m_ARROWLAKE_S | m_CORE_ATOM | m_GENERIC | m_GDS)) /* X86_TUNE_USE_SCATTER_4PARTS: Use scater instructions for vectors with 4 elements. */ @@ -511,13 +512,13 @@ DEF_TUNE (X86_TUNE_USE_SCATTER_4PARTS, "use_scatter_4parts", /* X86_TUNE_USE_GATHER: Use gather instructions for vectors with 8 or more elements. */ -DEF_TUNE (X86_TUNE_USE_GATHER, "use_gather", +DEF_TUNE (X86_TUNE_USE_GATHER_8PARTS, "use_gather_8parts", ~(m_ZNVER1 | m_ZNVER2 | m_ZNVER4 | m_ALDERLAKE | m_ARROWLAKE - | m_CORE_ATOM | m_GENERIC)) + | m_ARROWLAKE_S | m_CORE_ATOM | m_GENERIC | m_GDS)) /* X86_TUNE_USE_SCATTER: Use scater instructions for vectors with 8 or more elements. */ -DEF_TUNE (X86_TUNE_USE_SCATTER, "use_scatter", +DEF_TUNE (X86_TUNE_USE_SCATTER_8PARTS, "use_scatter_8parts", ~(m_ZNVER4)) /* X86_TUNE_AVOID_128FMA_CHAINS: Avoid creating loops with tight 128bit or @@ -527,7 +528,7 @@ DEF_TUNE (X86_TUNE_AVOID_128FMA_CHAINS, "avoid_fma_chains", m_ZNVER1 | m_ZNVER2 /* X86_TUNE_AVOID_256FMA_CHAINS: Avoid creating loops with tight 256bit or smaller FMA chain. */ DEF_TUNE (X86_TUNE_AVOID_256FMA_CHAINS, "avoid_fma256_chains", m_ZNVER2 | m_ZNVER3 - | m_ALDERLAKE | m_ARROWLAKE | m_SAPPHIRERAPIDS + | m_ALDERLAKE | m_ARROWLAKE | m_ARROWLAKE_S | m_SAPPHIRERAPIDS | m_CORE_ATOM) /* X86_TUNE_AVOID_512FMA_CHAINS: Avoid creating loops with tight 512bit or @@ -572,13 +573,13 @@ DEF_TUNE (X86_TUNE_AVX512_SPLIT_REGS, "avx512_split_regs", m_ZNVER4) /* X86_TUNE_AVX256_MOVE_BY_PIECES: Optimize move_by_pieces with 256-bit AVX instructions. */ DEF_TUNE (X86_TUNE_AVX256_MOVE_BY_PIECES, "avx256_move_by_pieces", - m_ALDERLAKE | m_ARROWLAKE | m_CORE_AVX2 | m_ZNVER1 + m_ALDERLAKE | m_ARROWLAKE | m_ARROWLAKE_S | m_CORE_AVX2 | m_ZNVER1 | m_ZNVER2 | m_ZNVER3) /* X86_TUNE_AVX256_STORE_BY_PIECES: Optimize store_by_pieces with 256-bit AVX instructions. */ DEF_TUNE (X86_TUNE_AVX256_STORE_BY_PIECES, "avx256_store_by_pieces", - m_ALDERLAKE | m_ARROWLAKE | m_CORE_AVX2 | m_ZNVER1 + m_ALDERLAKE | m_ARROWLAKE | m_ARROWLAKE_S | m_CORE_AVX2 | m_ZNVER1 | m_ZNVER2 | m_ZNVER3) /* X86_TUNE_AVX512_MOVE_BY_PIECES: Optimize move_by_pieces with 512-bit diff --git a/gcc/config/ia64/ia64.cc b/gcc/config/ia64/ia64.cc index 92f34dd1ee7b..c241e1a50fc5 100644 --- a/gcc/config/ia64/ia64.cc +++ b/gcc/config/ia64/ia64.cc @@ -313,7 +313,8 @@ static tree ia64_gimplify_va_arg (tree, tree, gimple_seq *, gimple_seq *); static bool ia64_scalar_mode_supported_p (scalar_mode mode); static bool ia64_vector_mode_supported_p (machine_mode mode); static bool ia64_legitimate_constant_p (machine_mode, rtx); -static bool ia64_legitimate_address_p (machine_mode, rtx, bool); +static bool ia64_legitimate_address_p (machine_mode, rtx, bool, + code_helper = ERROR_MARK); static bool ia64_cannot_force_const_mem (machine_mode, rtx); static const char *ia64_mangle_type (const_tree); static const char *ia64_invalid_conversion (const_tree, const_tree); @@ -1024,8 +1025,8 @@ ia64_legitimate_address_disp (const_rtx reg, const_rtx disp, bool strict) /* Implement TARGET_LEGITIMATE_ADDRESS_P. */ static bool -ia64_legitimate_address_p (machine_mode mode ATTRIBUTE_UNUSED, - rtx x, bool strict) +ia64_legitimate_address_p (machine_mode mode ATTRIBUTE_UNUSED, rtx x, + bool strict, code_helper) { if (ia64_legitimate_address_reg (x, strict)) return true; diff --git a/gcc/config/iq2000/iq2000.cc b/gcc/config/iq2000/iq2000.cc index 733fecac2b72..54404e8d05ac 100644 --- a/gcc/config/iq2000/iq2000.cc +++ b/gcc/config/iq2000/iq2000.cc @@ -170,7 +170,8 @@ static pad_direction iq2000_function_arg_padding (machine_mode, const_tree); static unsigned int iq2000_function_arg_boundary (machine_mode, const_tree); static void iq2000_va_start (tree, rtx); -static bool iq2000_legitimate_address_p (machine_mode, rtx, bool); +static bool iq2000_legitimate_address_p (machine_mode, rtx, bool, + code_helper = ERROR_MARK); static bool iq2000_can_eliminate (const int, const int); static void iq2000_asm_trampoline_template (FILE *); static void iq2000_trampoline_init (rtx, tree, rtx); @@ -304,7 +305,8 @@ iq2000_reg_mode_ok_for_base_p (rtx reg, function is called during reload. */ bool -iq2000_legitimate_address_p (machine_mode mode, rtx xinsn, bool strict) +iq2000_legitimate_address_p (machine_mode mode, rtx xinsn, bool strict, + code_helper) { if (TARGET_DEBUG_A_MODE) { diff --git a/gcc/config/lm32/lm32.cc b/gcc/config/lm32/lm32.cc index 6528358009d4..9d65d66719c5 100644 --- a/gcc/config/lm32/lm32.cc +++ b/gcc/config/lm32/lm32.cc @@ -69,8 +69,8 @@ static void lm32_setup_incoming_varargs (cumulative_args_t cum, static bool lm32_rtx_costs (rtx x, machine_mode mode, int outer_code, int opno, int *total, bool speed); static bool lm32_can_eliminate (const int, const int); -static bool -lm32_legitimate_address_p (machine_mode mode, rtx x, bool strict); +static bool lm32_legitimate_address_p (machine_mode mode, rtx x, bool strict, + code_helper = ERROR_MARK); static HOST_WIDE_INT lm32_compute_frame_size (int size); static void lm32_option_override (void); static rtx lm32_function_arg (cumulative_args_t, const function_arg_info &); @@ -1192,7 +1192,8 @@ lm32_can_eliminate (const int from ATTRIBUTE_UNUSED, const int to) /* Implement TARGET_LEGITIMATE_ADDRESS_P. */ static bool -lm32_legitimate_address_p (machine_mode mode ATTRIBUTE_UNUSED, rtx x, bool strict) +lm32_legitimate_address_p (machine_mode mode ATTRIBUTE_UNUSED, rtx x, + bool strict, code_helper) { /* (rM) */ if (strict && REG_P (x) && STRICT_REG_OK_FOR_BASE_P (x)) diff --git a/gcc/config/loongarch/loongarch-builtins.cc b/gcc/config/loongarch/loongarch-builtins.cc index b929f224dfad..58b612bf4455 100644 --- a/gcc/config/loongarch/loongarch-builtins.cc +++ b/gcc/config/loongarch/loongarch-builtins.cc @@ -256,6 +256,11 @@ loongarch_init_builtins (void) unsigned int i; tree type; + /* Register the type float128_type_node as a built-in type and + give it an alias "__float128". */ + (*lang_hooks.types.register_builtin_type) (float128_type_node, + "__float128"); + /* Iterate through all of the bdesc arrays, initializing all of the builtin functions. */ for (i = 0; i < ARRAY_SIZE (loongarch_builtins); i++) diff --git a/gcc/config/loongarch/loongarch-c.cc b/gcc/config/loongarch/loongarch-c.cc index 67911b78f283..6ffbf7483161 100644 --- a/gcc/config/loongarch/loongarch-c.cc +++ b/gcc/config/loongarch/loongarch-c.cc @@ -99,6 +99,17 @@ loongarch_cpu_cpp_builtins (cpp_reader *pfile) else builtin_define ("__loongarch_frlen=0"); + /* Add support for FLOAT128_TYPE on the LoongArch architecture. */ + builtin_define ("__FLOAT128_TYPE__"); + + /* Map the old _Float128 'q' builtins into the new 'f128' builtins. */ + builtin_define ("__builtin_fabsq=__builtin_fabsf128"); + builtin_define ("__builtin_copysignq=__builtin_copysignf128"); + builtin_define ("__builtin_nanq=__builtin_nanf128"); + builtin_define ("__builtin_nansq=__builtin_nansf128"); + builtin_define ("__builtin_infq=__builtin_inff128"); + builtin_define ("__builtin_huge_valq=__builtin_huge_valf128"); + /* Native Data Sizes. */ builtin_define_with_int_value ("_LOONGARCH_SZINT", INT_TYPE_SIZE); builtin_define_with_int_value ("_LOONGARCH_SZLONG", LONG_TYPE_SIZE); diff --git a/gcc/config/loongarch/loongarch.cc b/gcc/config/loongarch/loongarch.cc index 5b8b93eb24b2..28f771bb0755 100644 --- a/gcc/config/loongarch/loongarch.cc +++ b/gcc/config/loongarch/loongarch.cc @@ -1112,7 +1112,9 @@ loongarch_first_stack_step (struct loongarch_frame_info *frame) static void loongarch_emit_stack_tie (void) { - emit_insn (gen_stack_tie (Pmode, stack_pointer_rtx, hard_frame_pointer_rtx)); + emit_insn (gen_stack_tie (Pmode, stack_pointer_rtx, + frame_pointer_needed ? hard_frame_pointer_rtx + : stack_pointer_rtx)); } #define PROBE_INTERVAL (1 << STACK_CHECK_PROBE_INTERVAL_EXP) @@ -2096,7 +2098,8 @@ loongarch_classify_address (struct loongarch_address_info *info, rtx x, /* Implement TARGET_LEGITIMATE_ADDRESS_P. */ static bool -loongarch_legitimate_address_p (machine_mode mode, rtx x, bool strict_p) +loongarch_legitimate_address_p (machine_mode mode, rtx x, bool strict_p, + code_helper = ERROR_MARK) { struct loongarch_address_info addr; @@ -4222,11 +4225,21 @@ loongarch_allocate_fcc (machine_mode mode) static void loongarch_extend_comparands (rtx_code code, rtx *op0, rtx *op1) { - /* Comparisons consider all XLEN bits, so extend sub-XLEN values. */ + /* Comparisons consider all GRLEN bits, so extend sub-GRLEN values. */ if (GET_MODE_SIZE (word_mode) > GET_MODE_SIZE (GET_MODE (*op0))) { - /* TODO: checkout It is more profitable to zero-extend QImode values. */ - if (unsigned_condition (code) == code && GET_MODE (*op0) == QImode) + /* It is more profitable to zero-extend QImode values. But not if the + first operand has already been sign-extended, and the second one is + is a constant or has already been sign-extended also. */ + if (unsigned_condition (code) == code + && (GET_MODE (*op0) == QImode + && ! (GET_CODE (*op0) == SUBREG + && SUBREG_PROMOTED_VAR_P (*op0) + && SUBREG_PROMOTED_SIGNED_P (*op0) + && (CONST_INT_P (*op1) + || (GET_CODE (*op1) == SUBREG + && SUBREG_PROMOTED_VAR_P (*op1) + && SUBREG_PROMOTED_SIGNED_P (*op1)))))) { *op0 = gen_rtx_ZERO_EXTEND (word_mode, *op0); if (CONST_INT_P (*op1)) @@ -4383,14 +4396,30 @@ loongarch_expand_conditional_move (rtx *operands) enum rtx_code code = GET_CODE (operands[1]); rtx op0 = XEXP (operands[1], 0); rtx op1 = XEXP (operands[1], 1); + rtx op0_extend = op0; + rtx op1_extend = op1; + + /* Record whether operands[2] and operands[3] modes are promoted to word_mode. */ + bool promote_p = false; + machine_mode mode = GET_MODE (operands[0]); if (FLOAT_MODE_P (GET_MODE (op1))) loongarch_emit_float_compare (&code, &op0, &op1); else { + if ((REGNO (op0) == REGNO (operands[2]) + || (REGNO (op1) == REGNO (operands[3]) && (op1 != const0_rtx))) + && (GET_MODE_SIZE (GET_MODE (op0)) < word_mode)) + { + mode = word_mode; + promote_p = true; + } + loongarch_extend_comparands (code, &op0, &op1); op0 = force_reg (word_mode, op0); + op0_extend = op0; + op1_extend = force_reg (word_mode, op1); if (code == EQ || code == NE) { @@ -4417,23 +4446,52 @@ loongarch_expand_conditional_move (rtx *operands) && register_operand (operands[2], VOIDmode) && register_operand (operands[3], VOIDmode)) { - machine_mode mode = GET_MODE (operands[0]); + rtx op2 = operands[2]; + rtx op3 = operands[3]; + + if (promote_p) + { + if (REGNO (XEXP (operands[1], 0)) == REGNO (operands[2])) + op2 = op0_extend; + else + { + loongarch_extend_comparands (code, &op2, &const0_rtx); + op2 = force_reg (mode, op2); + } + + if (REGNO (XEXP (operands[1], 1)) == REGNO (operands[3])) + op3 = op1_extend; + else + { + loongarch_extend_comparands (code, &op3, &const0_rtx); + op3 = force_reg (mode, op3); + } + } + rtx temp = gen_reg_rtx (mode); rtx temp2 = gen_reg_rtx (mode); emit_insn (gen_rtx_SET (temp, gen_rtx_IF_THEN_ELSE (mode, cond, - operands[2], const0_rtx))); + op2, const0_rtx))); /* Flip the test for the second operand. */ cond = gen_rtx_fmt_ee ((code == EQ) ? NE : EQ, GET_MODE (op0), op0, op1); emit_insn (gen_rtx_SET (temp2, gen_rtx_IF_THEN_ELSE (mode, cond, - operands[3], const0_rtx))); + op3, const0_rtx))); /* Merge the two results, at least one is guaranteed to be zero. */ - emit_insn (gen_rtx_SET (operands[0], gen_rtx_IOR (mode, temp, temp2))); + if (promote_p) + { + rtx temp3 = gen_reg_rtx (mode); + emit_insn (gen_rtx_SET (temp3, gen_rtx_IOR (mode, temp, temp2))); + temp3 = gen_lowpart (GET_MODE (operands[0]), temp3); + loongarch_emit_move (operands[0], temp3); + } + else + emit_insn (gen_rtx_SET (operands[0], gen_rtx_IOR (mode, temp, temp2))); } else emit_insn (gen_rtx_SET (operands[0], diff --git a/gcc/config/loongarch/loongarch.md b/gcc/config/loongarch/loongarch.md index b37e070660f1..25e2e1e05970 100644 --- a/gcc/config/loongarch/loongarch.md +++ b/gcc/config/loongarch/loongarch.md @@ -357,7 +357,7 @@ ;; pointer-sized quantities. Exactly one of the two alternatives will match. (define_mode_iterator P [(SI "Pmode == SImode") (DI "Pmode == DImode")]) -;; Likewise, but for XLEN-sized quantities. +;; Likewise, but for GRLEN-sized quantities. (define_mode_iterator X [(SI "!TARGET_64BIT") (DI "TARGET_64BIT")]) ;; 64-bit modes for which we provide move patterns. @@ -1827,8 +1827,8 @@ }) (define_insn_and_split "*movsi_internal" - [(set (match_operand:SI 0 "nonimmediate_operand" "=r,r,r,w,*f,*f,*r,*m,*r,*z") - (match_operand:SI 1 "move_operand" "r,Yd,w,rJ,*r*J,*m,*f,*f,*z,*r"))] + [(set (match_operand:SI 0 "nonimmediate_operand" "=r,r,r,w,*f,f,*r,*m,*r,*z") + (match_operand:SI 1 "move_operand" "r,Yd,w,rJ,*r*J,m,*f,*f,*z,*r"))] "(register_operand (operands[0], SImode) || reg_or_0_operand (operands[1], SImode))" { return loongarch_output_move (operands[0], operands[1]); } @@ -1915,13 +1915,13 @@ }) (define_insn "*movsf_hardfloat" - [(set (match_operand:SF 0 "nonimmediate_operand" "=f,f,f,m,f,k,m,*f,*r,*r,*r,*m") - (match_operand:SF 1 "move_operand" "f,G,m,f,k,f,G,*r,*f,*G*r,*m,*r"))] + [(set (match_operand:SF 0 "nonimmediate_operand" "=f,f,f,m,f,k,m,k,*f,*r,*r,*r,*m") + (match_operand:SF 1 "move_operand" "f,G,m,f,k,f,G,G,*r,*f,*G*r,*m,*r"))] "TARGET_HARD_FLOAT && (register_operand (operands[0], SFmode) || reg_or_0_operand (operands[1], SFmode))" { return loongarch_output_move (operands[0], operands[1]); } - [(set_attr "move_type" "fmove,mgtf,fpload,fpstore,fpload,fpstore,store,mgtf,mftg,move,load,store") + [(set_attr "move_type" "fmove,mgtf,fpload,fpstore,fpload,fpstore,store,store,mgtf,mftg,move,load,store") (set_attr "mode" "SF")]) (define_insn "*movsf_softfloat" @@ -1946,13 +1946,13 @@ }) (define_insn "*movdf_hardfloat" - [(set (match_operand:DF 0 "nonimmediate_operand" "=f,f,f,m,f,k,m,*f,*r,*r,*r,*m") - (match_operand:DF 1 "move_operand" "f,G,m,f,k,f,G,*r,*f,*r*G,*m,*r"))] + [(set (match_operand:DF 0 "nonimmediate_operand" "=f,f,f,m,f,k,m,k,*f,*r,*r,*r,*m") + (match_operand:DF 1 "move_operand" "f,G,m,f,k,f,G,G,*r,*f,*r*G,*m,*r"))] "TARGET_DOUBLE_FLOAT && (register_operand (operands[0], DFmode) || reg_or_0_operand (operands[1], DFmode))" { return loongarch_output_move (operands[0], operands[1]); } - [(set_attr "move_type" "fmove,mgtf,fpload,fpstore,fpload,fpstore,store,mgtf,mftg,move,load,store") + [(set_attr "move_type" "fmove,mgtf,fpload,fpstore,fpload,fpstore,store,store,mgtf,mftg,move,load,store") (set_attr "mode" "DF")]) (define_insn "*movdf_softfloat" @@ -2733,11 +2733,15 @@ [(set_attr "type" "branch")]) +;; Branches operate on GRLEN-sized quantities, but for LoongArch64 we accept +;; QImode values so we can force zero-extension. +(define_mode_iterator BR [(QI "TARGET_64BIT") SI (DI "TARGET_64BIT")]) + (define_expand "cbranch4" [(set (pc) (if_then_else (match_operator 0 "comparison_operator" - [(match_operand:GPR 1 "register_operand") - (match_operand:GPR 2 "nonmemory_operand")]) + [(match_operand:BR 1 "register_operand") + (match_operand:BR 2 "nonmemory_operand")]) (label_ref (match_operand 3 "")) (pc)))] "" diff --git a/gcc/config/loongarch/t-loongarch b/gcc/config/loongarch/t-loongarch index 4ca08035bc8a..43088a05643b 100644 --- a/gcc/config/loongarch/t-loongarch +++ b/gcc/config/loongarch/t-loongarch @@ -16,6 +16,10 @@ # along with GCC; see the file COPYING3. If not see # . +TM_H += $(srcdir)/config/loongarch/loongarch-driver.h +OPTIONS_H_EXTRA += $(srcdir)/config/loongarch/loongarch-def.h \ + $(srcdir)/config/loongarch/loongarch-tune.h + # Canonical target triplet from config.gcc LA_MULTIARCH_TRIPLET = $(patsubst LA_MULTIARCH_TRIPLET=%,%,$\ $(filter LA_MULTIARCH_TRIPLET=%,$(tm_defines))) diff --git a/gcc/config/m32c/m32c.cc b/gcc/config/m32c/m32c.cc index 65971d629902..e18efc3c7f22 100644 --- a/gcc/config/m32c/m32c.cc +++ b/gcc/config/m32c/m32c.cc @@ -75,8 +75,11 @@ static int m32c_comp_type_attributes (const_tree, const_tree); static bool m32c_fixed_condition_code_regs (unsigned int *, unsigned int *); static struct machine_function *m32c_init_machine_status (void); static void m32c_insert_attributes (tree, tree *); -static bool m32c_legitimate_address_p (machine_mode, rtx, bool); -static bool m32c_addr_space_legitimate_address_p (machine_mode, rtx, bool, addr_space_t); +static bool m32c_legitimate_address_p (machine_mode, rtx, bool, + code_helper = ERROR_MARK); +static bool m32c_addr_space_legitimate_address_p (machine_mode, rtx, bool, + addr_space_t, + code_helper = ERROR_MARK); static rtx m32c_function_arg (cumulative_args_t, const function_arg_info &); static bool m32c_pass_by_reference (cumulative_args_t, const function_arg_info &); @@ -1648,7 +1651,7 @@ m32c_trampoline_init (rtx m_tramp, tree fndecl, rtx chainval) #undef TARGET_LEGITIMATE_ADDRESS_P #define TARGET_LEGITIMATE_ADDRESS_P m32c_legitimate_address_p bool -m32c_legitimate_address_p (machine_mode mode, rtx x, bool strict) +m32c_legitimate_address_p (machine_mode mode, rtx x, bool strict, code_helper) { int mode_adjust; if (CONSTANT_P (x)) @@ -1966,8 +1969,8 @@ m32c_addr_space_address_mode (addr_space_t addrspace) #define TARGET_ADDR_SPACE_LEGITIMATE_ADDRESS_P \ m32c_addr_space_legitimate_address_p static bool -m32c_addr_space_legitimate_address_p (machine_mode mode, rtx x, - bool strict, addr_space_t as) +m32c_addr_space_legitimate_address_p (machine_mode mode, rtx x, bool strict, + addr_space_t as, code_helper ch) { if (as == ADDR_SPACE_FAR) { @@ -2048,7 +2051,7 @@ m32c_addr_space_legitimate_address_p (machine_mode mode, rtx x, else if (as != ADDR_SPACE_GENERIC) gcc_unreachable (); - return m32c_legitimate_address_p (mode, x, strict); + return m32c_legitimate_address_p (mode, x, strict, ch); } /* Like m32c_legitimate_address, except with named address support. */ diff --git a/gcc/config/m32r/m32r.cc b/gcc/config/m32r/m32r.cc index 155a248459bc..63a1798da3d6 100644 --- a/gcc/config/m32r/m32r.cc +++ b/gcc/config/m32r/m32r.cc @@ -66,7 +66,8 @@ static void m32r_option_override (void); static void init_reg_tables (void); static void block_move_call (rtx, rtx, rtx); static int m32r_is_insn (rtx); -static bool m32r_legitimate_address_p (machine_mode, rtx, bool); +static bool m32r_legitimate_address_p (machine_mode, rtx, bool, + code_helper = ERROR_MARK); static rtx m32r_legitimize_address (rtx, rtx, machine_mode); static bool m32r_mode_dependent_address_p (const_rtx, addr_space_t); static tree m32r_handle_model_attribute (tree *, tree, tree, int, bool *); @@ -2913,7 +2914,7 @@ m32r_store_preinc_predec_p (machine_mode mode, const_rtx x, bool strict) /* Implement TARGET_LEGITIMATE_ADDRESS_P. */ static bool -m32r_legitimate_address_p (machine_mode mode, rtx x, bool strict) +m32r_legitimate_address_p (machine_mode mode, rtx x, bool strict, code_helper) { if (m32r_rtx_ok_for_base_p (x, strict) || m32r_legitimate_offset_addres_p (mode, x, strict) diff --git a/gcc/config/m68k/m68k.cc b/gcc/config/m68k/m68k.cc index 03db2b6a9369..145a92d8710b 100644 --- a/gcc/config/m68k/m68k.cc +++ b/gcc/config/m68k/m68k.cc @@ -158,7 +158,8 @@ static int m68k_sched_first_cycle_multipass_dfa_lookahead (void); static bool m68k_can_eliminate (const int, const int); static void m68k_conditional_register_usage (void); -static bool m68k_legitimate_address_p (machine_mode, rtx, bool); +static bool m68k_legitimate_address_p (machine_mode, rtx, bool, + code_helper = ERROR_MARK); static void m68k_option_override (void); static void m68k_override_options_after_change (void); static rtx find_addr_reg (rtx); @@ -2311,7 +2312,7 @@ m68k_decompose_address (machine_mode mode, rtx x, STRICT_P says whether strict checking is needed. */ bool -m68k_legitimate_address_p (machine_mode mode, rtx x, bool strict_p) +m68k_legitimate_address_p (machine_mode mode, rtx x, bool strict_p, code_helper) { struct m68k_address address; diff --git a/gcc/config/mcore/mcore.cc b/gcc/config/mcore/mcore.cc index e933b03cdff5..6f1d7af79371 100644 --- a/gcc/config/mcore/mcore.cc +++ b/gcc/config/mcore/mcore.cc @@ -144,7 +144,8 @@ static bool mcore_warn_func_return (tree); static void mcore_option_override (void); static bool mcore_legitimate_constant_p (machine_mode, rtx); static bool mcore_legitimate_address_p (machine_mode, rtx, bool, - addr_space_t); + addr_space_t, + code_helper = ERROR_MARK); static bool mcore_hard_regno_mode_ok (unsigned int, machine_mode); static bool mcore_modes_tieable_p (machine_mode, machine_mode); @@ -3249,7 +3250,7 @@ mcore_legitimate_index_p (machine_mode mode, const_rtx op) static bool mcore_legitimate_address_p (machine_mode mode, rtx x, bool strict_p, - addr_space_t as) + addr_space_t as, code_helper) { gcc_assert (ADDR_SPACE_GENERIC_P (as)); diff --git a/gcc/config/microblaze/microblaze-protos.h b/gcc/config/microblaze/microblaze-protos.h index 31a6515176b1..93fd8d17e3c0 100644 --- a/gcc/config/microblaze/microblaze-protos.h +++ b/gcc/config/microblaze/microblaze-protos.h @@ -22,6 +22,8 @@ #ifndef GCC_MICROBLAZE_PROTOS_H #define GCC_MICROBLAZE_PROTOS_H +#include "tree.h" /* For ERROR_MARK. */ + #ifdef RTX_CODE extern int pic_address_needs_scratch (rtx); extern bool microblaze_constant_address_p (rtx x); @@ -40,7 +42,8 @@ extern int microblaze_can_use_return_insn (void); extern void print_operand (FILE *, rtx, int); extern void print_operand_address (FILE *, rtx); extern void init_cumulative_args (CUMULATIVE_ARGS *,tree, rtx); -extern bool microblaze_legitimate_address_p (machine_mode, rtx, bool); +extern bool microblaze_legitimate_address_p (machine_mode, rtx, bool, + code_helper = ERROR_MARK); extern int microblaze_is_interrupt_variant (void); extern int microblaze_is_break_handler (void); extern int microblaze_break_function_p (tree func); diff --git a/gcc/config/microblaze/microblaze.cc b/gcc/config/microblaze/microblaze.cc index cbabf1af7120..c9f6c4198cfd 100644 --- a/gcc/config/microblaze/microblaze.cc +++ b/gcc/config/microblaze/microblaze.cc @@ -919,7 +919,8 @@ microblaze_classify_address (struct microblaze_address_info *info, rtx x, is called during reload. */ bool -microblaze_legitimate_address_p (machine_mode mode, rtx x, bool strict) +microblaze_legitimate_address_p (machine_mode mode, rtx x, bool strict, + code_helper) { struct microblaze_address_info addr; diff --git a/gcc/config/mips/mips.cc b/gcc/config/mips/mips.cc index f98610209027..a304e1c56377 100644 --- a/gcc/config/mips/mips.cc +++ b/gcc/config/mips/mips.cc @@ -2696,7 +2696,8 @@ mips_classify_address (struct mips_address_info *info, rtx x, /* Implement TARGET_LEGITIMATE_ADDRESS_P. */ static bool -mips_legitimate_address_p (machine_mode mode, rtx x, bool strict_p) +mips_legitimate_address_p (machine_mode mode, rtx x, bool strict_p, + code_helper = ERROR_MARK) { struct mips_address_info addr; diff --git a/gcc/config/mmix/mmix.cc b/gcc/config/mmix/mmix.cc index 1d36306fdb69..347430927499 100644 --- a/gcc/config/mmix/mmix.cc +++ b/gcc/config/mmix/mmix.cc @@ -132,7 +132,8 @@ static void mmix_target_asm_function_end_prologue (FILE *); static void mmix_target_asm_function_epilogue (FILE *); static reg_class_t mmix_preferred_reload_class (rtx, reg_class_t); static reg_class_t mmix_preferred_output_reload_class (rtx, reg_class_t); -static bool mmix_legitimate_address_p (machine_mode, rtx, bool); +static bool mmix_legitimate_address_p (machine_mode, rtx, bool, + code_helper = ERROR_MARK); static bool mmix_legitimate_constant_p (machine_mode, rtx); static void mmix_reorg (void); static void mmix_asm_output_mi_thunk @@ -1109,7 +1110,8 @@ mmix_constant_address_p (rtx x) bool mmix_legitimate_address_p (machine_mode mode ATTRIBUTE_UNUSED, rtx x, - bool strict_checking) + bool strict_checking, + code_helper) { #define MMIX_REG_OK(X) \ ((strict_checking \ diff --git a/gcc/config/mmix/predicates.md b/gcc/config/mmix/predicates.md index 4a9b0177a786..3c98f2686aa8 100644 --- a/gcc/config/mmix/predicates.md +++ b/gcc/config/mmix/predicates.md @@ -158,7 +158,7 @@ ;; See also comment above the "*call_real" pattern. (define_predicate "mmix_address_operand" - (if_then_else (match_test "reload_in_progress || reload_completed") + (if_then_else (match_test "lra_in_progress || reload_completed") (match_test "strict_memory_address_p (Pmode, op)") (match_test "memory_address_p (Pmode, op)"))) @@ -171,4 +171,14 @@ (match_code "plus") (match_code "reg" "0") (match_code "const_int" "1") - (match_test "XEXP (op, 0) == stack_pointer_rtx")))) + (ior + (match_test "XEXP (op, 0) == stack_pointer_rtx") + ;; We can temporarily have a FP+offset here, where we (for FP) + ;; accept only FP and the equivalent elimination of SP+offset. + ;; See lra_eliminate_regs_1 in lra-eliminations.cc c:a line 370: + ;; "rtx to = subst_p ? ep->to_rtx : ep->from_rtx;" + (and + (match_test "lra_in_progress") + (ior + (match_test "XEXP (op, 0) == hard_frame_pointer_rtx") + (match_test "XEXP (op, 0) == frame_pointer_rtx"))))))) diff --git a/gcc/config/mn10300/mn10300.cc b/gcc/config/mn10300/mn10300.cc index a8b01a543cc7..cd1de1b2d833 100644 --- a/gcc/config/mn10300/mn10300.cc +++ b/gcc/config/mn10300/mn10300.cc @@ -1932,7 +1932,8 @@ mn10300_legitimate_pic_operand_p (rtx x) function record_unscaled_index_insn_codes. */ static bool -mn10300_legitimate_address_p (machine_mode mode, rtx x, bool strict) +mn10300_legitimate_address_p (machine_mode mode, rtx x, bool strict, + code_helper = ERROR_MARK) { rtx base, index; diff --git a/gcc/config/moxie/moxie.cc b/gcc/config/moxie/moxie.cc index 2132b6e48a3d..209d03077ea3 100644 --- a/gcc/config/moxie/moxie.cc +++ b/gcc/config/moxie/moxie.cc @@ -577,7 +577,8 @@ moxie_reg_ok_for_base_p (const_rtx reg, bool strict_p) static bool moxie_legitimate_address_p (machine_mode mode ATTRIBUTE_UNUSED, rtx x, bool strict_p, - addr_space_t as) + addr_space_t as, + code_helper = ERROR_MARK) { gcc_assert (ADDR_SPACE_GENERIC_P (as)); diff --git a/gcc/config/msp430/msp430.cc b/gcc/config/msp430/msp430.cc index 6f9c56187ee3..061a9c77961a 100644 --- a/gcc/config/msp430/msp430.cc +++ b/gcc/config/msp430/msp430.cc @@ -927,7 +927,8 @@ reg_ok_for_addr (rtx r, bool strict) bool msp430_legitimate_address_p (machine_mode mode ATTRIBUTE_UNUSED, rtx x ATTRIBUTE_UNUSED, - bool strict ATTRIBUTE_UNUSED) + bool strict ATTRIBUTE_UNUSED, + code_helper = ERROR_MARK) { switch (GET_CODE (x)) { @@ -980,9 +981,10 @@ bool msp430_addr_space_legitimate_address_p (machine_mode mode, rtx x, bool strict, - addr_space_t as ATTRIBUTE_UNUSED) + addr_space_t as ATTRIBUTE_UNUSED, + code_helper ch = ERROR_MARK) { - return msp430_legitimate_address_p (mode, x, strict); + return msp430_legitimate_address_p (mode, x, strict, ch); } #undef TARGET_ASM_INTEGER diff --git a/gcc/config/nds32/nds32.cc b/gcc/config/nds32/nds32.cc index 91ed91d914f8..1f8de2a514a2 100644 --- a/gcc/config/nds32/nds32.cc +++ b/gcc/config/nds32/nds32.cc @@ -2565,7 +2565,8 @@ nds32_trampoline_init (rtx m_tramp, tree fndecl, rtx chain_value) /* Addressing Modes. */ static bool -nds32_legitimate_address_p (machine_mode mode, rtx x, bool strict) +nds32_legitimate_address_p (machine_mode mode, rtx x, bool strict, + code_helper = ERROR_MARK) { if (TARGET_FPU_SINGLE || TARGET_FPU_DOUBLE) { diff --git a/gcc/config/nios2/nios2.cc b/gcc/config/nios2/nios2.cc index 936eb34ace4a..b435d7475f98 100644 --- a/gcc/config/nios2/nios2.cc +++ b/gcc/config/nios2/nios2.cc @@ -2141,8 +2141,9 @@ nios2_valid_addr_expr_p (rtx base, rtx offset, bool strict_p) /* Implement TARGET_LEGITIMATE_ADDRESS_P. */ static bool -nios2_legitimate_address_p (machine_mode mode ATTRIBUTE_UNUSED, - rtx operand, bool strict_p) +nios2_legitimate_address_p (machine_mode mode ATTRIBUTE_UNUSED, rtx operand, + bool strict_p, + code_helper = ERROR_MARK) { switch (GET_CODE (operand)) { diff --git a/gcc/config/nvptx/nvptx.cc b/gcc/config/nvptx/nvptx.cc index 16ed78030d73..edef39fb5e1e 100644 --- a/gcc/config/nvptx/nvptx.cc +++ b/gcc/config/nvptx/nvptx.cc @@ -2202,7 +2202,7 @@ nvptx_gen_shared_bcast (rtx reg, propagate_mask pm, unsigned rep, /* Returns true if X is a valid address for use in a memory reference. */ static bool -nvptx_legitimate_address_p (machine_mode, rtx x, bool) +nvptx_legitimate_address_p (machine_mode, rtx x, bool, code_helper) { enum rtx_code code = GET_CODE (x); diff --git a/gcc/config/or1k/or1k.cc b/gcc/config/or1k/or1k.cc index ec30bc8156cb..5eeed0e91be5 100644 --- a/gcc/config/or1k/or1k.cc +++ b/gcc/config/or1k/or1k.cc @@ -575,7 +575,8 @@ or1k_initial_elimination_offset (int from, int to) Returns true if X is a legitimate address RTX on OpenRISC. */ static bool -or1k_legitimate_address_p (machine_mode, rtx x, bool strict_p) +or1k_legitimate_address_p (machine_mode, rtx x, bool strict_p, + code_helper = ERROR_MARK) { rtx base, addend; diff --git a/gcc/config/pa/pa.cc b/gcc/config/pa/pa.cc index 0fa9e5fd632f..2e906cff7ffe 100644 --- a/gcc/config/pa/pa.cc +++ b/gcc/config/pa/pa.cc @@ -196,7 +196,8 @@ static section *pa_function_section (tree, enum node_frequency, bool, bool); static bool pa_cannot_force_const_mem (machine_mode, rtx); static bool pa_legitimate_constant_p (machine_mode, rtx); static unsigned int pa_section_type_flags (tree, const char *, int); -static bool pa_legitimate_address_p (machine_mode, rtx, bool); +static bool pa_legitimate_address_p (machine_mode, rtx, bool, + code_helper = ERROR_MARK); static bool pa_callee_copies (cumulative_args_t, const function_arg_info &); static unsigned int pa_hard_regno_nregs (unsigned int, machine_mode); static bool pa_hard_regno_mode_ok (unsigned int, machine_mode); @@ -10787,7 +10788,7 @@ pa_section_type_flags (tree decl, const char *name, int reloc) output as REG+SMALLINT. */ static bool -pa_legitimate_address_p (machine_mode mode, rtx x, bool strict) +pa_legitimate_address_p (machine_mode mode, rtx x, bool strict, code_helper) { if ((REG_P (x) && (strict ? STRICT_REG_OK_FOR_BASE_P (x) diff --git a/gcc/config/pdp11/pdp11.cc b/gcc/config/pdp11/pdp11.cc index 311a1d225e05..78c1927f1439 100644 --- a/gcc/config/pdp11/pdp11.cc +++ b/gcc/config/pdp11/pdp11.cc @@ -1615,8 +1615,8 @@ pdp11_secondary_memory_needed (machine_mode, reg_class_t c1, reg_class_t c2) */ static bool -pdp11_legitimate_address_p (machine_mode mode, - rtx operand, bool strict) +pdp11_legitimate_address_p (machine_mode mode, rtx operand, bool strict, + code_helper = ERROR_MARK) { rtx xfoob; diff --git a/gcc/config/pru/predicates.md b/gcc/config/pru/predicates.md index e4a7fcf259bd..faa0dbf9fb41 100644 --- a/gcc/config/pru/predicates.md +++ b/gcc/config/pru/predicates.md @@ -22,6 +22,10 @@ (and (match_code "const_int") (match_test "INTVAL (op) == 1"))) +(define_predicate "const_0_operand" + (and (match_code "const_int") + (match_test "INTVAL (op) == 0"))) + ; Note: Always pass a valid mode! (define_predicate "const_ubyte_operand" (match_code "const_int") @@ -49,6 +53,10 @@ (define_predicate "pru_fp_comparison_operator" (match_code "eq,ne,lt,gt,le,ge")) +;; TRUE for comparisons supported by PRU's cstore. +(define_predicate "pru_cstore_comparison_operator" + (match_code "eq,ne,gtu")) + ;; Return true if OP is a constant that contains only one 1 in its ;; binary representation. (define_predicate "single_one_operand" diff --git a/gcc/config/pru/pru.cc b/gcc/config/pru/pru.cc index e855bbb8195c..6e8112be64a7 100644 --- a/gcc/config/pru/pru.cc +++ b/gcc/config/pru/pru.cc @@ -1466,7 +1466,8 @@ int pru_symref2ioregno (rtx op) /* Implement TARGET_ADDR_SPACE_LEGITIMATE_ADDRESS_P. */ static bool pru_addr_space_legitimate_address_p (machine_mode mode, rtx operand, - bool strict_p, addr_space_t as) + bool strict_p, addr_space_t as, + code_helper = ERROR_MARK) { if (as == ADDR_SPACE_REGIO) { diff --git a/gcc/config/pru/pru.md b/gcc/config/pru/pru.md index 6deb5ecfecb3..93ad7b6ad7e7 100644 --- a/gcc/config/pru/pru.md +++ b/gcc/config/pru/pru.md @@ -1489,6 +1489,68 @@ gcc_unreachable (); }) +;; Emit efficient code for two specific cstore cases: +;; X == 0 +;; X != 0 +;; +;; These can be efficiently compiled on the PRU using the umin +;; instruction. +;; +;; This expansion does not handle "X > 0 unsigned" and "X >= 1 unsigned" +;; because it is assumed that those would have been replaced with the +;; canonical "X != 0". +(define_expand "cstore4" + [(set (match_operand:QISI 0 "register_operand") + (match_operator:QISI 1 "pru_cstore_comparison_operator" + [(match_operand:QISI 2 "register_operand") + (match_operand:QISI 3 "const_0_operand")]))] + "" +{ + const enum rtx_code op1code = GET_CODE (operands[1]); + + /* Crash if OP1 is GTU. It would mean that "X > 0 unsigned" + had not been canonicalized before calling this expansion. */ + gcc_assert (op1code == NE || op1code == EQ); + gcc_assert (CONST_INT_P (operands[3]) && INTVAL (operands[3]) == 0); + + if (op1code == NE) + { + emit_insn (gen_umin3 (operands[0], operands[2], const1_rtx)); + DONE; + } + else if (op1code == EQ) + { + rtx tmpval = gen_reg_rtx (mode); + emit_insn (gen_umin3 (tmpval, operands[2], const1_rtx)); + emit_insn (gen_xor3 (operands[0], tmpval, const1_rtx)); + DONE; + } + + gcc_unreachable (); +}) + +(define_expand "cstoredi4" + [(set (match_operand:SI 0 "register_operand") + (match_operator:SI 1 "pru_cstore_comparison_operator" + [(match_operand:DI 2 "register_operand") + (match_operand:DI 3 "const_0_operand")]))] + "" +{ + /* Combining the two SImode suboperands with IOR works only for + the currently supported set of cstoresi3 operations. */ + const enum rtx_code op1code = GET_CODE (operands[1]); + gcc_assert (op1code == NE || op1code == EQ); + gcc_assert (CONST_INT_P (operands[3]) && INTVAL (operands[3]) == 0); + + rtx tmpval = gen_reg_rtx (SImode); + rtx src_lo = simplify_gen_subreg (SImode, operands[2], DImode, 0); + rtx src_hi = simplify_gen_subreg (SImode, operands[2], DImode, 4); + emit_insn (gen_iorsi3 (tmpval, src_lo, src_hi)); + emit_insn (gen_cstoresi4 (operands[0], operands[1], tmpval, const0_rtx)); + + DONE; +}) + ; ; Bit test branch diff --git a/gcc/config/riscv/autovec-opt.md b/gcc/config/riscv/autovec-opt.md index 99b609a99d97..1ca5ce971933 100644 --- a/gcc/config/riscv/autovec-opt.md +++ b/gcc/config/riscv/autovec-opt.md @@ -45,7 +45,7 @@ insn_code icode = code_for_pred_vf2 (, mode); rtx tmp = gen_reg_rtx (mode); rtx ops[] = {tmp, operands[4]}; - riscv_vector::emit_vlmax_insn (icode, riscv_vector::RVV_UNOP, ops); + riscv_vector::emit_vlmax_insn (icode, riscv_vector::UNARY_OP, ops); emit_insn (gen_pred (MULT, mode, operands[0], operands[1], operands[2], operands[3], tmp, operands[5], operands[6], @@ -138,7 +138,7 @@ [(const_int 0)] { insn_code icode = code_for_pred_not (, mode); - riscv_vector::emit_vlmax_insn (icode, riscv_vector::RVV_BINOP, operands); + riscv_vector::emit_vlmax_insn (icode, riscv_vector::BINARY_MASK_OP, operands); DONE; } [(set_attr "type" "vmalu") @@ -165,7 +165,7 @@ [(const_int 0)] { insn_code icode = code_for_pred_n (, mode); - riscv_vector::emit_vlmax_insn (icode, riscv_vector::RVV_BINOP, operands); + riscv_vector::emit_vlmax_insn (icode, riscv_vector::BINARY_MASK_OP, operands); DONE; } [(set_attr "type" "vmalu") @@ -202,8 +202,8 @@ "&& 1" [(const_int 0)] { - riscv_vector::emit_vlmax_ternary_insn (code_for_pred_widen_mul_plus (, mode), - riscv_vector::RVV_WIDEN_TERNOP, operands); + riscv_vector::emit_vlmax_insn (code_for_pred_widen_mul_plus (, mode), + riscv_vector::WIDEN_TERNARY_OP, operands); DONE; } [(set_attr "type" "viwmuladd") @@ -226,7 +226,7 @@ insn_code icode = code_for_pred_vf2 (, mode); rtx tmp = gen_reg_rtx (mode); rtx ext_ops[] = {tmp, operands[2]}; - riscv_vector::emit_vlmax_insn (icode, riscv_vector::RVV_UNOP, ext_ops); + riscv_vector::emit_vlmax_insn (icode, riscv_vector::UNARY_OP, ext_ops); rtx dst = expand_ternary_op (mode, fma_optab, tmp, operands[3], operands[1], operands[0], 0); @@ -301,8 +301,8 @@ "&& 1" [(const_int 0)] { - riscv_vector::emit_vlmax_ternary_insn (code_for_pred_widen_mul_plussu (mode), - riscv_vector::RVV_WIDEN_TERNOP, operands); + riscv_vector::emit_vlmax_insn (code_for_pred_widen_mul_plussu (mode), + riscv_vector::WIDEN_TERNARY_OP, operands); DONE; } [(set_attr "type" "viwmuladd") @@ -324,8 +324,8 @@ [(const_int 0)] { rtx ops[] = {operands[0], operands[1], operands[3], operands[2]}; - riscv_vector::emit_vlmax_ternary_insn (code_for_pred_widen_mul_plussu (mode), - riscv_vector::RVV_WIDEN_TERNOP, ops); + riscv_vector::emit_vlmax_insn (code_for_pred_widen_mul_plussu (mode), + riscv_vector::WIDEN_TERNARY_OP, ops); DONE; } [(set_attr "type" "viwmuladd") @@ -352,7 +352,7 @@ [(const_int 0)] { insn_code icode = code_for_pred_narrow (, mode); - riscv_vector::emit_vlmax_insn (icode, riscv_vector::RVV_BINOP, operands); + riscv_vector::emit_vlmax_insn (icode, riscv_vector::BINARY_OP, operands); DONE; } [(set_attr "type" "vnshift") @@ -371,7 +371,7 @@ { operands[2] = gen_lowpart (Pmode, operands[2]); insn_code icode = code_for_pred_narrow_scalar (, mode); - riscv_vector::emit_vlmax_insn (icode, riscv_vector::RVV_BINOP, operands); + riscv_vector::emit_vlmax_insn (icode, riscv_vector::BINARY_OP, operands); DONE; } [(set_attr "type" "vnshift") @@ -435,7 +435,7 @@ insn_code icode = code_for_pred_extend (mode); rtx tmp = gen_reg_rtx (mode); rtx ops[] = {tmp, operands[4]}; - riscv_vector::emit_vlmax_insn (icode, riscv_vector::RVV_UNOP, ops); + riscv_vector::emit_vlmax_insn (icode, riscv_vector::UNARY_OP, ops); emit_insn (gen_pred (MULT, mode, operands[0], operands[1], operands[2], operands[3], tmp, operands[5], operands[6], @@ -459,32 +459,37 @@ ;; vect__13.182_33 = .FMA (vect__11.180_35, vect__8.176_40, vect__4.172_45); (define_insn_and_split "*double_widen_fma" [(set (match_operand:VWEXTF 0 "register_operand") - (fma:VWEXTF - (float_extend:VWEXTF - (match_operand: 2 "register_operand")) - (float_extend:VWEXTF - (match_operand: 3 "register_operand")) - (match_operand:VWEXTF 1 "register_operand")))] + (unspec:VWEXTF + [(fma:VWEXTF + (float_extend:VWEXTF + (match_operand: 2 "register_operand")) + (float_extend:VWEXTF + (match_operand: 3 "register_operand")) + (match_operand:VWEXTF 1 "register_operand")) + (reg:SI FRM_REGNUM)] UNSPEC_VFFMA))] "TARGET_VECTOR && can_create_pseudo_p ()" "#" "&& 1" [(const_int 0)] { - riscv_vector::emit_vlmax_fp_ternary_insn (code_for_pred_widen_mul (PLUS, mode), - riscv_vector::RVV_WIDEN_TERNOP, operands); + riscv_vector::emit_vlmax_insn (code_for_pred_widen_mul (PLUS, mode), + riscv_vector::WIDEN_TERNARY_OP_FRM_DYN, operands); DONE; } [(set_attr "type" "vfwmuladd") - (set_attr "mode" "")]) + (set_attr "mode" "") + (set (attr "frm_mode") (symbol_ref "riscv_vector::FRM_DYN"))]) ;; This helps to match ext + fma. (define_insn_and_split "*single_widen_fma" [(set (match_operand:VWEXTF 0 "register_operand") - (fma:VWEXTF - (float_extend:VWEXTF - (match_operand: 2 "register_operand")) - (match_operand:VWEXTF 3 "register_operand") - (match_operand:VWEXTF 1 "register_operand")))] + (unspec:VWEXTF + [(fma:VWEXTF + (float_extend:VWEXTF + (match_operand: 2 "register_operand")) + (match_operand:VWEXTF 3 "register_operand") + (match_operand:VWEXTF 1 "register_operand")) + (reg:SI FRM_REGNUM)] UNSPEC_VFFMA))] "TARGET_VECTOR && can_create_pseudo_p ()" "#" "&& 1" @@ -493,7 +498,7 @@ insn_code icode = code_for_pred_extend (mode); rtx tmp = gen_reg_rtx (mode); rtx ext_ops[] = {tmp, operands[2]}; - riscv_vector::emit_vlmax_insn (icode, riscv_vector::RVV_UNOP, ext_ops); + riscv_vector::emit_vlmax_insn (icode, riscv_vector::UNARY_OP, ext_ops); rtx dst = expand_ternary_op (mode, fma_optab, tmp, operands[3], operands[1], operands[0], 0); @@ -501,7 +506,8 @@ DONE; } [(set_attr "type" "vfwmuladd") - (set_attr "mode" "")]) + (set_attr "mode" "") + (set (attr "frm_mode") (symbol_ref "riscv_vector::FRM_DYN"))]) ;; ------------------------------------------------------------------------- ;; ---- [FP] VFWNMSAC @@ -517,34 +523,39 @@ ;; vect__13.182_33 = .FNMA (vect__11.180_35, vect__8.176_40, vect__4.172_45); (define_insn_and_split "*double_widen_fnma" [(set (match_operand:VWEXTF 0 "register_operand") - (fma:VWEXTF - (neg:VWEXTF + (unspec:VWEXTF + [(fma:VWEXTF + (neg:VWEXTF + (float_extend:VWEXTF + (match_operand: 2 "register_operand"))) (float_extend:VWEXTF - (match_operand: 2 "register_operand"))) - (float_extend:VWEXTF - (match_operand: 3 "register_operand")) - (match_operand:VWEXTF 1 "register_operand")))] + (match_operand: 3 "register_operand")) + (match_operand:VWEXTF 1 "register_operand")) + (reg:SI FRM_REGNUM)] UNSPEC_VFFMA))] "TARGET_VECTOR && can_create_pseudo_p ()" "#" "&& 1" [(const_int 0)] { - riscv_vector::emit_vlmax_fp_ternary_insn (code_for_pred_widen_mul_neg (PLUS, mode), - riscv_vector::RVV_WIDEN_TERNOP, operands); + riscv_vector::emit_vlmax_insn (code_for_pred_widen_mul_neg (PLUS, mode), + riscv_vector::WIDEN_TERNARY_OP_FRM_DYN, operands); DONE; } [(set_attr "type" "vfwmuladd") - (set_attr "mode" "")]) + (set_attr "mode" "") + (set (attr "frm_mode") (symbol_ref "riscv_vector::FRM_DYN"))]) ;; This helps to match ext + fnma. (define_insn_and_split "*single_widen_fnma" [(set (match_operand:VWEXTF 0 "register_operand") - (fma:VWEXTF - (neg:VWEXTF - (float_extend:VWEXTF - (match_operand: 2 "register_operand"))) - (match_operand:VWEXTF 3 "register_operand") - (match_operand:VWEXTF 1 "register_operand")))] + (unspec:VWEXTF + [(fma:VWEXTF + (neg:VWEXTF + (float_extend:VWEXTF + (match_operand: 2 "register_operand"))) + (match_operand:VWEXTF 3 "register_operand") + (match_operand:VWEXTF 1 "register_operand")) + (reg:SI FRM_REGNUM)] UNSPEC_VFFMA))] "TARGET_VECTOR && can_create_pseudo_p ()" "#" "&& 1" @@ -553,7 +564,7 @@ insn_code icode = code_for_pred_extend (mode); rtx tmp = gen_reg_rtx (mode); rtx ext_ops[] = {tmp, operands[2]}; - riscv_vector::emit_vlmax_insn (icode, riscv_vector::RVV_UNOP, ext_ops); + riscv_vector::emit_vlmax_insn (icode, riscv_vector::UNARY_OP, ext_ops); rtx dst = expand_ternary_op (mode, fnma_optab, tmp, operands[3], operands[1], operands[0], 0); @@ -561,7 +572,8 @@ DONE; } [(set_attr "type" "vfwmuladd") - (set_attr "mode" "")]) + (set_attr "mode" "") + (set (attr "frm_mode") (symbol_ref "riscv_vector::FRM_DYN"))]) ;; ------------------------------------------------------------------------- ;; ---- [FP] VFWMSAC @@ -577,34 +589,39 @@ ;; vect__13.182_33 = .FMS (vect__11.180_35, vect__8.176_40, vect__4.172_45); (define_insn_and_split "*double_widen_fms" [(set (match_operand:VWEXTF 0 "register_operand") - (fma:VWEXTF - (float_extend:VWEXTF - (match_operand: 2 "register_operand")) - (float_extend:VWEXTF - (match_operand: 3 "register_operand")) - (neg:VWEXTF - (match_operand:VWEXTF 1 "register_operand"))))] + (unspec:VWEXTF + [(fma:VWEXTF + (float_extend:VWEXTF + (match_operand: 2 "register_operand")) + (float_extend:VWEXTF + (match_operand: 3 "register_operand")) + (neg:VWEXTF + (match_operand:VWEXTF 1 "register_operand"))) + (reg:SI FRM_REGNUM)] UNSPEC_VFFMA))] "TARGET_VECTOR && can_create_pseudo_p ()" "#" "&& 1" [(const_int 0)] { - riscv_vector::emit_vlmax_fp_ternary_insn (code_for_pred_widen_mul (MINUS, mode), - riscv_vector::RVV_WIDEN_TERNOP, operands); + riscv_vector::emit_vlmax_insn (code_for_pred_widen_mul (MINUS, mode), + riscv_vector::WIDEN_TERNARY_OP_FRM_DYN, operands); DONE; } [(set_attr "type" "vfwmuladd") - (set_attr "mode" "")]) + (set_attr "mode" "") + (set (attr "frm_mode") (symbol_ref "riscv_vector::FRM_DYN"))]) ;; This helps to match ext + fms. (define_insn_and_split "*single_widen_fms" [(set (match_operand:VWEXTF 0 "register_operand") - (fma:VWEXTF - (float_extend:VWEXTF - (match_operand: 2 "register_operand")) - (match_operand:VWEXTF 3 "register_operand") - (neg:VWEXTF - (match_operand:VWEXTF 1 "register_operand"))))] + (unspec:VWEXTF + [(fma:VWEXTF + (float_extend:VWEXTF + (match_operand: 2 "register_operand")) + (match_operand:VWEXTF 3 "register_operand") + (neg:VWEXTF + (match_operand:VWEXTF 1 "register_operand"))) + (reg:SI FRM_REGNUM)] UNSPEC_VFFMA))] "TARGET_VECTOR && can_create_pseudo_p ()" "#" "&& 1" @@ -613,7 +630,7 @@ insn_code icode = code_for_pred_extend (mode); rtx tmp = gen_reg_rtx (mode); rtx ext_ops[] = {tmp, operands[2]}; - riscv_vector::emit_vlmax_insn (icode, riscv_vector::RVV_UNOP, ext_ops); + riscv_vector::emit_vlmax_insn (icode, riscv_vector::UNARY_OP, ext_ops); rtx dst = expand_ternary_op (mode, fms_optab, tmp, operands[3], operands[1], operands[0], 0); @@ -621,7 +638,8 @@ DONE; } [(set_attr "type" "vfwmuladd") - (set_attr "mode" "")]) + (set_attr "mode" "") + (set (attr "frm_mode") (symbol_ref "riscv_vector::FRM_DYN"))]) ;; ------------------------------------------------------------------------- ;; ---- [FP] VFWNMACC @@ -637,36 +655,41 @@ ;; vect__13.182_33 = .FNMS (vect__11.180_35, vect__8.176_40, vect__4.172_45); (define_insn_and_split "*double_widen_fnms" [(set (match_operand:VWEXTF 0 "register_operand") - (fma:VWEXTF - (neg:VWEXTF + (unspec:VWEXTF + [(fma:VWEXTF + (neg:VWEXTF + (float_extend:VWEXTF + (match_operand: 2 "register_operand"))) (float_extend:VWEXTF - (match_operand: 2 "register_operand"))) - (float_extend:VWEXTF - (match_operand: 3 "register_operand")) - (neg:VWEXTF - (match_operand:VWEXTF 1 "register_operand"))))] + (match_operand: 3 "register_operand")) + (neg:VWEXTF + (match_operand:VWEXTF 1 "register_operand"))) + (reg:SI FRM_REGNUM)] UNSPEC_VFFMA))] "TARGET_VECTOR && can_create_pseudo_p ()" "#" "&& 1" [(const_int 0)] { - riscv_vector::emit_vlmax_fp_ternary_insn (code_for_pred_widen_mul_neg (MINUS, mode), - riscv_vector::RVV_WIDEN_TERNOP, operands); + riscv_vector::emit_vlmax_insn (code_for_pred_widen_mul_neg (MINUS, mode), + riscv_vector::WIDEN_TERNARY_OP_FRM_DYN, operands); DONE; } [(set_attr "type" "vfwmuladd") - (set_attr "mode" "")]) + (set_attr "mode" "") + (set (attr "frm_mode") (symbol_ref "riscv_vector::FRM_DYN"))]) ;; This helps to match ext + fnms. (define_insn_and_split "*single_widen_fnms" [(set (match_operand:VWEXTF 0 "register_operand") - (fma:VWEXTF - (neg:VWEXTF - (float_extend:VWEXTF - (match_operand: 2 "register_operand"))) - (match_operand:VWEXTF 3 "register_operand") - (neg:VWEXTF - (match_operand:VWEXTF 1 "register_operand"))))] + (unspec:VWEXTF + [(fma:VWEXTF + (neg:VWEXTF + (float_extend:VWEXTF + (match_operand: 2 "register_operand"))) + (match_operand:VWEXTF 3 "register_operand") + (neg:VWEXTF + (match_operand:VWEXTF 1 "register_operand"))) + (reg:SI FRM_REGNUM)] UNSPEC_VFFMA))] "TARGET_VECTOR && can_create_pseudo_p ()" "#" "&& 1" @@ -675,7 +698,7 @@ insn_code icode = code_for_pred_extend (mode); rtx tmp = gen_reg_rtx (mode); rtx ext_ops[] = {tmp, operands[2]}; - riscv_vector::emit_vlmax_insn (icode, riscv_vector::RVV_UNOP, ext_ops); + riscv_vector::emit_vlmax_insn (icode, riscv_vector::UNARY_OP, ext_ops); rtx dst = expand_ternary_op (mode, fnms_optab, tmp, operands[3], operands[1], operands[0], 0); @@ -683,4 +706,280 @@ DONE; } [(set_attr "type" "vfwmuladd") - (set_attr "mode" "")]) + (set_attr "mode" "") + (set (attr "frm_mode") (symbol_ref "riscv_vector::FRM_DYN"))]) + +;; Combine and vcond_mask generated by midend into cond_len_ +;; Currently supported operations: +;; abs(FP) +(define_insn_and_split "*cond_abs" + [(set (match_operand:VF 0 "register_operand") + (if_then_else:VF + (match_operand: 3 "register_operand") + (abs:VF (match_operand:VF 1 "nonmemory_operand")) + (match_operand:VF 2 "register_operand")))] + "TARGET_VECTOR && can_create_pseudo_p ()" + "#" + "&& 1" + [(const_int 0)] +{ + emit_insn (gen_cond_len_abs (operands[0], operands[3], operands[1], + operands[2], + gen_int_mode (GET_MODE_NUNITS (mode), Pmode), + const0_rtx)); + DONE; +}) + +;; Combine vlmax neg and UNSPEC_VCOPYSIGN +(define_insn_and_split "*copysign_neg" + [(set (match_operand:VF 0 "register_operand") + (neg:VF + (unspec:VF [ + (match_operand:VF 1 "register_operand") + (match_operand:VF 2 "register_operand") + ] UNSPEC_VCOPYSIGN)))] + "TARGET_VECTOR && can_create_pseudo_p ()" + "#" + "&& 1" + [(const_int 0)] +{ + riscv_vector::emit_vlmax_insn (code_for_pred_ncopysign (mode), + riscv_vector::BINARY_OP, operands); + DONE; +}) + +;; Combine sign_extend/zero_extend(vf2) and vcond_mask +(define_insn_and_split "*cond_" + [(set (match_operand:VWEXTI 0 "register_operand") + (if_then_else:VWEXTI + (match_operand: 1 "register_operand") + (any_extend:VWEXTI (match_operand: 2 "register_operand")) + (match_operand:VWEXTI 3 "register_operand")))] + "TARGET_VECTOR && can_create_pseudo_p ()" + "#" + "&& 1" + [(const_int 0)] +{ + insn_code icode = code_for_pred_vf2 (, mode); + rtx ops[] = {operands[0], operands[1], operands[2], operands[3], + gen_int_mode (GET_MODE_NUNITS (mode), Pmode)}; + riscv_vector::expand_cond_len_unop (icode, ops); + DONE; +}) + +;; Combine sign_extend/zero_extend(vf4) and vcond_mask +(define_insn_and_split "*cond_" + [(set (match_operand:VQEXTI 0 "register_operand") + (if_then_else:VQEXTI + (match_operand: 1 "register_operand") + (any_extend:VQEXTI (match_operand: 2 "register_operand")) + (match_operand:VQEXTI 3 "register_operand")))] + "TARGET_VECTOR && can_create_pseudo_p ()" + "#" + "&& 1" + [(const_int 0)] +{ + insn_code icode = code_for_pred_vf4 (, mode); + rtx ops[] = {operands[0], operands[1], operands[2], operands[3], + gen_int_mode (GET_MODE_NUNITS (mode), Pmode)}; + riscv_vector::expand_cond_len_unop (icode, ops); + DONE; +}) + +;; Combine sign_extend/zero_extend(vf8) and vcond_mask +(define_insn_and_split "*cond_" + [(set (match_operand:VOEXTI 0 "register_operand") + (if_then_else:VOEXTI + (match_operand: 1 "register_operand") + (any_extend:VOEXTI (match_operand: 2 "register_operand")) + (match_operand:VOEXTI 3 "register_operand")))] + "TARGET_VECTOR && can_create_pseudo_p ()" + "#" + "&& 1" + [(const_int 0)] +{ + insn_code icode = code_for_pred_vf8 (, mode); + rtx ops[] = {operands[0], operands[1], operands[2], operands[3], + gen_int_mode (GET_MODE_NUNITS (mode), Pmode)}; + riscv_vector::expand_cond_len_unop (icode, ops); + DONE; +}) + +;; Combine trunc(vf2) + vcond_mask +(define_insn_and_split "*cond_trunc" + [(set (match_operand: 0 "register_operand") + (if_then_else: + (match_operand: 1 "register_operand") + (truncate: + (match_operand:VWEXTI 2 "register_operand")) + (match_operand: 3 "register_operand")))] + "TARGET_VECTOR && can_create_pseudo_p ()" + "#" + "&& 1" + [(const_int 0)] +{ + insn_code icode = code_for_pred_trunc (mode); + rtx ops[] = {operands[0], operands[1], operands[2], operands[3], + gen_int_mode (GET_MODE_NUNITS (mode), Pmode)}; + riscv_vector::expand_cond_len_unop (icode, ops); + DONE; +}) + +;; Combine FP sign_extend/zero_extend(vf2) and vcond_mask +(define_insn_and_split "*cond_extend" + [(set (match_operand:VWEXTF_ZVFHMIN 0 "register_operand") + (if_then_else:VWEXTF_ZVFHMIN + (match_operand: 1 "register_operand") + (float_extend:VWEXTF_ZVFHMIN (match_operand: 2 "register_operand")) + (match_operand:VWEXTF_ZVFHMIN 3 "register_operand")))] + "TARGET_VECTOR && can_create_pseudo_p ()" + "#" + "&& 1" + [(const_int 0)] +{ + insn_code icode = code_for_pred_extend (mode); + rtx ops[] = {operands[0], operands[1], operands[2], operands[3], + gen_int_mode (GET_MODE_NUNITS (mode), Pmode)}; + riscv_vector::expand_cond_len_unop (icode, ops); + DONE; +}) + +;; Combine FP trunc(vf2) + vcond_mask +(define_insn_and_split "*cond_trunc" + [(set (match_operand: 0 "register_operand") + (if_then_else: + (match_operand: 1 "register_operand") + (float_truncate: + (match_operand:VWEXTF_ZVFHMIN 2 "register_operand")) + (match_operand: 3 "register_operand")))] + "TARGET_VECTOR && can_create_pseudo_p ()" + "#" + "&& 1" + [(const_int 0)] +{ + insn_code icode = code_for_pred_trunc (mode); + rtx ops[] = {operands[0], operands[1], operands[2], operands[3], + gen_int_mode (GET_MODE_NUNITS (mode), Pmode)}; + riscv_vector::expand_cond_len_unop (icode, ops); + DONE; +}) + +;; Combine convert(FP->INT) + vcond_mask +(define_insn_and_split "*cond_" + [(set (match_operand: 0 "register_operand") + (if_then_else: + (match_operand: 1 "register_operand") + (any_fix: + (match_operand:VF 2 "register_operand")) + (match_operand: 3 "register_operand")))] + "TARGET_VECTOR && can_create_pseudo_p ()" + "#" + "&& 1" + [(const_int 0)] +{ + insn_code icode = code_for_pred (, mode); + rtx ops[] = {operands[0], operands[1], operands[2], operands[3], + gen_int_mode (GET_MODE_NUNITS (mode), Pmode)}; + riscv_vector::expand_cond_len_unop (icode, ops); + DONE; +}) + +;; Combine convert(INT->FP) + vcond_mask +(define_insn_and_split "*cond_" + [(set (match_operand:VF 0 "register_operand") + (if_then_else:VF + (match_operand: 1 "register_operand") + (any_float:VF + (match_operand: 2 "register_operand")) + (match_operand:VF 3 "register_operand")))] + "TARGET_VECTOR && can_create_pseudo_p ()" + "#" + "&& 1" + [(const_int 0)] +{ + insn_code icode = code_for_pred (, mode); + rtx ops[] = {operands[0], operands[1], operands[2], operands[3], + gen_int_mode (GET_MODE_NUNITS (mode), Pmode)}; + riscv_vector::expand_cond_len_unop (icode, ops); + DONE; +}) + +;; Combine convert(FP->2xINT) + vcond_mask +(define_insn_and_split "*cond_" + [(set (match_operand:VWCONVERTI 0 "register_operand") + (if_then_else:VWCONVERTI + (match_operand: 1 "register_operand") + (any_fix:VWCONVERTI + (match_operand: 2 "register_operand")) + (match_operand:VWCONVERTI 3 "register_operand")))] + "TARGET_VECTOR && can_create_pseudo_p ()" + "#" + "&& 1" + [(const_int 0)] +{ + insn_code icode = code_for_pred_widen (, mode); + rtx ops[] = {operands[0], operands[1], operands[2], operands[3], + gen_int_mode (GET_MODE_NUNITS (mode), Pmode)}; + riscv_vector::expand_cond_len_unop (icode, ops); + DONE; +}) + +;; Combine convert(INT->2xFP) + vcond_mask +(define_insn_and_split "*cond_" + [(set (match_operand:VF 0 "register_operand") + (if_then_else:VF + (match_operand: 1 "register_operand") + (any_float:VF + (match_operand: 2 "register_operand")) + (match_operand:VF 3 "register_operand")))] + "TARGET_VECTOR && can_create_pseudo_p ()" + "#" + "&& 1" + [(const_int 0)] +{ + insn_code icode = code_for_pred_widen (, mode); + rtx ops[] = {operands[0], operands[1], operands[2], operands[3], + gen_int_mode (GET_MODE_NUNITS (mode), Pmode)}; + riscv_vector::expand_cond_len_unop (icode, ops); + DONE; +}) + +;; Combine convert(2xFP->INT) + vcond_mask +(define_insn_and_split "*cond_" + [(set (match_operand: 0 "register_operand") + (if_then_else: + (match_operand: 1 "register_operand") + (any_fix: + (match_operand:VF 2 "register_operand")) + (match_operand: 3 "register_operand")))] + "TARGET_VECTOR && can_create_pseudo_p ()" + "#" + "&& 1" + [(const_int 0)] +{ + insn_code icode = code_for_pred_narrow (, mode); + rtx ops[] = {operands[0], operands[1], operands[2], operands[3], + gen_int_mode (GET_MODE_NUNITS (mode), Pmode)}; + riscv_vector::expand_cond_len_unop (icode, ops); + DONE; +}) + +;; Combine convert(2xINT->FP) + vcond_mask +(define_insn_and_split "*cond_2" + [(set (match_operand: 0 "register_operand") + (if_then_else: + (match_operand: 1 "register_operand") + (any_float: + (match_operand:VWCONVERTI 2 "register_operand")) + (match_operand: 3 "register_operand")))] + "TARGET_VECTOR && can_create_pseudo_p ()" + "#" + "&& 1" + [(const_int 0)] +{ + insn_code icode = code_for_pred_narrow (, mode); + rtx ops[] = {operands[0], operands[1], operands[2], operands[3], + gen_int_mode (GET_MODE_NUNITS (mode), Pmode)}; + riscv_vector::expand_cond_len_unop (icode, ops); + DONE; +}) diff --git a/gcc/config/riscv/autovec-vls.md b/gcc/config/riscv/autovec-vls.md index 1a64dfdd91e3..7ef29637e338 100644 --- a/gcc/config/riscv/autovec-vls.md +++ b/gcc/config/riscv/autovec-vls.md @@ -68,6 +68,7 @@ } DONE; } + [(set_attr "type" "vmov")] ) (define_insn_and_split "*mov" @@ -89,6 +90,7 @@ gcc_assert (ok_p); DONE; } + [(set_attr "type" "vmov")] ) (define_expand "mov" @@ -127,10 +129,12 @@ emit_move_insn (operands[2], gen_int_mode (GET_MODE_NUNITS (mode), Pmode)); riscv_vector::emit_nonvlmax_insn (code_for_pred_mov (mode), - riscv_vector::RVV_UNOP, operands, operands[2]); + riscv_vector::UNARY_OP, operands, operands[2]); } DONE; -}) +} + [(set_attr "type" "vmov")] +) (define_insn "*mov_vls" [(set (match_operand:VLS 0 "register_operand" "=vr") @@ -140,6 +144,25 @@ [(set_attr "type" "vmov") (set_attr "mode" "")]) +(define_expand "movmisalign" + [(set (match_operand:VLS 0 "nonimmediate_operand") + (match_operand:VLS 1 "general_operand"))] + "TARGET_VECTOR" + { + /* To support misalign data movement, we should use + minimum element alignment load/store. */ + unsigned int size = GET_MODE_SIZE (GET_MODE_INNER (mode)); + poly_int64 nunits = GET_MODE_NUNITS (mode) * size; + machine_mode mode = riscv_vector::get_vector_mode (QImode, nunits).require (); + operands[0] = gen_lowpart (mode, operands[0]); + operands[1] = gen_lowpart (mode, operands[1]); + if (MEM_P (operands[0]) && !register_operand (operands[1], mode)) + operands[1] = force_reg (mode, operands[1]); + riscv_vector::emit_vlmax_insn (code_for_pred_mov (mode), riscv_vector::UNARY_OP, operands); + DONE; + } +) + ;; ----------------------------------------------------------------- ;; ---- Duplicate Operations ;; ----------------------------------------------------------------- @@ -154,7 +177,103 @@ [(const_int 0)] { riscv_vector::emit_vlmax_insn (code_for_pred_broadcast (mode), - riscv_vector::RVV_UNOP, operands); + riscv_vector::UNARY_OP, operands); DONE; } + [(set_attr "type" "vector")] +) + +;; ------------------------------------------------------------------------- +;; ---- [INT] Binary operations +;; ------------------------------------------------------------------------- +;; Includes: +;; - vadd.vv/vsub.vv/... +;; - vadd.vi/vsub.vi/... +;; ------------------------------------------------------------------------- + +(define_insn_and_split "3" + [(set (match_operand:VLSI 0 "register_operand") + (any_int_binop_no_shift:VLSI + (match_operand:VLSI 1 "") + (match_operand:VLSI 2 "")))] + "TARGET_VECTOR && can_create_pseudo_p ()" + "#" + "&& 1" + [(const_int 0)] +{ + riscv_vector::emit_vlmax_insn (code_for_pred (, mode), + riscv_vector::BINARY_OP, operands); + DONE; +} +[(set_attr "type" "vector")] +) + +;; ------------------------------------------------------------------------- +;; ---- [FP] Binary operations +;; ------------------------------------------------------------------------- +;; Includes: +;; - vfadd.vv/vfsub.vv/vfmul.vv/vfdiv.vv +;; - vfadd.vf/vfsub.vf/vfmul.vf/vfdiv.vf +;; ------------------------------------------------------------------------- +(define_insn_and_split "3" + [(set (match_operand:VLSF 0 "register_operand") + (any_float_binop:VLSF + (match_operand:VLSF 1 "") + (match_operand:VLSF 2 "")))] + "TARGET_VECTOR && can_create_pseudo_p ()" + "#" + "&& 1" + [(const_int 0)] +{ + riscv_vector::emit_vlmax_insn (code_for_pred (, mode), + riscv_vector::BINARY_OP_FRM_DYN, operands); + DONE; +} +[(set_attr "type" "vector")] +) + +;; ------------------------------------------------------------------------- +;; Includes: +;; - vfmin.vv/vfmax.vv +;; - vfmin.vf/vfmax.vf +;; - fmax/fmaxf in math.h +;; ------------------------------------------------------------------------- +(define_insn_and_split "3" + [(set (match_operand:VLSF 0 "register_operand") + (any_float_binop_nofrm:VLSF + (match_operand:VLSF 1 "") + (match_operand:VLSF 2 "")))] + "TARGET_VECTOR && can_create_pseudo_p ()" + "#" + "&& 1" + [(const_int 0)] +{ + riscv_vector::emit_vlmax_insn (code_for_pred (, mode), + riscv_vector::BINARY_OP, operands); + DONE; +} +[(set_attr "type" "vector")] +) + +;; ------------------------------------------------------------------------------- +;; ---- [INT] Unary operations +;; ------------------------------------------------------------------------------- +;; Includes: +;; - vneg.v/vnot.v +;; ------------------------------------------------------------------------------- + +(define_insn_and_split "2" + [(set (match_operand:VLSI 0 "register_operand") + (any_int_unop:VLSI + (match_operand:VLSI 1 "register_operand")))] + "TARGET_VECTOR && can_create_pseudo_p ()" + "#" + "&& 1" + [(const_int 0)] +{ + insn_code icode = code_for_pred (, mode); + riscv_vector::emit_vlmax_insn (icode, riscv_vector::UNARY_OP, operands); + DONE; +} +[(set_attr "type" "vector")] ) diff --git a/gcc/config/riscv/autovec.md b/gcc/config/riscv/autovec.md index fd7ec911e87c..0f9d1fe2c8ec 100644 --- a/gcc/config/riscv/autovec.md +++ b/gcc/config/riscv/autovec.md @@ -46,17 +46,6 @@ DONE; }) -(define_expand "movmisalign" - [(set (match_operand:V 0 "nonimmediate_operand") - (match_operand:V 1 "general_operand"))] - "TARGET_VECTOR" - { - /* Equivalent to a normal move for our purpooses. */ - emit_move_insn (operands[0], operands[1]); - DONE; - } -) - ;; ========================================================================= ;; == Gather Load ;; ========================================================================= @@ -283,10 +272,61 @@ DONE; }) +;; ========================================================================= +;; == Array Load/Store +;; ========================================================================= + +(define_expand "vec_mask_len_load_lanes" + [(match_operand:VT 0 "register_operand") + (match_operand:VT 1 "memory_operand") + (match_operand: 2 "vector_mask_operand") + (match_operand 3 "autovec_length_operand") + (match_operand 4 "const_0_operand")] + "TARGET_VECTOR" + { + riscv_vector::expand_lanes_load_store (operands, true); + DONE; + } +) + +(define_expand "vec_mask_len_store_lanes" + [(match_operand:VT 0 "memory_operand") + (match_operand:VT 1 "register_operand") + (match_operand: 2 "vector_mask_operand") + (match_operand 3 "autovec_length_operand") + (match_operand 4 "const_0_operand")] + "TARGET_VECTOR" + { + riscv_vector::expand_lanes_load_store (operands, false); + DONE; + } +) + ;; ========================================================================= ;; == Vector creation ;; ========================================================================= +;; ------------------------------------------------------------------------- +;; ---- [BOOL] Duplicate element +;; ------------------------------------------------------------------------- +;; The patterns in this section are synthetic. +;; ------------------------------------------------------------------------- + +;; Implement a predicate broadcast by shifting the low bit of the scalar +;; input into the top bit by duplicate the input and do a compare with zero. +(define_expand "vec_duplicate" + [(set (match_operand:VB 0 "register_operand") + (vec_duplicate:VB (match_operand:QI 1 "register_operand")))] + "TARGET_VECTOR" + { + poly_int64 nunits = GET_MODE_NUNITS (mode); + machine_mode mode = riscv_vector::get_vector_mode (QImode, nunits).require (); + rtx dup = expand_vector_broadcast (mode, operands[1]); + riscv_vector::expand_vec_cmp (operands[0], NE, dup, CONST0_RTX (mode)); + DONE; + } +) + ;; ------------------------------------------------------------------------- ;; ---- [INT] Linear series ;; ------------------------------------------------------------------------- @@ -297,7 +337,7 @@ ;; ------------------------------------------------------------------------- (define_expand "@vec_series" - [(match_operand:VI 0 "register_operand") + [(match_operand:V_VLSI 0 "register_operand") (match_operand: 1 "reg_or_int_operand") (match_operand: 2 "reg_or_int_operand")] "TARGET_VECTOR" @@ -350,8 +390,8 @@ "TARGET_VECTOR" { insn_code icode = code_for_pred_slide (UNSPEC_VSLIDE1UP, mode); - rtx ops[] = {operands[0], RVV_VUNDEF (mode), operands[1], operands[2]}; - riscv_vector::emit_vlmax_slide_insn (icode, ops); + rtx ops[] = {operands[0], operands[1], operands[2]}; + riscv_vector::emit_vlmax_insn (icode, riscv_vector::BINARY_OP, ops); DONE; }) @@ -362,8 +402,8 @@ "TARGET_VECTOR" { insn_code icode = code_for_pred_slide (UNSPEC_VFSLIDE1UP, mode); - rtx ops[] = {operands[0], RVV_VUNDEF (mode), operands[1], operands[2]}; - riscv_vector::emit_vlmax_slide_insn (icode, ops); + rtx ops[] = {operands[0], operands[1], operands[2]}; + riscv_vector::emit_vlmax_insn (icode, riscv_vector::BINARY_OP, ops); DONE; }) @@ -387,7 +427,7 @@ "TARGET_VECTOR" { riscv_vector::emit_vlmax_insn (code_for_pred (, mode), - riscv_vector::RVV_BINOP, operands); + riscv_vector::BINARY_OP, operands); DONE; }) @@ -400,10 +440,10 @@ ;; ------------------------------------------------------------------------- (define_insn_and_split "3" - [(set (match_operand:VI 0 "register_operand" "=vr") - (any_shift:VI - (match_operand:VI 1 "register_operand" " vr") - (match_operand: 2 "csr_operand" " rK")))] + [(set (match_operand:V_VLSI 0 "register_operand" "=vr") + (any_shift:V_VLSI + (match_operand:V_VLSI 1 "register_operand" " vr") + (match_operand: 2 "vector_scalar_shift_operand" " rK")))] "TARGET_VECTOR && can_create_pseudo_p ()" "#" "&& 1" @@ -411,7 +451,7 @@ { operands[2] = gen_lowpart (Pmode, operands[2]); riscv_vector::emit_vlmax_insn (code_for_pred_scalar (, mode), - riscv_vector::RVV_BINOP, operands); + riscv_vector::BINARY_OP, operands); DONE; } [(set_attr "type" "vshift") @@ -425,17 +465,17 @@ ;; ------------------------------------------------------------------------- (define_insn_and_split "v3" - [(set (match_operand:VI 0 "register_operand" "=vr,vr") - (any_shift:VI - (match_operand:VI 1 "register_operand" " vr,vr") - (match_operand:VI 2 "vector_shift_operand" " vr,vk")))] + [(set (match_operand:V_VLSI 0 "register_operand" "=vr,vr") + (any_shift:V_VLSI + (match_operand:V_VLSI 1 "register_operand" " vr,vr") + (match_operand:V_VLSI 2 "vector_shift_operand" " vr,vk")))] "TARGET_VECTOR && can_create_pseudo_p ()" "#" "&& 1" [(const_int 0)] { riscv_vector::emit_vlmax_insn (code_for_pred (, mode), - riscv_vector::RVV_BINOP, operands); + riscv_vector::BINARY_OP, operands); DONE; } [(set_attr "type" "vshift") @@ -460,7 +500,7 @@ [(const_int 0)] { insn_code icode = code_for_pred (, mode); - riscv_vector::emit_vlmax_insn (icode, riscv_vector::RVV_BINOP, operands); + riscv_vector::emit_vlmax_insn (icode, riscv_vector::BINARY_MASK_OP, operands); DONE; } [(set_attr "type" "vmalu") @@ -482,7 +522,7 @@ [(const_int 0)] { insn_code icode = code_for_pred_not (mode); - riscv_vector::emit_vlmax_insn (icode, riscv_vector::RVV_UNOP, operands); + riscv_vector::emit_vlmax_insn (icode, riscv_vector::UNARY_MASK_OP, operands); DONE; } [(set_attr "type" "vmalu") @@ -501,17 +541,21 @@ ;; - vfmerge.vf ;; ------------------------------------------------------------------------- -(define_expand "@vcond_mask_" - [(match_operand:V 0 "register_operand") - (match_operand: 3 "register_operand") - (match_operand:V 1 "nonmemory_operand") - (match_operand:V 2 "register_operand")] - "TARGET_VECTOR" +(define_insn_and_split "@vcond_mask_" + [(set (match_operand:V 0 "register_operand") + (if_then_else:V + (match_operand: 3 "register_operand") + (match_operand:V 1 "nonmemory_operand") + (match_operand:V 2 "register_operand")))] + "TARGET_VECTOR && can_create_pseudo_p ()" + "#" + "&& 1" + [(const_int 0)] { /* The order of vcond_mask is opposite to pred_merge. */ std::swap (operands[1], operands[2]); - riscv_vector::emit_vlmax_merge_insn (code_for_pred_merge (mode), - riscv_vector::RVV_MERGE_OP, operands); + riscv_vector::emit_vlmax_insn (code_for_pred_merge (mode), + riscv_vector::MERGE_OP, operands); DONE; } ) @@ -583,31 +627,37 @@ [(const_int 0)] { insn_code icode = code_for_pred_vf2 (, mode); - riscv_vector::emit_vlmax_insn (icode, riscv_vector::RVV_UNOP, operands); + riscv_vector::emit_vlmax_insn (icode, riscv_vector::UNARY_OP, operands); DONE; } [(set_attr "type" "vext") (set_attr "mode" "")]) -(define_expand "2" +(define_insn_and_split "2" [(set (match_operand:VQEXTI 0 "register_operand") (any_extend:VQEXTI (match_operand: 1 "register_operand")))] - "TARGET_VECTOR" + "TARGET_VECTOR && can_create_pseudo_p ()" + "#" + "&& 1" + [(const_int 0)] { insn_code icode = code_for_pred_vf4 (, mode); - riscv_vector::emit_vlmax_insn (icode, riscv_vector::RVV_UNOP, operands); + riscv_vector::emit_vlmax_insn (icode, riscv_vector::UNARY_OP, operands); DONE; }) -(define_expand "2" +(define_insn_and_split "2" [(set (match_operand:VOEXTI 0 "register_operand") (any_extend:VOEXTI (match_operand: 1 "register_operand")))] - "TARGET_VECTOR" + "TARGET_VECTOR && can_create_pseudo_p ()" + "#" + "&& 1" + [(const_int 0)] { insn_code icode = code_for_pred_vf8 (, mode); - riscv_vector::emit_vlmax_insn (icode, riscv_vector::RVV_UNOP, operands); + riscv_vector::emit_vlmax_insn (icode, riscv_vector::UNARY_OP, operands); DONE; }) @@ -626,7 +676,7 @@ [(const_int 0)] { insn_code icode = code_for_pred_trunc (mode); - riscv_vector::emit_vlmax_insn (icode, riscv_vector::RVV_UNOP, operands); + riscv_vector::emit_vlmax_insn (icode, riscv_vector::UNARY_OP, operands); DONE; } [(set_attr "type" "vshift") @@ -643,13 +693,8 @@ "TARGET_VECTOR" { rtx half = gen_reg_rtx (mode); - rtx opshalf[] = {half, operands[1]}; - insn_code icode = code_for_pred_trunc (mode); - riscv_vector::emit_vlmax_insn (icode, riscv_vector::RVV_UNOP, opshalf); - - rtx ops[] = {operands[0], half}; - icode = code_for_pred_trunc (mode); - riscv_vector::emit_vlmax_insn (icode, riscv_vector::RVV_UNOP, ops); + emit_insn (gen_trunc2 (half, operands[1])); + emit_insn (gen_trunc2 (operands[0], half)); DONE; }) @@ -663,19 +708,9 @@ (match_operand:VOEXTI 1 "register_operand")))] "TARGET_VECTOR" { - rtx half = gen_reg_rtx (mode); - rtx opshalf[] = {half, operands[1]}; - insn_code icode = code_for_pred_trunc (mode); - riscv_vector::emit_vlmax_insn (icode, riscv_vector::RVV_UNOP, opshalf); - rtx quarter = gen_reg_rtx (mode); - rtx opsquarter[] = {quarter, half}; - icode = code_for_pred_trunc (mode); - riscv_vector::emit_vlmax_insn (icode, riscv_vector::RVV_UNOP, opsquarter); - - rtx ops[] = {operands[0], quarter}; - icode = code_for_pred_trunc (mode); - riscv_vector::emit_vlmax_insn (icode, riscv_vector::RVV_UNOP, ops); + emit_insn (gen_trunc2 (quarter, operands[1])); + emit_insn (gen_trunc2 (operands[0], quarter)); DONE; }) @@ -694,7 +729,7 @@ [(const_int 0)] { insn_code icode = code_for_pred_extend (mode); - riscv_vector::emit_vlmax_insn (icode, riscv_vector::RVV_UNOP, operands); + riscv_vector::emit_vlmax_insn (icode, riscv_vector::UNARY_OP, operands); DONE; } [(set_attr "type" "vfwcvtftof") @@ -707,13 +742,8 @@ "TARGET_VECTOR && (TARGET_ZVFHMIN || TARGET_ZVFH)" { rtx dblw = gen_reg_rtx (mode); - insn_code icode = code_for_pred_extend (mode); - rtx ops1[] = {dblw, operands[1]}; - riscv_vector::emit_vlmax_insn (icode, riscv_vector::RVV_UNOP, ops1); - - icode = code_for_pred_extend (mode); - rtx ops2[] = {operands[0], dblw}; - riscv_vector::emit_vlmax_insn (icode, riscv_vector::RVV_UNOP, ops2); + emit_insn (gen_extend2 (dblw, operands[1])); + emit_insn (gen_extend2 (operands[0], dblw)); DONE; }) @@ -732,7 +762,7 @@ [(const_int 0)] { insn_code icode = code_for_pred_trunc (mode); - riscv_vector::emit_vlmax_fp_insn (icode, riscv_vector::RVV_UNOP, operands); + riscv_vector::emit_vlmax_insn (icode, riscv_vector::UNARY_OP_FRM_DYN, operands); DONE; } [(set_attr "type" "vfncvtftof") @@ -754,11 +784,9 @@ /* According to the RISC-V V Spec 13.19. we need to use vfncvt.rod.f.f.w for all steps but the last. */ insn_code icode = code_for_pred_rod_trunc (mode); - riscv_vector::emit_vlmax_insn (icode, riscv_vector::RVV_UNOP, opshalf); + riscv_vector::emit_vlmax_insn (icode, riscv_vector::UNARY_OP, opshalf); - rtx ops[] = {operands[0], half}; - icode = code_for_pred_trunc (mode); - riscv_vector::emit_vlmax_fp_insn (icode, riscv_vector::RVV_UNOP, ops); + emit_insn (gen_trunc2 (operands[0], half)); DONE; }) @@ -775,14 +803,17 @@ ;; - vfcvt.rtz.x.f.v ;; ------------------------------------------------------------------------- -(define_expand "2" +(define_insn_and_split "2" [(set (match_operand: 0 "register_operand") (any_fix: (match_operand:VF 1 "register_operand")))] - "TARGET_VECTOR" + "TARGET_VECTOR && can_create_pseudo_p ()" + "#" + "&& 1" + [(const_int 0)] { insn_code icode = code_for_pred (, mode); - riscv_vector::emit_vlmax_insn (icode, riscv_vector::RVV_UNOP, operands); + riscv_vector::emit_vlmax_insn (icode, riscv_vector::UNARY_OP, operands); DONE; }) @@ -794,14 +825,17 @@ ;; - vfcvt.f.x.v ;; ------------------------------------------------------------------------- -(define_expand "2" +(define_insn_and_split "2" [(set (match_operand:VF 0 "register_operand") (any_float:VF (match_operand: 1 "register_operand")))] - "TARGET_VECTOR" + "TARGET_VECTOR && can_create_pseudo_p ()" + "#" + "&& 1" + [(const_int 0)] { insn_code icode = code_for_pred (, mode); - riscv_vector::emit_vlmax_fp_insn (icode, riscv_vector::RVV_UNOP, operands); + riscv_vector::emit_vlmax_insn (icode, riscv_vector::UNARY_OP_FRM_DYN, operands); DONE; }) @@ -816,14 +850,17 @@ ;; - vfwcvt.rtz.xu.f.v ;; - vfwcvt.rtz.x.f.v ;; ------------------------------------------------------------------------- -(define_expand "2" +(define_insn_and_split "2" [(set (match_operand:VWCONVERTI 0 "register_operand") (any_fix:VWCONVERTI (match_operand: 1 "register_operand")))] - "TARGET_VECTOR" + "TARGET_VECTOR && can_create_pseudo_p ()" + "#" + "&& 1" + [(const_int 0)] { insn_code icode = code_for_pred_widen (, mode); - riscv_vector::emit_vlmax_insn (icode, riscv_vector::RVV_UNOP, operands); + riscv_vector::emit_vlmax_insn (icode, riscv_vector::UNARY_OP, operands); DONE; }) @@ -834,14 +871,17 @@ ;; - vfwcvt.f.xu.v ;; - vfwcvt.f.x.v ;; ------------------------------------------------------------------------- -(define_expand "2" +(define_insn_and_split "2" [(set (match_operand:VF 0 "register_operand") (any_float:VF (match_operand: 1 "register_operand")))] - "TARGET_VECTOR" + "TARGET_VECTOR && can_create_pseudo_p ()" + "#" + "&& 1" + [(const_int 0)] { insn_code icode = code_for_pred_widen (, mode); - riscv_vector::emit_vlmax_insn (icode, riscv_vector::RVV_UNOP, operands); + riscv_vector::emit_vlmax_insn (icode, riscv_vector::UNARY_OP, operands); DONE; }) @@ -852,14 +892,17 @@ ;; - vfncvt.rtz.xu.f.v ;; - vfncvt.rtz.x.f.v ;; ------------------------------------------------------------------------- -(define_expand "2" +(define_insn_and_split "2" [(set (match_operand: 0 "register_operand") (any_fix: (match_operand:VF 1 "register_operand")))] - "TARGET_VECTOR" + "TARGET_VECTOR && can_create_pseudo_p ()" + "#" + "&& 1" + [(const_int 0)] { insn_code icode = code_for_pred_narrow (, mode); - riscv_vector::emit_vlmax_insn (icode, riscv_vector::RVV_UNOP, operands); + riscv_vector::emit_vlmax_insn (icode, riscv_vector::UNARY_OP, operands); DONE; }) @@ -870,14 +913,17 @@ ;; - vfncvt.f.xu.w ;; - vfncvt.f.x.w ;; ------------------------------------------------------------------------- -(define_expand "2" +(define_insn_and_split "2" [(set (match_operand: 0 "register_operand") (any_float: (match_operand:VWCONVERTI 1 "register_operand")))] - "TARGET_VECTOR" + "TARGET_VECTOR && can_create_pseudo_p ()" + "#" + "&& 1" + [(const_int 0)] { insn_code icode = code_for_pred_narrow (, mode); - riscv_vector::emit_vlmax_fp_insn (icode, riscv_vector::RVV_UNOP, operands); + riscv_vector::emit_vlmax_insn (icode, riscv_vector::UNARY_OP_FRM_DYN, operands); DONE; }) @@ -898,7 +944,7 @@ "TARGET_VECTOR" { insn_code icode = code_for_pred (, mode); - riscv_vector::emit_vlmax_insn (icode, riscv_vector::RVV_UNOP, operands); + riscv_vector::emit_vlmax_insn (icode, riscv_vector::UNARY_OP, operands); DONE; }) @@ -917,8 +963,8 @@ riscv_vector::expand_vec_cmp (mask, LT, operands[1], zero); rtx ops[] = {operands[0], mask, operands[1], operands[1]}; - riscv_vector::emit_vlmax_masked_mu_insn (code_for_pred (NEG, mode), - riscv_vector::RVV_UNOP_MU, ops); + riscv_vector::emit_vlmax_insn (code_for_pred (NEG, mode), + riscv_vector::UNARY_OP_TAMU, ops); DONE; }) @@ -928,14 +974,17 @@ ;; Includes: ;; - vfneg.v/vfabs.v ;; ------------------------------------------------------------------------------- -(define_expand "2" +(define_insn_and_split "2" [(set (match_operand:VF 0 "register_operand") (any_float_unop_nofrm:VF (match_operand:VF 1 "register_operand")))] - "TARGET_VECTOR" + "TARGET_VECTOR && can_create_pseudo_p ()" + "#" + "&& 1" + [(const_int 0)] { insn_code icode = code_for_pred (, mode); - riscv_vector::emit_vlmax_insn (icode, riscv_vector::RVV_UNOP, operands); + riscv_vector::emit_vlmax_insn (icode, riscv_vector::UNARY_OP, operands); DONE; }) @@ -952,7 +1001,7 @@ "TARGET_VECTOR" { insn_code icode = code_for_pred (, mode); - riscv_vector::emit_vlmax_fp_insn (icode, riscv_vector::RVV_UNOP, operands); + riscv_vector::emit_vlmax_insn (icode, riscv_vector::UNARY_OP_FRM_DYN, operands); DONE; }) @@ -1013,8 +1062,8 @@ { riscv_vector::emit_vlmax_vsetvl (mode, operands[4]); rtx ops[] = {operands[0], operands[1], operands[2], operands[3], operands[0]}; - riscv_vector::emit_vlmax_ternary_insn (code_for_pred_mul_plus (mode), - riscv_vector::RVV_TERNOP, ops, operands[4]); + riscv_vector::emit_vlmax_insn_lra (code_for_pred_mul_plus (mode), + riscv_vector::TERNARY_OP, ops, operands[4]); DONE; } [(set_attr "type" "vimuladd") @@ -1057,8 +1106,8 @@ { riscv_vector::emit_vlmax_vsetvl (mode, operands[4]); rtx ops[] = {operands[0], operands[1], operands[2], operands[3], operands[0]}; - riscv_vector::emit_vlmax_ternary_insn (code_for_pred_minus_mul (mode), - riscv_vector::RVV_TERNOP, ops, operands[4]); + riscv_vector::emit_vlmax_insn_lra (code_for_pred_minus_mul (mode), + riscv_vector::TERNARY_OP, ops, operands[4]); DONE; } [(set_attr "type" "vimuladd") @@ -1075,22 +1124,27 @@ (define_expand "fma4" [(parallel [(set (match_operand:VF 0 "register_operand") - (fma:VF - (match_operand:VF 1 "register_operand") - (match_operand:VF 2 "register_operand") - (match_operand:VF 3 "register_operand"))) + (unspec:VF + [(fma:VF + (match_operand:VF 1 "register_operand") + (match_operand:VF 2 "register_operand") + (match_operand:VF 3 "register_operand")) + (reg:SI FRM_REGNUM)] UNSPEC_VFFMA)) (clobber (match_dup 4))])] "TARGET_VECTOR" { operands[4] = gen_reg_rtx (Pmode); - }) + } + [(set (attr "frm_mode") (symbol_ref "riscv_vector::FRM_DYN"))]) (define_insn_and_split "*fma" [(set (match_operand:VF 0 "register_operand" "=vr, vr, ?&vr") - (fma:VF - (match_operand:VF 1 "register_operand" " %0, vr, vr") - (match_operand:VF 2 "register_operand" " vr, vr, vr") - (match_operand:VF 3 "register_operand" " vr, 0, vr"))) + (unspec:VF + [(fma:VF + (match_operand:VF 1 "register_operand" " %0, vr, vr") + (match_operand:VF 2 "register_operand" " vr, vr, vr") + (match_operand:VF 3 "register_operand" " vr, 0, vr")) + (reg:SI FRM_REGNUM)] UNSPEC_VFFMA)) (clobber (match_operand:P 4 "register_operand" "=r,r,r"))] "TARGET_VECTOR" "#" @@ -1099,12 +1153,13 @@ { riscv_vector::emit_vlmax_vsetvl (mode, operands[4]); rtx ops[] = {operands[0], operands[1], operands[2], operands[3], operands[0]}; - riscv_vector::emit_vlmax_fp_ternary_insn (code_for_pred_mul (PLUS, mode), - riscv_vector::RVV_TERNOP, ops, operands[4]); + riscv_vector::emit_vlmax_insn_lra (code_for_pred_mul (PLUS, mode), + riscv_vector::TERNARY_OP_FRM_DYN, ops, operands[4]); DONE; } [(set_attr "type" "vfmuladd") - (set_attr "mode" "")]) + (set_attr "mode" "") + (set (attr "frm_mode") (symbol_ref "riscv_vector::FRM_DYN"))]) ;; ------------------------------------------------------------------------- ;; ---- [FP] VFNMSAC and VFNMSUB @@ -1117,24 +1172,29 @@ (define_expand "fnma4" [(parallel [(set (match_operand:VF 0 "register_operand") - (fma:VF - (neg:VF - (match_operand:VF 1 "register_operand")) - (match_operand:VF 2 "register_operand") - (match_operand:VF 3 "register_operand"))) + (unspec:VF + [(fma:VF + (neg:VF + (match_operand:VF 1 "register_operand")) + (match_operand:VF 2 "register_operand") + (match_operand:VF 3 "register_operand")) + (reg:SI FRM_REGNUM)] UNSPEC_VFFMA)) (clobber (match_dup 4))])] "TARGET_VECTOR" { operands[4] = gen_reg_rtx (Pmode); - }) + } + [(set (attr "frm_mode") (symbol_ref "riscv_vector::FRM_DYN"))]) (define_insn_and_split "*fnma" [(set (match_operand:VF 0 "register_operand" "=vr, vr, ?&vr") - (fma:VF - (neg:VF - (match_operand:VF 1 "register_operand" " %0, vr, vr")) - (match_operand:VF 2 "register_operand" " vr, vr, vr") - (match_operand:VF 3 "register_operand" " vr, 0, vr"))) + (unspec:VF + [(fma:VF + (neg:VF + (match_operand:VF 1 "register_operand" " %0, vr, vr")) + (match_operand:VF 2 "register_operand" " vr, vr, vr") + (match_operand:VF 3 "register_operand" " vr, 0, vr")) + (reg:SI FRM_REGNUM)] UNSPEC_VFFMA)) (clobber (match_operand:P 4 "register_operand" "=r,r,r"))] "TARGET_VECTOR" "#" @@ -1143,12 +1203,13 @@ { riscv_vector::emit_vlmax_vsetvl (mode, operands[4]); rtx ops[] = {operands[0], operands[1], operands[2], operands[3], operands[0]}; - riscv_vector::emit_vlmax_fp_ternary_insn (code_for_pred_mul_neg (PLUS, mode), - riscv_vector::RVV_TERNOP, ops, operands[4]); + riscv_vector::emit_vlmax_insn_lra (code_for_pred_mul_neg (PLUS, mode), + riscv_vector::TERNARY_OP_FRM_DYN, ops, operands[4]); DONE; } [(set_attr "type" "vfmuladd") - (set_attr "mode" "")]) + (set_attr "mode" "") + (set (attr "frm_mode") (symbol_ref "riscv_vector::FRM_DYN"))]) ;; ------------------------------------------------------------------------- ;; ---- [FP] VFMSAC and VFMSUB @@ -1161,24 +1222,29 @@ (define_expand "fms4" [(parallel [(set (match_operand:VF 0 "register_operand") - (fma:VF - (match_operand:VF 1 "register_operand") - (match_operand:VF 2 "register_operand") - (neg:VF - (match_operand:VF 3 "register_operand")))) + (unspec:VF + [(fma:VF + (match_operand:VF 1 "register_operand") + (match_operand:VF 2 "register_operand") + (neg:VF + (match_operand:VF 3 "register_operand"))) + (reg:SI FRM_REGNUM)] UNSPEC_VFFMA)) (clobber (match_dup 4))])] "TARGET_VECTOR" { operands[4] = gen_reg_rtx (Pmode); - }) + } + [(set (attr "frm_mode") (symbol_ref "riscv_vector::FRM_DYN"))]) (define_insn_and_split "*fms" [(set (match_operand:VF 0 "register_operand" "=vr, vr, ?&vr") - (fma:VF - (match_operand:VF 1 "register_operand" " %0, vr, vr") - (match_operand:VF 2 "register_operand" " vr, vr, vr") - (neg:VF - (match_operand:VF 3 "register_operand" " vr, 0, vr")))) + (unspec:VF + [(fma:VF + (match_operand:VF 1 "register_operand" " %0, vr, vr") + (match_operand:VF 2 "register_operand" " vr, vr, vr") + (neg:VF + (match_operand:VF 3 "register_operand" " vr, 0, vr"))) + (reg:SI FRM_REGNUM)] UNSPEC_VFFMA)) (clobber (match_operand:P 4 "register_operand" "=r,r,r"))] "TARGET_VECTOR" "#" @@ -1187,44 +1253,50 @@ { riscv_vector::emit_vlmax_vsetvl (mode, operands[4]); rtx ops[] = {operands[0], operands[1], operands[2], operands[3], operands[0]}; - riscv_vector::emit_vlmax_fp_ternary_insn (code_for_pred_mul (MINUS, mode), - riscv_vector::RVV_TERNOP, ops, operands[4]); + riscv_vector::emit_vlmax_insn_lra (code_for_pred_mul (MINUS, mode), + riscv_vector::TERNARY_OP_FRM_DYN, ops, operands[4]); DONE; } [(set_attr "type" "vfmuladd") - (set_attr "mode" "")]) + (set_attr "mode" "") + (set (attr "frm_mode") (symbol_ref "riscv_vector::FRM_DYN"))]) ;; ------------------------------------------------------------------------- -;; ---- [FP] VFMSAC and VFMSUB +;; ---- [FP] VFNMACC and VFNMADD ;; ------------------------------------------------------------------------- ;; Includes: -;; - vfmsac -;; - vfmsub +;; - vfnmacc +;; - vfnmadd ;; ------------------------------------------------------------------------- (define_expand "fnms4" [(parallel [(set (match_operand:VF 0 "register_operand") - (fma:VF - (neg:VF - (match_operand:VF 1 "register_operand")) - (match_operand:VF 2 "register_operand") - (neg:VF - (match_operand:VF 3 "register_operand")))) + (unspec:VF + [(fma:VF + (neg:VF + (match_operand:VF 1 "register_operand")) + (match_operand:VF 2 "register_operand") + (neg:VF + (match_operand:VF 3 "register_operand"))) + (reg:SI FRM_REGNUM)] UNSPEC_VFFMA)) (clobber (match_dup 4))])] "TARGET_VECTOR" { operands[4] = gen_reg_rtx (Pmode); - }) + } + [(set (attr "frm_mode") (symbol_ref "riscv_vector::FRM_DYN"))]) (define_insn_and_split "*fnms" [(set (match_operand:VF 0 "register_operand" "=vr, vr, ?&vr") - (fma:VF - (neg:VF - (match_operand:VF 1 "register_operand" " %0, vr, vr")) - (match_operand:VF 2 "register_operand" " vr, vr, vr") - (neg:VF - (match_operand:VF 3 "register_operand" " vr, 0, vr")))) + (unspec:VF + [(fma:VF + (neg:VF + (match_operand:VF 1 "register_operand" " %0, vr, vr")) + (match_operand:VF 2 "register_operand" " vr, vr, vr") + (neg:VF + (match_operand:VF 3 "register_operand" " vr, 0, vr"))) + (reg:SI FRM_REGNUM)] UNSPEC_VFFMA)) (clobber (match_operand:P 4 "register_operand" "=r,r,r"))] "TARGET_VECTOR" "#" @@ -1233,12 +1305,13 @@ { riscv_vector::emit_vlmax_vsetvl (mode, operands[4]); rtx ops[] = {operands[0], operands[1], operands[2], operands[3], operands[0]}; - riscv_vector::emit_vlmax_fp_ternary_insn (code_for_pred_mul_neg (MINUS, mode), - riscv_vector::RVV_TERNOP, ops, operands[4]); + riscv_vector::emit_vlmax_insn_lra (code_for_pred_mul_neg (MINUS, mode), + riscv_vector::TERNARY_OP_FRM_DYN, ops, operands[4]); DONE; } [(set_attr "type" "vfmuladd") - (set_attr "mode" "")]) + (set_attr "mode" "") + (set (attr "frm_mode") (symbol_ref "riscv_vector::FRM_DYN"))]) ;; ========================================================================= ;; == SELECT_VL @@ -1267,10 +1340,9 @@ /* If we set the first element, emit an v(f)mv.s.[xf]. */ if (operands[2] == const0_rtx) { - rtx ops[] = {operands[0], riscv_vector::gen_scalar_move_mask (mode), - RVV_VUNDEF (mode), operands[1]}; - riscv_vector::emit_scalar_move_insn - (code_for_pred_broadcast (mode), ops); + rtx ops[] = {operands[0], operands[1]}; + riscv_vector::emit_nonvlmax_insn (code_for_pred_broadcast (mode), + riscv_vector::SCALAR_MOVE_OP, ops, CONST1_RTX (Pmode)); } else { @@ -1294,14 +1366,14 @@ VL we need for the slide. */ rtx tmp = gen_reg_rtx (mode); rtx ops1[] = {tmp, operands[1]}; - riscv_vector::emit_nonvlmax_integer_move_insn - (code_for_pred_broadcast (mode), ops1, length); + emit_nonvlmax_insn (code_for_pred_broadcast (mode), + riscv_vector::UNARY_OP, ops1, length); /* Slide exactly one element up leaving the tail elements unchanged. */ rtx ops2[] = {operands[0], operands[0], tmp, operands[2]}; - riscv_vector::emit_nonvlmax_slide_tu_insn - (code_for_pred_slide (UNSPEC_VSLIDEUP, mode), ops2, length); + riscv_vector::emit_nonvlmax_insn + (code_for_pred_slide (UNSPEC_VSLIDEUP, mode), riscv_vector::BINARY_OP_TUMA, ops2, length); } DONE; }) @@ -1328,9 +1400,9 @@ /* Emit the slide down to index 0 in a new vector. */ tmp = gen_reg_rtx (mode); operands[2] = gen_lowpart (Pmode, operands[2]); - rtx ops[] = {tmp, RVV_VUNDEF (mode), operands[1], operands[2]}; - riscv_vector::emit_vlmax_slide_insn - (code_for_pred_slide (UNSPEC_VSLIDEDOWN, mode), ops); + rtx ops[] = {tmp, operands[1], operands[2]}; + riscv_vector::emit_vlmax_insn + (code_for_pred_slide (UNSPEC_VSLIDEDOWN, mode), riscv_vector::BINARY_OP, ops); } /* Emit v(f)mv.[xf].s. */ @@ -1339,6 +1411,42 @@ DONE; }) +;; ------------------------------------------------------------------------- +;; This extracts a bit (via QImode) from a bitmask vector. +;; ------------------------------------------------------------------------- +(define_expand "vec_extractqi" + [(set (match_operand:QI 0 "register_operand") + (vec_select:QI + (match_operand:VB 1 "register_operand") + (parallel + [(match_operand 2 "nonmemory_operand")])))] + "TARGET_VECTOR" +{ + /* Create an empty byte vector and set it to one under mask. */ + machine_mode qimode = riscv_vector::get_vector_mode + (QImode, GET_MODE_NUNITS (mode)).require (); + + rtx tmp1 = gen_reg_rtx (qimode); + emit_move_insn (tmp1, gen_const_vec_duplicate (qimode, GEN_INT (0))); + rtx ones = gen_const_vec_duplicate (qimode, GEN_INT (1)); + + rtx ops1[] = {tmp1, tmp1, ones, operands[1]}; + riscv_vector::emit_vlmax_insn (code_for_pred_merge (qimode), + riscv_vector::MERGE_OP, ops1); + + /* Slide down the requested byte element. */ + rtx tmp2 = gen_reg_rtx (qimode); + + rtx ops2[] = {tmp2, tmp1, operands[2]}; + riscv_vector::emit_vlmax_insn + (code_for_pred_slide (UNSPEC_VSLIDEDOWN, qimode), + riscv_vector::BINARY_OP, ops2); + + /* Extract it. */ + emit_insn (gen_pred_extract_first (qimode, operands[0], tmp2)); + DONE; +}) + ;; ------------------------------------------------------------------------- ;; ---- [FP] Binary operations ;; ------------------------------------------------------------------------- @@ -1353,8 +1461,8 @@ (match_operand:VF 2 "register_operand"))] "TARGET_VECTOR" { - riscv_vector::emit_vlmax_fp_insn (code_for_pred (, mode), - riscv_vector::RVV_BINOP, operands); + riscv_vector::emit_vlmax_insn (code_for_pred (, mode), + riscv_vector::BINARY_OP_FRM_DYN, operands); DONE; }) @@ -1371,7 +1479,7 @@ "TARGET_VECTOR" { riscv_vector::emit_vlmax_insn (code_for_pred (, mode), - riscv_vector::RVV_BINOP, operands); + riscv_vector::BINARY_OP, operands); DONE; }) @@ -1396,7 +1504,7 @@ [(const_int 0)] { riscv_vector::emit_vlmax_insn (code_for_pred (UNSPEC_VCOPYSIGN, mode), - riscv_vector::RVV_BINOP, operands); + riscv_vector::BINARY_OP, operands); DONE; } [(set_attr "type" "vfsgnj") @@ -1414,7 +1522,7 @@ "TARGET_VECTOR" { riscv_vector::emit_vlmax_insn (code_for_pred (UNSPEC_VXORSIGN, mode), - riscv_vector::RVV_BINOP, operands); + riscv_vector::BINARY_OP, operands); DONE; }) @@ -1433,7 +1541,7 @@ "TARGET_VECTOR" { insn_code icode = code_for_pred_mulh (UNSPEC_VMULHS, mode); - riscv_vector::emit_vlmax_insn (icode, riscv_vector::RVV_BINOP, operands); + riscv_vector::emit_vlmax_insn (icode, riscv_vector::BINARY_OP, operands); DONE; }) @@ -1444,7 +1552,123 @@ "TARGET_VECTOR" { insn_code icode = code_for_pred_mulh (UNSPEC_VMULHU, mode); - riscv_vector::emit_vlmax_insn (icode, riscv_vector::RVV_BINOP, operands); + riscv_vector::emit_vlmax_insn (icode, riscv_vector::BINARY_OP, operands); + DONE; +}) + +;; ------------------------------------------------------------------------- +;; ---- [INT] Conditional unary operations +;; ------------------------------------------------------------------------- +;; Includes: +;; - vneg/vnot +;; ------------------------------------------------------------------------- + +(define_expand "cond_" + [(match_operand:VI 0 "register_operand") + (match_operand: 1 "vector_mask_operand") + (any_int_unop:VI + (match_operand:VI 2 "register_operand")) + (match_operand:VI 3 "register_operand")] + "TARGET_VECTOR" +{ + /* Normalize into cond_len_* operations. */ + emit_insn (gen_cond_len_ (operands[0], operands[1], operands[2], + operands[3], + gen_int_mode (GET_MODE_NUNITS (mode), Pmode), + const0_rtx)); + DONE; +}) + +(define_expand "cond_len_" + [(match_operand:VI 0 "register_operand") + (match_operand: 1 "vector_mask_operand") + (any_int_unop:VI + (match_operand:VI 2 "register_operand")) + (match_operand:VI 3 "register_operand") + (match_operand 4 "autovec_length_operand") + (match_operand 5 "const_0_operand")] + "TARGET_VECTOR" +{ + insn_code icode = code_for_pred (, mode); + riscv_vector::expand_cond_len_unop (icode, operands); + DONE; +}) + +;; ------------------------------------------------------------------------- +;; ---- [FP] Conditional unary operations +;; ------------------------------------------------------------------------- +;; Includes: +;; - vfneg/vfabs +;; ------------------------------------------------------------------------- + +(define_expand "cond_" + [(match_operand:VF 0 "register_operand") + (match_operand: 1 "vector_mask_operand") + (any_float_unop_nofrm:VF + (match_operand:VF 2 "register_operand")) + (match_operand:VF 3 "register_operand")] + "TARGET_VECTOR" +{ + /* Normalize into cond_len_* operations. */ + emit_insn (gen_cond_len_ (operands[0], operands[1], operands[2], + operands[3], + gen_int_mode (GET_MODE_NUNITS (mode), Pmode), + const0_rtx)); + DONE; +}) + +(define_expand "cond_len_" + [(match_operand:VF 0 "register_operand") + (match_operand: 1 "vector_mask_operand") + (any_float_unop_nofrm:VF + (match_operand:VF 2 "register_operand")) + (match_operand:VF 3 "register_operand") + (match_operand 4 "autovec_length_operand") + (match_operand 5 "const_0_operand")] + "TARGET_VECTOR" +{ + insn_code icode = code_for_pred (, mode); + riscv_vector::expand_cond_len_unop (icode, operands); + DONE; +}) + +;; ------------------------------------------------------------------------- +;; ---- [INT] Conditional binary operations +;; ------------------------------------------------------------------------- +;; Includes: +;; - vsra/vsrl/vsll +;; ------------------------------------------------------------------------- + +(define_expand "cond_" + [(match_operand:VI 0 "register_operand") + (match_operand: 1 "vector_mask_operand") + (any_shift:VI + (match_operand:VI 2 "register_operand") + (match_operand:VI 3 "vector_shift_operand")) + (match_operand:VI 4 "register_operand")] + "TARGET_VECTOR" +{ + /* Normalize into cond_len_* operations. */ + emit_insn (gen_cond_len_ (operands[0], operands[1], operands[2], + operands[3], operands[4], + gen_int_mode (GET_MODE_NUNITS (mode), Pmode), + const0_rtx)); + DONE; +}) + +(define_expand "cond_len_" + [(match_operand:VI 0 "register_operand") + (match_operand: 1 "vector_mask_operand") + (any_shift:VI + (match_operand:VI 2 "register_operand") + (match_operand:VI 3 "vector_shift_operand")) + (match_operand:VI 4 "register_operand") + (match_operand 5 "autovec_length_operand") + (match_operand 6 "const_0_operand")] + "TARGET_VECTOR" +{ + insn_code icode = code_for_pred (, mode); + riscv_vector::expand_cond_len_binop (icode, operands); DONE; }) @@ -1456,6 +1680,23 @@ ;; - vadd.vi/vsub.vi/... ;; ------------------------------------------------------------------------- +(define_expand "cond_" + [(match_operand:VI 0 "register_operand") + (match_operand: 1 "vector_mask_operand") + (any_int_binop_no_shift:VI + (match_operand:VI 2 "") + (match_operand:VI 3 "")) + (match_operand:VI 4 "register_operand")] + "TARGET_VECTOR" +{ + /* Normalize into cond_len_* operations. */ + emit_insn (gen_cond_len_ (operands[0], operands[1], operands[2], + operands[3], operands[4], + gen_int_mode (GET_MODE_NUNITS (mode), Pmode), + const0_rtx)); + DONE; +}) + (define_expand "cond_len_" [(match_operand:VI 0 "register_operand") (match_operand: 1 "vector_mask_operand") @@ -1467,7 +1708,8 @@ (match_operand 6 "const_0_operand")] "TARGET_VECTOR" { - riscv_vector::expand_cond_len_binop (, operands); + insn_code icode = code_for_pred (, mode); + riscv_vector::expand_cond_len_binop (icode, operands); DONE; }) @@ -1479,6 +1721,23 @@ ;; - vfadd.vf/vfsub.vf/... ;; ------------------------------------------------------------------------- +(define_expand "cond_" + [(match_operand:VF 0 "register_operand") + (match_operand: 1 "vector_mask_operand") + (any_float_binop:VF + (match_operand:VF 2 "register_operand") + (match_operand:VF 3 "register_operand")) + (match_operand:VF 4 "register_operand")] + "TARGET_VECTOR" +{ + /* Normalize into cond_len_* operations. */ + emit_insn (gen_cond_len_ (operands[0], operands[1], operands[2], + operands[3], operands[4], + gen_int_mode (GET_MODE_NUNITS (mode), Pmode), + const0_rtx)); + DONE; +}) + (define_expand "cond_len_" [(match_operand:VF 0 "register_operand") (match_operand: 1 "vector_mask_operand") @@ -1490,7 +1749,8 @@ (match_operand 6 "const_0_operand")] "TARGET_VECTOR" { - riscv_vector::expand_cond_len_binop (, operands); + insn_code icode = code_for_pred (, mode); + riscv_vector::expand_cond_len_binop (icode, operands); DONE; }) @@ -1500,6 +1760,23 @@ ;; - vfmin.vf/vfmax.vf ;; ------------------------------------------------------------------------- +(define_expand "cond_" + [(match_operand:VF 0 "register_operand") + (match_operand: 1 "vector_mask_operand") + (any_float_binop_nofrm:VF + (match_operand:VF 2 "register_operand") + (match_operand:VF 3 "register_operand")) + (match_operand:VF 4 "register_operand")] + "TARGET_VECTOR" +{ + /* Normalize into cond_len_* operations. */ + emit_insn (gen_cond_len_ (operands[0], operands[1], operands[2], + operands[3], operands[4], + gen_int_mode (GET_MODE_NUNITS (mode), Pmode), + const0_rtx)); + DONE; +}) + (define_expand "cond_len_" [(match_operand:VF 0 "register_operand") (match_operand: 1 "vector_mask_operand") @@ -1511,7 +1788,81 @@ (match_operand 6 "const_0_operand")] "TARGET_VECTOR" { - riscv_vector::expand_cond_len_binop (, operands); + insn_code icode = code_for_pred (, mode); + riscv_vector::expand_cond_len_binop (icode, operands); + DONE; +}) + +;; ------------------------------------------------------------------------- +;; ---- [INT] Conditional ternary operations +;; ------------------------------------------------------------------------- +;; Includes: +;; - vmacc/... +;; ------------------------------------------------------------------------- + +(define_expand "cond_fma" + [(match_operand:VI 0 "register_operand") + (match_operand: 1 "vector_mask_operand") + (match_operand:VI 2 "register_operand") + (match_operand:VI 3 "register_operand") + (match_operand:VI 4 "register_operand") + (match_operand:VI 5 "register_operand")] + "TARGET_VECTOR" +{ + /* Normalize into cond_len_* operations. */ + emit_insn (gen_cond_len_fma (operands[0], operands[1], operands[2], + operands[3], operands[4], operands[5], + gen_int_mode (GET_MODE_NUNITS (mode), Pmode), + const0_rtx)); + DONE; +}) + +(define_expand "cond_len_fma" + [(match_operand:VI 0 "register_operand") + (match_operand: 1 "vector_mask_operand") + (match_operand:VI 2 "register_operand") + (match_operand:VI 3 "register_operand") + (match_operand:VI 4 "register_operand") + (match_operand:VI 5 "register_operand") + (match_operand 6 "autovec_length_operand") + (match_operand 7 "const_0_operand")] + "TARGET_VECTOR" +{ + insn_code icode = code_for_pred_mul_plus (mode); + riscv_vector::expand_cond_len_ternop (icode, operands); + DONE; +}) + +(define_expand "cond_fnma" + [(match_operand:VI 0 "register_operand") + (match_operand: 1 "vector_mask_operand") + (match_operand:VI 2 "register_operand") + (match_operand:VI 3 "register_operand") + (match_operand:VI 4 "register_operand") + (match_operand:VI 5 "register_operand")] + "TARGET_VECTOR" +{ + /* Normalize into cond_len_* operations. */ + emit_insn (gen_cond_len_fnma (operands[0], operands[1], operands[2], + operands[3], operands[4], operands[5], + gen_int_mode (GET_MODE_NUNITS (mode), Pmode), + const0_rtx)); + DONE; +}) + +(define_expand "cond_len_fnma" + [(match_operand:VI 0 "register_operand") + (match_operand: 1 "vector_mask_operand") + (match_operand:VI 2 "register_operand") + (match_operand:VI 3 "register_operand") + (match_operand:VI 4 "register_operand") + (match_operand:VI 5 "register_operand") + (match_operand 6 "autovec_length_operand") + (match_operand 7 "const_0_operand")] + "TARGET_VECTOR" +{ + insn_code icode = code_for_pred_minus_mul (mode); + riscv_vector::expand_cond_len_ternop (icode, operands); DONE; }) @@ -1522,6 +1873,23 @@ ;; - vfmacc/... ;; ------------------------------------------------------------------------- +(define_expand "cond_fma" + [(match_operand:VF 0 "register_operand") + (match_operand: 1 "vector_mask_operand") + (match_operand:VF 2 "register_operand") + (match_operand:VF 3 "register_operand") + (match_operand:VF 4 "register_operand") + (match_operand:VF 5 "register_operand")] + "TARGET_VECTOR" +{ + /* Normalize into cond_len_* operations. */ + emit_insn (gen_cond_len_fma (operands[0], operands[1], operands[2], + operands[3], operands[4], operands[5], + gen_int_mode (GET_MODE_NUNITS (mode), Pmode), + const0_rtx)); + DONE; +}) + (define_expand "cond_len_fma" [(match_operand:VF 0 "register_operand") (match_operand: 1 "vector_mask_operand") @@ -1538,6 +1906,105 @@ DONE; }) +(define_expand "cond_fnma" + [(match_operand:VF 0 "register_operand") + (match_operand: 1 "vector_mask_operand") + (match_operand:VF 2 "register_operand") + (match_operand:VF 3 "register_operand") + (match_operand:VF 4 "register_operand") + (match_operand:VF 5 "register_operand")] + "TARGET_VECTOR" +{ + /* Normalize into cond_len_* operations. */ + emit_insn (gen_cond_len_fnma (operands[0], operands[1], operands[2], + operands[3], operands[4], operands[5], + gen_int_mode (GET_MODE_NUNITS (mode), Pmode), + const0_rtx)); + DONE; +}) + +(define_expand "cond_len_fnma" + [(match_operand:VF 0 "register_operand") + (match_operand: 1 "vector_mask_operand") + (match_operand:VF 2 "register_operand") + (match_operand:VF 3 "register_operand") + (match_operand:VF 4 "register_operand") + (match_operand:VF 5 "register_operand") + (match_operand 6 "autovec_length_operand") + (match_operand 7 "const_0_operand")] + "TARGET_VECTOR" +{ + insn_code icode = code_for_pred_mul_neg (PLUS, mode); + riscv_vector::expand_cond_len_ternop (icode, operands); + DONE; +}) + +(define_expand "cond_fms" + [(match_operand:VF 0 "register_operand") + (match_operand: 1 "vector_mask_operand") + (match_operand:VF 2 "register_operand") + (match_operand:VF 3 "register_operand") + (match_operand:VF 4 "register_operand") + (match_operand:VF 5 "register_operand")] + "TARGET_VECTOR" +{ + /* Normalize into cond_len_* operations. */ + emit_insn (gen_cond_len_fms (operands[0], operands[1], operands[2], + operands[3], operands[4], operands[5], + gen_int_mode (GET_MODE_NUNITS (mode), Pmode), + const0_rtx)); + DONE; +}) + +(define_expand "cond_len_fms" + [(match_operand:VF 0 "register_operand") + (match_operand: 1 "vector_mask_operand") + (match_operand:VF 2 "register_operand") + (match_operand:VF 3 "register_operand") + (match_operand:VF 4 "register_operand") + (match_operand:VF 5 "register_operand") + (match_operand 6 "autovec_length_operand") + (match_operand 7 "const_0_operand")] + "TARGET_VECTOR" +{ + insn_code icode = code_for_pred_mul (MINUS, mode); + riscv_vector::expand_cond_len_ternop (icode, operands); + DONE; +}) + +(define_expand "cond_fnms" + [(match_operand:VF 0 "register_operand") + (match_operand: 1 "vector_mask_operand") + (match_operand:VF 2 "register_operand") + (match_operand:VF 3 "register_operand") + (match_operand:VF 4 "register_operand") + (match_operand:VF 5 "register_operand")] + "TARGET_VECTOR" +{ + /* Normalize into cond_len_* operations. */ + emit_insn (gen_cond_len_fnms (operands[0], operands[1], operands[2], + operands[3], operands[4], operands[5], + gen_int_mode (GET_MODE_NUNITS (mode), Pmode), + const0_rtx)); + DONE; +}) + +(define_expand "cond_len_fnms" + [(match_operand:VF 0 "register_operand") + (match_operand: 1 "vector_mask_operand") + (match_operand:VF 2 "register_operand") + (match_operand:VF 3 "register_operand") + (match_operand:VF 4 "register_operand") + (match_operand:VF 5 "register_operand") + (match_operand 6 "autovec_length_operand") + (match_operand 7 "const_0_operand")] + "TARGET_VECTOR" +{ + insn_code icode = code_for_pred_mul_neg (MINUS, mode); + riscv_vector::expand_cond_len_ternop (icode, operands); + DONE; +}) + ;; ========================================================================= ;; == Reductions ;; ========================================================================= @@ -1714,3 +2181,93 @@ riscv_vector::reduction_type::MASK_LEN_FOLD_LEFT); DONE; }) + +;; ------------------------------------------------------------------------- +;; ---- [INT,FP] Extract active element +;; ------------------------------------------------------------------------- +;; Includes: +;; - vcompress.vm +;; - vcpop.m +;; - vslidedown.vx +;; - vmv.x.s +;; - vfmv.f.s +;; ------------------------------------------------------------------------- + +(define_expand "len_fold_extract_last_" + [(match_operand: 0 "register_operand") + (match_operand: 1 "register_operand") + (match_operand: 2 "register_operand") + (match_operand:V 3 "register_operand") + (match_operand 4 "autovec_length_operand") + (match_operand 5 "const_0_operand")] + "TARGET_VECTOR" + { + riscv_vector::expand_fold_extract_last (operands); + DONE; + }) + +;; ------------------------------------------------------------------------- +;; ---- [INT] Average. +;; ------------------------------------------------------------------------- +;; Implements the following "average" patterns: +;; floor: +;; op[0] = (narrow) ((wide) op[1] + (wide) op[2]) >> 1; +;; ceil: +;; op[0] = (narrow) ((wide) op[1] + (wide) op[2] + 1)) >> 1; +;; ------------------------------------------------------------------------- + +(define_expand "avg3_floor" + [(set (match_operand: 0 "register_operand") + (truncate: + (:VWEXTI + (plus:VWEXTI + (any_extend:VWEXTI + (match_operand: 1 "register_operand")) + (any_extend:VWEXTI + (match_operand: 2 "register_operand"))))))] + "TARGET_VECTOR" +{ + /* First emit a widening addition. */ + rtx tmp1 = gen_reg_rtx (mode); + rtx ops1[] = {tmp1, operands[1], operands[2]}; + insn_code icode = code_for_pred_dual_widen (PLUS, , mode); + riscv_vector::emit_vlmax_insn (icode, riscv_vector::BINARY_OP, ops1); + + /* Then a narrowing shift. */ + rtx ops2[] = {operands[0], tmp1, const1_rtx}; + icode = code_for_pred_narrow_scalar (, mode); + riscv_vector::emit_vlmax_insn (icode, riscv_vector::BINARY_OP, ops2); + DONE; +}) + +(define_expand "avg3_ceil" + [(set (match_operand: 0 "register_operand") + (truncate: + (:VWEXTI + (plus:VWEXTI + (plus:VWEXTI + (any_extend:VWEXTI + (match_operand: 1 "register_operand")) + (any_extend:VWEXTI + (match_operand: 2 "register_operand"))) + (const_int 1)))))] + "TARGET_VECTOR" +{ + /* First emit a widening addition. */ + rtx tmp1 = gen_reg_rtx (mode); + rtx ops1[] = {tmp1, operands[1], operands[2]}; + insn_code icode = code_for_pred_dual_widen (PLUS, , mode); + riscv_vector::emit_vlmax_insn (icode, riscv_vector::BINARY_OP, ops1); + + /* Then add 1. */ + rtx tmp2 = gen_reg_rtx (mode); + rtx ops2[] = {tmp2, tmp1, const1_rtx}; + icode = code_for_pred_scalar (PLUS, mode); + riscv_vector::emit_vlmax_insn (icode, riscv_vector::BINARY_OP, ops2); + + /* Finally, a narrowing shift. */ + rtx ops3[] = {operands[0], tmp2, const1_rtx}; + icode = code_for_pred_narrow_scalar (, mode); + riscv_vector::emit_vlmax_insn (icode, riscv_vector::BINARY_OP, ops3); + DONE; +}) diff --git a/gcc/config/riscv/bitmanip.md b/gcc/config/riscv/bitmanip.md index c42e7b890db2..7b55528ee49a 100644 --- a/gcc/config/riscv/bitmanip.md +++ b/gcc/config/riscv/bitmanip.md @@ -103,7 +103,8 @@ (match_dup 4)))] { operands[3] = GEN_INT (INTVAL (operands[3]) >> INTVAL (operands[2])); -}) +} +[(set_attr "type" "bitmanip")]) (define_insn "*shNadduw" [(set (match_operand:DI 0 "register_operand" "=r") @@ -261,7 +262,7 @@ (match_operand:DI 2 "const_int_operand")))] "TARGET_64BIT && TARGET_ZBB && ((INTVAL (operands[2]) & 0x3f) == 0x3f)" "w\t%0,%1" - [(set_attr "type" "bitmanip") + [(set_attr "type" "") (set_attr "mode" "SI")]) (define_insn "*di2" @@ -533,7 +534,9 @@ "&& reload_completed" [(set (match_dup 3) (sign_extend:DI (match_dup 1))) (set (match_dup 4) (match_dup 2)) - (set (match_dup 0) (:DI (match_dup 3) (match_dup 4)))]) + (set (match_dup 0) (:DI (match_dup 3) (match_dup 4)))] + "" + [(set_attr "type" "bitmanip")]) ;; ZBS extension. @@ -628,7 +631,8 @@ operands[3] = GEN_INT (~bits | topbit); operands[4] = GEN_INT (~topbit); -}) +} +[(set_attr "type" "bitmanip")]) ;; In case of a paradoxical subreg, the sign bit and the high bits are ;; not allowed to be changed @@ -648,7 +652,8 @@ operands[3] = GEN_INT (~bits | topbit); operands[4] = GEN_INT (~topbit); -}) +} +[(set_attr "type" "bitmanip")]) (define_insn "*binv" [(set (match_operand:X 0 "register_operand" "=r") @@ -743,7 +748,8 @@ operands[3] = GEN_INT (bits &~ topbit); operands[4] = GEN_INT (topbit); -}) +} +[(set_attr "type" "bitmanip")]) ;; Same to use blcri + andi and blcri + bclri (define_insn_and_split "*andi_extrabit" @@ -761,7 +767,8 @@ operands[3] = GEN_INT (bits | topbit); operands[4] = GEN_INT (~topbit); -}) +} +[(set_attr "type" "bitmanip")]) ;; IF_THEN_ELSE: test for 2 bits of opposite polarity (define_insn_and_split "*branch_mask_twobits_equals_singlebit" @@ -803,7 +810,8 @@ operands[8] = GEN_INT (setbit); operands[9] = GEN_INT (clearbit); -}) +} +[(set_attr "type" "bitmanip")]) ;; IF_THEN_ELSE: test for (a & (1 << BIT_NO)) (define_insn_and_split "*branch_bext" @@ -826,7 +834,9 @@ (zero_extend:X (match_dup 3)))) (set (pc) (if_then_else (match_op_dup 1 [(match_dup 4) (const_int 0)]) (label_ref (match_dup 0)) - (pc)))]) + (pc)))] + "" + [(set_attr "type" "bitmanip")]) ;; ZBKC or ZBC extension (define_insn "riscv_clmul_" diff --git a/gcc/config/riscv/constraints.md b/gcc/config/riscv/constraints.md index 44525b2da491..3f52bc76f67f 100644 --- a/gcc/config/riscv/constraints.md +++ b/gcc/config/riscv/constraints.md @@ -118,6 +118,19 @@ (and (match_operand 0 "move_operand") (match_test "CONSTANT_P (op)"))) +;; Zfa constraints. + +(define_constraint "zfli" + "A floating point number that can be loaded using instruction `fli` in zfa." + (and (match_code "const_double") + (match_test "TARGET_ZFA && (riscv_float_const_rtx_index_for_fli (op) != -1)"))) + +(define_register_constraint "zmvf" "(TARGET_ZFA || TARGET_XTHEADFMV) ? FP_REGS : NO_REGS" + "A floating-point register for ZFA or XTheadFmv.") + +(define_register_constraint "zmvr" "(TARGET_ZFA || TARGET_XTHEADFMV) ? GR_REGS : NO_REGS" + "An integer register for ZFA or XTheadFmv.") + ;; Vector constraints. (define_register_constraint "vr" "TARGET_VECTOR ? V_REGS : NO_REGS" @@ -180,11 +193,3 @@ "Vector duplicate memory operand" (and (match_code "mem") (match_code "reg" "0"))) - -;; Vendor ISA extension constraints. - -(define_register_constraint "th_f_fmv" "TARGET_XTHEADFMV ? FP_REGS : NO_REGS" - "A floating-point register for XTheadFmv.") - -(define_register_constraint "th_r_fmv" "TARGET_XTHEADFMV ? GR_REGS : NO_REGS" - "An integer register for XTheadFmv.") diff --git a/gcc/config/riscv/iterators.md b/gcc/config/riscv/iterators.md index d374a10810c6..ecf033f2fa79 100644 --- a/gcc/config/riscv/iterators.md +++ b/gcc/config/riscv/iterators.md @@ -67,6 +67,11 @@ (DF "TARGET_DOUBLE_FLOAT || TARGET_ZDINX") (HF "TARGET_ZFH || TARGET_ZHINX")]) +;; Iterator for hardware-supported load/store floating-point modes. +(define_mode_iterator ANYLSF [(SF "TARGET_HARD_FLOAT || TARGET_ZFINX") + (DF "TARGET_DOUBLE_FLOAT || TARGET_ZDINX") + (HF "TARGET_ZFHMIN || TARGET_ZHINXMIN")]) + ;; Iterator for floating-point modes that can be loaded into X registers. (define_mode_iterator SOFTF [SF (DF "TARGET_64BIT") (HF "TARGET_ZFHMIN")]) @@ -120,6 +125,21 @@ (define_mode_attr shiftm1 [(SI "const_si_mask_operand") (DI "const_di_mask_operand")]) (define_mode_attr shiftm1p [(SI "DsS") (DI "DsD")]) +; zcmp mode attribute +(define_mode_attr slot0_offset [(SI "-4") (DI "-8")]) +(define_mode_attr slot1_offset [(SI "-8") (DI "-16")]) +(define_mode_attr slot2_offset [(SI "-12") (DI "-24")]) +(define_mode_attr slot3_offset [(SI "-16") (DI "-32")]) +(define_mode_attr slot4_offset [(SI "-20") (DI "-40")]) +(define_mode_attr slot5_offset [(SI "-24") (DI "-48")]) +(define_mode_attr slot6_offset [(SI "-28") (DI "-56")]) +(define_mode_attr slot7_offset [(SI "-32") (DI "-64")]) +(define_mode_attr slot8_offset [(SI "-36") (DI "-72")]) +(define_mode_attr slot9_offset [(SI "-40") (DI "-80")]) +(define_mode_attr slot10_offset [(SI "-44") (DI "-88")]) +(define_mode_attr slot11_offset [(SI "-48") (DI "-96")]) +(define_mode_attr slot12_offset [(SI "-52") (DI "-104")]) + ;; ------------------------------------------------------------------- ;; Code Iterators ;; ------------------------------------------------------------------- @@ -300,3 +320,8 @@ (define_int_attr quiet_pattern [(UNSPEC_FLT_QUIET "lt") (UNSPEC_FLE_QUIET "le")]) (define_int_attr QUIET_PATTERN [(UNSPEC_FLT_QUIET "LT") (UNSPEC_FLE_QUIET "LE")]) +(define_int_iterator ROUND [UNSPEC_ROUND UNSPEC_FLOOR UNSPEC_CEIL UNSPEC_BTRUNC UNSPEC_ROUNDEVEN UNSPEC_NEARBYINT]) +(define_int_attr round_pattern [(UNSPEC_ROUND "round") (UNSPEC_FLOOR "floor") (UNSPEC_CEIL "ceil") + (UNSPEC_BTRUNC "btrunc") (UNSPEC_ROUNDEVEN "roundeven") (UNSPEC_NEARBYINT "nearbyint")]) +(define_int_attr round_rm [(UNSPEC_ROUND "rmm") (UNSPEC_FLOOR "rdn") (UNSPEC_CEIL "rup") + (UNSPEC_BTRUNC "rtz") (UNSPEC_ROUNDEVEN "rne") (UNSPEC_NEARBYINT "dyn")]) diff --git a/gcc/config/riscv/peephole.md b/gcc/config/riscv/peephole.md index 0ef0c04410bd..92e57f9a447b 100644 --- a/gcc/config/riscv/peephole.md +++ b/gcc/config/riscv/peephole.md @@ -38,3 +38,31 @@ { operands[5] = GEN_INT (INTVAL (operands[2]) - INTVAL (operands[5])); }) + +;; ZCMP +(define_peephole2 + [(set (match_operand:X 0 "a0a1_reg_operand") + (match_operand:X 1 "zcmp_mv_sreg_operand")) + (set (match_operand:X 2 "a0a1_reg_operand") + (match_operand:X 3 "zcmp_mv_sreg_operand"))] + "TARGET_ZCMP + && (REGNO (operands[2]) != REGNO (operands[0]))" + [(parallel [(set (match_dup 0) + (match_dup 1)) + (set (match_dup 2) + (match_dup 3))])] +) + +(define_peephole2 + [(set (match_operand:X 0 "zcmp_mv_sreg_operand") + (match_operand:X 1 "a0a1_reg_operand")) + (set (match_operand:X 2 "zcmp_mv_sreg_operand") + (match_operand:X 3 "a0a1_reg_operand"))] + "TARGET_ZCMP + && (REGNO (operands[0]) != REGNO (operands[2])) + && (REGNO (operands[1]) != REGNO (operands[3]))" + [(parallel [(set (match_dup 0) + (match_dup 1)) + (set (match_dup 2) + (match_dup 3))])] +) diff --git a/gcc/config/riscv/pic.md b/gcc/config/riscv/pic.md index 9507850455a6..da636e31619e 100644 --- a/gcc/config/riscv/pic.md +++ b/gcc/config/riscv/pic.md @@ -43,17 +43,17 @@ "u\t%0,%1" [(set (attr "length") (const_int 8))]) -;; We can support ANYF loads into X register if there is no double support +;; We can support ANYLSF loads into X register if there is no double support ;; or if the target is 64-bit. -(define_insn "*local_pic_load" - [(set (match_operand:ANYF 0 "register_operand" "=f,*r") - (mem:ANYF (match_operand 1 "absolute_symbolic_operand" ""))) +(define_insn "*local_pic_load" + [(set (match_operand:ANYLSF 0 "register_operand" "=f,*r") + (mem:ANYLSF (match_operand 1 "absolute_symbolic_operand" ""))) (clobber (match_scratch:P 2 "=r,X"))] "TARGET_HARD_FLOAT && USE_LOAD_ADDRESS_MACRO (operands[1]) && (!TARGET_DOUBLE_FLOAT || TARGET_64BIT)" "@ - \t%0,%1,%2 + \t%0,%1,%2 \t%0,%1" [(set (attr "length") (const_int 8))]) @@ -61,13 +61,13 @@ ;; supported. ld is not valid in that case. Punt for now. Maybe add a split ;; for this later. -(define_insn "*local_pic_load_32d" - [(set (match_operand:ANYF 0 "register_operand" "=f") - (mem:ANYF (match_operand 1 "absolute_symbolic_operand" ""))) +(define_insn "*local_pic_load_32d" + [(set (match_operand:ANYLSF 0 "register_operand" "=f") + (mem:ANYLSF (match_operand 1 "absolute_symbolic_operand" ""))) (clobber (match_scratch:P 2 "=r"))] "TARGET_HARD_FLOAT && USE_LOAD_ADDRESS_MACRO (operands[1]) && (TARGET_DOUBLE_FLOAT && !TARGET_64BIT)" - "\t%0,%1,%2" + "\t%0,%1,%2" [(set (attr "length") (const_int 8))]) (define_insn "*local_pic_load_sf" @@ -88,14 +88,14 @@ "\t%z1,%0,%2" [(set (attr "length") (const_int 8))]) -(define_insn "*local_pic_store" - [(set (mem:ANYF (match_operand 0 "absolute_symbolic_operand" "")) - (match_operand:ANYF 1 "register_operand" "f,*r")) +(define_insn "*local_pic_store" + [(set (mem:ANYLSF (match_operand 0 "absolute_symbolic_operand" "")) + (match_operand:ANYLSF 1 "register_operand" "f,*r")) (clobber (match_scratch:P 2 "=r,&r"))] "TARGET_HARD_FLOAT && USE_LOAD_ADDRESS_MACRO (operands[0]) && (!TARGET_DOUBLE_FLOAT || TARGET_64BIT)" "@ - \t%1,%0,%2 + \t%1,%0,%2 \t%1,%0,%2" [(set (attr "length") (const_int 8))]) @@ -103,13 +103,13 @@ ;; supported. sd is not valid in that case. Punt for now. Maybe add a split ;; for this later. -(define_insn "*local_pic_store_32d" - [(set (match_operand:ANYF 0 "register_operand" "=f") - (mem:ANYF (match_operand 1 "absolute_symbolic_operand" ""))) +(define_insn "*local_pic_store_32d" + [(set (match_operand:ANYLSF 0 "register_operand" "=f") + (mem:ANYLSF (match_operand 1 "absolute_symbolic_operand" ""))) (clobber (match_scratch:P 2 "=r"))] "TARGET_HARD_FLOAT && USE_LOAD_ADDRESS_MACRO (operands[1]) && (TARGET_DOUBLE_FLOAT && !TARGET_64BIT)" - "\t%1,%0,%2" + "\t%1,%0,%2" [(set (attr "length") (const_int 8))]) (define_insn "*local_pic_store_sf" diff --git a/gcc/config/riscv/predicates.md b/gcc/config/riscv/predicates.md index 9db28c2def7e..53e7c1d03aa6 100644 --- a/gcc/config/riscv/predicates.md +++ b/gcc/config/riscv/predicates.md @@ -49,6 +49,11 @@ (ior (match_operand 0 "const_csr_operand") (match_operand 0 "register_operand"))) +;; V has 32-bit unsigned immediates. This happens to be the same constraint as +;; the csr_operand, but it's not CSR related. +(define_predicate "vector_scalar_shift_operand" + (match_operand 0 "csr_operand")) + (define_predicate "sle_operand" (and (match_code "const_int") (match_test "SMALL_OPERAND (INTVAL (op) + 1)"))) @@ -69,6 +74,113 @@ (ior (match_operand 0 "const_0_operand") (match_operand 0 "register_operand"))) +(define_predicate "stack_push_up_to_ra_operand" + (and (match_code "const_int") + (match_test "riscv_zcmp_valid_stack_adj_bytes_p (INTVAL (op) * -1, 1)"))) + +(define_predicate "stack_push_up_to_s0_operand" + (and (match_code "const_int") + (match_test "riscv_zcmp_valid_stack_adj_bytes_p (INTVAL (op) * -1, 2)"))) + +(define_predicate "stack_push_up_to_s1_operand" + (and (match_code "const_int") + (match_test "riscv_zcmp_valid_stack_adj_bytes_p (INTVAL (op) * -1, 3)"))) + +(define_predicate "stack_push_up_to_s2_operand" + (and (match_code "const_int") + (match_test "riscv_zcmp_valid_stack_adj_bytes_p (INTVAL (op) * -1, 4)"))) + +(define_predicate "stack_push_up_to_s3_operand" + (and (match_code "const_int") + (match_test "riscv_zcmp_valid_stack_adj_bytes_p (INTVAL (op) * -1, 5)"))) + +(define_predicate "stack_push_up_to_s4_operand" + (and (match_code "const_int") + (match_test "riscv_zcmp_valid_stack_adj_bytes_p (INTVAL (op) * -1, 6)"))) + +(define_predicate "stack_push_up_to_s5_operand" + (and (match_code "const_int") + (match_test "riscv_zcmp_valid_stack_adj_bytes_p (INTVAL (op) * -1, 7)"))) + +(define_predicate "stack_push_up_to_s6_operand" + (and (match_code "const_int") + (match_test "riscv_zcmp_valid_stack_adj_bytes_p (INTVAL (op) * -1, 8)"))) + +(define_predicate "stack_push_up_to_s7_operand" + (and (match_code "const_int") + (match_test "riscv_zcmp_valid_stack_adj_bytes_p (INTVAL (op) * -1, 9)"))) + +(define_predicate "stack_push_up_to_s8_operand" + (and (match_code "const_int") + (match_test "riscv_zcmp_valid_stack_adj_bytes_p (INTVAL (op) * -1, 10)"))) + +(define_predicate "stack_push_up_to_s9_operand" + (and (match_code "const_int") + (match_test "riscv_zcmp_valid_stack_adj_bytes_p (INTVAL (op) * -1, 11)"))) + +(define_predicate "stack_push_up_to_s11_operand" + (and (match_code "const_int") + (match_test "riscv_zcmp_valid_stack_adj_bytes_p (INTVAL (op) * -1, 13)"))) + +(define_predicate "stack_pop_up_to_ra_operand" + (and (match_code "const_int") + (match_test "riscv_zcmp_valid_stack_adj_bytes_p (INTVAL (op), 1)"))) + +(define_predicate "stack_pop_up_to_s0_operand" + (and (match_code "const_int") + (match_test "riscv_zcmp_valid_stack_adj_bytes_p (INTVAL (op), 2)"))) + +(define_predicate "stack_pop_up_to_s1_operand" + (and (match_code "const_int") + (match_test "riscv_zcmp_valid_stack_adj_bytes_p (INTVAL (op), 3)"))) + +(define_predicate "stack_pop_up_to_s2_operand" + (and (match_code "const_int") + (match_test "riscv_zcmp_valid_stack_adj_bytes_p (INTVAL (op), 4)"))) + +(define_predicate "stack_pop_up_to_s3_operand" + (and (match_code "const_int") + (match_test "riscv_zcmp_valid_stack_adj_bytes_p (INTVAL (op), 5)"))) + +(define_predicate "stack_pop_up_to_s4_operand" + (and (match_code "const_int") + (match_test "riscv_zcmp_valid_stack_adj_bytes_p (INTVAL (op), 6)"))) + +(define_predicate "stack_pop_up_to_s5_operand" + (and (match_code "const_int") + (match_test "riscv_zcmp_valid_stack_adj_bytes_p (INTVAL (op), 7)"))) + +(define_predicate "stack_pop_up_to_s6_operand" + (and (match_code "const_int") + (match_test "riscv_zcmp_valid_stack_adj_bytes_p (INTVAL (op), 8)"))) + +(define_predicate "stack_pop_up_to_s7_operand" + (and (match_code "const_int") + (match_test "riscv_zcmp_valid_stack_adj_bytes_p (INTVAL (op), 9)"))) + +(define_predicate "stack_pop_up_to_s8_operand" + (and (match_code "const_int") + (match_test "riscv_zcmp_valid_stack_adj_bytes_p (INTVAL (op), 10)"))) + +(define_predicate "stack_pop_up_to_s9_operand" + (and (match_code "const_int") + (match_test "riscv_zcmp_valid_stack_adj_bytes_p (INTVAL (op), 11)"))) + +(define_predicate "stack_pop_up_to_s11_operand" + (and (match_code "const_int") + (match_test "riscv_zcmp_valid_stack_adj_bytes_p (INTVAL (op), 13)"))) + +;; ZCMP predicates +(define_predicate "a0a1_reg_operand" + (and (match_operand 0 "register_operand") + (match_test "IN_RANGE (REGNO (op), A0_REGNUM, A1_REGNUM)"))) + +(define_predicate "zcmp_mv_sreg_operand" + (and (match_operand 0 "register_operand") + (match_test "TARGET_RVE ? IN_RANGE (REGNO (op), S0_REGNUM, S1_REGNUM) + : IN_RANGE (REGNO (op), S0_REGNUM, S1_REGNUM) + || IN_RANGE (REGNO (op), S2_REGNUM, S7_REGNUM)"))) + ;; Only use branch-on-bit sequences when the mask is not an ANDI immediate. (define_predicate "branch_on_bit_operand" (and (match_code "const_int") @@ -282,10 +394,7 @@ (define_special_predicate "autovec_length_operand" (ior (match_operand 0 "pmode_register_operand") - (ior (match_operand 0 "const_csr_operand") - (match_test "rtx_equal_p (op, gen_int_mode - (GET_MODE_NUNITS (GET_MODE (op)), - Pmode))")))) + (match_code "const_int,const_poly_int"))) (define_predicate "reg_or_mem_operand" (ior (match_operand 0 "register_operand") @@ -295,6 +404,15 @@ (ior (match_operand 0 "register_operand") (match_operand 0 "const_int_operand"))) +(define_predicate "vector_const_0_operand" + (and (match_code "const_vector") + (match_test "satisfies_constraint_Wc0 (op)"))) + +(define_predicate "vector_const_int_or_double_0_operand" + (and (match_code "const_vector") + (match_test "satisfies_constraint_vi (op) + || satisfies_constraint_Wc0 (op)"))) + (define_predicate "vector_move_operand" (ior (match_operand 0 "nonimmediate_operand") (and (match_code "const_vector") diff --git a/gcc/config/riscv/riscv-builtins.cc b/gcc/config/riscv/riscv-builtins.cc index 79681d759628..8afe7b7e97d3 100644 --- a/gcc/config/riscv/riscv-builtins.cc +++ b/gcc/config/riscv/riscv-builtins.cc @@ -122,7 +122,7 @@ AVAIL (clmul_zbkc32_or_zbc32, (TARGET_ZBKC || TARGET_ZBC) && !TARGET_64BIT) AVAIL (clmul_zbkc64_or_zbc64, (TARGET_ZBKC || TARGET_ZBC) && TARGET_64BIT) AVAIL (clmulr_zbc32, TARGET_ZBC && !TARGET_64BIT) AVAIL (clmulr_zbc64, TARGET_ZBC && TARGET_64BIT) -AVAIL (always, (!0)) +AVAIL (hint_pause, (!0)) /* Construct a riscv_builtin_description from the given arguments. @@ -179,7 +179,7 @@ static const struct riscv_builtin_description riscv_builtins[] = { DIRECT_BUILTIN (frflags, RISCV_USI_FTYPE, hard_float), DIRECT_NO_TARGET_BUILTIN (fsflags, RISCV_VOID_FTYPE_USI, hard_float), - DIRECT_NO_TARGET_BUILTIN (pause, RISCV_VOID_FTYPE, always), + RISCV_BUILTIN (pause, "pause", RISCV_BUILTIN_DIRECT_NO_TARGET, RISCV_VOID_FTYPE, hint_pause), }; /* Index I is the function declaration for riscv_builtins[I], or null if the diff --git a/gcc/config/riscv/riscv-c.cc b/gcc/config/riscv/riscv-c.cc index 6ad562dcb8b2..283052ae3131 100644 --- a/gcc/config/riscv/riscv-c.cc +++ b/gcc/config/riscv/riscv-c.cc @@ -47,7 +47,7 @@ riscv_cpu_cpp_builtins (cpp_reader *pfile) { builtin_define ("__riscv"); - if (TARGET_RVC) + if (TARGET_RVC || TARGET_ZCA) builtin_define ("__riscv_compressed"); if (TARGET_RVE) @@ -108,6 +108,13 @@ riscv_cpu_cpp_builtins (cpp_reader *pfile) } + if (riscv_user_wants_strict_align) + builtin_define_with_int_value ("__riscv_unaligned_avoid", 1); + else if (riscv_slow_unaligned_access_p) + builtin_define_with_int_value ("__riscv_unaligned_slow", 1); + else + builtin_define_with_int_value ("__riscv_unaligned_fast", 1); + if (TARGET_MIN_VLEN != 0) builtin_define_with_int_value ("__riscv_v_min_vlen", TARGET_MIN_VLEN); diff --git a/gcc/config/riscv/riscv-opts.h b/gcc/config/riscv/riscv-opts.h index 28d9b81bd800..79e0f12e3885 100644 --- a/gcc/config/riscv/riscv-opts.h +++ b/gcc/config/riscv/riscv-opts.h @@ -79,7 +79,9 @@ enum riscv_autovec_lmul_enum { RVV_M1 = 1, RVV_M2 = 2, RVV_M4 = 4, - RVV_M8 = 8 + RVV_M8 = 8, + /* For dynamic LMUL, we compare COST start with LMUL8. */ + RVV_DYNAMIC = RVV_M8 }; enum riscv_multilib_select_kind { @@ -102,10 +104,12 @@ enum riscv_entity #define MASK_ZICSR (1 << 0) #define MASK_ZIFENCEI (1 << 1) #define MASK_ZIHINTNTL (1 << 2) +#define MASK_ZIHINTPAUSE (1 << 3) #define TARGET_ZICSR ((riscv_zi_subext & MASK_ZICSR) != 0) #define TARGET_ZIFENCEI ((riscv_zi_subext & MASK_ZIFENCEI) != 0) #define TARGET_ZIHINTNTL ((riscv_zi_subext & MASK_ZIHINTNTL) != 0) +#define TARGET_ZIHINTPAUSE ((riscv_zi_subext & MASK_ZIHINTPAUSE) != 0) #define MASK_ZAWRS (1 << 0) #define TARGET_ZAWRS ((riscv_za_subext & MASK_ZAWRS) != 0) @@ -152,6 +156,10 @@ enum riscv_entity #define TARGET_ZKSH ((riscv_zk_subext & MASK_ZKSH) != 0) #define TARGET_ZKT ((riscv_zk_subext & MASK_ZKT) != 0) +#define MASK_ZTSO (1 << 0) + +#define TARGET_ZTSO ((riscv_ztso_subext & MASK_ZTSO) != 0) + #define MASK_VECTOR_ELEN_32 (1 << 0) #define MASK_VECTOR_ELEN_64 (1 << 1) #define MASK_VECTOR_ELEN_FP_32 (1 << 2) @@ -241,6 +249,9 @@ enum riscv_entity #define MASK_ZICOND (1 << 2) #define TARGET_ZICOND ((riscv_zi_subext & MASK_ZICOND) != 0) +#define MASK_ZFA (1 << 0) +#define TARGET_ZFA ((riscv_zfa_subext & MASK_ZFA) != 0) + #define MASK_ZFHMIN (1 << 0) #define MASK_ZFH (1 << 1) #define MASK_ZVFHMIN (1 << 2) @@ -254,6 +265,22 @@ enum riscv_entity #define MASK_ZMMUL (1 << 0) #define TARGET_ZMMUL ((riscv_zm_subext & MASK_ZMMUL) != 0) +#define MASK_ZCA (1 << 0) +#define MASK_ZCB (1 << 1) +#define MASK_ZCE (1 << 2) +#define MASK_ZCF (1 << 3) +#define MASK_ZCD (1 << 4) +#define MASK_ZCMP (1 << 5) +#define MASK_ZCMT (1 << 6) + +#define TARGET_ZCA ((riscv_zc_subext & MASK_ZCA) != 0) +#define TARGET_ZCB ((riscv_zc_subext & MASK_ZCB) != 0) +#define TARGET_ZCE ((riscv_zc_subext & MASK_ZCE) != 0) +#define TARGET_ZCF ((riscv_zc_subext & MASK_ZCF) != 0) +#define TARGET_ZCD ((riscv_zc_subext & MASK_ZCD) != 0) +#define TARGET_ZCMP ((riscv_zc_subext & MASK_ZCMP) != 0) +#define TARGET_ZCMT ((riscv_zc_subext & MASK_ZCMT) != 0) + #define MASK_SVINVAL (1 << 0) #define MASK_SVNAPOT (1 << 1) @@ -296,6 +323,7 @@ enum riscv_entity /* We only enable VLS modes for VLA vectorization since fixed length VLMAX mode is the highest priority choice and should not conflict with VLS modes. */ -#define TARGET_VECTOR_VLS (riscv_autovec_preference == RVV_SCALABLE) +#define TARGET_VECTOR_VLS \ + (TARGET_VECTOR && riscv_autovec_preference == RVV_SCALABLE) #endif /* ! GCC_RISCV_OPTS_H */ diff --git a/gcc/config/riscv/riscv-protos.h b/gcc/config/riscv/riscv-protos.h index 53b87cb28d31..dd7aa360ec5b 100644 --- a/gcc/config/riscv/riscv-protos.h +++ b/gcc/config/riscv/riscv-protos.h @@ -83,6 +83,7 @@ struct riscv_address_info { /* Routines implemented in riscv.cc. */ extern enum riscv_symbol_type riscv_classify_symbolic_expression (rtx); extern bool riscv_symbolic_constant_p (rtx, enum riscv_symbol_type *); +extern int riscv_float_const_rtx_index_for_fli (rtx); extern int riscv_regno_mode_ok_for_base_p (int, machine_mode, bool); extern enum reg_class riscv_index_reg_class (); extern int riscv_regno_ok_for_index_p (int); @@ -101,6 +102,8 @@ extern bool riscv_split_64bit_move_p (rtx, rtx); extern void riscv_split_doubleword_move (rtx, rtx); extern const char *riscv_output_move (rtx, rtx); extern const char *riscv_output_return (); +extern bool +riscv_zcmp_valid_stack_adj_bytes_p (HOST_WIDE_INT, int); #ifdef RTX_CODE extern void riscv_expand_int_scc (rtx, enum rtx_code, rtx, rtx, bool *invert_ptr = 0); @@ -128,6 +131,7 @@ extern poly_uint64 riscv_regmode_natural_size (machine_mode); extern bool riscv_v_ext_vector_mode_p (machine_mode); extern bool riscv_v_ext_tuple_mode_p (machine_mode); extern bool riscv_v_ext_vls_mode_p (machine_mode); +extern int riscv_get_v_regno_alignment (machine_mode); extern bool riscv_shamt_matches_mask_p (int, HOST_WIDE_INT); extern void riscv_subword_address (rtx, rtx *, rtx *, rtx *, rtx *); extern void riscv_lshift_subword (machine_mode, rtx, rtx, rtx *); @@ -179,29 +183,167 @@ namespace riscv_vector { #define RVV_VUNDEF(MODE) \ gen_rtx_UNSPEC (MODE, gen_rtvec (1, gen_rtx_REG (SImode, X0_REGNUM)), \ UNSPEC_VUNDEF) -enum insn_type + +/* These flags describe how to pass the operands to a rvv insn pattern. + e.g.: + If a insn has this flags: + HAS_DEST_P | HAS_MASK_P | USE_VUNDEF_MERGE_P + | TU_POLICY_P | BINARY_OP_P | FRM_DYN_P + that means: + operands[0] is the dest operand + operands[1] is the mask operand + operands[2] is the merge operand + operands[3] and operands[4] is the two operand to do the operation. + operands[5] is the vl operand + operands[6] is the tail policy operand + operands[7] is the mask policy operands + operands[8] is the rounding mode operands + + Then you can call `emit_vlmax_insn (flags, icode, ops)` to emit a insn. + and ops[0] is the dest operand (operands[0]), ops[1] is the mask + operand (operands[1]), ops[2] and ops[3] is the two + operands (operands[3], operands[4]) to do the operation. Other operands + will be created by emit_vlmax_insn according to the flags information. +*/ +enum insn_flags : unsigned int { - RVV_MISC_OP = 1, - RVV_UNOP = 2, - RVV_BINOP = 3, - RVV_BINOP_MU = RVV_BINOP + 2, - RVV_BINOP_TU = RVV_BINOP + 2, - RVV_MERGE_OP = 4, - RVV_CMP_OP = 4, - RVV_CMP_MU_OP = RVV_CMP_OP + 2, /* +2 means mask and maskoff operand. */ - RVV_UNOP_MU = RVV_UNOP + 2, /* Likewise. */ - RVV_UNOP_M = RVV_UNOP + 2, /* Likewise. */ - RVV_TERNOP = 5, - RVV_TERNOP_TU = RVV_TERNOP + 1, - RVV_WIDEN_TERNOP = 4, - RVV_SCALAR_MOV_OP = 4, /* +1 for VUNDEF according to vector.md. */ - RVV_SLIDE_OP = 4, /* Dest, VUNDEF, source and offset. */ - RVV_COMPRESS_OP = 4, - RVV_GATHER_M_OP = 5, - RVV_SCATTER_M_OP = 4, - RVV_REDUCTION_OP = 3, - RVV_REDUCTION_TU_OP = RVV_REDUCTION_OP + 2, + /* flags for dest, mask, merge operands. */ + /* Means INSN has dest operand. False for STORE insn. */ + HAS_DEST_P = 1 << 0, + /* Means INSN has mask operand. */ + HAS_MASK_P = 1 << 1, + /* Means using ALL_TRUES for mask operand. */ + USE_ALL_TRUES_MASK_P = 1 << 2, + /* Means using ONE_TRUE for mask operand. */ + USE_ONE_TRUE_MASK_P = 1 << 3, + /* Means INSN has merge operand. */ + HAS_MERGE_P = 1 << 4, + /* Means using VUNDEF for merge operand. */ + USE_VUNDEF_MERGE_P = 1 << 5, + + /* flags for tail policy and mask plicy operands. */ + /* Means the tail policy is TAIL_UNDISTURBED. */ + TU_POLICY_P = 1 << 6, + /* Means the tail policy is default (return by get_prefer_tail_policy). */ + TDEFAULT_POLICY_P = 1 << 7, + /* Means the mask policy is MASK_UNDISTURBED. */ + MU_POLICY_P = 1 << 8, + /* Means the mask policy is default (return by get_prefer_mask_policy). */ + MDEFAULT_POLICY_P = 1 << 9, + + /* flags for the number operands to do the operation. */ + /* Means INSN need zero operand to do the operation. e.g. vid.v */ + NULLARY_OP_P = 1 << 10, + /* Means INSN need one operand to do the operation. */ + UNARY_OP_P = 1 << 11, + /* Means INSN need two operands to do the operation. */ + BINARY_OP_P = 1 << 12, + /* Means INSN need two operands to do the operation. */ + TERNARY_OP_P = 1 << 13, + + /* flags for get mask mode from the index number. default from dest operand. */ + MASK_MODE_FROM_OP1_P = 1 << 14, + + /* flags for the floating-point rounding mode. */ + /* Means INSN has FRM operand and the value is FRM_DYN. */ + FRM_DYN_P = 1 << 15, }; + +enum insn_type : unsigned int +{ + /* some flags macros. */ + /* For non-mask insn with tama. */ + __NORMAL_OP = HAS_DEST_P | HAS_MASK_P | USE_ALL_TRUES_MASK_P | HAS_MERGE_P + | USE_VUNDEF_MERGE_P | TDEFAULT_POLICY_P | MDEFAULT_POLICY_P, + /* For non-mask insn with ta, without mask policy operand. */ + __NORMAL_OP_TA = HAS_DEST_P | HAS_MASK_P | USE_ALL_TRUES_MASK_P | HAS_MERGE_P + | USE_VUNDEF_MERGE_P | TDEFAULT_POLICY_P, + /* For non-mask insn with ta, without mask operand and mask policy operand. */ + __NORMAL_OP_TA2 + = HAS_DEST_P | HAS_MERGE_P | USE_VUNDEF_MERGE_P | TDEFAULT_POLICY_P, + /* For non-mask insn with ma, without tail policy operand. */ + __NORMAL_OP_MA = HAS_DEST_P | HAS_MASK_P | USE_ALL_TRUES_MASK_P | HAS_MERGE_P + | USE_VUNDEF_MERGE_P | MDEFAULT_POLICY_P, + /* For mask insn with tama. */ + __MASK_OP_TAMA = HAS_DEST_P | HAS_MASK_P | HAS_MERGE_P | USE_VUNDEF_MERGE_P + | TDEFAULT_POLICY_P | MDEFAULT_POLICY_P, + /* For mask insn with tamu. */ + __MASK_OP_TAMU + = HAS_DEST_P | HAS_MASK_P | HAS_MERGE_P | TDEFAULT_POLICY_P | MU_POLICY_P, + /* For mask insn with tuma. */ + __MASK_OP_TUMA = HAS_DEST_P | HAS_MASK_P | USE_ALL_TRUES_MASK_P | HAS_MERGE_P + | TU_POLICY_P | MDEFAULT_POLICY_P, + /* For mask insn with mu. */ + __MASK_OP_MU = HAS_DEST_P | HAS_MASK_P | HAS_MERGE_P | MU_POLICY_P, + /* For mask insn with ta, without mask policy operand. */ + __MASK_OP_TA = HAS_DEST_P | HAS_MASK_P | HAS_MERGE_P | USE_VUNDEF_MERGE_P + | TDEFAULT_POLICY_P, + + /* Nullary operator. e.g. vid.v */ + NULLARY_OP = __NORMAL_OP | NULLARY_OP_P, + + /* Unary operator. */ + UNARY_OP = __NORMAL_OP | UNARY_OP_P, + UNARY_OP_TAMA = __MASK_OP_TAMA | UNARY_OP_P, + UNARY_OP_TAMU = __MASK_OP_TAMU | UNARY_OP_P, + UNARY_OP_FRM_DYN = UNARY_OP | FRM_DYN_P, + + /* Binary operator. */ + BINARY_OP = __NORMAL_OP | BINARY_OP_P, + BINARY_OP_TAMA = __MASK_OP_TAMA | BINARY_OP_P, + BINARY_OP_TAMU = __MASK_OP_TAMU | BINARY_OP_P, + BINARY_OP_TUMA = __MASK_OP_TUMA | BINARY_OP_P, + BINARY_OP_FRM_DYN = BINARY_OP | FRM_DYN_P, + + /* Ternary operator. Always have real merge operand. */ + TERNARY_OP = HAS_DEST_P | HAS_MASK_P | USE_ALL_TRUES_MASK_P | HAS_MERGE_P + | TDEFAULT_POLICY_P | MDEFAULT_POLICY_P | TERNARY_OP_P, + TERNARY_OP_FRM_DYN = TERNARY_OP | FRM_DYN_P, + + /* For vwmacc, no merge operand. */ + WIDEN_TERNARY_OP = HAS_DEST_P | HAS_MASK_P | USE_ALL_TRUES_MASK_P + | TDEFAULT_POLICY_P | MDEFAULT_POLICY_P | TERNARY_OP_P, + WIDEN_TERNARY_OP_FRM_DYN = WIDEN_TERNARY_OP | FRM_DYN_P, + + /* For vmerge, no mask operand, no mask policy operand. */ + MERGE_OP = __NORMAL_OP_TA2 | TERNARY_OP_P, + + /* For vm, no tail policy operand. */ + COMPARE_OP = __NORMAL_OP_MA | TERNARY_OP_P, + COMPARE_OP_MU = __MASK_OP_MU | TERNARY_OP_P, + + /* For scatter insn: no dest operand, no merge operand, no tail and mask + policy operands. */ + SCATTER_OP_M = HAS_MASK_P | TERNARY_OP_P, + + /* For vcpop.m, no merge operand, no tail and mask policy operands. */ + CPOP_OP = HAS_DEST_P | HAS_MASK_P | USE_ALL_TRUES_MASK_P | UNARY_OP_P + | MASK_MODE_FROM_OP1_P, + + /* For mask instrunctions, no tail and mask policy operands. */ + UNARY_MASK_OP = HAS_DEST_P | HAS_MASK_P | USE_ALL_TRUES_MASK_P | HAS_MERGE_P + | USE_VUNDEF_MERGE_P | UNARY_OP_P, + BINARY_MASK_OP = HAS_DEST_P | HAS_MASK_P | USE_ALL_TRUES_MASK_P | HAS_MERGE_P + | USE_VUNDEF_MERGE_P | BINARY_OP_P, + + /* For vcompress.vm */ + COMPRESS_OP = __NORMAL_OP_TA2 | BINARY_OP_P, + /* has merge operand but use ta. */ + COMPRESS_OP_MERGE + = HAS_DEST_P | HAS_MERGE_P | TDEFAULT_POLICY_P | BINARY_OP_P, + + /* For vreduce, no mask policy operand. */ + REDUCE_OP = __NORMAL_OP_TA | BINARY_OP_P | MASK_MODE_FROM_OP1_P, + REDUCE_OP_FRM_DYN = REDUCE_OP | FRM_DYN_P | MASK_MODE_FROM_OP1_P, + REDUCE_OP_M_FRM_DYN + = __MASK_OP_TA | BINARY_OP_P | FRM_DYN_P | MASK_MODE_FROM_OP1_P, + + /* For vmv.s.x/vfmv.s.f. */ + SCALAR_MOVE_OP = HAS_DEST_P | HAS_MASK_P | USE_ONE_TRUE_MASK_P | HAS_MERGE_P + | USE_VUNDEF_MERGE_P | TDEFAULT_POLICY_P | MDEFAULT_POLICY_P + | UNARY_OP_P, +}; + enum vlmul_type { LMUL_1 = 0, @@ -238,20 +380,11 @@ bool const_vec_all_same_in_range_p (rtx, HOST_WIDE_INT, HOST_WIDE_INT); bool legitimize_move (rtx, rtx); void emit_vlmax_vsetvl (machine_mode, rtx); void emit_hard_vlmax_vsetvl (machine_mode, rtx); -void emit_vlmax_insn (unsigned, int, rtx *, rtx = 0); -void emit_vlmax_fp_insn (unsigned, int, rtx *, rtx = 0); -void emit_vlmax_ternary_insn (unsigned, int, rtx *, rtx = 0); -void emit_vlmax_fp_ternary_insn (unsigned, int, rtx *, rtx = 0); -void emit_nonvlmax_insn (unsigned, int, rtx *, rtx); -void emit_vlmax_slide_insn (unsigned, rtx *); -void emit_nonvlmax_slide_tu_insn (unsigned, rtx *, rtx); -void emit_vlmax_merge_insn (unsigned, int, rtx *); -void emit_vlmax_cmp_insn (unsigned, rtx *); -void emit_vlmax_cmp_mu_insn (unsigned, rtx *); -void emit_vlmax_masked_mu_insn (unsigned, int, rtx *); -void emit_scalar_move_insn (unsigned, rtx *, rtx = 0); -void emit_nonvlmax_integer_move_insn (unsigned, rtx *, rtx); +void emit_vlmax_insn (unsigned, unsigned, rtx *); +void emit_nonvlmax_insn (unsigned, unsigned, rtx *, rtx); +void emit_vlmax_insn_lra (unsigned, unsigned, rtx *, rtx); enum vlmul_type get_vlmul (machine_mode); +rtx get_vlmax_rtx (machine_mode); unsigned int get_ratio (machine_mode); unsigned int get_nf (machine_mode); machine_mode get_subpart_mode (machine_mode); @@ -273,6 +406,9 @@ enum mask_policy MASK_ANY = 2, }; +/* Return true if VALUE is agnostic or any policy. */ +#define IS_AGNOSTIC(VALUE) (bool) (VALUE & 0x1 || (VALUE >> 1 & 0x1)) + enum class reduction_type { UNORDERED, @@ -290,7 +426,8 @@ bool neg_simm5_p (rtx); bool has_vi_variant_p (rtx_code, rtx); void expand_vec_cmp (rtx, rtx_code, rtx, rtx); bool expand_vec_cmp_float (rtx, rtx_code, rtx, rtx, bool); -void expand_cond_len_binop (rtx_code, rtx *); +void expand_cond_len_unop (unsigned, rtx *); +void expand_cond_len_binop (unsigned, rtx *); void expand_reduction (rtx_code, rtx *, rtx, reduction_type = reduction_type::UNORDERED); #endif @@ -320,6 +457,9 @@ void expand_select_vl (rtx *); void expand_load_store (rtx *, bool); void expand_gather_scatter (rtx *, bool); void expand_cond_len_ternop (unsigned, rtx *); +void prepare_ternary_operands (rtx *, bool = false); +void expand_lanes_load_store (rtx *, bool); +void expand_fold_extract_last (rtx *); /* Rounding mode bitfield for fixed point VXRM. */ enum fixed_point_rounding_mode @@ -344,8 +484,12 @@ enum floating_point_rounding_mode FRM_DYN = 7, /* Aka 0b111. */ FRM_STATIC_MIN = FRM_RNE, FRM_STATIC_MAX = FRM_RMM, + FRM_DYN_EXIT = 8, + FRM_DYN_CALL = 9, + FRM_NONE = 10, }; +enum floating_point_rounding_mode get_frm_mode (rtx); opt_machine_mode vectorize_related_mode (machine_mode, scalar_mode, poly_uint64); unsigned int autovectorize_vector_modes (vec *, bool); diff --git a/gcc/config/riscv/riscv-shorten-memrefs.cc b/gcc/config/riscv/riscv-shorten-memrefs.cc index 8f10d24ec39a..6f2b973278eb 100644 --- a/gcc/config/riscv/riscv-shorten-memrefs.cc +++ b/gcc/config/riscv/riscv-shorten-memrefs.cc @@ -65,7 +65,8 @@ public: /* opt_pass methods: */ virtual bool gate (function *) { - return TARGET_RVC && riscv_mshorten_memrefs && optimize > 0; + return (TARGET_RVC || TARGET_ZCA) + && riscv_mshorten_memrefs && optimize > 0; } virtual unsigned int execute (function *); diff --git a/gcc/config/riscv/riscv-v.cc b/gcc/config/riscv/riscv-v.cc index 278452b9e053..fc833b0df49c 100644 --- a/gcc/config/riscv/riscv-v.cc +++ b/gcc/config/riscv/riscv-v.cc @@ -70,50 +70,64 @@ const_vlmax_p (machine_mode mode) template class insn_expander { public: - insn_expander () - : m_opno (0), m_op_num (0), m_has_dest_p (false), - m_fully_unmasked_p (false), m_use_real_merge_p (false), - m_needs_avl_p (false), m_vlmax_p (false), m_has_tail_policy_p (false), - m_has_mask_policy_p (false), m_has_fp_rounding_mode_p (false), - m_tail_policy (TAIL_ANY), m_mask_policy (MASK_ANY), - m_fp_rounding_mode (FRM_DYN), - m_dest_mode (VOIDmode), m_mask_mode (VOIDmode), - m_vl_op (NULL_RTX) - {} + insn_expander () = delete; - /* Initializer for various configurations. */ - insn_expander (int op_num, bool has_dest_p, bool use_all_trues_mask_p, - bool use_real_merge_p, bool needs_avl_p, bool vlmax_p, - machine_mode dest_mode, machine_mode mask_mode) - : m_opno (0), m_op_num (op_num), m_has_dest_p (has_dest_p), - m_fully_unmasked_p (use_all_trues_mask_p), - m_use_real_merge_p (use_real_merge_p), m_needs_avl_p (needs_avl_p), - m_vlmax_p (vlmax_p), m_has_tail_policy_p (false), - m_has_mask_policy_p (false), m_has_fp_rounding_mode_p (false), - m_tail_policy (TAIL_ANY), m_mask_policy (MASK_ANY), - m_fp_rounding_mode (FRM_DYN), - m_dest_mode (dest_mode), - m_mask_mode (mask_mode), m_vl_op (NULL_RTX) - {} + insn_expander (unsigned insn_flags, bool vlmax_p, machine_mode dest_mode, + machine_mode mask_mode) + : m_insn_flags (insn_flags), m_opno (0), m_vlmax_p (vlmax_p), + m_dest_mode (dest_mode), m_mask_mode (mask_mode), m_vl_op (NULL_RTX) + { + check_insn_flags (); + } - void set_policy (enum tail_policy ta) + void check_insn_flags () const { - m_has_tail_policy_p = true; - m_tail_policy = ta; - } - void set_policy (enum mask_policy ma) - { - m_has_mask_policy_p = true; - m_mask_policy = ma; + if (m_insn_flags & USE_ONE_TRUE_MASK_P) + /* USE_ONE_TRUE_MASK_P is dependent on HAS_MASK_P. */ + gcc_assert ((m_insn_flags & HAS_MASK_P)); + + if (m_insn_flags & USE_ALL_TRUES_MASK_P) + /* USE_ALL_TRUES_MASK_P is dependent on HAS_MASK_P. */ + gcc_assert ((m_insn_flags & HAS_MASK_P)); + + /* USE_ONE_TRUE_MASK_P and USE_ALL_TRUES_MASK_P are mutually exclusive. */ + gcc_assert (!((m_insn_flags & USE_ONE_TRUE_MASK_P) + && (m_insn_flags & USE_ALL_TRUES_MASK_P))); + + if (m_insn_flags & USE_VUNDEF_MERGE_P) + /* USE_VUNDEF_MERGE_P is dependent on HAS_MERGE_P. */ + gcc_assert ((m_insn_flags & HAS_MERGE_P)); + + /* TU_POLICY_P and TDEFAULT_POLICY_P are mutually exclusive. */ + gcc_assert ( + !((m_insn_flags & TU_POLICY_P) && (m_insn_flags & TDEFAULT_POLICY_P))); + + /* MU_POLICY_P and MDEFAULT_POLICY_P are mutually exclusive. */ + gcc_assert ( + !((m_insn_flags & MU_POLICY_P) && (m_insn_flags & MDEFAULT_POLICY_P))); + + /* NULLARY_OP_P, UNARY_OP_P, BINARY_OP_P, TERNARY_OP_P are mutually + exclusive. */ + gcc_assert ( + !((m_insn_flags & NULLARY_OP_P) + && ((m_insn_flags & UNARY_OP_P) || (m_insn_flags & BINARY_OP_P) + || (m_insn_flags & TERNARY_OP_P)))); + gcc_assert ( + !((m_insn_flags & UNARY_OP_P) + && ((m_insn_flags & NULLARY_OP_P) || (m_insn_flags & BINARY_OP_P) + || (m_insn_flags & TERNARY_OP_P)))); + gcc_assert ( + !((m_insn_flags & BINARY_OP_P) + && ((m_insn_flags & NULLARY_OP_P) || (m_insn_flags & UNARY_OP_P) + || (m_insn_flags & TERNARY_OP_P)))); + gcc_assert ( + !((m_insn_flags & TERNARY_OP_P) + && ((m_insn_flags & NULLARY_OP_P) || (m_insn_flags & UNARY_OP_P) + || (m_insn_flags & BINARY_OP_P)))); } + void set_vl (rtx vl) { m_vl_op = vl; } - void set_rounding_mode (enum floating_point_rounding_mode mode) - { - m_has_fp_rounding_mode_p = true; - m_fp_rounding_mode = mode; - } - void add_output_operand (rtx x, machine_mode mode) { create_output_operand (&m_ops[m_opno++], x, mode); @@ -134,14 +148,25 @@ public: } void add_policy_operand () { - if (m_has_tail_policy_p) + if (m_insn_flags & TU_POLICY_P) { - rtx tail_policy_rtx = gen_int_mode (m_tail_policy, Pmode); + rtx tail_policy_rtx = gen_int_mode (TAIL_UNDISTURBED, Pmode); add_input_operand (tail_policy_rtx, Pmode); } - if (m_has_mask_policy_p) + else if (m_insn_flags & TDEFAULT_POLICY_P) { - rtx mask_policy_rtx = gen_int_mode (m_mask_policy, Pmode); + rtx tail_policy_rtx = gen_int_mode (get_prefer_tail_policy (), Pmode); + add_input_operand (tail_policy_rtx, Pmode); + } + + if (m_insn_flags & MU_POLICY_P) + { + rtx mask_policy_rtx = gen_int_mode (MASK_UNDISTURBED, Pmode); + add_input_operand (mask_policy_rtx, Pmode); + } + else if (m_insn_flags & MDEFAULT_POLICY_P) + { + rtx mask_policy_rtx = gen_int_mode (get_prefer_mask_policy (), Pmode); add_input_operand (mask_policy_rtx, Pmode); } } @@ -150,39 +175,69 @@ public: add_input_operand (gen_int_mode (type, Pmode), Pmode); } - void add_rounding_mode_operand () + void + add_rounding_mode_operand (enum floating_point_rounding_mode rounding_mode) { - if (m_has_fp_rounding_mode_p) - { - rtx frm_rtx = gen_int_mode (m_fp_rounding_mode, Pmode); - add_input_operand (frm_rtx, Pmode); - } + rtx frm_rtx = gen_int_mode (rounding_mode, Pmode); + add_input_operand (frm_rtx, Pmode); + } + + void add_oprand (rtx *ops, int opno) + { + } void emit_insn (enum insn_code icode, rtx *ops) { int opno = 0; + int num_ops; /* It's true if any operand is memory operand. */ bool any_mem_p = false; - /* It's true if all operands are mask operand. */ - bool all_mask_p = true; - if (m_has_dest_p) + + /* Add dest operand. */ + if (m_insn_flags & HAS_DEST_P) { any_mem_p |= MEM_P (ops[opno]); - all_mask_p &= GET_MODE_CLASS (GET_MODE (ops[opno])) == MODE_VECTOR_BOOL; add_output_operand (ops[opno++], m_dest_mode); } - if (m_fully_unmasked_p) + /* Add mask operand. */ + if (m_insn_flags & USE_ONE_TRUE_MASK_P) + add_input_operand (gen_scalar_move_mask (m_mask_mode), m_mask_mode); + else if (m_insn_flags & USE_ALL_TRUES_MASK_P) add_all_one_mask_operand (); + else if (m_insn_flags & HAS_MASK_P) + { + machine_mode mode = insn_data[(int) icode].operand[m_opno].mode; + gcc_assert (mode != VOIDmode); + add_input_operand (ops[opno++], mode); + } - if (!m_use_real_merge_p) + /* Add merge operand. */ + if (m_insn_flags & USE_VUNDEF_MERGE_P) add_vundef_operand (); + else if (m_insn_flags & HAS_MERGE_P) + { + machine_mode mode = insn_data[(int) icode].operand[m_opno].mode; + gcc_assert (mode != VOIDmode); + add_input_operand (ops[opno++], mode); + } - for (; opno < m_op_num; opno++) + if (m_insn_flags & NULLARY_OP_P) + num_ops = 0; + else if (m_insn_flags & UNARY_OP_P) + num_ops = 1; + else if (m_insn_flags & BINARY_OP_P) + num_ops = 2; + else if (m_insn_flags & TERNARY_OP_P) + num_ops = 3; + else + gcc_unreachable (); + + /* Add the remain operands. */ + for (; num_ops; num_ops--, opno++) { any_mem_p |= MEM_P (ops[opno]); - all_mask_p &= GET_MODE_CLASS (GET_MODE (ops[opno])) == MODE_VECTOR_BOOL; machine_mode mode = insn_data[(int) icode].operand[m_opno].mode; /* 'create_input_operand doesn't allow VOIDmode. According to vector.md, we may have some patterns that do not have @@ -190,48 +245,59 @@ public: always Pmode. */ if (mode == VOIDmode) mode = Pmode; + else + /* Early assertion ensures same mode since maybe_legitimize_operand + will check this. */ + gcc_assert (GET_MODE (ops[opno]) == VOIDmode + || GET_MODE (ops[opno]) == mode); + add_input_operand (ops[opno], mode); } - if (m_needs_avl_p) + /* Add vl operand. */ + rtx len = m_vl_op; + machine_mode mode = VECTOR_MODE_P (m_dest_mode) ? m_dest_mode : m_mask_mode; + if (m_vlmax_p) { - rtx len = m_vl_op; - if (m_vlmax_p) + if (riscv_v_ext_vls_mode_p (mode)) { - if (riscv_v_ext_vls_mode_p (m_dest_mode)) - { - /* VLS modes always set VSETVL by - "vsetvl zero, rs1/imm". */ - poly_uint64 nunits = GET_MODE_NUNITS (m_dest_mode); - len = gen_int_mode (nunits, Pmode); - if (!satisfies_constraint_K (len)) - len = force_reg (Pmode, len); - m_vlmax_p = false; /* It has became NONVLMAX now. */ - } - else if (const_vlmax_p (m_dest_mode)) - { - /* Optimize VLS-VLMAX code gen, we can use vsetivli instead of - the vsetvli to obtain the value of vlmax. */ - poly_uint64 nunits = GET_MODE_NUNITS (m_dest_mode); - len = gen_int_mode (nunits, Pmode); - m_vlmax_p = false; /* It has became NONVLMAX now. */ - } - else if (can_create_pseudo_p ()) - { - len = gen_reg_rtx (Pmode); - emit_vlmax_vsetvl (m_dest_mode, len); - } + /* VLS modes always set VSETVL by + "vsetvl zero, rs1/imm". */ + poly_uint64 nunits = GET_MODE_NUNITS (mode); + len = gen_int_mode (nunits, Pmode); + if (!satisfies_constraint_K (len)) + len = force_reg (Pmode, len); + m_vlmax_p = false; + } + else if (const_vlmax_p (mode)) + { + /* Optimize VLS-VLMAX code gen, we can use vsetivli instead of + the vsetvli to obtain the value of vlmax. */ + poly_uint64 nunits = GET_MODE_NUNITS (mode); + len = gen_int_mode (nunits, Pmode); + m_vlmax_p = false; + } + else if (can_create_pseudo_p ()) + { + len = gen_reg_rtx (Pmode); + emit_vlmax_vsetvl (mode, len); } - add_input_operand (len, Pmode); } - if (!all_mask_p) - add_policy_operand (); - if (m_needs_avl_p) - add_avl_type_operand (m_vlmax_p ? avl_type::VLMAX : avl_type::NONVLMAX); + gcc_assert (len != NULL_RTX); + add_input_operand (len, Pmode); - add_rounding_mode_operand (); + /* Add tail and mask policy operands. */ + add_policy_operand (); + /* Add avl_type operand. */ + add_avl_type_operand (m_vlmax_p ? avl_type::VLMAX : avl_type::NONVLMAX); + + /* Add rounding mode operand. */ + if (m_insn_flags & FRM_DYN_P) + add_rounding_mode_operand (FRM_DYN); + + gcc_assert (insn_data[(int) icode].n_operands == m_opno); expand (icode, any_mem_p); } @@ -247,32 +313,67 @@ public: } private: + int m_insn_flags; int m_opno; - int m_op_num; - /* It't true when the pattern has a dest operand. Most of the patterns have - dest operand wheras some patterns like STOREs does not have dest operand. - For example, according to vector.md. We can see indexed loads/stores do - not have dest operand. - */ - bool m_has_dest_p; - /* It't true if the pattern uses all trues mask operand. */ - bool m_fully_unmasked_p; - /* It's true if the pattern uses real merge operand. */ - bool m_use_real_merge_p; - bool m_needs_avl_p; bool m_vlmax_p; - bool m_has_tail_policy_p; - bool m_has_mask_policy_p; - bool m_has_fp_rounding_mode_p; - enum tail_policy m_tail_policy; - enum mask_policy m_mask_policy; - enum floating_point_rounding_mode m_fp_rounding_mode; machine_mode m_dest_mode; machine_mode m_mask_mode; rtx m_vl_op; expand_operand m_ops[MAX_OPERANDS]; }; +/* Return the mask mode based on insn_flags */ +static machine_mode +get_mask_mode_from_insn_flags (unsigned insn_flags, rtx *ops) +{ + machine_mode mask_mode; + if (insn_flags & MASK_MODE_FROM_OP1_P) + mask_mode = get_mask_mode (GET_MODE (ops[1])); + else + mask_mode = get_mask_mode (GET_MODE (ops[0])); + return mask_mode; +} + +/* Emit RVV insn which vl is VLMAX. + This function can only be used before LRA pass or + for VLS_AVL_IMM modes. */ +void +emit_vlmax_insn (unsigned icode, unsigned insn_flags, rtx *ops) +{ + machine_mode dest_mode = GET_MODE (ops[0]); + machine_mode mask_mode = get_mask_mode_from_insn_flags (insn_flags, ops); + + insn_expander e (insn_flags, true, dest_mode, + mask_mode); + e.emit_insn ((enum insn_code) icode, ops); +} + +/* Emit RVV insn which vl is VL. */ +void +emit_nonvlmax_insn (unsigned icode, unsigned insn_flags, rtx *ops, rtx vl) +{ + machine_mode dest_mode = GET_MODE (ops[0]); + machine_mode mask_mode = get_mask_mode_from_insn_flags (insn_flags, ops); + insn_expander e (insn_flags, false, dest_mode, + mask_mode); + e.set_vl (vl); + e.emit_insn ((enum insn_code) icode, ops); +} + +/* Emit RVV insn which vl is VL but the AVL_TYPE insn attr is VLMAX. + This function used after LRA pass that cann't create pseudo register. */ +void +emit_vlmax_insn_lra (unsigned icode, unsigned insn_flags, rtx *ops, rtx vl) +{ + gcc_assert (!can_create_pseudo_p ()); + + machine_mode dest_mode = GET_MODE (ops[0]); + machine_mode mask_mode = get_mask_mode_from_insn_flags (insn_flags, ops); + insn_expander e (insn_flags, true, dest_mode, + mask_mode); + e.set_vl (vl); + e.emit_insn ((enum insn_code) icode, ops); +} class rvv_builder : public rtx_vector_builder { @@ -670,404 +771,6 @@ autovec_use_vlmax_p (void) For that case we also allow to set the avl_type to VLMAX. */ -/* This function emits a {VLMAX, TAIL_ANY, MASK_ANY} vsetvli followed by the - * actual operation. */ -void -emit_vlmax_insn (unsigned icode, int op_num, rtx *ops, rtx vl) -{ - machine_mode dest_mode = GET_MODE (ops[0]); - machine_mode mask_mode = get_mask_mode (dest_mode); - insn_expander e (op_num, - /* HAS_DEST_P */ true, - /* FULLY_UNMASKED_P */ true, - /* USE_REAL_MERGE_P */ false, - /* HAS_AVL_P */ true, - /* VLMAX_P */ true, - dest_mode, - mask_mode); - - e.set_policy (TAIL_ANY); - e.set_policy (MASK_ANY); - /* According to LRA mov pattern in vector.md, we have a clobber operand - to be used ad VL operand. */ - e.set_vl (vl); - e.emit_insn ((enum insn_code) icode, ops); -} - -void -emit_vlmax_fp_insn (unsigned icode, int op_num, rtx *ops, rtx vl) -{ - machine_mode dest_mode = GET_MODE (ops[0]); - machine_mode mask_mode = get_mask_mode (dest_mode); - insn_expander e (op_num, - /* HAS_DEST_P */ true, - /* FULLY_UNMASKED_P */ true, - /* USE_REAL_MERGE_P */ false, - /* HAS_AVL_P */ true, - /* VLMAX_P */ true, - dest_mode, - mask_mode); - - e.set_policy (TAIL_ANY); - e.set_policy (MASK_ANY); - e.set_rounding_mode (FRM_DYN); - e.set_vl (vl); - e.emit_insn ((enum insn_code) icode, ops); -} - -/* This function emits a {VLMAX, TAIL_ANY, MASK_ANY} vsetvli followed by the - * ternary operation which always has a real merge operand. */ -void -emit_vlmax_ternary_insn (unsigned icode, int op_num, rtx *ops, rtx vl) -{ - machine_mode dest_mode = GET_MODE (ops[0]); - machine_mode mask_mode = get_mask_mode (dest_mode); - insn_expander e (/*OP_NUM*/ op_num, - /*HAS_DEST_P*/ true, - /*FULLY_UNMASKED_P*/ true, - /*USE_REAL_MERGE_P*/ true, - /*HAS_AVL_P*/ true, - /*VLMAX_P*/ true, - /*DEST_MODE*/ dest_mode, - /*MASK_MODE*/ mask_mode); - e.set_policy (TAIL_ANY); - e.set_policy (MASK_ANY); - e.set_vl (vl); - e.emit_insn ((enum insn_code) icode, ops); -} - -/* This function emits a {VLMAX, TAIL_ANY, MASK_ANY} vsetvli followed by the - * ternary operation which always has a real merge operand. */ -void -emit_vlmax_fp_ternary_insn (unsigned icode, int op_num, rtx *ops, rtx vl) -{ - machine_mode dest_mode = GET_MODE (ops[0]); - machine_mode mask_mode = get_mask_mode (dest_mode); - insn_expander e (/*OP_NUM*/ op_num, - /*HAS_DEST_P*/ true, - /*FULLY_UNMASKED_P*/ true, - /*USE_REAL_MERGE_P*/ true, - /*HAS_AVL_P*/ true, - /*VLMAX_P*/ true, - /*DEST_MODE*/ dest_mode, - /*MASK_MODE*/ mask_mode); - e.set_policy (TAIL_ANY); - e.set_policy (MASK_ANY); - e.set_rounding_mode (FRM_DYN); - e.set_vl (vl); - e.emit_insn ((enum insn_code) icode, ops); -} - -/* This function emits a {NONVLMAX, TAIL_UNDISTURBED, MASK_ANY} vsetvli followed - * by the ternary operation which always has a real merge operand. */ -static void -emit_nonvlmax_fp_ternary_tu_insn (unsigned icode, int op_num, rtx *ops, rtx vl) -{ - machine_mode dest_mode = GET_MODE (ops[0]); - machine_mode mask_mode = get_mask_mode (dest_mode); - insn_expander e (/*OP_NUM*/ op_num, - /*HAS_DEST_P*/ true, - /*FULLY_UNMASKED_P*/ false, - /*USE_REAL_MERGE_P*/ true, - /*HAS_AVL_P*/ true, - /*VLMAX_P*/ false, - /*DEST_MODE*/ dest_mode, - /*MASK_MODE*/ mask_mode); - e.set_policy (TAIL_UNDISTURBED); - e.set_policy (MASK_ANY); - e.set_rounding_mode (FRM_DYN); - e.set_vl (vl); - e.emit_insn ((enum insn_code) icode, ops); -} - -/* This function emits a {NONVLMAX, TAIL_ANY, MASK_ANY} vsetvli followed by the - * actual operation. */ -void -emit_nonvlmax_insn (unsigned icode, int op_num, rtx *ops, rtx avl) -{ - machine_mode dest_mode = GET_MODE (ops[0]); - machine_mode mask_mode = get_mask_mode (dest_mode); - insn_expander e (op_num, - /* HAS_DEST_P */ true, - /* FULLY_UNMASKED_P */ true, - /* USE_REAL_MERGE_P */ false, - /* HAS_AVL_P */ true, - /* VLMAX_P */ false, - dest_mode, - mask_mode); - - e.set_policy (TAIL_ANY); - e.set_policy (MASK_ANY); - e.set_vl (avl); - e.emit_insn ((enum insn_code) icode, ops); -} - -/* This function emits a {NONVLMAX, TAIL_UNDISTURBED, MASK_ANY} vsetvli - followed by a vslide insn (with real merge operand). */ -void -emit_vlmax_slide_insn (unsigned icode, rtx *ops) -{ - machine_mode dest_mode = GET_MODE (ops[0]); - machine_mode mask_mode = get_mask_mode (dest_mode); - insn_expander e (RVV_SLIDE_OP, - /* HAS_DEST_P */ true, - /* FULLY_UNMASKED_P */ true, - /* USE_REAL_MERGE_P */ true, - /* HAS_AVL_P */ true, - /* VLMAX_P */ true, - dest_mode, - mask_mode); - - e.set_policy (TAIL_ANY); - e.set_policy (MASK_ANY); - - e.emit_insn ((enum insn_code) icode, ops); -} - -/* This function emits a {NONVLMAX, TAIL_UNDISTURBED, MASK_ANY} vsetvli - followed by a vslide insn (with real merge operand). */ -void -emit_nonvlmax_slide_tu_insn (unsigned icode, rtx *ops, rtx avl) -{ - machine_mode dest_mode = GET_MODE (ops[0]); - machine_mode mask_mode = get_mask_mode (dest_mode); - insn_expander e (RVV_SLIDE_OP, - /* HAS_DEST_P */ true, - /* FULLY_UNMASKED_P */ true, - /* USE_REAL_MERGE_P */ true, - /* HAS_AVL_P */ true, - /* VLMAX_P */ false, - dest_mode, - mask_mode); - - e.set_policy (TAIL_UNDISTURBED); - e.set_policy (MASK_ANY); - e.set_vl (avl); - - e.emit_insn ((enum insn_code) icode, ops); -} - - -/* This function emits merge instruction. */ -void -emit_vlmax_merge_insn (unsigned icode, int op_num, rtx *ops) -{ - machine_mode dest_mode = GET_MODE (ops[0]); - machine_mode mask_mode = get_mask_mode (dest_mode); - insn_expander e (op_num, - /* HAS_DEST_P */ true, - /* FULLY_UNMASKED_P */ false, - /* USE_REAL_MERGE_P */ false, - /* HAS_AVL_P */ true, - /* VLMAX_P */ true, - dest_mode, - mask_mode); - - e.set_policy (TAIL_ANY); - e.emit_insn ((enum insn_code) icode, ops); -} - -/* This function emits cmp instruction. */ -void -emit_vlmax_cmp_insn (unsigned icode, rtx *ops) -{ - machine_mode mode = GET_MODE (ops[0]); - insn_expander e (RVV_CMP_OP, - /* HAS_DEST_P */ true, - /* FULLY_UNMASKED_P */ true, - /* USE_REAL_MERGE_P */ false, - /* HAS_AVL_P */ true, - /* VLMAX_P */ true, - mode, - mode); - - e.set_policy (MASK_ANY); - e.emit_insn ((enum insn_code) icode, ops); -} - -/* This function emits cmp with MU instruction. */ -void -emit_vlmax_cmp_mu_insn (unsigned icode, rtx *ops) -{ - machine_mode mode = GET_MODE (ops[0]); - insn_expander e (RVV_CMP_MU_OP, - /* HAS_DEST_P */ true, - /* FULLY_UNMASKED_P */ false, - /* USE_REAL_MERGE_P */ true, - /* HAS_AVL_P */ true, - /* VLMAX_P */ true, - mode, - mode); - - e.set_policy (MASK_UNDISTURBED); - e.emit_insn ((enum insn_code) icode, ops); -} - -/* This function emits a masked instruction. */ -static void -emit_vlmax_masked_insn (unsigned icode, int op_num, rtx *ops) -{ - machine_mode dest_mode = GET_MODE (ops[0]); - machine_mode mask_mode = get_mask_mode (dest_mode); - insn_expander e (/*OP_NUM*/ op_num, - /*HAS_DEST_P*/ true, - /*FULLY_UNMASKED_P*/ false, - /*USE_REAL_MERGE_P*/ true, - /*HAS_AVL_P*/ true, - /*VLMAX_P*/ true, dest_mode, - mask_mode); - e.set_policy (TAIL_ANY); - e.set_policy (MASK_ANY); - e.emit_insn ((enum insn_code) icode, ops); -} - -/* This function emits a masked instruction. */ -static void -emit_nonvlmax_masked_insn (unsigned icode, int op_num, rtx *ops, rtx avl) -{ - machine_mode dest_mode = GET_MODE (ops[0]); - machine_mode mask_mode = get_mask_mode (dest_mode); - insn_expander e (/*OP_NUM*/ op_num, - /*HAS_DEST_P*/ true, - /*FULLY_UNMASKED_P*/ false, - /*USE_REAL_MERGE_P*/ true, - /*HAS_AVL_P*/ true, - /*VLMAX_P*/ false, dest_mode, - mask_mode); - e.set_policy (TAIL_ANY); - e.set_policy (MASK_ANY); - e.set_vl (avl); - e.emit_insn ((enum insn_code) icode, ops); -} - -/* This function emits a VLMAX masked store instruction. */ -static void -emit_vlmax_masked_store_insn (unsigned icode, int op_num, rtx *ops) -{ - machine_mode dest_mode = GET_MODE (ops[0]); - machine_mode mask_mode = get_mask_mode (dest_mode); - insn_expander e (/*OP_NUM*/ op_num, - /*HAS_DEST_P*/ false, - /*FULLY_UNMASKED_P*/ false, - /*USE_REAL_MERGE_P*/ true, - /*HAS_AVL_P*/ true, - /*VLMAX_P*/ true, dest_mode, - mask_mode); - e.emit_insn ((enum insn_code) icode, ops); -} - -/* This function emits a non-VLMAX masked store instruction. */ -static void -emit_nonvlmax_masked_store_insn (unsigned icode, int op_num, rtx *ops, rtx avl) -{ - machine_mode dest_mode = GET_MODE (ops[0]); - machine_mode mask_mode = get_mask_mode (dest_mode); - insn_expander e (/*OP_NUM*/ op_num, - /*HAS_DEST_P*/ false, - /*FULLY_UNMASKED_P*/ false, - /*USE_REAL_MERGE_P*/ true, - /*HAS_AVL_P*/ true, - /*VLMAX_P*/ false, dest_mode, - mask_mode); - e.set_vl (avl); - e.emit_insn ((enum insn_code) icode, ops); -} - -/* This function emits a masked instruction. */ -void -emit_vlmax_masked_mu_insn (unsigned icode, int op_num, rtx *ops) -{ - machine_mode dest_mode = GET_MODE (ops[0]); - machine_mode mask_mode = get_mask_mode (dest_mode); - insn_expander e (/*OP_NUM*/ op_num, - /*HAS_DEST_P*/ true, - /*FULLY_UNMASKED_P*/ false, - /*USE_REAL_MERGE_P*/ true, - /*HAS_AVL_P*/ true, - /*VLMAX_P*/ true, dest_mode, - mask_mode); - e.set_policy (TAIL_ANY); - e.set_policy (MASK_UNDISTURBED); - e.emit_insn ((enum insn_code) icode, ops); -} - -/* This function emits a TU instruction. */ -static void -emit_nonvlmax_tu_insn (unsigned icode, int op_num, rtx *ops, rtx avl) -{ - machine_mode dest_mode = GET_MODE (ops[0]); - machine_mode mask_mode = get_mask_mode (dest_mode); - insn_expander e (/*OP_NUM*/ op_num, - /*HAS_DEST_P*/ true, - /*FULLY_UNMASKED_P*/ false, - /*USE_REAL_MERGE_P*/ true, - /*HAS_AVL_P*/ true, - /*VLMAX_P*/ false, dest_mode, - mask_mode); - e.set_policy (TAIL_UNDISTURBED); - e.set_policy (MASK_ANY); - e.set_vl (avl); - e.emit_insn ((enum insn_code) icode, ops); -} - -/* This function emits a TU instruction. */ -static void -emit_nonvlmax_fp_tu_insn (unsigned icode, int op_num, rtx *ops, rtx avl) -{ - machine_mode dest_mode = GET_MODE (ops[0]); - machine_mode mask_mode = get_mask_mode (dest_mode); - insn_expander e (/*OP_NUM*/ op_num, - /*HAS_DEST_P*/ true, - /*FULLY_UNMASKED_P*/ false, - /*USE_REAL_MERGE_P*/ true, - /*HAS_AVL_P*/ true, - /*VLMAX_P*/ false, dest_mode, - mask_mode); - e.set_policy (TAIL_UNDISTURBED); - e.set_policy (MASK_ANY); - e.set_rounding_mode (FRM_DYN); - e.set_vl (avl); - e.emit_insn ((enum insn_code) icode, ops); -} - -/* Emit vmv.s.x instruction. */ - -void -emit_scalar_move_insn (unsigned icode, rtx *ops, rtx len) -{ - machine_mode dest_mode = GET_MODE (ops[0]); - machine_mode mask_mode = get_mask_mode (dest_mode); - insn_expander e (RVV_SCALAR_MOV_OP, - /* HAS_DEST_P */ true, - /* FULLY_UNMASKED_P */ false, - /* USE_REAL_MERGE_P */ true, - /* HAS_AVL_P */ true, - /* VLMAX_P */ false, - dest_mode, - mask_mode); - - e.set_policy (TAIL_ANY); - e.set_policy (MASK_ANY); - e.set_vl (len ? len : CONST1_RTX (Pmode)); - e.emit_insn ((enum insn_code) icode, ops); -} - -/* Emit vmv.v.x instruction with vlmax. */ - -static void -emit_vlmax_integer_move_insn (unsigned icode, rtx *ops, rtx vl) -{ - emit_vlmax_insn (icode, riscv_vector::RVV_UNOP, ops, vl); -} - -/* Emit vmv.v.x instruction with nonvlmax. */ - -void -emit_nonvlmax_integer_move_insn (unsigned icode, rtx *ops, rtx avl) -{ - emit_nonvlmax_insn (icode, riscv_vector::RVV_UNOP, ops, avl); -} - /* This function emits VLMAX vrgather instruction. Emit vrgather.vx/vi when sel is a const duplicate vector. Otherwise, emit vrgather.vv. */ static void @@ -1087,7 +790,7 @@ emit_vlmax_gather_insn (rtx target, rtx op, rtx sel) else icode = code_for_pred_gather (data_mode); rtx ops[] = {target, op, sel}; - emit_vlmax_insn (icode, RVV_BINOP, ops); + emit_vlmax_insn (icode, BINARY_OP, ops); } static void @@ -1107,7 +810,7 @@ emit_vlmax_masked_gather_mu_insn (rtx target, rtx op, rtx sel, rtx mask) else icode = code_for_pred_gather (data_mode); rtx ops[] = {target, mask, target, op, sel}; - emit_vlmax_masked_mu_insn (icode, RVV_BINOP_MU, ops); + emit_vlmax_insn (icode, BINARY_OP_TAMU, ops); } /* According to RVV ISA spec (16.5.1. Synthesizing vdecompress): @@ -1146,86 +849,11 @@ emit_vlmax_decompress_insn (rtx target, rtx op0, rtx op1, rtx mask) rtx sel = gen_reg_rtx (sel_mode); rtx iota_ops[] = {sel, mask}; - emit_vlmax_insn (code_for_pred_iota (sel_mode), RVV_UNOP, iota_ops); + emit_vlmax_insn (code_for_pred_iota (sel_mode), UNARY_OP, iota_ops); emit_vlmax_gather_insn (target, op0, sel); emit_vlmax_masked_gather_mu_insn (target, op1, sel, mask); } -/* Emit compress instruction. */ -static void -emit_vlmax_compress_insn (unsigned icode, rtx *ops) -{ - machine_mode dest_mode = GET_MODE (ops[0]); - machine_mode mask_mode = get_mask_mode (dest_mode); - insn_expander e (RVV_COMPRESS_OP, - /* HAS_DEST_P */ true, - /* FULLY_UNMASKED_P */ false, - /* USE_REAL_MERGE_P */ true, - /* HAS_AVL_P */ true, - /* VLMAX_P */ true, dest_mode, - mask_mode); - - e.set_policy (TAIL_ANY); - e.emit_insn ((enum insn_code) icode, ops); -} - -/* Emit reduction instruction. */ -static void -emit_vlmax_reduction_insn (unsigned icode, int op_num, rtx *ops) -{ - machine_mode dest_mode = GET_MODE (ops[0]); - machine_mode mask_mode = get_mask_mode (GET_MODE (ops[1])); - insn_expander e (op_num, - /* HAS_DEST_P */ true, - /* FULLY_UNMASKED_P */ true, - /* USE_REAL_MERGE_P */ false, - /* HAS_AVL_P */ true, - /* VLMAX_P */ true, dest_mode, - mask_mode); - - e.set_policy (TAIL_ANY); - e.emit_insn ((enum insn_code) icode, ops); -} - -/* Emit reduction instruction. */ -static void -emit_vlmax_fp_reduction_insn (unsigned icode, int op_num, rtx *ops) -{ - machine_mode dest_mode = GET_MODE (ops[0]); - machine_mode mask_mode = get_mask_mode (GET_MODE (ops[1])); - insn_expander e (op_num, - /* HAS_DEST_P */ true, - /* FULLY_UNMASKED_P */ true, - /* USE_REAL_MERGE_P */ false, - /* HAS_AVL_P */ true, - /* VLMAX_P */ true, dest_mode, - mask_mode); - - e.set_policy (TAIL_ANY); - e.set_rounding_mode (FRM_DYN); - e.emit_insn ((enum insn_code) icode, ops); -} - -/* Emit reduction instruction. */ -static void -emit_nonvlmax_fp_reduction_insn (unsigned icode, int op_num, rtx *ops, rtx vl) -{ - machine_mode dest_mode = GET_MODE (ops[0]); - machine_mode mask_mode = get_mask_mode (GET_MODE (ops[1])); - insn_expander e (op_num, - /* HAS_DEST_P */ true, - /* FULLY_UNMASKED_P */ false, - /* USE_REAL_MERGE_P */ true, - /* HAS_AVL_P */ true, - /* VLMAX_P */ false, dest_mode, - mask_mode); - - e.set_policy (TAIL_ANY); - e.set_rounding_mode (FRM_DYN); - e.set_vl (vl); - e.emit_insn ((enum insn_code) icode, ops); -} - /* Emit merge instruction. */ static machine_mode @@ -1250,23 +878,19 @@ expand_vec_series (rtx dest, rtx base, rtx step) machine_mode mode = GET_MODE (dest); poly_int64 nunits_m1 = GET_MODE_NUNITS (mode) - 1; poly_int64 value; + rtx result = register_operand (dest, mode) ? dest : gen_reg_rtx (mode); /* VECT_IV = BASE + I * STEP. */ /* Step 1: Generate I = { 0, 1, 2, ... } by vid.v. */ rtx vid = gen_reg_rtx (mode); rtx op[] = {vid}; - emit_vlmax_insn (code_for_pred_series (mode), RVV_MISC_OP, op); + emit_vlmax_insn (code_for_pred_series (mode), NULLARY_OP, op); - /* Step 2: Generate I * STEP. - - STEP is 1, we don't emit any instructions. - - STEP is power of 2, we use vsll.vi/vsll.vx. - - STEP is non-power of 2, we use vmul.vx. */ rtx step_adj; - if (rtx_equal_p (step, const1_rtx)) - step_adj = vid; - else if (rtx_equal_p (step, constm1_rtx) && poly_int_rtx_p (base, &value) - && known_eq (nunits_m1, value)) + if (rtx_equal_p (step, constm1_rtx) + && poly_int_rtx_p (base, &value) + && known_eq (nunits_m1, value)) { /* Special case: {nunits - 1, nunits - 2, ... , 0}. @@ -1275,46 +899,54 @@ expand_vec_series (rtx dest, rtx base, rtx step) Code sequence: vid.v v vrsub nunits - 1, v. */ - rtx ops[] = {dest, vid, gen_int_mode (nunits_m1, GET_MODE_INNER (mode))}; + rtx ops[] + = {result, vid, gen_int_mode (nunits_m1, GET_MODE_INNER (mode))}; insn_code icode = code_for_pred_sub_reverse_scalar (mode); - emit_vlmax_insn (icode, RVV_BINOP, ops); - return; + emit_vlmax_insn (icode, BINARY_OP, ops); } else { - step_adj = gen_reg_rtx (mode); - if (CONST_INT_P (step) && pow2p_hwi (INTVAL (step))) - { - /* Emit logical left shift operation. */ - int shift = exact_log2 (INTVAL (step)); - rtx shift_amount = gen_int_mode (shift, Pmode); - insn_code icode = code_for_pred_scalar (ASHIFT, mode); - rtx ops[] = {step_adj, vid, shift_amount}; - emit_vlmax_insn (icode, RVV_BINOP, ops); - } + /* Step 2: Generate I * STEP. + - STEP is 1, we don't emit any instructions. + - STEP is power of 2, we use vsll.vi/vsll.vx. + - STEP is non-power of 2, we use vmul.vx. */ + if (rtx_equal_p (step, const1_rtx)) + step_adj = vid; else { - insn_code icode = code_for_pred_scalar (MULT, mode); - rtx ops[] = {step_adj, vid, step}; - emit_vlmax_insn (icode, RVV_BINOP, ops); + step_adj = gen_reg_rtx (mode); + if (CONST_INT_P (step) && pow2p_hwi (INTVAL (step))) + { + /* Emit logical left shift operation. */ + int shift = exact_log2 (INTVAL (step)); + rtx shift_amount = gen_int_mode (shift, Pmode); + insn_code icode = code_for_pred_scalar (ASHIFT, mode); + rtx ops[] = {step_adj, vid, shift_amount}; + emit_vlmax_insn (icode, BINARY_OP, ops); + } + else + { + insn_code icode = code_for_pred_scalar (MULT, mode); + rtx ops[] = {step_adj, vid, step}; + emit_vlmax_insn (icode, BINARY_OP, ops); + } + } + + /* Step 3: Generate BASE + I * STEP. + - BASE is 0, use result of vid. + - BASE is not 0, we use vadd.vx/vadd.vi. */ + if (rtx_equal_p (base, const0_rtx)) + emit_move_insn (result, step_adj); + else + { + insn_code icode = code_for_pred_scalar (PLUS, mode); + rtx ops[] = {result, step_adj, base}; + emit_vlmax_insn (icode, BINARY_OP, ops); } } - /* Step 3: Generate BASE + I * STEP. - - BASE is 0, use result of vid. - - BASE is not 0, we use vadd.vx/vadd.vi. */ - if (rtx_equal_p (base, const0_rtx)) - { - emit_move_insn (dest, step_adj); - } - else - { - rtx result = gen_reg_rtx (mode); - insn_code icode = code_for_pred_scalar (PLUS, mode); - rtx ops[] = {result, step_adj, base}; - emit_vlmax_insn (icode, RVV_BINOP, ops); - emit_move_insn (dest, result); - } + if (result != dest) + emit_move_insn (dest, result); } static void @@ -1328,7 +960,7 @@ expand_const_vector (rtx target, rtx src) const_vec_duplicate_p (src, &elt) && (rtx_equal_p (elt, const0_rtx) || rtx_equal_p (elt, const1_rtx))); rtx ops[] = {target, src}; - emit_vlmax_insn (code_for_pred_mov (mode), RVV_UNOP, ops); + emit_vlmax_insn (code_for_pred_mov (mode), UNARY_MASK_OP, ops); return; } @@ -1341,12 +973,12 @@ expand_const_vector (rtx target, rtx src) if (satisfies_constraint_vi (src) || satisfies_constraint_Wc0 (src)) { rtx ops[] = {tmp, src}; - emit_vlmax_insn (code_for_pred_mov (mode), RVV_UNOP, ops); + emit_vlmax_insn (code_for_pred_mov (mode), UNARY_OP, ops); } else { rtx ops[] = {tmp, elt}; - emit_vlmax_insn (code_for_pred_broadcast (mode), RVV_UNOP, ops); + emit_vlmax_insn (code_for_pred_broadcast (mode), UNARY_OP, ops); } if (tmp != target) @@ -1411,19 +1043,19 @@ expand_const_vector (rtx target, rtx src) rtx vid = gen_reg_rtx (builder.int_mode ()); rtx op[] = {vid}; emit_vlmax_insn (code_for_pred_series (builder.int_mode ()), - RVV_MISC_OP, op); + NULLARY_OP, op); /* Generate vid_repeat = { 0, 1, ... nbits, ... } */ rtx vid_repeat = gen_reg_rtx (builder.int_mode ()); rtx and_ops[] = {vid_repeat, vid, gen_int_mode (nbits, builder.inner_int_mode ())}; emit_vlmax_insn (code_for_pred_scalar (AND, builder.int_mode ()), - RVV_BINOP, and_ops); + BINARY_OP, and_ops); rtx tmp = gen_reg_rtx (builder.mode ()); rtx dup_ops[] = {tmp, builder.elt (0)}; - emit_vlmax_insn (code_for_pred_broadcast (builder.mode ()), RVV_UNOP, - dup_ops); + emit_vlmax_insn (code_for_pred_broadcast (builder.mode ()), UNARY_OP, + dup_ops); for (unsigned int i = 1; i < builder.npatterns (); i++) { /* Generate mask according to i. */ @@ -1435,7 +1067,7 @@ expand_const_vector (rtx target, rtx src) rtx tmp2 = gen_reg_rtx (builder.mode ()); rtx merge_ops[] = {tmp2, tmp, builder.elt (i), mask}; insn_code icode = code_for_pred_merge_scalar (builder.mode ()); - emit_vlmax_merge_insn (icode, RVV_MERGE_OP, merge_ops); + emit_vlmax_insn (icode, MERGE_OP, merge_ops); tmp = tmp2; } emit_move_insn (target, tmp); @@ -1453,7 +1085,7 @@ expand_const_vector (rtx target, rtx src) rtx vid = gen_reg_rtx (builder.mode ()); rtx vid_ops[] = {vid}; icode = code_for_pred_series (builder.mode ()); - emit_vlmax_insn (icode, RVV_MISC_OP, vid_ops); + emit_vlmax_insn (icode, NULLARY_OP, vid_ops); if (builder.npatterns_all_equal_p ()) { @@ -1471,7 +1103,7 @@ expand_const_vector (rtx target, rtx src) rtx tmp = gen_reg_rtx (builder.mode ()); rtx and_ops[] = {tmp, vid, imm}; icode = code_for_pred_scalar (AND, builder.mode ()); - emit_vlmax_insn (icode, RVV_BINOP, and_ops); + emit_vlmax_insn (icode, BINARY_OP, and_ops); HOST_WIDE_INT init_val = INTVAL (builder.elt (0)); if (init_val == 0) emit_move_insn (target, tmp); @@ -1480,7 +1112,7 @@ expand_const_vector (rtx target, rtx src) rtx dup = gen_const_vector_dup (builder.mode (), init_val); rtx add_ops[] = {target, tmp, dup}; icode = code_for_pred (PLUS, builder.mode ()); - emit_vlmax_insn (icode, RVV_BINOP, add_ops); + emit_vlmax_insn (icode, BINARY_OP, add_ops); } } else @@ -1501,10 +1133,29 @@ expand_const_vector (rtx target, rtx src) /* Step 2: Generate result = VID + diff. */ rtx vec = v.build (); rtx add_ops[] = {target, vid, vec}; - emit_vlmax_insn (code_for_pred (PLUS, builder.mode ()), RVV_BINOP, - add_ops); + emit_vlmax_insn (code_for_pred (PLUS, builder.mode ()), + BINARY_OP, add_ops); } } + else if (npatterns == 1 && nelts_per_pattern == 3) + { + /* Generate the following CONST_VECTOR: + { base0, base1, base1 + step, base1 + step * 2, ... } */ + rtx base0 = CONST_VECTOR_ELT (src, 0); + rtx base1 = CONST_VECTOR_ELT (src, 1); + rtx step = CONST_VECTOR_ELT (src, 2); + /* Step 1 - { base1, base1 + step, base1 + step * 2, ... } */ + rtx tmp = gen_reg_rtx (mode); + emit_insn (gen_vec_series (mode, tmp, base1, step)); + /* Step 2 - { base0, base1, base1 + step, base1 + step * 2, ... } */ + scalar_mode elem_mode = GET_MODE_INNER (mode); + if (!rtx_equal_p (base0, const0_rtx)) + base0 = force_reg (elem_mode, base0); + + insn_code icode = optab_handler (vec_shl_insert_optab, mode); + gcc_assert (icode != CODE_FOR_nothing); + emit_insn (GEN_FCN (icode) (target, tmp, base0)); + } else /* TODO: We will enable more variable-length vector in the future. */ gcc_unreachable (); @@ -1513,6 +1164,34 @@ expand_const_vector (rtx target, rtx src) gcc_unreachable (); } +/* Get the frm mode with given CONST_INT rtx, the default mode is + FRM_DYN. */ +enum floating_point_rounding_mode +get_frm_mode (rtx operand) +{ + gcc_assert (CONST_INT_P (operand)); + + switch (INTVAL (operand)) + { + case FRM_RNE: + return FRM_RNE; + case FRM_RTZ: + return FRM_RTZ; + case FRM_RDN: + return FRM_RDN; + case FRM_RUP: + return FRM_RUP; + case FRM_RMM: + return FRM_RMM; + case FRM_DYN: + return FRM_DYN; + default: + gcc_unreachable (); + } + + gcc_unreachable (); +} + /* Expand a pre-RA RVV data move from SRC to DEST. It expands move for RVV fractional vector modes. */ bool @@ -1578,13 +1257,15 @@ legitimize_move (rtx dest, rtx src) return true; } + unsigned insn_flags + = GET_MODE_CLASS (mode) == MODE_VECTOR_BOOL ? UNARY_MASK_OP : UNARY_OP; if (!register_operand (src, mode) && !register_operand (dest, mode)) { rtx tmp = gen_reg_rtx (mode); if (MEM_P (src)) { rtx ops[] = {tmp, src}; - emit_vlmax_insn (code_for_pred_mov (mode), RVV_UNOP, ops); + emit_vlmax_insn (code_for_pred_mov (mode), insn_flags, ops); } else emit_move_insn (tmp, src); @@ -1595,7 +1276,7 @@ legitimize_move (rtx dest, rtx src) return false; rtx ops[] = {dest, src}; - emit_vlmax_insn (code_for_pred_mov (mode), RVV_UNOP, ops); + emit_vlmax_insn (code_for_pred_mov (mode), insn_flags, ops); return true; } @@ -1686,6 +1367,14 @@ get_vlmul (machine_mode mode) return mode_vtype_infos.vlmul[mode]; } +/* Return the VLMAX rtx of vector mode MODE. */ +rtx +get_vlmax_rtx (machine_mode mode) +{ + gcc_assert (riscv_v_ext_vector_mode_p (mode)); + return gen_int_mode (GET_MODE_NUNITS (mode), Pmode); +} + /* Return the NF value of the corresponding mode. */ unsigned int get_nf (machine_mode mode) @@ -1790,7 +1479,13 @@ get_avl_type_rtx (enum avl_type type) machine_mode get_mask_mode (machine_mode mode) { - return get_vector_mode (BImode, GET_MODE_NUNITS (mode)).require(); + poly_int64 nunits = GET_MODE_NUNITS (mode); + if (riscv_v_ext_tuple_mode_p (mode)) + { + unsigned int nf = get_nf (mode); + nunits = exact_div (nunits, nf); + } + return get_vector_mode (BImode, nunits).require (); } /* Return the appropriate M1 mode for MODE. */ @@ -1926,8 +1621,7 @@ sew64_scalar_helper (rtx *operands, rtx *scalar_op, rtx vl, rtx tmp = gen_reg_rtx (vector_mode); rtx ops[] = {tmp, *scalar_op}; - riscv_vector::emit_nonvlmax_insn (code_for_pred_broadcast (vector_mode), - riscv_vector::RVV_UNOP, ops, vl); + emit_nonvlmax_insn (code_for_pred_broadcast (vector_mode), UNARY_OP, ops, vl); emit_vector_func (operands, tmp); return true; @@ -1985,9 +1679,11 @@ static rtx gen_no_side_effects_vsetvl_rtx (machine_mode vmode, rtx vl, rtx avl) { unsigned int sew = get_sew (vmode); + rtx tail_policy = gen_int_mode (get_prefer_tail_policy (), Pmode); + rtx mask_policy = gen_int_mode (get_prefer_mask_policy (), Pmode); return gen_vsetvl_no_side_effects (Pmode, vl, avl, gen_int_mode (sew, Pmode), gen_int_mode (get_vlmul (vmode), Pmode), - const0_rtx, const0_rtx); + tail_policy, mask_policy); } /* GET VL * 2 rtx. */ @@ -2103,9 +1799,8 @@ slide1_sew64_helper (int unspec, machine_mode mode, machine_mode demote_mode, CONSTM1_RTX (demote_mask_mode), merge, temp, demote_scalar_op2, vl_x2, ta, ma, ops[8])); - if (rtx_equal_p (ops[1], CONSTM1_RTX (GET_MODE (ops[1])))) - return true; - else + if (!rtx_equal_p (ops[1], CONSTM1_RTX (GET_MODE (ops[1]))) + && !rtx_equal_p (ops[2], RVV_VUNDEF (GET_MODE (ops[2])))) emit_insn (gen_pred_merge (mode, ops[0], ops[2], ops[2], ops[0], ops[1], force_vector_length_operand (ops[5]), ops[6], ops[8])); @@ -2235,8 +1930,8 @@ expand_tuple_move (rtx *ops) if (fractional_p) { rtx operands[] = {subreg, mem}; - emit_vlmax_insn (code_for_pred_mov (subpart_mode), RVV_UNOP, - operands, ops[4]); + emit_vlmax_insn_lra (code_for_pred_mov (subpart_mode), + UNARY_OP, operands, ops[4]); } else emit_move_insn (subreg, mem); @@ -2260,8 +1955,8 @@ expand_tuple_move (rtx *ops) if (fractional_p) { rtx operands[] = {mem, subreg}; - emit_vlmax_insn (code_for_pred_mov (subpart_mode), RVV_UNOP, - operands, ops[4]); + emit_vlmax_insn_lra (code_for_pred_mov (subpart_mode), + UNARY_OP, operands, ops[4]); } else emit_move_insn (mem, subreg); @@ -2325,7 +2020,7 @@ expand_vector_init_insert_elems (rtx target, const rvv_builder &builder, = FLOAT_MODE_P (mode) ? UNSPEC_VFSLIDE1DOWN : UNSPEC_VSLIDE1DOWN; insn_code icode = code_for_pred_slide (unspec, mode); rtx ops[] = {target, target, builder.elt (i)}; - emit_vlmax_insn (icode, RVV_BINOP, ops); + emit_vlmax_insn (icode, BINARY_OP, ops); } } @@ -2341,15 +2036,13 @@ expand_vector_init_merge_repeating_sequence (rtx target, const rvv_builder &builder) { machine_mode dup_mode = get_repeating_sequence_dup_machine_mode (builder); - machine_mode dup_mask_mode = get_mask_mode (dup_mode); machine_mode mask_mode = get_mask_mode (builder.mode ()); uint64_t full_nelts = builder.full_nelts ().to_constant (); /* Step 1: Broadcast the first pattern. */ rtx ops[] = {target, force_reg (GET_MODE_INNER (dup_mode), builder.elt (0))}; - emit_vlmax_integer_move_insn (code_for_pred_broadcast (builder.mode ()), - ops, NULL_RTX); - + emit_vlmax_insn (code_for_pred_broadcast (builder.mode ()), + UNARY_OP, ops); /* Step 2: Merge the rest iteration of pattern. */ for (unsigned int i = 1; i < builder.npatterns (); i++) { @@ -2360,26 +2053,25 @@ expand_vector_init_merge_repeating_sequence (rtx target, if (full_nelts <= builder.inner_bits_size ()) /* vmv.s.x. */ { - rtx ops[] = {dup, gen_scalar_move_mask (dup_mask_mode), - RVV_VUNDEF (dup_mode), merge_mask}; - emit_scalar_move_insn (code_for_pred_broadcast (GET_MODE (dup)), - ops); + rtx ops[] = {dup, merge_mask}; + emit_nonvlmax_insn (code_for_pred_broadcast (GET_MODE (dup)), + SCALAR_MOVE_OP, ops, CONST1_RTX (Pmode)); } else /* vmv.v.x. */ { rtx ops[] = {dup, force_reg (GET_MODE_INNER (dup_mode), merge_mask)}; rtx vl = gen_int_mode (CEIL (full_nelts, builder.inner_bits_size ()), Pmode); - emit_nonvlmax_integer_move_insn (code_for_pred_broadcast (dup_mode), - ops, vl); + emit_nonvlmax_insn (code_for_pred_broadcast (dup_mode), UNARY_OP, + ops, vl); } emit_move_insn (mask, gen_lowpart (mask_mode, dup)); /* Step 2-2: Merge pattern according to the mask. */ rtx ops[] = {target, target, builder.elt (i), mask}; - emit_vlmax_merge_insn (code_for_pred_merge_scalar (GET_MODE (target)), - riscv_vector::RVV_MERGE_OP, ops); + emit_vlmax_insn (code_for_pred_merge_scalar (GET_MODE (target)), + MERGE_OP, ops); } } @@ -2488,7 +2180,7 @@ autovectorize_vector_modes (vector_modes *modes, bool) full vectors for wider elements. - full_size / 8: Try using 64-bit containers for all element types. */ - static const int rvv_factors[] = {1, 2, 4, 8}; + static const int rvv_factors[] = {1, 2, 4, 8, 16, 32, 64}; for (unsigned int i = 0; i < sizeof (rvv_factors) / sizeof (int); i++) { poly_uint64 units; @@ -2498,12 +2190,8 @@ autovectorize_vector_modes (vector_modes *modes, bool) modes->safe_push (mode); } } - unsigned int flag = 0; if (TARGET_VECTOR_VLS) { - /* Enable VECT_COMPARE_COSTS between VLA modes VLS modes for scalable - auto-vectorization. */ - flag |= VECT_COMPARE_COSTS; /* Push all VLSmodes according to TARGET_MIN_VLEN. */ unsigned int i = 0; unsigned int base_size = TARGET_MIN_VLEN * riscv_autovec_lmul / 8; @@ -2516,7 +2204,8 @@ autovectorize_vector_modes (vector_modes *modes, bool) size = base_size / (1U << i); } } - return flag; + /* Enable LOOP_VINFO comparison in COST model. */ + return VECT_COMPARE_COSTS; } /* If the given VECTOR_MODE is an RVV mode, first get the largest number @@ -2576,13 +2265,13 @@ expand_vec_cmp (rtx target, rtx_code code, rtx op0, rtx op1) expand_vec_cmp (gt, GT, op0, op1); icode = code_for_pred (IOR, mask_mode); rtx ops[] = {target, lt, gt}; - emit_vlmax_insn (icode, riscv_vector::RVV_BINOP, ops); + emit_vlmax_insn (icode, BINARY_MASK_OP, ops); return; } rtx cmp = gen_rtx_fmt_ee (code, mask_mode, op0, op1); rtx ops[] = {target, cmp, op0, op1}; - emit_vlmax_cmp_insn (icode, ops); + emit_vlmax_insn (icode, COMPARE_OP, ops); } void @@ -2601,13 +2290,13 @@ expand_vec_cmp (rtx target, rtx_code code, rtx mask, rtx maskoff, rtx op0, expand_vec_cmp (gt, GT, mask, maskoff, op0, op1); icode = code_for_pred (IOR, mask_mode); rtx ops[] = {target, lt, gt}; - emit_vlmax_insn (icode, RVV_BINOP, ops); + emit_vlmax_insn (icode, BINARY_MASK_OP, ops); return; } rtx cmp = gen_rtx_fmt_ee (code, mask_mode, op0, op1); rtx ops[] = {target, mask, maskoff, cmp, op0, op1}; - emit_vlmax_cmp_mu_insn (icode, ops); + emit_vlmax_insn (icode, COMPARE_OP_MU, ops); } /* Expand an RVV floating-point comparison: @@ -2680,7 +2369,7 @@ expand_vec_cmp_float (rtx target, rtx_code code, rtx op0, rtx op1, expand_vec_cmp (eq1, EQ, op1, op1); insn_code icode = code_for_pred (AND, mask_mode); rtx ops[] = {eq0, eq0, eq1}; - emit_vlmax_insn (icode, riscv_vector::RVV_BINOP, ops); + emit_vlmax_insn (icode, BINARY_MASK_OP, ops); } else { @@ -2809,7 +2498,7 @@ expand_vec_perm (rtx target, rtx op0, rtx op1, rtx sel) [0, max_of_mode - nunits]. */ rtx tmp = gen_reg_rtx (sel_mode); rtx ops[] = {tmp, sel_mod, max_sel}; - emit_vlmax_insn (code_for_pred (MINUS, sel_mode), RVV_BINOP, ops); + emit_vlmax_insn (code_for_pred (MINUS, sel_mode), BINARY_OP, ops); /* Step4: gather those into the previously masked-out elements of target. */ @@ -2874,10 +2563,12 @@ shuffle_merge_patterns (struct expand_vec_perm_d *d) insn_code icode = code_for_pred_cmp_scalar (sel_mode); rtx cmp = gen_rtx_fmt_ee (LTU, mask_mode, sel, x); rtx ops[] = {mask, cmp, sel, x}; - emit_vlmax_cmp_insn (icode, ops); + emit_vlmax_insn (icode, COMPARE_OP, ops); /* TARGET = MASK ? OP0 : OP1. */ - emit_insn (gen_vcond_mask (vmode, vmode, d->target, d->op0, d->op1, mask)); + /* swap op0 and op1 since the order is opposite to pred_merge. */ + rtx ops2[] = {d->target, d->op1, d->op0, mask}; + emit_vlmax_insn (code_for_pred_merge (vmode), MERGE_OP, ops2); return true; } @@ -3008,16 +2699,15 @@ shuffle_compress_patterns (struct expand_vec_perm_d *d) if (need_slideup_p) { int slideup_cnt = vlen - (d->perm[vlen - 1].to_constant () % vlen) - 1; - rtx ops[] = {d->target, RVV_VUNDEF (vmode), d->op1, - gen_int_mode (slideup_cnt, Pmode)}; + rtx ops[] = {d->target, d->op1, gen_int_mode (slideup_cnt, Pmode)}; insn_code icode = code_for_pred_slide (UNSPEC_VSLIDEUP, vmode); - emit_vlmax_slide_insn (icode, ops); + emit_vlmax_insn (icode, BINARY_OP, ops); merge = d->target; } insn_code icode = code_for_pred_compress (vmode); rtx ops[] = {d->target, merge, d->op0, mask}; - emit_vlmax_compress_insn (icode, ops); + emit_vlmax_insn (icode, COMPRESS_OP_MERGE, ops); return true; } @@ -3073,15 +2763,15 @@ shuffle_decompress_patterns (struct expand_vec_perm_d *d) insn_code icode = code_for_pred_slide (UNSPEC_VSLIDEDOWN, d->vmode); rtx ops0[] = {op0, d->op0, gen_int_mode (first, Pmode)}; rtx ops1[] = {op1, d->op1, gen_int_mode (first, Pmode)}; - emit_vlmax_insn (icode, RVV_BINOP, ops0); - emit_vlmax_insn (icode, RVV_BINOP, ops1); + emit_vlmax_insn (icode, BINARY_OP, ops0); + emit_vlmax_insn (icode, BINARY_OP, ops1); } /* Generate { 0, 1, .... } mask. */ rtx vid = gen_reg_rtx (sel_mode); rtx vid_repeat = gen_reg_rtx (sel_mode); emit_insn (gen_vec_series (sel_mode, vid, const0_rtx, const1_rtx)); rtx and_ops[] = {vid_repeat, vid, const1_rtx}; - emit_vlmax_insn (code_for_pred_scalar (AND, sel_mode), RVV_BINOP, and_ops); + emit_vlmax_insn (code_for_pred_scalar (AND, sel_mode), BINARY_OP, and_ops); rtx const_vec = gen_const_vector_dup (sel_mode, 1); rtx mask = gen_reg_rtx (mask_mode); expand_vec_cmp (mask, EQ, vid_repeat, const_vec); @@ -3235,8 +2925,8 @@ expand_load_store (rtx *ops, bool is_load) /* If the length operand is equal to VF, it is VLMAX load/store. */ if (is_load) { - rtx m_ops[] = {ops[0], mask, RVV_VUNDEF (mode), ops[1]}; - emit_vlmax_masked_insn (code_for_pred_mov (mode), RVV_UNOP_M, m_ops); + rtx m_ops[] = {ops[0], mask, ops[1]}; + emit_vlmax_insn (code_for_pred_mov (mode), UNARY_OP_TAMA, m_ops); } else { @@ -3252,9 +2942,9 @@ expand_load_store (rtx *ops, bool is_load) len = force_reg (Pmode, len); if (is_load) { - rtx m_ops[] = {ops[0], mask, RVV_VUNDEF (mode), ops[1]}; - emit_nonvlmax_masked_insn (code_for_pred_mov (mode), RVV_UNOP_M, - m_ops, len); + rtx m_ops[] = {ops[0], mask, ops[1]}; + emit_nonvlmax_insn (code_for_pred_mov (mode), UNARY_OP_TAMA, m_ops, + len); } else emit_insn (gen_pred_store (mode, ops[0], mask, ops[1], len, @@ -3265,16 +2955,69 @@ expand_load_store (rtx *ops, bool is_load) /* Return true if the operation is the floating-point operation need FRM. */ static bool -needs_fp_rounding (rtx_code code, machine_mode mode) +needs_fp_rounding (unsigned icode, machine_mode mode) { if (!FLOAT_MODE_P (mode)) return false; - return code != SMIN && code != SMAX; + + return icode != maybe_code_for_pred (SMIN, mode) + && icode != maybe_code_for_pred (SMAX, mode) + && icode != maybe_code_for_pred (NEG, mode) + && icode != maybe_code_for_pred (ABS, mode) + /* narrower-FP -> FP */ + && icode != maybe_code_for_pred_extend (mode) + /* narrower-INT -> FP */ + && icode != maybe_code_for_pred_widen (FLOAT, mode) + && icode != maybe_code_for_pred_widen (UNSIGNED_FLOAT, mode); } -/* Expand COND_LEN_*. */ +/* Subroutine to expand COND_LEN_* patterns. */ +static void +expand_cond_len_op (unsigned icode, insn_flags op_type, rtx *ops, rtx len) +{ + rtx dest = ops[0]; + rtx mask = ops[1]; + machine_mode mode = GET_MODE (dest); + machine_mode mask_mode = GET_MODE (mask); + poly_int64 value; + bool is_dummy_mask = rtx_equal_p (mask, CONSTM1_RTX (mask_mode)); + bool is_vlmax_len + = poly_int_rtx_p (len, &value) && known_eq (value, GET_MODE_NUNITS (mode)); + + unsigned insn_flags = HAS_DEST_P | HAS_MASK_P | HAS_MERGE_P | op_type; + if (is_dummy_mask) + insn_flags |= TU_POLICY_P | MDEFAULT_POLICY_P; + else if (is_vlmax_len) + insn_flags |= TDEFAULT_POLICY_P | MU_POLICY_P; + else + insn_flags |= TU_POLICY_P | MU_POLICY_P; + + if (needs_fp_rounding (icode, mode)) + insn_flags |= FRM_DYN_P; + + if (is_vlmax_len) + emit_vlmax_insn (icode, insn_flags, ops); + else + emit_nonvlmax_insn (icode, insn_flags, ops, len); +} + +/* Expand unary ops COND_LEN_*. */ void -expand_cond_len_binop (rtx_code code, rtx *ops) +expand_cond_len_unop (unsigned icode, rtx *ops) +{ + rtx dest = ops[0]; + rtx mask = ops[1]; + rtx src = ops[2]; + rtx merge = ops[3]; + rtx len = ops[4]; + + rtx cond_ops[] = {dest, mask, merge, src}; + expand_cond_len_op (icode, UNARY_OP_P, cond_ops, len); +} + +/* Expand binary ops COND_LEN_*. */ +void +expand_cond_len_binop (unsigned icode, rtx *ops) { rtx dest = ops[0]; rtx mask = ops[1]; @@ -3282,25 +3025,9 @@ expand_cond_len_binop (rtx_code code, rtx *ops) rtx src2 = ops[3]; rtx merge = ops[4]; rtx len = ops[5]; - machine_mode mode = GET_MODE (dest); - machine_mode mask_mode = GET_MODE (mask); - poly_uint64 value; - bool is_dummy_mask = rtx_equal_p (mask, CONSTM1_RTX (mask_mode)); - - if (is_dummy_mask) - { - /* Use TU, MASK ANY policy. */ - rtx ops[] = {dest, mask, merge, src1, src2}; - insn_code icode = code_for_pred (code, mode); - if (needs_fp_rounding (code, mode)) - emit_nonvlmax_fp_tu_insn (icode, RVV_BINOP_TU, ops, len); - else - emit_nonvlmax_tu_insn (icode, RVV_BINOP_TU, ops, len); - } - else - /* FIXME: Enable this case when we support it in the middle-end. */ - gcc_unreachable (); + rtx cond_ops[] = {dest, mask, merge, src1, src2}; + expand_cond_len_op (icode, BINARY_OP_P, cond_ops, len); } /* Prepare insn_code for gather_load/scatter_store according to @@ -3434,13 +3161,13 @@ expand_gather_scatter (rtx *ops, bool is_load) if (is_load) { rtx load_ops[] - = {vec_reg, mask, RVV_VUNDEF (vec_mode), ptr, vec_offset}; - emit_vlmax_masked_insn (icode, RVV_GATHER_M_OP, load_ops); + = {vec_reg, mask, ptr, vec_offset}; + emit_vlmax_insn (icode, BINARY_OP_TAMA, load_ops); } else { rtx store_ops[] = {mask, ptr, vec_offset, vec_reg}; - emit_vlmax_masked_store_insn (icode, RVV_SCATTER_M_OP, store_ops); + emit_vlmax_insn (icode, SCATTER_OP_M, store_ops); } } else @@ -3448,14 +3175,13 @@ expand_gather_scatter (rtx *ops, bool is_load) if (is_load) { rtx load_ops[] - = {vec_reg, mask, RVV_VUNDEF (vec_mode), ptr, vec_offset}; - emit_nonvlmax_masked_insn (icode, RVV_GATHER_M_OP, load_ops, len); + = {vec_reg, mask, ptr, vec_offset}; + emit_nonvlmax_insn (icode, BINARY_OP_TAMA, load_ops, len); } else { rtx store_ops[] = {mask, ptr, vec_offset, vec_reg}; - emit_nonvlmax_masked_store_insn (icode, RVV_SCATTER_M_OP, store_ops, - len); + emit_nonvlmax_insn (icode, SCATTER_OP_M, store_ops, len); } } } @@ -3466,25 +3192,14 @@ expand_cond_len_ternop (unsigned icode, rtx *ops) { rtx dest = ops[0]; rtx mask = ops[1]; + rtx src1 = ops[2]; + rtx src2 = ops[3]; + rtx src3 = ops[4]; + rtx merge = ops[5]; rtx len = ops[6]; - machine_mode mode = GET_MODE (dest); - machine_mode mask_mode = GET_MODE (mask); - poly_uint64 value; - bool is_dummy_mask = rtx_equal_p (mask, CONSTM1_RTX (mask_mode)); - - if (is_dummy_mask) - { - /* Use TU, MASK ANY policy. */ - if (FLOAT_MODE_P (mode)) - emit_nonvlmax_fp_ternary_tu_insn (icode, RVV_TERNOP_TU, ops, len); - else - /* FIXME: Enable this case when we support it in the middle-end. */ - gcc_unreachable (); - } - else - /* FIXME: Enable this case when we support it in the middle-end. */ - gcc_unreachable (); + rtx cond_ops[] = {dest, mask, src1, src2, src3, merge}; + expand_cond_len_op (icode, TERNARY_OP_P, cond_ops, len); } /* Expand reduction operations. */ @@ -3494,16 +3209,14 @@ expand_reduction (rtx_code code, rtx *ops, rtx init, reduction_type type) rtx vector = type == reduction_type::UNORDERED ? ops[1] : ops[2]; machine_mode vmode = GET_MODE (vector); machine_mode m1_mode = get_m1_mode (vmode).require (); - machine_mode m1_mmode = get_mask_mode (m1_mode); rtx m1_tmp = gen_reg_rtx (m1_mode); - rtx m1_mask = gen_scalar_move_mask (m1_mmode); - rtx m1_undef = RVV_VUNDEF (m1_mode); - rtx scalar_move_ops[] = {m1_tmp, m1_mask, m1_undef, init}; - rtx len = type == reduction_type::MASK_LEN_FOLD_LEFT ? ops[4] : NULL_RTX; - emit_scalar_move_insn (code_for_pred_broadcast (m1_mode), scalar_move_ops, - len); - + rtx scalar_move_ops[] = {m1_tmp, init}; + emit_nonvlmax_insn (code_for_pred_broadcast (m1_mode), SCALAR_MOVE_OP, + scalar_move_ops, + type == reduction_type::MASK_LEN_FOLD_LEFT + ? ops[4] + : CONST1_RTX (Pmode)); rtx m1_tmp2 = gen_reg_rtx (m1_mode); rtx reduc_ops[] = {m1_tmp2, vector, m1_tmp}; @@ -3517,21 +3230,160 @@ expand_reduction (rtx_code code, rtx *ops, rtx init, reduction_type type) if (type == reduction_type::MASK_LEN_FOLD_LEFT) { rtx mask = ops[3]; - rtx mask_len_reduc_ops[] - = {m1_tmp2, mask, RVV_VUNDEF (m1_mode), vector, m1_tmp}; - emit_nonvlmax_fp_reduction_insn (icode, RVV_REDUCTION_TU_OP, - mask_len_reduc_ops, len); + rtx mask_len_reduc_ops[] = {m1_tmp2, mask, vector, m1_tmp}; + emit_nonvlmax_insn (icode, REDUCE_OP_M_FRM_DYN, mask_len_reduc_ops, + ops[4]); } else - emit_vlmax_fp_reduction_insn (icode, RVV_REDUCTION_OP, reduc_ops); + emit_vlmax_insn (icode, REDUCE_OP_FRM_DYN, reduc_ops); } else { insn_code icode = code_for_pred_reduc (code, vmode, m1_mode); - emit_vlmax_reduction_insn (icode, RVV_REDUCTION_OP, reduc_ops); + emit_vlmax_insn (icode, REDUCE_OP, reduc_ops); } emit_insn (gen_pred_extract_first (m1_mode, ops[0], m1_tmp2)); } +/* Prepare ops for ternary operations. + It can be called before or after RA. */ +void +prepare_ternary_operands (rtx *ops, bool split_p) +{ + machine_mode mode = GET_MODE (ops[0]); + + if (split_p + || (!rtx_equal_p (ops[2], ops[5]) + && !rtx_equal_p (ops[3], ops[5]) + && !rtx_equal_p (ops[4], ops[5]) + && riscv_get_v_regno_alignment (mode) == 8)) + { + /* RA will fail to find vector REG and report ICE, so we pre-merge + the ops for LMUL = 8. */ + if (satisfies_constraint_Wc1 (ops[1])) + { + emit_move_insn (ops[0], ops[5]); + emit_insn (gen_pred_mov (mode, ops[0], ops[1], ops[0], ops[4], ops[6], + ops[7], ops[8], ops[9])); + } + else + emit_insn (gen_pred_merge (mode, ops[0], RVV_VUNDEF (mode), ops[5], + ops[4], ops[1], ops[6], ops[7], ops[9])); + ops[5] = ops[4] = ops[0]; + } + else + { + /* Swap the multiplication ops if the fallback value is the + second of the two. */ + if (rtx_equal_p (ops[3], ops[5])) + std::swap (ops[2], ops[3]); + + /* TODO: ??? Maybe we could support splitting FMA (a, 4, b) + into PLUS (ASHIFT (a, 2), b) according to uarchs. */ + } +} + +/* Expand VEC_MASK_LEN_{LOAD_LANES,STORE_LANES}. */ +void +expand_lanes_load_store (rtx *ops, bool is_load) +{ + poly_int64 value; + rtx mask = ops[2]; + rtx len = ops[3]; + rtx addr = is_load ? XEXP (ops[1], 0) : XEXP (ops[0], 0); + rtx reg = is_load ? ops[0] : ops[1]; + machine_mode mode = GET_MODE (ops[0]); + + if (poly_int_rtx_p (len, &value) && known_eq (value, GET_MODE_NUNITS (mode))) + { + /* If the length operand is equal to VF, it is VLMAX load/store. */ + if (is_load) + { + rtx m_ops[] = {reg, mask, addr}; + emit_vlmax_insn (code_for_pred_unit_strided_load (mode), UNARY_OP_TAMA, + m_ops); + } + else + { + len = gen_reg_rtx (Pmode); + emit_vlmax_vsetvl (mode, len); + emit_insn (gen_pred_unit_strided_store (mode, mask, addr, reg, len, + get_avl_type_rtx (VLMAX))); + } + } + else + { + if (!satisfies_constraint_K (len)) + len = force_reg (Pmode, len); + if (is_load) + { + rtx m_ops[] = {reg, mask, addr}; + emit_nonvlmax_insn (code_for_pred_unit_strided_load (mode), + UNARY_OP_TAMA, m_ops, len); + } + else + emit_insn (gen_pred_unit_strided_store (mode, mask, addr, reg, len, + get_avl_type_rtx (NONVLMAX))); + } +} + +/* Expand LEN_FOLD_EXTRACT_LAST. */ +void +expand_fold_extract_last (rtx *ops) +{ + rtx dst = ops[0]; + rtx default_value = ops[1]; + rtx mask = ops[2]; + rtx anchor = gen_reg_rtx (Pmode); + rtx index = gen_reg_rtx (Pmode); + rtx vect = ops[3]; + rtx else_label = gen_label_rtx (); + rtx end_label = gen_label_rtx (); + rtx len = ops[4]; + poly_int64 value; + machine_mode mode = GET_MODE (vect); + machine_mode mask_mode = GET_MODE (mask); + rtx compress_vect = gen_reg_rtx (mode); + rtx slide_vect = gen_reg_rtx (mode); + insn_code icode; + + if (poly_int_rtx_p (len, &value) && known_eq (value, GET_MODE_NUNITS (mode))) + len = NULL_RTX; + + /* Calculate the number of 1-bit in mask. */ + rtx cpop_ops[] = {anchor, mask}; + if (len) + emit_nonvlmax_insn (code_for_pred_popcount (mask_mode, Pmode), CPOP_OP, + cpop_ops, len); + else + emit_vlmax_insn (code_for_pred_popcount (mask_mode, Pmode), CPOP_OP, + cpop_ops); + + riscv_expand_conditional_branch (else_label, EQ, anchor, const0_rtx); + emit_insn (gen_rtx_SET (index, gen_rtx_PLUS (Pmode, anchor, constm1_rtx))); + /* Compress the vector. */ + icode = code_for_pred_compress (mode); + rtx compress_ops[] = {compress_vect, vect, mask}; + if (len) + emit_nonvlmax_insn (icode, COMPRESS_OP, compress_ops, len); + else + emit_vlmax_insn (icode, COMPRESS_OP, compress_ops); + /* Emit the slide down to index 0 in a new vector. */ + rtx slide_ops[] = {slide_vect, compress_vect, index}; + icode = code_for_pred_slide (UNSPEC_VSLIDEDOWN, mode); + if (len) + emit_nonvlmax_insn (icode, BINARY_OP, slide_ops, len); + else + emit_vlmax_insn (icode, BINARY_OP, slide_ops); + /* Emit v(f)mv.[xf].s. */ + emit_insn (gen_pred_extract_first (mode, dst, slide_vect)); + + emit_jump_insn (gen_jump (end_label)); + emit_barrier (); + emit_label (else_label); + emit_move_insn (dst, default_value); + emit_label (end_label); +} + } // namespace riscv_vector diff --git a/gcc/config/riscv/riscv-vector-builtins-bases.cc b/gcc/config/riscv/riscv-vector-builtins-bases.cc index afe3735f5ee8..8e679f723927 100644 --- a/gcc/config/riscv/riscv-vector-builtins-bases.cc +++ b/gcc/config/riscv/riscv-vector-builtins-bases.cc @@ -58,6 +58,12 @@ enum lst_type LST_INDEXED, }; +enum frm_op_type +{ + NO_FRM, + HAS_FRM, +}; + /* Helper function to fold vleff and vlsegff. */ static gimple * fold_fault_load (gimple_folder &f) @@ -133,11 +139,11 @@ public: /* LMUL. */ e.add_input_operand (Pmode, gen_int_mode (get_vlmul (mode), Pmode)); - /* TA. */ - e.add_input_operand (Pmode, gen_int_mode (1, Pmode)); + /* TAIL_ANY. */ + e.add_input_operand (Pmode, gen_int_mode (get_prefer_tail_policy (), Pmode)); - /* MU. */ - e.add_input_operand (Pmode, gen_int_mode (0, Pmode)); + /* MASK_ANY. */ + e.add_input_operand (Pmode, gen_int_mode (get_prefer_mask_policy (), Pmode)); return e.generate_insn (code_for_vsetvl_no_side_effects (Pmode)); } }; @@ -256,15 +262,21 @@ public: vremu/vsadd/vsaddu/vssub/vssubu vfadd/vfsub/ */ -template +template class binop : public function_base { public: + bool has_rounding_mode_operand_p () const override + { + return FRM_OP == HAS_FRM; + } + rtx expand (function_expander &e) const override { switch (e.op_info->op) { case OP_TYPE_vx: + gcc_assert (FRM_OP == NO_FRM); case OP_TYPE_vf: return e.use_exact_insn (code_for_pred_scalar (CODE, e.vector_mode ())); case OP_TYPE_vv: @@ -275,87 +287,6 @@ public: } }; -/* Implements below instructions for now. - - vfadd - - vfsub - - vfmul - - vfdiv -*/ -template -class binop_frm : public function_base -{ -public: - bool has_rounding_mode_operand_p () const override { return true; } - - rtx expand (function_expander &e) const override - { - switch (e.op_info->op) - { - case OP_TYPE_vf: - return e.use_exact_insn (code_for_pred_scalar (CODE, e.vector_mode ())); - case OP_TYPE_vv: - return e.use_exact_insn (code_for_pred (CODE, e.vector_mode ())); - default: - gcc_unreachable (); - } - } -}; - -/* Implements below instructions for frm - - vfrsub - - vfrdiv -*/ -template -class reverse_binop_frm : public function_base -{ -public: - bool has_rounding_mode_operand_p () const override { return true; } - -public: - rtx expand (function_expander &e) const override - { - return e.use_exact_insn ( - code_for_pred_reverse_scalar (CODE, e.vector_mode ())); - } -}; - -/* Implements below instructions for frm - - vfwadd - - vfwsub - - vfwmul -*/ -template -class widen_binop_frm : public function_base -{ -public: - bool has_rounding_mode_operand_p () const override { return true; } - - rtx expand (function_expander &e) const override - { - switch (e.op_info->op) - { - case OP_TYPE_vv: - return e.use_exact_insn ( - code_for_pred_dual_widen (CODE, e.vector_mode ())); - case OP_TYPE_vf: - return e.use_exact_insn ( - code_for_pred_dual_widen_scalar (CODE, e.vector_mode ())); - case OP_TYPE_wv: - if (CODE == PLUS) - return e.use_exact_insn ( - code_for_pred_single_widen_add (e.vector_mode ())); - else - return e.use_exact_insn ( - code_for_pred_single_widen_sub (e.vector_mode ())); - case OP_TYPE_wf: - return e.use_exact_insn ( - code_for_pred_single_widen_scalar (CODE, e.vector_mode ())); - default: - gcc_unreachable (); - } - } -}; - /* Implements vrsub. */ class vrsub : public function_base { @@ -368,10 +299,15 @@ public: }; /* Implements vneg/vnot. */ -template +template class unop : public function_base { public: + bool has_rounding_mode_operand_p () const override + { + return FRM_OP == HAS_FRM; + } + rtx expand (function_expander &e) const override { return e.use_exact_insn (code_for_pred (CODE, e.vector_mode ())); @@ -420,7 +356,7 @@ public: } }; -/* Implements vwadd/vwsub/vwmul/vfwadd/vfwsub/vfwmul. */ +/* Implements vwadd/vwsub/vwmul. */ template class widen_binop : public function_base { @@ -450,10 +386,17 @@ public: } } }; -template -class widen_binop : public function_base + +/* Implement vfwadd/vfwsub/vfwmul. */ +template +class widen_binop_fp : public function_base { public: + bool has_rounding_mode_operand_p () const override + { + return FRM_OP == HAS_FRM; + } + rtx expand (function_expander &e) const override { switch (e.op_info->op) @@ -1072,10 +1015,15 @@ public: }; /* Implements vfrsub/vfrdiv. */ -template +template class reverse_binop : public function_base { public: + bool has_rounding_mode_operand_p () const override + { + return FRM_OP == HAS_FRM; + } + rtx expand (function_expander &e) const override { return e.use_exact_insn ( @@ -1083,9 +1031,15 @@ public: } }; +template class vfmacc : public function_base { public: + bool has_rounding_mode_operand_p () const override + { + return FRM_OP == HAS_FRM; + } + bool has_merge_operand_p () const override { return false; } rtx expand (function_expander &e) const override @@ -1101,9 +1055,15 @@ public: } }; +template class vfnmsac : public function_base { public: + bool has_rounding_mode_operand_p () const override + { + return FRM_OP == HAS_FRM; + } + bool has_merge_operand_p () const override { return false; } rtx expand (function_expander &e) const override @@ -1118,9 +1078,15 @@ public: } }; +template class vfmadd : public function_base { public: + bool has_rounding_mode_operand_p () const override + { + return FRM_OP == HAS_FRM; + } + bool has_merge_operand_p () const override { return false; } rtx expand (function_expander &e) const override @@ -1136,9 +1102,15 @@ public: } }; +template class vfnmsub : public function_base { public: + bool has_rounding_mode_operand_p () const override + { + return FRM_OP == HAS_FRM; + } + bool has_merge_operand_p () const override { return false; } rtx expand (function_expander &e) const override @@ -1153,9 +1125,15 @@ public: } }; +template class vfnmacc : public function_base { public: + bool has_rounding_mode_operand_p () const override + { + return FRM_OP == HAS_FRM; + } + bool has_merge_operand_p () const override { return false; } rtx expand (function_expander &e) const override @@ -1170,9 +1148,15 @@ public: } }; +template class vfmsac : public function_base { public: + bool has_rounding_mode_operand_p () const override + { + return FRM_OP == HAS_FRM; + } + bool has_merge_operand_p () const override { return false; } rtx expand (function_expander &e) const override @@ -1188,9 +1172,15 @@ public: } }; +template class vfnmadd : public function_base { public: + bool has_rounding_mode_operand_p () const override + { + return FRM_OP == HAS_FRM; + } + bool has_merge_operand_p () const override { return false; } rtx expand (function_expander &e) const override @@ -1205,9 +1195,15 @@ public: } }; +template class vfmsub : public function_base { public: + bool has_rounding_mode_operand_p () const override + { + return FRM_OP == HAS_FRM; + } + bool has_merge_operand_p () const override { return false; } rtx expand (function_expander &e) const override @@ -1223,9 +1219,15 @@ public: } }; +template class vfwmacc : public function_base { public: + bool has_rounding_mode_operand_p () const override + { + return FRM_OP == HAS_FRM; + } + bool has_merge_operand_p () const override { return false; } rtx expand (function_expander &e) const override @@ -1240,9 +1242,15 @@ public: } }; +template class vfwnmacc : public function_base { public: + bool has_rounding_mode_operand_p () const override + { + return FRM_OP == HAS_FRM; + } + bool has_merge_operand_p () const override { return false; } rtx expand (function_expander &e) const override @@ -1257,9 +1265,15 @@ public: } }; +template class vfwmsac : public function_base { public: + bool has_rounding_mode_operand_p () const override + { + return FRM_OP == HAS_FRM; + } + bool has_merge_operand_p () const override { return false; } rtx expand (function_expander &e) const override @@ -1274,9 +1288,15 @@ public: } }; +template class vfwnmsac : public function_base { public: + bool has_rounding_mode_operand_p () const override + { + return FRM_OP == HAS_FRM; + } + bool has_merge_operand_p () const override { return false; } rtx expand (function_expander &e) const override @@ -1292,10 +1312,15 @@ public: }; /* Implements vfsqrt7/vfrec7/vfclass/vfsgnj/vfsgnjx. */ -template +template class float_misc : public function_base { public: + bool has_rounding_mode_operand_p () const override + { + return FRM_OP == HAS_FRM; + } + rtx expand (function_expander &e) const override { if (e.op_info->op == OP_TYPE_vf) @@ -1358,10 +1383,15 @@ public: }; /* Implements vfcvt.x. */ -template +template class vfcvt_x : public function_base { public: + bool has_rounding_mode_operand_p () const override + { + return FRM_OP == HAS_FRM; + } + rtx expand (function_expander &e) const override { return e.use_exact_insn (code_for_pred_fcvt_x_f (UNSPEC, e.arg_mode (0))); @@ -1379,9 +1409,15 @@ public: } }; +template class vfcvt_f : public function_base { public: + bool has_rounding_mode_operand_p () const override + { + return FRM_OP == HAS_FRM; + } + rtx expand (function_expander &e) const override { if (e.op_info->op == OP_TYPE_x_v) @@ -1394,10 +1430,15 @@ public: }; /* Implements vfwcvt.x. */ -template +template class vfwcvt_x : public function_base { public: + bool has_rounding_mode_operand_p () const override + { + return FRM_OP == HAS_FRM; + } + rtx expand (function_expander &e) const override { return e.use_exact_insn ( @@ -1433,10 +1474,15 @@ public: }; /* Implements vfncvt.x. */ -template +template class vfncvt_x : public function_base { public: + bool has_rounding_mode_operand_p () const override + { + return FRM_OP == HAS_FRM; + } + rtx expand (function_expander &e) const override { return e.use_exact_insn ( @@ -1455,9 +1501,15 @@ public: } }; +template class vfncvt_f : public function_base { public: + bool has_rounding_mode_operand_p () const override + { + return FRM_OP == HAS_FRM; + } + rtx expand (function_expander &e) const override { if (e.op_info->op == OP_TYPE_f_w) @@ -1510,10 +1562,15 @@ public: }; /* Implements floating-point reduction instructions. */ -template +template class freducop : public function_base { public: + bool has_rounding_mode_operand_p () const override + { + return FRM_OP == HAS_FRM; + } + bool apply_mask_policy_p () const override { return false; } rtx expand (function_expander &e) const override @@ -1524,10 +1581,15 @@ public: }; /* Implements widening floating-point reduction instructions. */ -template +template class widen_freducop : public function_base { public: + bool has_rounding_mode_operand_p () const override + { + return FRM_OP == HAS_FRM; + } + bool apply_mask_policy_p () const override { return false; } rtx expand (function_expander &e) const override @@ -2099,37 +2161,51 @@ static CONSTEXPR const viota viota_obj; static CONSTEXPR const vid vid_obj; static CONSTEXPR const binop vfadd_obj; static CONSTEXPR const binop vfsub_obj; -static CONSTEXPR const binop_frm vfadd_frm_obj; -static CONSTEXPR const binop_frm vfsub_frm_obj; +static CONSTEXPR const binop vfadd_frm_obj; +static CONSTEXPR const binop vfsub_frm_obj; static CONSTEXPR const reverse_binop vfrsub_obj; -static CONSTEXPR const reverse_binop_frm vfrsub_frm_obj; -static CONSTEXPR const widen_binop vfwadd_obj; -static CONSTEXPR const widen_binop_frm vfwadd_frm_obj; -static CONSTEXPR const widen_binop vfwsub_obj; -static CONSTEXPR const widen_binop_frm vfwsub_frm_obj; +static CONSTEXPR const reverse_binop vfrsub_frm_obj; +static CONSTEXPR const widen_binop_fp vfwadd_obj; +static CONSTEXPR const widen_binop_fp vfwadd_frm_obj; +static CONSTEXPR const widen_binop_fp vfwsub_obj; +static CONSTEXPR const widen_binop_fp vfwsub_frm_obj; static CONSTEXPR const binop vfmul_obj; -static CONSTEXPR const binop_frm vfmul_frm_obj; +static CONSTEXPR const binop vfmul_frm_obj; static CONSTEXPR const binop
vfdiv_obj; -static CONSTEXPR const binop_frm
vfdiv_frm_obj; +static CONSTEXPR const binop vfdiv_frm_obj; static CONSTEXPR const reverse_binop
vfrdiv_obj; -static CONSTEXPR const reverse_binop_frm
vfrdiv_frm_obj; -static CONSTEXPR const widen_binop vfwmul_obj; -static CONSTEXPR const widen_binop_frm vfwmul_frm_obj; -static CONSTEXPR const vfmacc vfmacc_obj; -static CONSTEXPR const vfnmsac vfnmsac_obj; -static CONSTEXPR const vfmadd vfmadd_obj; -static CONSTEXPR const vfnmsub vfnmsub_obj; -static CONSTEXPR const vfnmacc vfnmacc_obj; -static CONSTEXPR const vfmsac vfmsac_obj; -static CONSTEXPR const vfnmadd vfnmadd_obj; -static CONSTEXPR const vfmsub vfmsub_obj; -static CONSTEXPR const vfwmacc vfwmacc_obj; -static CONSTEXPR const vfwnmacc vfwnmacc_obj; -static CONSTEXPR const vfwmsac vfwmsac_obj; -static CONSTEXPR const vfwnmsac vfwnmsac_obj; +static CONSTEXPR const reverse_binop vfrdiv_frm_obj; +static CONSTEXPR const widen_binop_fp vfwmul_obj; +static CONSTEXPR const widen_binop_fp vfwmul_frm_obj; +static CONSTEXPR const vfmacc vfmacc_obj; +static CONSTEXPR const vfmacc vfmacc_frm_obj; +static CONSTEXPR const vfnmsac vfnmsac_obj; +static CONSTEXPR const vfnmsac vfnmsac_frm_obj; +static CONSTEXPR const vfmadd vfmadd_obj; +static CONSTEXPR const vfmadd vfmadd_frm_obj; +static CONSTEXPR const vfnmsub vfnmsub_obj; +static CONSTEXPR const vfnmsub vfnmsub_frm_obj; +static CONSTEXPR const vfnmacc vfnmacc_obj; +static CONSTEXPR const vfnmacc vfnmacc_frm_obj; +static CONSTEXPR const vfmsac vfmsac_obj; +static CONSTEXPR const vfmsac vfmsac_frm_obj; +static CONSTEXPR const vfnmadd vfnmadd_obj; +static CONSTEXPR const vfnmadd vfnmadd_frm_obj; +static CONSTEXPR const vfmsub vfmsub_obj; +static CONSTEXPR const vfmsub vfmsub_frm_obj; +static CONSTEXPR const vfwmacc vfwmacc_obj; +static CONSTEXPR const vfwmacc vfwmacc_frm_obj; +static CONSTEXPR const vfwnmacc vfwnmacc_obj; +static CONSTEXPR const vfwnmacc vfwnmacc_frm_obj; +static CONSTEXPR const vfwmsac vfwmsac_obj; +static CONSTEXPR const vfwmsac vfwmsac_frm_obj; +static CONSTEXPR const vfwnmsac vfwnmsac_obj; +static CONSTEXPR const vfwnmsac vfwnmsac_frm_obj; static CONSTEXPR const unop vfsqrt_obj; +static CONSTEXPR const unop vfsqrt_frm_obj; static CONSTEXPR const float_misc vfrsqrt7_obj; static CONSTEXPR const float_misc vfrec7_obj; +static CONSTEXPR const float_misc vfrec7_frm_obj; static CONSTEXPR const binop vfmin_obj; static CONSTEXPR const binop vfmax_obj; static CONSTEXPR const float_misc vfsgnj_obj; @@ -2147,20 +2223,28 @@ static CONSTEXPR const vfclass vfclass_obj; static CONSTEXPR const vmerge vfmerge_obj; static CONSTEXPR const vmv_v vfmv_v_obj; static CONSTEXPR const vfcvt_x vfcvt_x_obj; +static CONSTEXPR const vfcvt_x vfcvt_x_frm_obj; static CONSTEXPR const vfcvt_x vfcvt_xu_obj; +static CONSTEXPR const vfcvt_x vfcvt_xu_frm_obj; static CONSTEXPR const vfcvt_rtz_x vfcvt_rtz_x_obj; static CONSTEXPR const vfcvt_rtz_x vfcvt_rtz_xu_obj; -static CONSTEXPR const vfcvt_f vfcvt_f_obj; +static CONSTEXPR const vfcvt_f vfcvt_f_obj; +static CONSTEXPR const vfcvt_f vfcvt_f_frm_obj; static CONSTEXPR const vfwcvt_x vfwcvt_x_obj; +static CONSTEXPR const vfwcvt_x vfwcvt_x_frm_obj; static CONSTEXPR const vfwcvt_x vfwcvt_xu_obj; +static CONSTEXPR const vfwcvt_x vfwcvt_xu_frm_obj; static CONSTEXPR const vfwcvt_rtz_x vfwcvt_rtz_x_obj; static CONSTEXPR const vfwcvt_rtz_x vfwcvt_rtz_xu_obj; static CONSTEXPR const vfwcvt_f vfwcvt_f_obj; static CONSTEXPR const vfncvt_x vfncvt_x_obj; +static CONSTEXPR const vfncvt_x vfncvt_x_frm_obj; static CONSTEXPR const vfncvt_x vfncvt_xu_obj; +static CONSTEXPR const vfncvt_x vfncvt_xu_frm_obj; static CONSTEXPR const vfncvt_rtz_x vfncvt_rtz_x_obj; static CONSTEXPR const vfncvt_rtz_x vfncvt_rtz_xu_obj; -static CONSTEXPR const vfncvt_f vfncvt_f_obj; +static CONSTEXPR const vfncvt_f vfncvt_f_obj; +static CONSTEXPR const vfncvt_f vfncvt_f_frm_obj; static CONSTEXPR const vfncvt_rod_f vfncvt_rod_f_obj; static CONSTEXPR const reducop vredsum_obj; static CONSTEXPR const reducop vredmaxu_obj; @@ -2173,11 +2257,15 @@ static CONSTEXPR const reducop vredxor_obj; static CONSTEXPR const widen_reducop vwredsum_obj; static CONSTEXPR const widen_reducop vwredsumu_obj; static CONSTEXPR const freducop vfredusum_obj; +static CONSTEXPR const freducop vfredusum_frm_obj; static CONSTEXPR const freducop vfredosum_obj; +static CONSTEXPR const freducop vfredosum_frm_obj; static CONSTEXPR const reducop vfredmax_obj; static CONSTEXPR const reducop vfredmin_obj; static CONSTEXPR const widen_freducop vfwredusum_obj; +static CONSTEXPR const widen_freducop vfwredusum_frm_obj; static CONSTEXPR const widen_freducop vfwredosum_obj; +static CONSTEXPR const widen_freducop vfwredosum_frm_obj; static CONSTEXPR const vmv vmv_x_obj; static CONSTEXPR const vmv_s vmv_s_obj; static CONSTEXPR const vmv vfmv_f_obj; @@ -2351,20 +2439,34 @@ BASE (vfrdiv_frm) BASE (vfwmul) BASE (vfwmul_frm) BASE (vfmacc) +BASE (vfmacc_frm) BASE (vfnmsac) +BASE (vfnmsac_frm) BASE (vfmadd) +BASE (vfmadd_frm) BASE (vfnmsub) +BASE (vfnmsub_frm) BASE (vfnmacc) +BASE (vfnmacc_frm) BASE (vfmsac) +BASE (vfmsac_frm) BASE (vfnmadd) +BASE (vfnmadd_frm) BASE (vfmsub) +BASE (vfmsub_frm) BASE (vfwmacc) +BASE (vfwmacc_frm) BASE (vfwnmacc) +BASE (vfwnmacc_frm) BASE (vfwmsac) +BASE (vfwmsac_frm) BASE (vfwnmsac) +BASE (vfwnmsac_frm) BASE (vfsqrt) +BASE (vfsqrt_frm) BASE (vfrsqrt7) BASE (vfrec7) +BASE (vfrec7_frm) BASE (vfmin) BASE (vfmax) BASE (vfsgnj) @@ -2382,20 +2484,28 @@ BASE (vfclass) BASE (vfmerge) BASE (vfmv_v) BASE (vfcvt_x) +BASE (vfcvt_x_frm) BASE (vfcvt_xu) +BASE (vfcvt_xu_frm) BASE (vfcvt_rtz_x) BASE (vfcvt_rtz_xu) BASE (vfcvt_f) +BASE (vfcvt_f_frm) BASE (vfwcvt_x) +BASE (vfwcvt_x_frm) BASE (vfwcvt_xu) +BASE (vfwcvt_xu_frm) BASE (vfwcvt_rtz_x) BASE (vfwcvt_rtz_xu) BASE (vfwcvt_f) BASE (vfncvt_x) +BASE (vfncvt_x_frm) BASE (vfncvt_xu) +BASE (vfncvt_xu_frm) BASE (vfncvt_rtz_x) BASE (vfncvt_rtz_xu) BASE (vfncvt_f) +BASE (vfncvt_f_frm) BASE (vfncvt_rod_f) BASE (vredsum) BASE (vredmaxu) @@ -2408,11 +2518,15 @@ BASE (vredxor) BASE (vwredsum) BASE (vwredsumu) BASE (vfredusum) +BASE (vfredusum_frm) BASE (vfredosum) +BASE (vfredosum_frm) BASE (vfredmax) BASE (vfredmin) BASE (vfwredosum) +BASE (vfwredosum_frm) BASE (vfwredusum) +BASE (vfwredusum_frm) BASE (vmv_x) BASE (vmv_s) BASE (vfmv_f) diff --git a/gcc/config/riscv/riscv-vector-builtins-bases.h b/gcc/config/riscv/riscv-vector-builtins-bases.h index 2d2b52a312c7..69d4562091f0 100644 --- a/gcc/config/riscv/riscv-vector-builtins-bases.h +++ b/gcc/config/riscv/riscv-vector-builtins-bases.h @@ -160,20 +160,34 @@ extern const function_base *const vfrdiv_frm; extern const function_base *const vfwmul; extern const function_base *const vfwmul_frm; extern const function_base *const vfmacc; +extern const function_base *const vfmacc_frm; extern const function_base *const vfnmsac; +extern const function_base *const vfnmsac_frm; extern const function_base *const vfmadd; +extern const function_base *const vfmadd_frm; extern const function_base *const vfnmsub; +extern const function_base *const vfnmsub_frm; extern const function_base *const vfnmacc; +extern const function_base *const vfnmacc_frm; extern const function_base *const vfmsac; +extern const function_base *const vfmsac_frm; extern const function_base *const vfnmadd; +extern const function_base *const vfnmadd_frm; extern const function_base *const vfmsub; +extern const function_base *const vfmsub_frm; extern const function_base *const vfwmacc; +extern const function_base *const vfwmacc_frm; extern const function_base *const vfwnmacc; +extern const function_base *const vfwnmacc_frm; extern const function_base *const vfwmsac; +extern const function_base *const vfwmsac_frm; extern const function_base *const vfwnmsac; +extern const function_base *const vfwnmsac_frm; extern const function_base *const vfsqrt; +extern const function_base *const vfsqrt_frm; extern const function_base *const vfrsqrt7; extern const function_base *const vfrec7; +extern const function_base *const vfrec7_frm; extern const function_base *const vfmin; extern const function_base *const vfmax; extern const function_base *const vfsgnj; @@ -191,20 +205,28 @@ extern const function_base *const vfclass; extern const function_base *const vfmerge; extern const function_base *const vfmv_v; extern const function_base *const vfcvt_x; +extern const function_base *const vfcvt_x_frm; extern const function_base *const vfcvt_xu; +extern const function_base *const vfcvt_xu_frm; extern const function_base *const vfcvt_rtz_x; extern const function_base *const vfcvt_rtz_xu; extern const function_base *const vfcvt_f; +extern const function_base *const vfcvt_f_frm; extern const function_base *const vfwcvt_x; +extern const function_base *const vfwcvt_x_frm; extern const function_base *const vfwcvt_xu; +extern const function_base *const vfwcvt_xu_frm; extern const function_base *const vfwcvt_rtz_x; extern const function_base *const vfwcvt_rtz_xu; extern const function_base *const vfwcvt_f; extern const function_base *const vfncvt_x; +extern const function_base *const vfncvt_x_frm; extern const function_base *const vfncvt_xu; +extern const function_base *const vfncvt_xu_frm; extern const function_base *const vfncvt_rtz_x; extern const function_base *const vfncvt_rtz_xu; extern const function_base *const vfncvt_f; +extern const function_base *const vfncvt_f_frm; extern const function_base *const vfncvt_rod_f; extern const function_base *const vredsum; extern const function_base *const vredmaxu; @@ -217,11 +239,15 @@ extern const function_base *const vredxor; extern const function_base *const vwredsum; extern const function_base *const vwredsumu; extern const function_base *const vfredusum; +extern const function_base *const vfredusum_frm; extern const function_base *const vfredosum; +extern const function_base *const vfredosum_frm; extern const function_base *const vfredmax; extern const function_base *const vfredmin; extern const function_base *const vfwredosum; +extern const function_base *const vfwredosum_frm; extern const function_base *const vfwredusum; +extern const function_base *const vfwredusum_frm; extern const function_base *const vmv_x; extern const function_base *const vmv_s; extern const function_base *const vfmv_f; diff --git a/gcc/config/riscv/riscv-vector-builtins-functions.def b/gcc/config/riscv/riscv-vector-builtins-functions.def index d43b33ded17a..3ce06dc60b75 100644 --- a/gcc/config/riscv/riscv-vector-builtins-functions.def +++ b/gcc/config/riscv/riscv-vector-builtins-functions.def @@ -349,6 +349,23 @@ DEF_RVV_FUNCTION (vfnmadd, alu, full_preds, f_vvfv_ops) DEF_RVV_FUNCTION (vfmsub, alu, full_preds, f_vvvv_ops) DEF_RVV_FUNCTION (vfmsub, alu, full_preds, f_vvfv_ops) +DEF_RVV_FUNCTION (vfmacc_frm, alu_frm, full_preds, f_vvvv_ops) +DEF_RVV_FUNCTION (vfmacc_frm, alu_frm, full_preds, f_vvfv_ops) +DEF_RVV_FUNCTION (vfnmacc_frm, alu_frm, full_preds, f_vvvv_ops) +DEF_RVV_FUNCTION (vfnmacc_frm, alu_frm, full_preds, f_vvfv_ops) +DEF_RVV_FUNCTION (vfmsac_frm, alu_frm, full_preds, f_vvvv_ops) +DEF_RVV_FUNCTION (vfmsac_frm, alu_frm, full_preds, f_vvfv_ops) +DEF_RVV_FUNCTION (vfnmsac_frm, alu_frm, full_preds, f_vvvv_ops) +DEF_RVV_FUNCTION (vfnmsac_frm, alu_frm, full_preds, f_vvfv_ops) +DEF_RVV_FUNCTION (vfmadd_frm, alu_frm, full_preds, f_vvvv_ops) +DEF_RVV_FUNCTION (vfmadd_frm, alu_frm, full_preds, f_vvfv_ops) +DEF_RVV_FUNCTION (vfnmadd_frm, alu_frm, full_preds, f_vvvv_ops) +DEF_RVV_FUNCTION (vfnmadd_frm, alu_frm, full_preds, f_vvfv_ops) +DEF_RVV_FUNCTION (vfmsub_frm, alu_frm, full_preds, f_vvvv_ops) +DEF_RVV_FUNCTION (vfmsub_frm, alu_frm, full_preds, f_vvfv_ops) +DEF_RVV_FUNCTION (vfnmsub_frm, alu_frm, full_preds, f_vvvv_ops) +DEF_RVV_FUNCTION (vfnmsub_frm, alu_frm, full_preds, f_vvfv_ops) + // 13.7. Vector Widening Floating-Point Fused Multiply-Add Instructions DEF_RVV_FUNCTION (vfwmacc, alu, full_preds, f_wwvv_ops) DEF_RVV_FUNCTION (vfwmacc, alu, full_preds, f_wwfv_ops) @@ -359,15 +376,28 @@ DEF_RVV_FUNCTION (vfwmsac, alu, full_preds, f_wwfv_ops) DEF_RVV_FUNCTION (vfwnmsac, alu, full_preds, f_wwvv_ops) DEF_RVV_FUNCTION (vfwnmsac, alu, full_preds, f_wwfv_ops) +DEF_RVV_FUNCTION (vfwmacc_frm, alu_frm, full_preds, f_wwvv_ops) +DEF_RVV_FUNCTION (vfwmacc_frm, alu_frm, full_preds, f_wwfv_ops) +DEF_RVV_FUNCTION (vfwnmacc_frm, alu_frm, full_preds, f_wwvv_ops) +DEF_RVV_FUNCTION (vfwnmacc_frm, alu_frm, full_preds, f_wwfv_ops) +DEF_RVV_FUNCTION (vfwmsac_frm, alu_frm, full_preds, f_wwvv_ops) +DEF_RVV_FUNCTION (vfwmsac_frm, alu_frm, full_preds, f_wwfv_ops) +DEF_RVV_FUNCTION (vfwnmsac_frm, alu_frm, full_preds, f_wwvv_ops) +DEF_RVV_FUNCTION (vfwnmsac_frm, alu_frm, full_preds, f_wwfv_ops) + // 13.8. Vector Floating-Point Square-Root Instruction DEF_RVV_FUNCTION (vfsqrt, alu, full_preds, f_v_ops) +DEF_RVV_FUNCTION (vfsqrt_frm, alu_frm, full_preds, f_v_ops) + // 13.9. Vector Floating-Point Reciprocal Square-Root Estimate Instruction DEF_RVV_FUNCTION (vfrsqrt7, alu, full_preds, f_v_ops) // 13.10. Vector Floating-Point Reciprocal Estimate Instruction DEF_RVV_FUNCTION (vfrec7, alu, full_preds, f_v_ops) +DEF_RVV_FUNCTION (vfrec7_frm, alu_frm, full_preds, f_v_ops) + // 13.11. Vector Floating-Point MIN/MAX Instructions DEF_RVV_FUNCTION (vfmin, alu, full_preds, f_vvv_ops) DEF_RVV_FUNCTION (vfmin, alu, full_preds, f_vvf_ops) @@ -415,6 +445,11 @@ DEF_RVV_FUNCTION (vfcvt_rtz_xu, alu, full_preds, f_to_u_f_v_ops) DEF_RVV_FUNCTION (vfcvt_f, alu, full_preds, i_to_f_x_v_ops) DEF_RVV_FUNCTION (vfcvt_f, alu, full_preds, u_to_f_xu_v_ops) +DEF_RVV_FUNCTION (vfcvt_x_frm, alu_frm, full_preds, f_to_i_f_v_ops) +DEF_RVV_FUNCTION (vfcvt_xu_frm, alu_frm, full_preds, f_to_u_f_v_ops) +DEF_RVV_FUNCTION (vfcvt_f_frm, alu_frm, full_preds, i_to_f_x_v_ops) +DEF_RVV_FUNCTION (vfcvt_f_frm, alu_frm, full_preds, u_to_f_xu_v_ops) + // 13.18. Widening Floating-Point/Integer Type-Convert Instructions DEF_RVV_FUNCTION (vfwcvt_x, alu, full_preds, f_to_wi_f_v_ops) DEF_RVV_FUNCTION (vfwcvt_xu, alu, full_preds, f_to_wu_f_v_ops) @@ -424,6 +459,9 @@ DEF_RVV_FUNCTION (vfwcvt_f, alu, full_preds, i_to_wf_x_v_ops) DEF_RVV_FUNCTION (vfwcvt_f, alu, full_preds, u_to_wf_xu_v_ops) DEF_RVV_FUNCTION (vfwcvt_f, alu, full_preds, f_to_wf_f_v_ops) +DEF_RVV_FUNCTION (vfwcvt_x_frm, alu_frm, full_preds, f_to_wi_f_v_ops) +DEF_RVV_FUNCTION (vfwcvt_xu_frm, alu_frm, full_preds, f_to_wu_f_v_ops) + // 13.19. Narrowing Floating-Point/Integer Type-Convert Instructions DEF_RVV_FUNCTION (vfncvt_x, narrow_alu, full_preds, f_to_ni_f_w_ops) DEF_RVV_FUNCTION (vfncvt_xu, narrow_alu, full_preds, f_to_nu_f_w_ops) @@ -434,6 +472,12 @@ DEF_RVV_FUNCTION (vfncvt_f, narrow_alu, full_preds, u_to_nf_xu_w_ops) DEF_RVV_FUNCTION (vfncvt_f, narrow_alu, full_preds, f_to_nf_f_w_ops) DEF_RVV_FUNCTION (vfncvt_rod_f, narrow_alu, full_preds, f_to_nf_f_w_ops) +DEF_RVV_FUNCTION (vfncvt_x_frm, narrow_alu_frm, full_preds, f_to_ni_f_w_ops) +DEF_RVV_FUNCTION (vfncvt_xu_frm, narrow_alu_frm, full_preds, f_to_nu_f_w_ops) +DEF_RVV_FUNCTION (vfncvt_f_frm, narrow_alu_frm, full_preds, i_to_nf_x_w_ops) +DEF_RVV_FUNCTION (vfncvt_f_frm, narrow_alu_frm, full_preds, u_to_nf_xu_w_ops) +DEF_RVV_FUNCTION (vfncvt_f_frm, narrow_alu_frm, full_preds, f_to_nf_f_w_ops) + /* 14. Vector Reduction Operations. */ // 14.1. Vector Single-Width Integer Reduction Instructions @@ -456,10 +500,16 @@ DEF_RVV_FUNCTION (vfredosum, reduc_alu, no_mu_preds, f_vs_ops) DEF_RVV_FUNCTION (vfredmax, reduc_alu, no_mu_preds, f_vs_ops) DEF_RVV_FUNCTION (vfredmin, reduc_alu, no_mu_preds, f_vs_ops) +DEF_RVV_FUNCTION (vfredusum_frm, reduc_alu_frm, no_mu_preds, f_vs_ops) +DEF_RVV_FUNCTION (vfredosum_frm, reduc_alu_frm, no_mu_preds, f_vs_ops) + // 14.4. Vector Widening Floating-Point Reduction Instructions DEF_RVV_FUNCTION (vfwredosum, reduc_alu, no_mu_preds, wf_vs_ops) DEF_RVV_FUNCTION (vfwredusum, reduc_alu, no_mu_preds, wf_vs_ops) +DEF_RVV_FUNCTION (vfwredosum_frm, reduc_alu_frm, no_mu_preds, wf_vs_ops) +DEF_RVV_FUNCTION (vfwredusum_frm, reduc_alu_frm, no_mu_preds, wf_vs_ops) + /* 15. Vector Mask Instructions. */ // 15.1. Vector Mask-Register Logical Instructions diff --git a/gcc/config/riscv/riscv-vector-builtins-shapes.cc b/gcc/config/riscv/riscv-vector-builtins-shapes.cc index 1d14fa21e81c..f8fdec863e6f 100644 --- a/gcc/config/riscv/riscv-vector-builtins-shapes.cc +++ b/gcc/config/riscv/riscv-vector-builtins-shapes.cc @@ -333,6 +333,82 @@ struct widen_alu_frm_def : public build_frm_base } }; +/* narrow_alu_frm_def class. */ +struct narrow_alu_frm_def : public build_frm_base +{ + char *get_name (function_builder &b, const function_instance &instance, + bool overloaded_p) const override + { + char base_name[BASE_NAME_MAX_LEN] = {}; + + normalize_base_name (base_name, instance.base_name, sizeof (base_name)); + + b.append_base_name (base_name); + + if (!overloaded_p) + { + /* vop --> vop_. */ + b.append_name (operand_suffixes[instance.op_info->op]); + /* vop_ --> vop__. */ + vector_type_index ret_type_idx + = instance.op_info->ret.get_function_type_index (instance.type.index); + b.append_name (type_suffixes[ret_type_idx].vector); + } + + /* According to rvv-intrinsic-doc, it does not add "_rm" suffix + for vop_rm C++ overloaded API. */ + if (!overloaded_p) + b.append_name ("_rm"); + + /* According to rvv-intrinsic-doc, it does not add "_m" suffix + for vop_m C++ overloaded API. */ + if (overloaded_p && instance.pred == PRED_TYPE_m) + return b.finish_name (); + + b.append_name (predication_suffixes[instance.pred]); + + return b.finish_name (); + } +}; + +/* reduc_alu_frm_def class. */ +struct reduc_alu_frm_def : public build_frm_base +{ + char *get_name (function_builder &b, const function_instance &instance, + bool overloaded_p) const override + { + char base_name[BASE_NAME_MAX_LEN] = {}; + + normalize_base_name (base_name, instance.base_name, sizeof (base_name)); + + b.append_base_name (base_name); + + /* vop_ --> vop__. */ + if (!overloaded_p) + { + b.append_name (operand_suffixes[instance.op_info->op]); + b.append_name (type_suffixes[instance.type.index].vector); + vector_type_index ret_type_idx + = instance.op_info->ret.get_function_type_index (instance.type.index); + b.append_name (type_suffixes[ret_type_idx].vector); + } + + /* According to rvv-intrinsic-doc, it does not add "_rm" suffix + for vop_rm C++ overloaded API. */ + if (!overloaded_p) + b.append_name ("_rm"); + + /* According to rvv-intrinsic-doc, it does not add "_m" suffix + for vop_m C++ overloaded API. */ + if (overloaded_p && instance.pred == PRED_TYPE_m) + return b.finish_name (); + + b.append_name (predication_suffixes[instance.pred]); + + return b.finish_name (); + } +}; + /* widen_alu_def class. Handle vwadd/vwsub. Unlike vadd.vx/vadd.vv/vwmul.vv/vwmul.vx, vwadd.vv/vwadd.vx/vwadd.wv/vwadd.wx has 'OP' suffix in overloaded API. */ @@ -856,9 +932,11 @@ SHAPE(widen_alu_frm, widen_alu_frm) SHAPE(no_mask_policy, no_mask_policy) SHAPE(return_mask, return_mask) SHAPE(narrow_alu, narrow_alu) +SHAPE(narrow_alu_frm, narrow_alu_frm) SHAPE(move, move) SHAPE(mask_alu, mask_alu) SHAPE(reduc_alu, reduc_alu) +SHAPE(reduc_alu_frm, reduc_alu_frm) SHAPE(scalar_move, scalar_move) SHAPE(vundefined, vundefined) SHAPE(misc, misc) diff --git a/gcc/config/riscv/riscv-vector-builtins-shapes.h b/gcc/config/riscv/riscv-vector-builtins-shapes.h index 841b930b5475..92eb8bc9d71d 100644 --- a/gcc/config/riscv/riscv-vector-builtins-shapes.h +++ b/gcc/config/riscv/riscv-vector-builtins-shapes.h @@ -35,9 +35,11 @@ extern const function_shape *const widen_alu_frm; extern const function_shape *const no_mask_policy; extern const function_shape *const return_mask; extern const function_shape *const narrow_alu; +extern const function_shape *const narrow_alu_frm; extern const function_shape *const move; extern const function_shape *const mask_alu; extern const function_shape *const reduc_alu; +extern const function_shape *const reduc_alu_frm; extern const function_shape *const scalar_move; extern const function_shape *const vundefined; extern const function_shape *const misc; diff --git a/gcc/config/riscv/riscv-vector-builtins-types.def b/gcc/config/riscv/riscv-vector-builtins-types.def index 1c3cc0eb222d..6aa45ae9a7e5 100644 --- a/gcc/config/riscv/riscv-vector-builtins-types.def +++ b/gcc/config/riscv/riscv-vector-builtins-types.def @@ -689,11 +689,20 @@ DEF_RVV_EI16_OPS (vuint64m1_t, RVV_REQUIRE_ELEN_64) DEF_RVV_EI16_OPS (vuint64m2_t, RVV_REQUIRE_ELEN_64) DEF_RVV_EI16_OPS (vuint64m4_t, RVV_REQUIRE_ELEN_64) DEF_RVV_EI16_OPS (vuint64m8_t, RVV_REQUIRE_ELEN_64) + +DEF_RVV_EI16_OPS (vfloat16mf4_t, RVV_REQUIRE_ELEN_FP_16 | RVV_REQUIRE_MIN_VLEN_64) +DEF_RVV_EI16_OPS (vfloat16mf2_t, RVV_REQUIRE_ELEN_FP_16) +DEF_RVV_EI16_OPS (vfloat16m1_t, RVV_REQUIRE_ELEN_FP_16) +DEF_RVV_EI16_OPS (vfloat16m2_t, RVV_REQUIRE_ELEN_FP_16) +DEF_RVV_EI16_OPS (vfloat16m4_t, RVV_REQUIRE_ELEN_FP_16) +DEF_RVV_EI16_OPS (vfloat16m8_t, RVV_REQUIRE_ELEN_FP_16) + DEF_RVV_EI16_OPS (vfloat32mf2_t, RVV_REQUIRE_ELEN_FP_32 | RVV_REQUIRE_MIN_VLEN_64) DEF_RVV_EI16_OPS (vfloat32m1_t, RVV_REQUIRE_ELEN_FP_32) DEF_RVV_EI16_OPS (vfloat32m2_t, RVV_REQUIRE_ELEN_FP_32) DEF_RVV_EI16_OPS (vfloat32m4_t, RVV_REQUIRE_ELEN_FP_32) DEF_RVV_EI16_OPS (vfloat32m8_t, RVV_REQUIRE_ELEN_FP_32) + DEF_RVV_EI16_OPS (vfloat64m1_t, RVV_REQUIRE_ELEN_FP_64) DEF_RVV_EI16_OPS (vfloat64m2_t, RVV_REQUIRE_ELEN_FP_64) DEF_RVV_EI16_OPS (vfloat64m4_t, RVV_REQUIRE_ELEN_FP_64) diff --git a/gcc/config/riscv/riscv-vector-builtins.cc b/gcc/config/riscv/riscv-vector-builtins.cc index 528dca7ae855..4a7eb47972e7 100644 --- a/gcc/config/riscv/riscv-vector-builtins.cc +++ b/gcc/config/riscv/riscv-vector-builtins.cc @@ -3471,7 +3471,14 @@ function_expander::function_expander (const function_instance &instance, exp (exp_in), target (target_in), opno (0) { if (!function_returns_void_p ()) - create_output_operand (&m_ops[opno++], target, TYPE_MODE (TREE_TYPE (exp))); + { + if (target != NULL_RTX && MEM_P (target)) + /* Since there is no intrinsic where target is a mem operand, it + should be converted to reg if it is a mem operand. */ + target = force_reg (GET_MODE (target), target); + create_output_operand (&m_ops[opno++], target, + TYPE_MODE (TREE_TYPE (exp))); + } } /* Take argument ARGNO from EXP's argument list and convert it into @@ -3730,17 +3737,29 @@ function_expander::use_ternop_insn (bool vd_accum_p, insn_code icode) } for (int argno = arg_offset; argno < call_expr_nargs (exp); argno++) - add_input_operand (argno); + { + if (base->has_rounding_mode_operand_p () + && argno == call_expr_nargs (exp) - 2) + { + /* Since the rounding mode argument position is not consistent with + the instruction pattern, we need to skip rounding mode argument + here. */ + continue; + } + add_input_operand (argno); + } add_input_operand (Pmode, get_tail_policy_for_pred (pred)); add_input_operand (Pmode, get_mask_policy_for_pred (pred)); add_input_operand (Pmode, get_avl_type_rtx (avl_type::NONVLMAX)); - /* TODO: Currently, we don't support intrinsic that is modeling rounding mode. - We add default rounding mode for the intrinsics that didn't model rounding - mode yet. */ + if (base->has_rounding_mode_operand_p ()) + add_input_operand (call_expr_nargs (exp) - 2); + + /* The RVV floating-point only support dynamic rounding mode in the + FRM register. */ if (opno != insn_data[icode].n_generator_args) - add_input_operand (Pmode, const0_rtx); + add_input_operand (Pmode, gen_int_mode (riscv_vector::FRM_DYN, Pmode)); return generate_insn (icode); } @@ -3759,17 +3778,29 @@ function_expander::use_widen_ternop_insn (insn_code icode) add_all_one_mask_operand (mask_mode ()); for (int argno = arg_offset; argno < call_expr_nargs (exp); argno++) - add_input_operand (argno); + { + if (base->has_rounding_mode_operand_p () + && argno == call_expr_nargs (exp) - 2) + { + /* Since the rounding mode argument position is not consistent with + the instruction pattern, we need to skip rounding mode argument + here. */ + continue; + } + add_input_operand (argno); + } add_input_operand (Pmode, get_tail_policy_for_pred (pred)); add_input_operand (Pmode, get_mask_policy_for_pred (pred)); add_input_operand (Pmode, get_avl_type_rtx (avl_type::NONVLMAX)); - /* TODO: Currently, we don't support intrinsic that is modeling rounding mode. - We add default rounding mode for the intrinsics that didn't model rounding - mode yet. */ + if (base->has_rounding_mode_operand_p ()) + add_input_operand (call_expr_nargs (exp) - 2); + + /* The RVV floating-point only support dynamic rounding mode in the + FRM register. */ if (opno != insn_data[icode].n_generator_args) - add_input_operand (Pmode, const0_rtx); + add_input_operand (Pmode, gen_int_mode (riscv_vector::FRM_DYN, Pmode)); return generate_insn (icode); } diff --git a/gcc/config/riscv/riscv-vector-costs.cc b/gcc/config/riscv/riscv-vector-costs.cc new file mode 100644 index 000000000000..1a5e13d5eb3b --- /dev/null +++ b/gcc/config/riscv/riscv-vector-costs.cc @@ -0,0 +1,66 @@ +/* Cost model implementation for RISC-V 'V' Extension for GNU compiler. + Copyright (C) 2023-2023 Free Software Foundation, Inc. + Contributed by Juzhe Zhong (juzhe.zhong@rivai.ai), RiVAI Technologies Ltd. + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 3, or (at your option) +any later version. + +GCC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +. */ + +#define IN_TARGET_CODE 1 + +#define INCLUDE_STRING +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "target.h" +#include "function.h" +#include "tree.h" +#include "basic-block.h" +#include "rtl.h" +#include "gimple.h" +#include "targhooks.h" +#include "cfgloop.h" +#include "fold-const.h" +#include "tm_p.h" +#include "tree-vectorizer.h" + +/* This file should be included last. */ +#include "riscv-vector-costs.h" + +namespace riscv_vector { + +costs::costs (vec_info *vinfo, bool costing_for_scalar) + : vector_costs (vinfo, costing_for_scalar) +{} + +unsigned +costs::add_stmt_cost (int count, vect_cost_for_stmt kind, + stmt_vec_info stmt_info, slp_tree, tree vectype, + int misalign, vect_cost_model_location where) +{ + /* TODO: Use default STMT cost model. + We will support more accurate STMT cost model later. */ + int stmt_cost = default_builtin_vectorization_cost (kind, vectype, misalign); + return record_stmt_cost (stmt_info, where, count * stmt_cost); +} + +void +costs::finish_cost (const vector_costs *scalar_costs) +{ + vector_costs::finish_cost (scalar_costs); +} + +} // namespace riscv_vector diff --git a/gcc/config/riscv/riscv-vector-costs.h b/gcc/config/riscv/riscv-vector-costs.h new file mode 100644 index 000000000000..57b1be010487 --- /dev/null +++ b/gcc/config/riscv/riscv-vector-costs.h @@ -0,0 +1,44 @@ +/* Cost model declaration of RISC-V 'V' Extension for GNU compiler. + Copyright (C) 2023-2023 Free Software Foundation, Inc. + Contributed by Juzhe Zhong (juzhe.zhong@rivai.ai), RiVAI Technologies Ltd. + + This file is part of GCC. + + GCC is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3, or (at your option) + any later version. + + GCC is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GCC; see the file COPYING3. If not see + . */ + +#ifndef GCC_RISCV_VECTOR_COST_H +#define GCC_RISCV_VECTOR_COST_H + +namespace riscv_vector { + +/* rvv-specific vector costs. */ +class costs : public vector_costs +{ + using vector_costs::vector_costs; + +public: + costs (vec_info *, bool); + +private: + unsigned int add_stmt_cost (int count, vect_cost_for_stmt kind, + stmt_vec_info stmt_info, slp_tree node, + tree vectype, int misalign, + vect_cost_model_location where) override; + void finish_cost (const vector_costs *) override; +}; + +} // namespace riscv_vector + +#endif // GCC_RISCV_VECTOR_COST_H diff --git a/gcc/config/riscv/riscv-vsetvl.cc b/gcc/config/riscv/riscv-vsetvl.cc index 628bf116db06..a81bb53a5218 100644 --- a/gcc/config/riscv/riscv-vsetvl.cc +++ b/gcc/config/riscv/riscv-vsetvl.cc @@ -43,8 +43,7 @@ along with GCC; see the file COPYING3. If not see - Phase 2 - Emit vsetvl instructions within each basic block according to demand, compute and save ANTLOC && AVLOC of each block. - - Phase 3 - Backward && forward demanded info propagation and fusion across - blocks. + - Phase 3 - LCM Earliest-edge baseed VSETVL demand fusion. - Phase 4 - Lazy code motion including: compute local properties, pre_edge_lcm and vsetvl insertion && delete edges for LCM results. @@ -53,7 +52,7 @@ along with GCC; see the file COPYING3. If not see used any more and VL operand of VSETVL instruction if it is not used by any non-debug instructions. - - Phase 6 - Propagate AVL between vsetvl instructions. + - Phase 6 - DF based post VSETVL optimizations. Implementation: @@ -240,6 +239,21 @@ vsetvl_discard_result_insn_p (rtx_insn *rinsn) || INSN_CODE (rinsn) == CODE_FOR_vsetvl_discard_resultsi); } +/* Return true if it is vsetvl zero, zero. */ +static bool +vsetvl_vtype_change_only_p (rtx_insn *rinsn) +{ + if (!vector_config_insn_p (rinsn)) + return false; + return (INSN_CODE (rinsn) == CODE_FOR_vsetvl_vtype_change_only); +} + +static bool +after_or_same_p (const insn_info *insn1, const insn_info *insn2) +{ + return insn1->compare_with (insn2) >= 0; +} + static bool real_insn_and_same_bb_p (const insn_info *insn, const bb_info *bb) { @@ -252,17 +266,6 @@ before_p (const insn_info *insn1, const insn_info *insn2) return insn1->compare_with (insn2) < 0; } -static insn_info * -find_reg_killed_by (const bb_info *bb, rtx x) -{ - if (!x || vlmax_avl_p (x) || !REG_P (x)) - return nullptr; - for (insn_info *insn : bb->reverse_real_nondebug_insns ()) - if (find_access (insn->defs (), REGNO (x))) - return insn; - return nullptr; -} - /* Helper function to get VL operand. */ static rtx get_vl (rtx_insn *rinsn) @@ -275,35 +278,6 @@ get_vl (rtx_insn *rinsn) return SET_DEST (XVECEXP (PATTERN (rinsn), 0, 0)); } -static bool -has_vsetvl_killed_avl_p (const bb_info *bb, const vector_insn_info &info) -{ - if (info.dirty_with_killed_avl_p ()) - { - rtx avl = info.get_avl (); - if (vlmax_avl_p (avl)) - return find_reg_killed_by (bb, info.get_avl_reg_rtx ()) != nullptr; - for (const insn_info *insn : bb->reverse_real_nondebug_insns ()) - { - def_info *def = find_access (insn->defs (), REGNO (avl)); - if (def) - { - set_info *set = safe_dyn_cast (def); - if (!set) - return false; - - rtx new_avl = gen_rtx_REG (GET_MODE (avl), REGNO (avl)); - gcc_assert (new_avl != avl); - if (!info.compatible_avl_p (avl_info (new_avl, set))) - return false; - - return true; - } - } - } - return false; -} - /* An "anticipatable occurrence" is one that is the first occurrence in the basic block, the operands are not modified in the basic block prior to the occurrence and the output is not used between the start of @@ -333,7 +307,31 @@ anticipatable_occurrence_p (const bb_info *bb, const vector_insn_info dem) if (dem.has_avl_reg ()) { /* rs1 (avl) are not modified in the basic block prior to the VSETVL. */ - if (!vlmax_avl_p (dem.get_avl ())) + rtx avl + = has_vl_op (insn->rtl ()) ? get_vl (insn->rtl ()) : dem.get_avl (); + if (dem.dirty_p ()) + { + gcc_assert (!vsetvl_insn_p (insn->rtl ())); + + /* Earliest VSETVL will be inserted at the end of the block. */ + for (const insn_info *i : bb->real_nondebug_insns ()) + { + /* rs1 (avl) are not modified in the basic block prior to the + VSETVL. */ + if (find_access (i->defs (), REGNO (avl))) + return false; + if (vlmax_avl_p (dem.get_avl ())) + { + /* rd (avl) is not used between the start of the block and + the occurrence. Note: Only for Dirty and VLMAX-avl. */ + if (find_access (i->uses (), REGNO (avl))) + return false; + } + } + + return true; + } + else if (!vlmax_avl_p (avl)) { set_info *set = dem.get_avl_source (); /* If it's undefined, it's not anticipatable conservatively. */ @@ -342,6 +340,14 @@ anticipatable_occurrence_p (const bb_info *bb, const vector_insn_info dem) if (real_insn_and_same_bb_p (set->insn (), bb) && before_p (set->insn (), insn)) return false; + for (insn_info *i = insn->prev_nondebug_insn (); + real_insn_and_same_bb_p (i, bb); i = i->prev_nondebug_insn ()) + { + /* rs1 (avl) are not modified in the basic block prior to the + VSETVL. */ + if (find_access (i->defs (), REGNO (avl))) + return false; + } } } @@ -540,16 +546,6 @@ get_all_predecessors (basic_block cfg_bb) return blocks; } -/* Return true if there is an INSN in insns staying in the block BB. */ -static bool -any_set_in_bb_p (hash_set sets, const bb_info *bb) -{ - for (const set_info *set : sets) - if (set->bb ()->index () == bb->index ()) - return true; - return false; -} - /* Helper function to get SEW operand. We always have SEW value for all RVV instructions that have VTYPE OP. */ static uint8_t @@ -659,7 +655,7 @@ gen_vsetvl_pat (rtx_insn *rinsn, const vector_insn_info &info, new_pat = gen_vsetvl_pat (VSETVL_NORMAL, new_info, vl); else { - if (vsetvl_insn_p (rinsn) || vlmax_avl_p (info.get_avl ())) + if (vsetvl_insn_p (rinsn)) new_pat = gen_vsetvl_pat (VSETVL_NORMAL, new_info, get_vl (rinsn)); else if (INSN_CODE (rinsn) == CODE_FOR_vsetvl_vtype_change_only) new_pat = gen_vsetvl_pat (VSETVL_VTYPE_CHANGE_ONLY, new_info, NULL_RTX); @@ -905,8 +901,8 @@ change_insn (function_info *ssa, insn_change change, insn_info *insn, ] UNSPEC_VPREDICATE) (plus:RVVM4DI (reg/v:RVVM4DI 104 v8 [orig:137 op1 ] [137]) (sign_extend:RVVM4DI (vec_duplicate:RVVM4SI (reg:SI 15 a5 - [140])))) (unspec:RVVM4DI [ (const_int 0 [0]) ] UNSPEC_VUNDEF))) "rvv.c":8:12 - 2784 {pred_single_widen_addsvnx8di_scalar} (expr_list:REG_EQUIV + [140])))) (unspec:RVVM4DI [ (const_int 0 [0]) ] UNSPEC_VUNDEF))) + "rvv.c":8:12 2784 {pred_single_widen_addsvnx8di_scalar} (expr_list:REG_EQUIV (mem/c:RVVM4DI (reg:DI 10 a0 [142]) [1 +0 S[64, 64] A128]) (expr_list:REG_EQUAL (if_then_else:RVVM4DI (unspec:RVVMF8BI [ (const_vector:RVVMF8BI repeat [ @@ -1181,18 +1177,36 @@ second_ratio_invalid_for_first_lmul_p (const vector_insn_info &info1, return calculate_sew (info1.get_vlmul (), info2.get_ratio ()) == 0; } +static bool +float_insn_valid_sew_p (const vector_insn_info &info, unsigned int sew) +{ + if (info.get_insn () && info.get_insn ()->is_real () + && get_attr_type (info.get_insn ()->rtl ()) == TYPE_VFMOVFV) + { + if (sew == 16) + return TARGET_VECTOR_ELEN_FP_16; + else if (sew == 32) + return TARGET_VECTOR_ELEN_FP_32; + else if (sew == 64) + return TARGET_VECTOR_ELEN_FP_64; + } + return true; +} + static bool second_sew_less_than_first_sew_p (const vector_insn_info &info1, const vector_insn_info &info2) { - return info2.get_sew () < info1.get_sew (); + return info2.get_sew () < info1.get_sew () + || !float_insn_valid_sew_p (info1, info2.get_sew ()); } static bool first_sew_less_than_second_sew_p (const vector_insn_info &info1, const vector_insn_info &info2) { - return info1.get_sew () < info2.get_sew (); + return info1.get_sew () < info2.get_sew () + || !float_insn_valid_sew_p (info2, info1.get_sew ()); } /* return 0 if LMUL1 == LMUL2. @@ -1403,8 +1417,14 @@ static bool ge_sew_ratio_unavailable_p (const vector_insn_info &info1, const vector_insn_info &info2) { - if (!info2.demand_p (DEMAND_LMUL) && info2.demand_p (DEMAND_GE_SEW)) - return info1.get_sew () < info2.get_sew (); + if (!info2.demand_p (DEMAND_LMUL)) + { + if (info2.demand_p (DEMAND_GE_SEW)) + return info1.get_sew () < info2.get_sew (); + /* Demand GE_SEW should be available for non-demand SEW. */ + else if (!info2.demand_p (DEMAND_SEW)) + return false; + } return true; } @@ -1483,75 +1503,6 @@ support_relaxed_compatible_p (const vector_insn_info &info1, return false; } -/* Return true if the block is worthwhile backward propagation. */ -static bool -backward_propagate_worthwhile_p (const basic_block cfg_bb, - const vector_block_info block_info) -{ - if (loop_basic_block_p (cfg_bb)) - { - if (block_info.reaching_out.valid_or_dirty_p ()) - { - if (block_info.local_dem.compatible_p (block_info.reaching_out)) - { - /* Case 1 (Can backward propagate): - .... - bb0: - ... - for (int i = 0; i < n; i++) - { - vint16mf4_t v = __riscv_vle16_v_i16mf4 (in + i + 5, 7); - __riscv_vse16_v_i16mf4 (out + i + 5, v, 7); - } - The local_dem is compatible with reaching_out. Such case is - worthwhile backward propagation. */ - return true; - } - else - { - if (support_relaxed_compatible_p (block_info.reaching_out, - block_info.local_dem)) - return true; - /* Case 2 (Don't backward propagate): - .... - bb0: - ... - for (int i = 0; i < n; i++) - { - vint16mf4_t v = __riscv_vle16_v_i16mf4 (in + i + 5, 7); - __riscv_vse16_v_i16mf4 (out + i + 5, v, 7); - vint16mf2_t v2 = __riscv_vle16_v_i16mf2 (in + i + 6, 8); - __riscv_vse16_v_i16mf2 (out + i + 6, v, 8); - } - The local_dem is incompatible with reaching_out. - It makes no sense to backward propagate the local_dem since we - can't avoid VSETVL inside the loop. */ - return false; - } - } - else - { - gcc_assert (block_info.reaching_out.unknown_p ()); - /* Case 3 (Don't backward propagate): - .... - bb0: - ... - for (int i = 0; i < n; i++) - { - vint16mf4_t v = __riscv_vle16_v_i16mf4 (in + i + 5, 7); - __riscv_vse16_v_i16mf4 (out + i + 5, v, 7); - fn3 (); - } - The local_dem is VALID, but the reaching_out is UNKNOWN. - It makes no sense to backward propagate the local_dem since we - can't avoid VSETVL inside the loop. */ - return false; - } - } - - return true; -} - /* Count the number of REGNO in RINSN. */ static int count_regno_occurrences (rtx_insn *rinsn, unsigned int regno) @@ -1564,6 +1515,93 @@ count_regno_occurrences (rtx_insn *rinsn, unsigned int regno) return count; } +/* Return TRUE if the demands can be fused. */ +static bool +demands_can_be_fused_p (const vector_insn_info &be_fused, + const vector_insn_info &to_fuse) +{ + return be_fused.compatible_p (to_fuse) && !be_fused.available_p (to_fuse); +} + +/* Return true if we can fuse VSETVL demand info into predecessor of earliest + * edge. */ +static bool +earliest_pred_can_be_fused_p (const bb_info *earliest_pred, + const vector_insn_info &earliest_info, + const vector_insn_info &expr, rtx *vlmax_vl) +{ + rtx vl = NULL_RTX; + /* Backward VLMAX VL: + bb 3: + vsetivli zero, 1 ... -> vsetvli t1, zero + vmv.s.x + bb 5: + vsetvli t1, zero ... -> to be elided. + vlse16.v + + We should forward "t1". */ + if (!earliest_info.has_avl_reg () && expr.has_avl_reg ()) + { + rtx avl = expr.get_avl (); + const insn_info *last_insn = earliest_info.get_insn (); + if (vlmax_avl_p (avl)) + vl = get_vl (expr.get_insn ()->rtl ()); + /* To fuse demand on earlest edge, we make sure AVL/VL + didn't change from the consume insn to the predecessor + of the edge. */ + for (insn_info *i = earliest_pred->end_insn ()->prev_nondebug_insn (); + real_insn_and_same_bb_p (i, earliest_pred) + && after_or_same_p (i, last_insn); + i = i->prev_nondebug_insn ()) + { + if (!vl && find_access (i->defs (), REGNO (avl))) + return false; + if (vl && find_access (i->defs (), REGNO (vl))) + return false; + if (vl && find_access (i->uses (), REGNO (vl))) + return false; + } + } + + if (vlmax_vl) + *vlmax_vl = vl; + return true; +} + +/* Return true if the current VSETVL 1 is dominated by preceding VSETVL 2. + + VSETVL 2 dominates VSETVL 1 should satisfy this following check: + + - VSETVL 2 should have the RATIO (SEW/LMUL) with VSETVL 1. + - VSETVL 2 is user vsetvl (vsetvl VL, AVL) + - VSETVL 2 "VL" result is the "AVL" of VSETL1. */ +static bool +vsetvl_dominated_by_p (const basic_block cfg_bb, + const vector_insn_info &vsetvl1, + const vector_insn_info &vsetvl2, bool fuse_p) +{ + if (!vsetvl1.valid_or_dirty_p () || !vsetvl2.valid_or_dirty_p ()) + return false; + if (!has_vl_op (vsetvl1.get_insn ()->rtl ()) + || !vsetvl_insn_p (vsetvl2.get_insn ()->rtl ())) + return false; + + hash_set sets + = get_all_sets (vsetvl1.get_avl_source (), true, false, false); + set_info *set = get_same_bb_set (sets, cfg_bb); + + if (!vsetvl1.has_avl_reg () || vlmax_avl_p (vsetvl1.get_avl ()) + || !vsetvl2.same_vlmax_p (vsetvl1) || !set + || set->insn () != vsetvl2.get_insn ()) + return false; + + if (fuse_p && vsetvl2.same_vtype_p (vsetvl1)) + return false; + else if (!fuse_p && !vsetvl2.same_vtype_p (vsetvl1)) + return false; + return true; +} + avl_info::avl_info (const avl_info &other) { m_value = other.get_value (); @@ -1795,8 +1833,7 @@ vector_insn_info::parse_insn (rtx_insn *rinsn) return; if (optimize == 0 && !has_vtype_op (rinsn)) return; - if (optimize > 0 && !vsetvl_insn_p (rinsn)) - return; + gcc_assert (!vsetvl_discard_result_insn_p (rinsn)); m_state = VALID; extract_insn_cached (rinsn); rtx avl = ::get_avl (rinsn); @@ -2185,31 +2222,66 @@ vector_insn_info::fuse_mask_policy (const vector_insn_info &info1, } vector_insn_info -vector_insn_info::merge (const vector_insn_info &merge_info, - enum merge_type type) const +vector_insn_info::local_merge (const vector_insn_info &merge_info) const { - if (!vsetvl_insn_p (get_insn ()->rtl ())) + if (!vsetvl_insn_p (get_insn ()->rtl ()) && *this != merge_info) gcc_assert (this->compatible_p (merge_info) && "Can't merge incompatible demanded infos"); vector_insn_info new_info; new_info.set_valid (); - if (type == LOCAL_MERGE) - { - /* For local backward data flow, we always update INSN && AVL as the - latest INSN and AVL so that we can keep track status of each INSN. */ - new_info.fuse_avl (merge_info, *this); - } - else - { - /* For global data flow, we should keep original INSN and AVL if they - valid since we should keep the life information of each block. + /* For local backward data flow, we always update INSN && AVL as the + latest INSN and AVL so that we can keep track status of each INSN. */ + new_info.fuse_avl (merge_info, *this); + new_info.fuse_sew_lmul (*this, merge_info); + new_info.fuse_tail_policy (*this, merge_info); + new_info.fuse_mask_policy (*this, merge_info); + return new_info; +} - For example: - bb 0 -> bb 1. - We should keep INSN && AVL of bb 1 since we will eventually emit - vsetvl instruction according to INSN and AVL of bb 1. */ - new_info.fuse_avl (*this, merge_info); +vector_insn_info +vector_insn_info::global_merge (const vector_insn_info &merge_info, + unsigned int bb_index) const +{ + if (!vsetvl_insn_p (get_insn ()->rtl ()) && *this != merge_info) + gcc_assert (this->compatible_p (merge_info) + && "Can't merge incompatible demanded infos"); + + vector_insn_info new_info; + new_info.set_valid (); + + /* For global data flow, we should keep original INSN and AVL if they + valid since we should keep the life information of each block. + + For example: + bb 0 -> bb 1. + We should keep INSN && AVL of bb 1 since we will eventually emit + vsetvl instruction according to INSN and AVL of bb 1. */ + new_info.fuse_avl (*this, merge_info); + /* Recompute the AVL source whose block index is equal to BB_INDEX. */ + if (new_info.get_avl_source () + && new_info.get_avl_source ()->insn ()->is_phi () + && new_info.get_avl_source ()->bb ()->index () != bb_index) + { + hash_set sets + = get_all_sets (new_info.get_avl_source (), true, true, true); + new_info.set_avl_source (nullptr); + bool can_find_set_p = false; + set_info *first_set = nullptr; + for (set_info *set : sets) + { + if (!first_set) + first_set = set; + if (set->bb ()->index () == bb_index) + { + gcc_assert (!can_find_set_p); + new_info.set_avl_source (set); + can_find_set_p = true; + } + } + if (!can_find_set_p && sets.elements () == 1 + && first_set->insn ()->is_real ()) + new_info.set_avl_source (first_set); } new_info.fuse_sew_lmul (*this, merge_info); @@ -2218,6 +2290,40 @@ vector_insn_info::merge (const vector_insn_info &merge_info, return new_info; } +/* Wrapper helps to return the AVL or VL operand for the + vector_insn_info. Return AVL if the AVL is not VLMAX. + Otherwise, return the VL operand. */ +rtx +vector_insn_info::get_avl_or_vl_reg (void) const +{ + gcc_assert (has_avl_reg ()); + if (!vlmax_avl_p (get_avl ())) + return get_avl (); + + if (get_avl_source ()) + return get_avl_reg_rtx (); + + rtx_insn *rinsn = get_insn ()->rtl (); + if (has_vl_op (rinsn) || vsetvl_insn_p (rinsn)) + { + rtx vl = ::get_vl (rinsn); + /* For VLMAX, we should make sure we get the + REG to emit 'vsetvl VL,zero' since the 'VL' + should be the REG according to RVV ISA. */ + if (REG_P (vl)) + return vl; + } + + /* A DIRTY (polluted EMPTY) block if: + - get_insn is scalar move (no AVL or VL operand). + - get_avl_source is null (no def in the current DIRTY block). + Then we trace the previous insn which must be the insn + already inserted in Phase 2 to get the VL operand for VLMAX. */ + rtx_insn *prev_rinsn = PREV_INSN (rinsn); + gcc_assert (prev_rinsn && vsetvl_insn_p (prev_rinsn)); + return ::get_vl (prev_rinsn); +} + bool vector_insn_info::update_fault_first_load_avl (insn_info *insn) { @@ -2280,10 +2386,6 @@ vector_insn_info::dump (FILE *file) const fprintf (file, "UNKNOWN,"); else if (empty_p ()) fprintf (file, "EMPTY,"); - else if (hard_empty_p ()) - fprintf (file, "HARD_EMPTY,"); - else if (dirty_with_killed_avl_p ()) - fprintf (file, "DIRTY_WITH_KILLED_AVL,"); else fprintf (file, "DIRTY,"); @@ -2326,6 +2428,9 @@ vector_infos_manager::vector_infos_manager () vector_comp = nullptr; vector_avin = nullptr; vector_avout = nullptr; + vector_antin = nullptr; + vector_antout = nullptr; + vector_earliest = nullptr; vector_insn_infos.safe_grow (get_max_uid ()); vector_block_infos.safe_grow (last_basic_block_for_fn (cfun)); if (!optimize) @@ -2382,21 +2487,6 @@ vector_infos_manager::get_all_available_exprs ( return available_list; } -bool -vector_infos_manager::all_empty_predecessor_p (const basic_block cfg_bb) const -{ - hash_set pred_cfg_bbs = get_all_predecessors (cfg_bb); - for (const basic_block pred_cfg_bb : pred_cfg_bbs) - { - const auto &pred_block_info = vector_block_infos[pred_cfg_bb->index]; - if (!pred_block_info.local_dem.valid_or_dirty_p () - && !pred_block_info.reaching_out.valid_or_dirty_p ()) - continue; - return false; - } - return true; -} - bool vector_infos_manager::all_same_ratio_p (sbitmap bitdata) const { @@ -2408,12 +2498,12 @@ vector_infos_manager::all_same_ratio_p (sbitmap bitdata) const sbitmap_iterator sbi; EXECUTE_IF_SET_IN_BITMAP (bitdata, 0, bb_index, sbi) - { - if (ratio == -1) - ratio = vector_exprs[bb_index]->get_ratio (); - else if (vector_exprs[bb_index]->get_ratio () != ratio) - return false; - } + { + if (ratio == -1) + ratio = vector_exprs[bb_index]->get_ratio (); + else if (vector_exprs[bb_index]->get_ratio () != ratio) + return false; + } return true; } @@ -2453,10 +2543,49 @@ vector_infos_manager::all_same_avl_p (const basic_block cfg_bb, sbitmap_iterator sbi; EXECUTE_IF_SET_IN_BITMAP (bitdata, 0, bb_index, sbi) - { - if (vector_exprs[bb_index]->get_avl_info () != avl) - return false; - } + { + if (vector_exprs[bb_index]->get_avl_info () != avl) + return false; + } + return true; +} + +bool +vector_infos_manager::earliest_fusion_worthwhile_p ( + const basic_block cfg_bb) const +{ + edge e; + edge_iterator ei; + profile_probability prob = profile_probability::uninitialized (); + FOR_EACH_EDGE (e, ei, cfg_bb->succs) + { + if (prob == profile_probability::uninitialized ()) + prob = vector_block_infos[e->dest->index].probability; + else if (prob == vector_block_infos[e->dest->index].probability) + continue; + else + /* We pick the highest probability among those incompatible VSETVL + infos. When all incompatible VSTEVL infos have same probability, we + don't pick any of them. */ + return true; + } + return false; +} + +bool +vector_infos_manager::vsetvl_dominated_by_all_preds_p ( + const basic_block cfg_bb, const vector_insn_info &info) const +{ + edge e; + edge_iterator ei; + FOR_EACH_EDGE (e, ei, cfg_bb->preds) + { + const auto &reaching_out = vector_block_infos[e->src->index].reaching_out; + if (e->src->index == cfg_bb->index && reaching_out.compatible_p (info)) + continue; + if (!vsetvl_dominated_by_p (e->src, info, reaching_out, false)) + return false; + } return true; } @@ -2502,10 +2631,17 @@ vector_infos_manager::create_bitmap_vectors (void) vector_exprs.length ()); vector_kill = sbitmap_vector_alloc (last_basic_block_for_fn (cfun), vector_exprs.length ()); + vector_antin = sbitmap_vector_alloc (last_basic_block_for_fn (cfun), + vector_exprs.length ()); + vector_antout = sbitmap_vector_alloc (last_basic_block_for_fn (cfun), + vector_exprs.length ()); bitmap_vector_ones (vector_transp, last_basic_block_for_fn (cfun)); bitmap_vector_clear (vector_antic, last_basic_block_for_fn (cfun)); bitmap_vector_clear (vector_comp, last_basic_block_for_fn (cfun)); + vector_edge_list = create_edge_list (); + vector_earliest = sbitmap_vector_alloc (NUM_EDGES (vector_edge_list), + vector_exprs.length ()); } void @@ -2529,6 +2665,12 @@ vector_infos_manager::free_bitmap_vectors (void) sbitmap_vector_free (vector_avin); if (vector_avout) sbitmap_vector_free (vector_avout); + if (vector_antin) + sbitmap_vector_free (vector_antin); + if (vector_antout) + sbitmap_vector_free (vector_antout); + if (vector_earliest) + sbitmap_vector_free (vector_earliest); vector_edge_list = nullptr; vector_kill = nullptr; @@ -2539,6 +2681,9 @@ vector_infos_manager::free_bitmap_vectors (void) vector_comp = nullptr; vector_avin = nullptr; vector_avout = nullptr; + vector_antin = nullptr; + vector_antout = nullptr; + vector_earliest = nullptr; } void @@ -2596,6 +2741,18 @@ vector_infos_manager::dump (FILE *file) const fprintf (file, "(nil)\n"); else dump_bitmap_file (file, vector_kill[cfg_bb->index]); + + fprintf (file, "="); + if (vector_antin == nullptr) + fprintf (file, "(nil)\n"); + else + dump_bitmap_file (file, vector_antin[cfg_bb->index]); + + fprintf (file, "="); + if (vector_antout == nullptr) + fprintf (file, "(nil)\n"); + else + dump_bitmap_file (file, vector_antout[cfg_bb->index]); } fprintf (file, "\n"); @@ -2623,17 +2780,36 @@ vector_infos_manager::dump (FILE *file) const dump_bitmap_file (file, vector_del[cfg_bb->index]); } - fprintf (file, "\nGlobal LCM (Lazy code motion) INSERT info:\n"); for (size_t i = 0; i < vector_exprs.length (); i++) { for (int ed = 0; ed < NUM_EDGES (vector_edge_list); ed++) { edge eg = INDEX_EDGE (vector_edge_list, ed); - if (bitmap_bit_p (vector_insert[ed], i)) - fprintf (dump_file, - "INSERT edge %d from bb %d to bb %d for VSETVL " - "expr[%ld]\n", - ed, eg->src->index, eg->dest->index, i); + if (vector_insert) + { + if (bitmap_bit_p (vector_insert[ed], i)) + { + fprintf (file, + "\nGlobal LCM (Lazy code motion) INSERT info:\n"); + fprintf (file, + "INSERT edge %d from to for VSETVL " + "expr[%ld]\n", + ed, eg->src->index, eg->dest->index, i); + } + } + else + { + if (bitmap_bit_p (vector_earliest[ed], i)) + { + fprintf (file, + "\nGlobal LCM (Lazy code motion) EARLIEST info:\n"); + fprintf ( + file, + "EARLIEST edge %d from to for VSETVL " + "expr[%ld]\n", + ed, eg->src->index, eg->dest->index, i); + } + } } } } @@ -2662,6 +2838,7 @@ private: vector_block_info &get_block_info (const basic_block); vector_block_info &get_block_info (const bb_info *); void update_vector_info (const insn_info *, const vector_insn_info &); + void update_block_info (int, profile_probability, const vector_insn_info &); void simple_vsetvl (void) const; void lazy_vsetvl (void); @@ -2676,13 +2853,8 @@ private: void emit_local_forward_vsetvls (const bb_info *); /* Phase 3. */ - enum fusion_type get_backward_fusion_type (const bb_info *, - const vector_insn_info &); - bool hard_empty_block_p (const bb_info *, const vector_insn_info &) const; - bool backward_demand_fusion (void); - bool forward_demand_fusion (void); - bool cleanup_illegal_dirty_blocks (void); - void demand_fusion (void); + bool earliest_fusion (void); + void vsetvl_fusion (void); /* Phase 4. */ void prune_expressions (void); @@ -2700,6 +2872,7 @@ private: void ssa_post_optimization (void) const; /* Phase 6. */ + bool cleanup_earliest_vsetvls (const basic_block) const; void df_post_optimization (void) const; void init (void); @@ -2757,6 +2930,17 @@ pass_vsetvl::update_vector_info (const insn_info *i, m_vector_manager->vector_insn_infos[i->uid ()] = new_info; } +void +pass_vsetvl::update_block_info (int index, profile_probability prob, + const vector_insn_info &new_info) +{ + m_vector_manager->vector_block_infos[index].probability = prob; + if (m_vector_manager->vector_block_infos[index].local_dem + == m_vector_manager->vector_block_infos[index].reaching_out) + m_vector_manager->vector_block_infos[index].local_dem = new_info; + m_vector_manager->vector_block_infos[index].reaching_out = new_info; +} + /* Simple m_vsetvl_insert vsetvl for optimize == 0. */ void pass_vsetvl::simple_vsetvl (void) const @@ -2813,7 +2997,7 @@ pass_vsetvl::compute_local_backward_infos (const bb_info *bb) && !reg_available_p (insn, change)) && change.compatible_p (info)) { - update_vector_info (insn, change.merge (info, LOCAL_MERGE)); + update_vector_info (insn, change.local_merge (info)); /* Fix PR109399, we should update user vsetvl instruction if there is a change in demand fusion. */ if (vsetvl_insn_p (insn->rtl ())) @@ -2931,682 +3115,6 @@ pass_vsetvl::emit_local_forward_vsetvls (const bb_info *bb) block_info.reaching_out = curr_info; } -enum fusion_type -pass_vsetvl::get_backward_fusion_type (const bb_info *bb, - const vector_insn_info &prop) -{ - insn_info *insn = prop.get_insn (); - - /* TODO: We don't backward propagate the explict VSETVL here - since we will change vsetvl and vsetvlmax intrinsics into - no side effects which can be optimized into optimal location - by GCC internal passes. We only need to support these backward - propagation if vsetvl intrinsics have side effects. */ - if (vsetvl_insn_p (insn->rtl ())) - return INVALID_FUSION; - - gcc_assert (has_vtype_op (insn->rtl ())); - rtx reg = NULL_RTX; - - /* Case 1: Don't need VL. Just let it backward propagate. */ - if (!prop.demand_p (DEMAND_AVL)) - return VALID_AVL_FUSION; - else - { - /* Case 2: CONST_INT AVL, we don't need to check def. */ - if (prop.has_avl_imm ()) - return VALID_AVL_FUSION; - else - { - /* Case 3: REG AVL, we need to check the distance of def to make - sure we won't backward propagate over the def. */ - gcc_assert (prop.has_avl_reg ()); - if (vlmax_avl_p (prop.get_avl ())) - /* Check VL operand for vsetvl vl,zero. */ - reg = prop.get_avl_reg_rtx (); - else - /* Check AVL operand for vsetvl zero,avl. */ - reg = prop.get_avl (); - } - } - - gcc_assert (reg); - if (!prop.get_avl_source ()->insn ()->is_phi () - && prop.get_avl_source ()->insn ()->bb () == insn->bb ()) - return INVALID_FUSION; - hash_set sets - = get_all_sets (prop.get_avl_source (), true, true, true); - if (any_set_in_bb_p (sets, insn->bb ())) - return INVALID_FUSION; - - if (vlmax_avl_p (prop.get_avl ())) - { - if (find_reg_killed_by (bb, reg)) - return INVALID_FUSION; - else - return VALID_AVL_FUSION; - } - - /* By default, we always enable backward fusion so that we can - gain more optimizations. */ - if (!find_reg_killed_by (bb, reg)) - return VALID_AVL_FUSION; - return KILLED_AVL_FUSION; -} - -/* We almost enable all cases in get_backward_fusion_type, this function - disable the backward fusion by changing dirty blocks into hard empty - blocks in forward dataflow. We can have more accurate optimization by - this method. */ -bool -pass_vsetvl::hard_empty_block_p (const bb_info *bb, - const vector_insn_info &info) const -{ - if (!info.dirty_p () || !info.has_avl_reg ()) - return false; - - basic_block cfg_bb = bb->cfg_bb (); - sbitmap avin = m_vector_manager->vector_avin[cfg_bb->index]; - set_info *set = info.get_avl_source (); - rtx avl = gen_rtx_REG (Pmode, set->regno ()); - hash_set sets = get_all_sets (set, true, false, false); - hash_set pred_cfg_bbs = get_all_predecessors (cfg_bb); - - if (find_reg_killed_by (bb, avl)) - { - /* Condition 1: - Dirty block with killed AVL means that the empty block (no RVV - instructions) are polluted as Dirty blocks with the value of current - AVL is killed. For example: - bb 0: - ... - bb 1: - def a5 - bb 2: - RVV (use a5) - In backward dataflow, we will polluted BB0 and BB1 as Dirt with AVL - killed. since a5 is killed in BB1. - In this case, let's take a look at this example: - - bb 3: bb 4: - def3 a5 def4 a5 - bb 5: bb 6: - def1 a5 def2 a5 - \ / - \ / - \ / - \ / - bb 7: - RVV (use a5) - In thi case, we can polluted BB5 and BB6 as dirty if get-def - of a5 from RVV instruction in BB7 is the def1 in BB5 and - def2 BB6 so we can return false early here for HARD_EMPTY_BLOCK_P. - However, we are not sure whether BB3 and BB4 can be - polluted as Dirty with AVL killed so we can't return false - for HARD_EMPTY_BLOCK_P here since it's too early which will - potentially produce issues. */ - gcc_assert (info.dirty_with_killed_avl_p ()); - if (info.get_avl_source () - && get_same_bb_set (sets, bb->cfg_bb ()) == info.get_avl_source ()) - return false; - } - - /* Condition 2: - Suppress the VL/VTYPE info backward propagation too early: - ________ - | BB0 | - |________| - | - ____|____ - | BB1 | - |________| - In this case, suppose BB 1 has multiple predecessors, BB 0 is one - of them. BB1 has VL/VTYPE info (may be VALID or DIRTY) to backward - propagate. - The AVIN (available in) which is calculated by LCM is empty only - in these 2 circumstances: - 1. all predecessors of BB1 are empty (not VALID - and can not be polluted in backward fusion flow) - 2. VL/VTYPE info of BB1 predecessors are conflict. - - We keep it as dirty in 2nd circumstance and set it as HARD_EMPTY - (can not be polluted as DIRTY any more) in 1st circumstance. - We don't backward propagate in 1st circumstance since there is - no VALID RVV instruction and no polluted blocks (dirty blocks) - by backward propagation from other following blocks. - It's meaningless to keep it as Dirty anymore. - - However, since we keep it as dirty in 2nd since there are VALID or - Dirty blocks in predecessors, we can still gain the benefits and - optimization opportunities. For example, in this case: - for (size_t i = 0; i < n; i++) - { - if (i != cond) { - vint8mf8_t v = *(vint8mf8_t*)(in + i + 100); - *(vint8mf8_t*)(out + i + 100) = v; - } else { - vbool1_t v = *(vbool1_t*)(in + i + 400); - *(vbool1_t*)(out + i + 400) = v; - } - } - VL/VTYPE in if-else are conflict which will produce empty AVIN LCM result - but we can still keep dirty blocks if *(i != cond)* is very unlikely then - we can preset vsetvl (VL/VTYPE) info from else (static propability model). - - We don't want to backward propagate VL/VTYPE information too early - which is not the optimal and may potentially produce issues. */ - if (bitmap_empty_p (avin)) - { - bool hard_empty_p = true; - for (const basic_block pred_cfg_bb : pred_cfg_bbs) - { - if (pred_cfg_bb == ENTRY_BLOCK_PTR_FOR_FN (cfun)) - continue; - sbitmap avout = m_vector_manager->vector_avout[pred_cfg_bb->index]; - if (!bitmap_empty_p (avout)) - { - hard_empty_p = false; - break; - } - } - if (hard_empty_p) - return true; - } - - edge e; - edge_iterator ei; - bool has_avl_killed_insn_p = false; - FOR_EACH_EDGE (e, ei, cfg_bb->succs) - { - const auto block_info - = m_vector_manager->vector_block_infos[e->dest->index]; - if (block_info.local_dem.dirty_with_killed_avl_p ()) - { - has_avl_killed_insn_p = true; - break; - } - } - if (!has_avl_killed_insn_p) - return false; - - bool any_set_in_bbs_p = false; - for (const basic_block pred_cfg_bb : pred_cfg_bbs) - { - insn_info *def_insn = extract_single_source (set); - if (def_insn) - { - /* Condition 3: - - Case 1: Case 2: - bb 0: bb 0: - def a5 101 ... - bb 1: bb 1: - ... ... - bb 2: bb 2: - RVV 1 (use a5 with TAIL ANY) ... - bb 3: bb 3: - def a5 101 def a5 101 - bb 4: bb 4: - ... ... - bb 5: bb 5: - RVV 2 (use a5 with TU) RVV 1 (use a5) - - Case 1: We can pollute BB3,BB2,BB1,BB0 are all Dirt blocks - with killed AVL so that we can merge TU demand info from RVV 2 - into RVV 1 and elide the vsevl instruction in BB5. - - TODO: We only optimize for single source def since multiple source - def is quite complicated. - - Case 2: We only can pollute bb 3 as dirty and it has been accepted - in Condition 2 and we can't pollute BB3,BB2,BB1,BB0 like case 1. */ - insn_info *last_killed_insn - = find_reg_killed_by (crtl->ssa->bb (pred_cfg_bb), avl); - if (!last_killed_insn || pred_cfg_bb == def_insn->bb ()->cfg_bb ()) - continue; - if (source_equal_p (last_killed_insn, def_insn)) - { - any_set_in_bbs_p = true; - break; - } - } - else - { - /* Condition 4: - - bb 0: bb 1: bb 3: - def1 a5 def2 a5 ... - \ / / - \ / / - \ / / - \ / / - bb 4: / - | / - | / - bb 5: / - | / - | / - bb 6: / - | / - | / - bb 8: - RVV 1 (use a5) - If we get-def (REAL) of a5 from RVV 1 instruction, we will get - def1 from BB0 and def2 from BB1. So we will pollute BB6,BB5,BB4, - BB0,BB1 with DIRTY and set BB3 as HARD_EMPTY so that we won't - propagate AVL to BB3. */ - if (any_set_in_bb_p (sets, crtl->ssa->bb (pred_cfg_bb))) - { - any_set_in_bbs_p = true; - break; - } - } - } - if (!any_set_in_bbs_p) - return true; - return false; -} - -/* Compute global backward demanded info. */ -bool -pass_vsetvl::backward_demand_fusion (void) -{ - /* We compute global infos by backward propagation. - We want to have better performance in these following cases: - - 1. for (size_t i = 0; i < n; i++) { - if (i != cond) { - vint8mf8_t v = *(vint8mf8_t*)(in + i + 100); - *(vint8mf8_t*)(out + i + 100) = v; - } else { - vbool1_t v = *(vbool1_t*)(in + i + 400); - *(vbool1_t*)(out + i + 400) = v; - } - } - - Since we don't have any RVV instruction in the BEFORE blocks, - LCM fails to optimize such case. We want to backward propagate - them into empty blocks so that we could have better performance - in LCM. - - 2. bb 0: - vsetvl e8,mf8 (demand RATIO) - bb 1: - vsetvl e32,mf2 (demand SEW and LMUL) - We backward propagate the first VSETVL into e32,mf2 so that we - could be able to eliminate the second VSETVL in LCM. */ - - bool changed_p = false; - for (const bb_info *bb : crtl->ssa->reverse_bbs ()) - { - basic_block cfg_bb = bb->cfg_bb (); - const auto &curr_block_info - = m_vector_manager->vector_block_infos[cfg_bb->index]; - const auto &prop = curr_block_info.local_dem; - - /* If there is nothing to propagate, just skip it. */ - if (!prop.valid_or_dirty_p ()) - continue; - - if (!backward_propagate_worthwhile_p (cfg_bb, curr_block_info)) - continue; - - /* Fix PR108270: - - bb 0 -> bb 1 - We don't need to backward fuse VL/VTYPE info from bb 1 to bb 0 - if bb 1 is not inside a loop and all predecessors of bb 0 are empty. */ - if (m_vector_manager->all_empty_predecessor_p (cfg_bb)) - continue; - - edge e; - edge_iterator ei; - /* Backward propagate to each predecessor. */ - FOR_EACH_EDGE (e, ei, cfg_bb->preds) - { - auto &block_info - = m_vector_manager->vector_block_infos[e->src->index]; - - /* We don't propagate through critical edges. */ - if (e->flags & EDGE_COMPLEX) - continue; - if (e->src->index == ENTRY_BLOCK_PTR_FOR_FN (cfun)->index) - continue; - /* If prop is demand of vsetvl instruction and reaching doesn't demand - AVL. We don't backward propagate since vsetvl instruction has no - side effects. */ - if (vsetvl_insn_p (prop.get_insn ()->rtl ()) - && propagate_avl_across_demands_p (prop, block_info.reaching_out)) - continue; - - if (block_info.reaching_out.unknown_p ()) - continue; - else if (block_info.reaching_out.hard_empty_p ()) - continue; - else if (block_info.reaching_out.empty_p ()) - { - enum fusion_type type - = get_backward_fusion_type (crtl->ssa->bb (e->src), prop); - if (type == INVALID_FUSION) - continue; - - block_info.reaching_out = prop; - block_info.reaching_out.set_dirty (type); - - if (prop.has_avl_reg () && !vlmax_avl_p (prop.get_avl ())) - { - hash_set sets - = get_all_sets (prop.get_avl_source (), true, true, true); - set_info *set = get_same_bb_set (sets, e->src); - if (set) - block_info.reaching_out.set_avl_info ( - avl_info (prop.get_avl (), set)); - } - - block_info.local_dem = block_info.reaching_out; - block_info.probability = curr_block_info.probability; - changed_p = true; - } - else if (block_info.reaching_out.dirty_p ()) - { - /* DIRTY -> DIRTY or VALID -> DIRTY. */ - vector_insn_info new_info; - - if (block_info.reaching_out.compatible_p (prop)) - { - if (block_info.reaching_out.available_p (prop)) - continue; - new_info = block_info.reaching_out.merge (prop, GLOBAL_MERGE); - new_info.set_dirty ( - block_info.reaching_out.dirty_with_killed_avl_p ()); - block_info.probability += curr_block_info.probability; - } - else - { - if (curr_block_info.probability > block_info.probability) - { - enum fusion_type type - = get_backward_fusion_type (crtl->ssa->bb (e->src), - prop); - if (type == INVALID_FUSION) - continue; - new_info = prop; - new_info.set_dirty (type); - block_info.probability = curr_block_info.probability; - } - else - continue; - } - - if (propagate_avl_across_demands_p (prop, - block_info.reaching_out)) - { - rtx reg = new_info.get_avl_reg_rtx (); - if (find_reg_killed_by (crtl->ssa->bb (e->src), reg)) - new_info.set_dirty (true); - } - - block_info.local_dem = new_info; - block_info.reaching_out = new_info; - changed_p = true; - } - else - { - /* We not only change the info during backward propagation, - but also change the VSETVL instruction. */ - gcc_assert (block_info.reaching_out.valid_p ()); - hash_set sets - = get_all_sets (prop.get_avl_source (), true, false, false); - set_info *set = get_same_bb_set (sets, e->src); - if (vsetvl_insn_p (block_info.reaching_out.get_insn ()->rtl ()) - && prop.has_avl_reg () && !vlmax_avl_p (prop.get_avl ())) - { - if (!block_info.reaching_out.same_vlmax_p (prop)) - continue; - if (block_info.reaching_out.same_vtype_p (prop)) - continue; - if (!set) - continue; - if (set->insn () != block_info.reaching_out.get_insn ()) - continue; - } - - if (!block_info.reaching_out.compatible_p (prop)) - continue; - if (block_info.reaching_out.available_p (prop)) - continue; - - vector_insn_info be_merged = block_info.reaching_out; - if (block_info.local_dem == block_info.reaching_out) - be_merged = block_info.local_dem; - vector_insn_info new_info = be_merged.merge (prop, GLOBAL_MERGE); - - if (curr_block_info.probability > block_info.probability) - block_info.probability = curr_block_info.probability; - - if (propagate_avl_across_demands_p (prop, block_info.reaching_out) - && !reg_available_p (crtl->ssa->bb (e->src)->end_insn (), - new_info)) - continue; - - rtx vl = NULL_RTX; - /* Backward VLMAX VL: - bb 3: - vsetivli zero, 1 ... -> vsetvli t1, zero - vmv.s.x - bb 5: - vsetvli t1, zero ... -> to be elided. - vlse16.v - - We should forward "t1". */ - if (!block_info.reaching_out.has_avl_reg () - && vlmax_avl_p (new_info.get_avl ())) - vl = get_vl (prop.get_insn ()->rtl ()); - change_vsetvl_insn (new_info.get_insn (), new_info, vl); - if (block_info.local_dem == block_info.reaching_out) - block_info.local_dem = new_info; - block_info.reaching_out = new_info; - changed_p = true; - } - } - } - return changed_p; -} - -/* Compute global forward demanded info. */ -bool -pass_vsetvl::forward_demand_fusion (void) -{ - /* Enhance the global information propagation especially - backward propagation miss the propagation. - Consider such case: - - bb0 - (TU) - / \ - bb1 bb2 - (TU) (ANY) - existing edge -----> \ / (TU) <----- LCM create this edge. - bb3 - (TU) - - Base on the situation, LCM fails to eliminate the VSETVL instruction and - insert an edge from bb2 to bb3 since we can't backward propagate bb3 into - bb2. To avoid this confusing LCM result and non-optimal codegen, we should - forward propagate information from bb0 to bb2 which is friendly to LCM. */ - bool changed_p = false; - for (const bb_info *bb : crtl->ssa->bbs ()) - { - basic_block cfg_bb = bb->cfg_bb (); - const auto &prop - = m_vector_manager->vector_block_infos[cfg_bb->index].reaching_out; - - /* If there is nothing to propagate, just skip it. */ - if (!prop.valid_or_dirty_p ()) - continue; - - if (cfg_bb == ENTRY_BLOCK_PTR_FOR_FN (cfun)) - continue; - - if (vsetvl_insn_p (prop.get_insn ()->rtl ())) - continue; - - edge e; - edge_iterator ei; - /* Forward propagate to each successor. */ - FOR_EACH_EDGE (e, ei, cfg_bb->succs) - { - auto &local_dem - = m_vector_manager->vector_block_infos[e->dest->index].local_dem; - auto &reaching_out - = m_vector_manager->vector_block_infos[e->dest->index].reaching_out; - - /* It's quite obvious, we don't need to propagate itself. */ - if (e->dest->index == cfg_bb->index) - continue; - /* We don't propagate through critical edges. */ - if (e->flags & EDGE_COMPLEX) - continue; - if (e->dest->index == EXIT_BLOCK_PTR_FOR_FN (cfun)->index) - continue; - - /* If there is nothing to propagate, just skip it. */ - if (!local_dem.valid_or_dirty_p ()) - continue; - if (local_dem.available_p (prop)) - continue; - if (!local_dem.compatible_p (prop)) - continue; - if (propagate_avl_across_demands_p (prop, local_dem)) - continue; - - vector_insn_info new_info = local_dem.merge (prop, GLOBAL_MERGE); - new_info.set_insn (local_dem.get_insn ()); - if (local_dem.dirty_p ()) - { - gcc_assert (local_dem == reaching_out); - new_info.set_dirty (local_dem.dirty_with_killed_avl_p ()); - local_dem = new_info; - reaching_out = local_dem; - } - else - { - if (reaching_out == local_dem) - reaching_out = new_info; - local_dem = new_info; - change_vsetvl_insn (local_dem.get_insn (), new_info); - } - auto &prob - = m_vector_manager->vector_block_infos[e->dest->index].probability; - auto &curr_prob - = m_vector_manager->vector_block_infos[cfg_bb->index].probability; - prob = curr_prob * e->probability; - changed_p = true; - } - } - return changed_p; -} - -void -pass_vsetvl::demand_fusion (void) -{ - bool changed_p = true; - while (changed_p) - { - changed_p = false; - /* To optimize the case like this: - void f2 (int8_t * restrict in, int8_t * restrict out, int n, int cond) - { - size_t vl = 101; - - for (size_t i = 0; i < n; i++) - { - vint8mf8_t v = __riscv_vle8_v_i8mf8 (in + i + 300, vl); - __riscv_vse8_v_i8mf8 (out + i + 300, v, vl); - } - - for (size_t i = 0; i < n; i++) - { - vint8mf8_t v = __riscv_vle8_v_i8mf8 (in + i, vl); - __riscv_vse8_v_i8mf8 (out + i, v, vl); - - vint8mf8_t v2 = __riscv_vle8_v_i8mf8_tu (v, in + i + 100, vl); - __riscv_vse8_v_i8mf8 (out + i + 100, v2, vl); - } - } - - bb 0: li a5, 101 (killed avl) - ... - bb 1: vsetvli zero, a5, ta - ... - bb 2: li a5, 101 (killed avl) - ... - bb 3: vsetvli zero, a3, tu - - We want to fuse VSEVLI instructions on bb 1 and bb 3. However, there is - an AVL kill instruction in bb 2 that we can't backward fuse bb 3 or - forward bb 1 arbitrarily. We need available information of each block to - help for such cases. */ - changed_p |= backward_demand_fusion (); - changed_p |= forward_demand_fusion (); - } - - changed_p = true; - while (changed_p) - { - changed_p = false; - prune_expressions (); - m_vector_manager->create_bitmap_vectors (); - compute_local_properties (); - compute_available (m_vector_manager->vector_comp, - m_vector_manager->vector_kill, - m_vector_manager->vector_avout, - m_vector_manager->vector_avin); - changed_p |= cleanup_illegal_dirty_blocks (); - m_vector_manager->free_bitmap_vectors (); - if (!m_vector_manager->vector_exprs.is_empty ()) - m_vector_manager->vector_exprs.release (); - } - - if (dump_file) - { - fprintf (dump_file, "\n\nDirty blocks list: "); - for (const bb_info *bb : crtl->ssa->bbs ()) - if (m_vector_manager->vector_block_infos[bb->index ()] - .reaching_out.dirty_p ()) - fprintf (dump_file, "%d ", bb->index ()); - fprintf (dump_file, "\n\n"); - } -} - -/* Cleanup illegal dirty blocks. */ -bool -pass_vsetvl::cleanup_illegal_dirty_blocks (void) -{ - bool changed_p = false; - for (const bb_info *bb : crtl->ssa->bbs ()) - { - basic_block cfg_bb = bb->cfg_bb (); - const auto &prop - = m_vector_manager->vector_block_infos[cfg_bb->index].reaching_out; - - /* If there is nothing to cleanup, just skip it. */ - if (!prop.valid_or_dirty_p ()) - continue; - - if (hard_empty_block_p (bb, prop)) - { - m_vector_manager->vector_block_infos[cfg_bb->index].local_dem - = vector_insn_info::get_hard_empty (); - m_vector_manager->vector_block_infos[cfg_bb->index].reaching_out - = vector_insn_info::get_hard_empty (); - changed_p = true; - continue; - } - } - return changed_p; -} - /* Assemble the candidates expressions for LCM. */ void pass_vsetvl::prune_expressions (void) @@ -3677,6 +3185,8 @@ pass_vsetvl::compute_local_properties (void) for (const bb_info *bb : crtl->ssa->bbs ()) { unsigned int curr_bb_idx = bb->index (); + if (curr_bb_idx == ENTRY_BLOCK || curr_bb_idx == EXIT_BLOCK) + continue; const auto local_dem = m_vector_manager->vector_block_infos[curr_bb_idx].local_dem; const auto reaching_out @@ -3685,57 +3195,33 @@ pass_vsetvl::compute_local_properties (void) /* Compute transparent. */ for (size_t i = 0; i < m_vector_manager->vector_exprs.length (); i++) { - const vector_insn_info *expr = m_vector_manager->vector_exprs[i]; - if (local_dem.real_dirty_p () || local_dem.valid_p () - || local_dem.unknown_p () - || has_vsetvl_killed_avl_p (bb, local_dem)) + const auto *expr = m_vector_manager->vector_exprs[i]; + if (local_dem.valid_or_dirty_p () || local_dem.unknown_p ()) bitmap_clear_bit (m_vector_manager->vector_transp[curr_bb_idx], i); - /* FIXME: Here we set the block as non-transparent (killed) if there - is an instruction killed the value of AVL according to the - definition of Local transparent. This is true for such following - case: - - bb 0 (Loop label): - vsetvl zero, a5, e8, mf8 - bb 1: - def a5 - bb 2: - branch bb 0 (Loop label). - - In this case, we known there is a loop bb 0->bb 1->bb 2. According - to LCM definition, it is correct when we set vsetvl zero, a5, e8, - mf8 as non-transparent (killed) so that LCM will not hoist outside - the bb 0. - - However, such conservative configuration will forbid optimization - on some unlucky case. For example: - - bb 0: - li a5, 101 - bb 1: - vsetvl zero, a5, e8, mf8 - bb 2: - li a5, 101 - bb 3: - vsetvl zero, a5, e8, mf8. - So we also relax def a5 as transparent to gain more optimizations - as long as the all real def insn of avl do not come from this - block. This configuration may be still missing some optimization - opportunities. */ - if (find_reg_killed_by (bb, expr->get_avl ())) + else if (expr->has_avl_reg ()) { - hash_set sets - = get_all_sets (expr->get_avl_source (), true, false, false); - if (any_set_in_bb_p (sets, bb)) - bitmap_clear_bit (m_vector_manager->vector_transp[curr_bb_idx], - i); + rtx reg = expr->get_avl_or_vl_reg (); + for (const insn_info *insn : bb->real_nondebug_insns ()) + { + if (find_access (insn->defs (), REGNO (reg))) + { + bitmap_clear_bit ( + m_vector_manager->vector_transp[curr_bb_idx], i); + break; + } + else if (vlmax_avl_p (expr->get_avl ()) + && find_access (insn->uses (), REGNO (reg))) + { + bitmap_clear_bit ( + m_vector_manager->vector_transp[curr_bb_idx], i); + break; + } + } } } /* Compute anticipatable occurrences. */ - if (local_dem.valid_p () || local_dem.real_dirty_p () - || (has_vsetvl_killed_avl_p (bb, local_dem) - && vlmax_avl_p (local_dem.get_avl ()))) + if (local_dem.valid_or_dirty_p ()) if (anticipatable_occurrence_p (bb, local_dem)) bitmap_set_bit (m_vector_manager->vector_antic[curr_bb_idx], m_vector_manager->get_expr_id (local_dem)); @@ -3749,13 +3235,17 @@ pass_vsetvl::compute_local_properties (void) { const vector_insn_info *expr = m_vector_manager->vector_exprs[available_list[i]]; - if (reaching_out.real_dirty_p () - || has_vsetvl_killed_avl_p (bb, reaching_out) - || available_occurrence_p (bb, *expr)) + if (available_occurrence_p (bb, *expr)) bitmap_set_bit (m_vector_manager->vector_comp[curr_bb_idx], available_list[i]); } } + + if (loop_basic_block_p (bb->cfg_bb ()) && local_dem.valid_or_dirty_p () + && reaching_out.valid_or_dirty_p () + && !local_dem.compatible_p (reaching_out)) + bitmap_clear_bit (m_vector_manager->vector_antic[curr_bb_idx], + m_vector_manager->get_expr_id (local_dem)); } /* Compute kill for each basic block using: @@ -3801,6 +3291,191 @@ pass_vsetvl::compute_local_properties (void) } } +/* Fuse demand info for earliest edge. */ +bool +pass_vsetvl::earliest_fusion (void) +{ + bool changed_p = false; + for (int ed = 0; ed < NUM_EDGES (m_vector_manager->vector_edge_list); ed++) + { + for (size_t i = 0; i < m_vector_manager->vector_exprs.length (); i++) + { + auto &expr = *m_vector_manager->vector_exprs[i]; + if (expr.empty_p ()) + continue; + edge eg = INDEX_EDGE (m_vector_manager->vector_edge_list, ed); + /* If it is the edge that we never reach, skip its possible PRE + fusion conservatively. */ + if (eg->probability == profile_probability::never ()) + break; + if (eg->src == ENTRY_BLOCK_PTR_FOR_FN (cfun) + || eg->dest == EXIT_BLOCK_PTR_FOR_FN (cfun)) + break; + if (bitmap_bit_p (m_vector_manager->vector_earliest[ed], i)) + { + auto &src_block_info = get_block_info (eg->src); + auto &dest_block_info = get_block_info (eg->dest); + if (src_block_info.reaching_out.unknown_p ()) + break; + + gcc_assert (!(eg->flags & EDGE_ABNORMAL)); + vector_insn_info new_info = vector_insn_info (); + profile_probability prob = src_block_info.probability; + /* We don't fuse user vsetvl into EMPTY or + DIRTY (EMPTY but polluted) block for these + following reasons: + + - The user vsetvl instruction is configured as + no side effects that the previous passes + (GSCE, Loop-invariant, ..., etc) + should be able to do a good job on optimization + of user explicit vsetvls so we don't need to + PRE optimization (The user vsetvls should be + on the optimal local already before this pass) + again for user vsetvls in VSETVL PASS here + (Phase 3 && Phase 4). + + - Allowing user vsetvls be optimized in PRE + optimization here (Phase 3 && Phase 4) will + complicate the codes so much so we prefer user + vsetvls be optimized in post-optimization + (Phase 5 && Phase 6). */ + if (vsetvl_insn_p (expr.get_insn ()->rtl ())) + { + if (src_block_info.reaching_out.empty_p ()) + continue; + else if (src_block_info.reaching_out.dirty_p () + && !src_block_info.reaching_out.compatible_p (expr)) + { + new_info.set_empty (); + /* Update probability as uninitialized status so that + we won't try to fuse any demand info into such EMPTY + block any more. */ + prob = profile_probability::uninitialized (); + update_block_info (eg->src->index, prob, new_info); + continue; + } + } + + if (src_block_info.reaching_out.empty_p ()) + { + if (src_block_info.probability + == profile_probability::uninitialized ()) + continue; + new_info = expr.global_merge (expr, eg->src->index); + new_info.set_dirty (); + prob = dest_block_info.probability; + update_block_info (eg->src->index, prob, new_info); + changed_p = true; + } + else if (src_block_info.reaching_out.dirty_p ()) + { + /* DIRTY -> DIRTY or VALID -> DIRTY. */ + if (demands_can_be_fused_p (src_block_info.reaching_out, + expr)) + { + new_info = src_block_info.reaching_out.global_merge ( + expr, eg->src->index); + new_info.set_dirty (); + prob += dest_block_info.probability; + } + else if (!src_block_info.reaching_out.compatible_p (expr) + && !m_vector_manager->earliest_fusion_worthwhile_p ( + eg->src)) + { + new_info.set_empty (); + prob = profile_probability::uninitialized (); + } + else if (!src_block_info.reaching_out.compatible_p (expr) + && dest_block_info.probability + > src_block_info.probability) + { + new_info = expr; + new_info.set_dirty (); + prob = dest_block_info.probability; + } + else + continue; + update_block_info (eg->src->index, prob, new_info); + changed_p = true; + } + else + { + rtx vl = NULL_RTX; + if (vsetvl_insn_p ( + src_block_info.reaching_out.get_insn ()->rtl ()) + && vsetvl_dominated_by_p (eg->src, expr, + src_block_info.reaching_out, + true)) + ; + else if (!demands_can_be_fused_p (src_block_info.reaching_out, + expr)) + continue; + else if (!earliest_pred_can_be_fused_p ( + crtl->ssa->bb (eg->src), + src_block_info.reaching_out, expr, &vl)) + continue; + + vector_insn_info new_info + = src_block_info.reaching_out.global_merge (expr, + eg->src->index); + + prob = std::max (dest_block_info.probability, + src_block_info.probability); + change_vsetvl_insn (new_info.get_insn (), new_info, vl); + update_block_info (eg->src->index, prob, new_info); + changed_p = true; + } + } + } + } + return changed_p; +} + +/* Fuse VSETVL demand info according LCM computed location. */ +void +pass_vsetvl::vsetvl_fusion (void) +{ + /* Fuse VSETVL demand info until VSETVL CFG fixed. */ + bool changed_p = true; + int fusion_no = 0; + while (changed_p) + { + changed_p = false; + fusion_no++; + prune_expressions (); + m_vector_manager->create_bitmap_vectors (); + compute_local_properties (); + /* Compute global availability. */ + compute_available (m_vector_manager->vector_comp, + m_vector_manager->vector_kill, + m_vector_manager->vector_avout, + m_vector_manager->vector_avin); + /* Compute global anticipatability. */ + compute_antinout_edge (m_vector_manager->vector_antic, + m_vector_manager->vector_transp, + m_vector_manager->vector_antin, + m_vector_manager->vector_antout); + /* Compute earliestness. */ + compute_earliest (m_vector_manager->vector_edge_list, + m_vector_manager->vector_exprs.length (), + m_vector_manager->vector_antin, + m_vector_manager->vector_antout, + m_vector_manager->vector_avout, + m_vector_manager->vector_kill, + m_vector_manager->vector_earliest); + changed_p |= earliest_fusion (); + if (dump_file) + { + fprintf (dump_file, "\nEARLIEST fusion %d\n", fusion_no); + m_vector_manager->dump (dump_file); + } + m_vector_manager->free_bitmap_vectors (); + if (!m_vector_manager->vector_exprs.is_empty ()) + m_vector_manager->vector_exprs.release (); + } +} + /* Return true if VSETVL in the block can be refined as vsetvl zero,zero. */ bool pass_vsetvl::can_refine_vsetvl_p (const basic_block cfg_bb, @@ -3855,7 +3530,7 @@ pass_vsetvl::refine_vsetvls (void) const basic_block cfg_bb; FOR_EACH_BB_FN (cfg_bb, cfun) { - auto info = get_block_info(cfg_bb).local_dem; + auto info = get_block_info (cfg_bb).local_dem; insn_info *insn = info.get_insn (); if (!info.valid_p ()) continue; @@ -3901,8 +3576,7 @@ pass_vsetvl::cleanup_vsetvls () basic_block cfg_bb; FOR_EACH_BB_FN (cfg_bb, cfun) { - auto &info - = get_block_info(cfg_bb).reaching_out; + auto &info = get_block_info (cfg_bb).reaching_out; gcc_assert (m_vector_manager->expr_set_num ( m_vector_manager->vector_del[cfg_bb->index]) <= 1); @@ -3914,9 +3588,7 @@ pass_vsetvl::cleanup_vsetvls () info.set_unknown (); else { - const auto dem - = get_block_info(cfg_bb) - .local_dem; + const auto dem = get_block_info (cfg_bb).local_dem; gcc_assert (dem == *m_vector_manager->vector_exprs[i]); insn_info *insn = dem.get_insn (); gcc_assert (insn && insn->rtl ()); @@ -3976,6 +3648,16 @@ pass_vsetvl::commit_vsetvls (void) gcc_assert (!(eg->flags & EDGE_ABNORMAL)); need_commit = true; insert_insn_on_edge (rinsn, eg); + + if (dump_file) + { + fprintf (dump_file, + "\nInsert vsetvl insn %d at edge %d from to " + ":\n", + INSN_UID (rinsn), ed, eg->src->index, + eg->dest->index); + print_rtl_single (dump_file, rinsn); + } } } } @@ -3983,33 +3665,10 @@ pass_vsetvl::commit_vsetvls (void) for (const bb_info *bb : crtl->ssa->bbs ()) { basic_block cfg_bb = bb->cfg_bb (); - const auto reaching_out - = get_block_info(cfg_bb).reaching_out; + const auto reaching_out = get_block_info (cfg_bb).reaching_out; if (!reaching_out.dirty_p ()) continue; - if (reaching_out.dirty_with_killed_avl_p ()) - { - if (!has_vsetvl_killed_avl_p (bb, reaching_out)) - continue; - - unsigned int bb_index; - sbitmap_iterator sbi; - sbitmap avin = m_vector_manager->vector_avin[cfg_bb->index]; - bool available_p = false; - EXECUTE_IF_SET_IN_BITMAP (avin, 0, bb_index, sbi) - { - if (m_vector_manager->vector_exprs[bb_index]->available_p ( - reaching_out)) - { - available_p = true; - break; - } - } - if (available_p) - continue; - } - rtx new_pat; if (!reaching_out.demand_p (DEMAND_AVL)) { @@ -4021,23 +3680,50 @@ pass_vsetvl::commit_vsetvls (void) new_pat = gen_vsetvl_pat (VSETVL_VTYPE_CHANGE_ONLY, reaching_out, NULL_RTX); else if (vlmax_avl_p (reaching_out.get_avl ())) - new_pat = gen_vsetvl_pat (VSETVL_NORMAL, reaching_out, - reaching_out.get_avl_reg_rtx ()); + { + rtx vl = reaching_out.get_avl_or_vl_reg (); + new_pat = gen_vsetvl_pat (VSETVL_NORMAL, reaching_out, vl); + } else new_pat = gen_vsetvl_pat (VSETVL_DISCARD_RESULT, reaching_out, NULL_RTX); - start_sequence (); - emit_insn (new_pat); - rtx_insn *rinsn = get_insns (); - end_sequence (); - rtx_insn *new_insn = insert_insn_end_basic_block (rinsn, cfg_bb); - if (dump_file) + edge eg; + edge_iterator eg_iterator; + FOR_EACH_EDGE (eg, eg_iterator, cfg_bb->succs) { - fprintf (dump_file, - "\nInsert vsetvl insn %d at the end of :\n", - INSN_UID (new_insn), cfg_bb->index); - print_rtl_single (dump_file, new_insn); + /* We should not get an abnormal edge here. */ + gcc_assert (!(eg->flags & EDGE_ABNORMAL)); + /* We failed to optimize this case in Phase 3 (earliest fusion): + + bb 2: vsetvl a5, a3 ... + goto bb 4 + bb 3: vsetvl a5, a2 ... + goto bb 4 + bb 4: vsetvli zero, a5 ---> Redundant, should be elided. + + Since "a5" value can come from either bb 2 or bb 3, we can't make + it optimized in Phase 3 which will make phase 3 so complicated. + Now, we do post optimization here to elide the redundant VSETVL + insn in bb4. */ + if (m_vector_manager->vsetvl_dominated_by_all_preds_p (cfg_bb, + reaching_out)) + continue; + + start_sequence (); + emit_insn (copy_rtx (new_pat)); + rtx_insn *rinsn = get_insns (); + end_sequence (); + + insert_insn_on_edge (rinsn, eg); + need_commit = true; + if (dump_file) + { + fprintf (dump_file, + "\nInsert vsetvl insn %d from to :\n", + INSN_UID (rinsn), cfg_bb->index, eg->dest->index); + print_rtl_single (dump_file, rinsn); + } } } @@ -4226,7 +3912,8 @@ pass_vsetvl::local_eliminate_vsetvl_insn (const bb_info *bb) const /* Local AVL compatibility checking is simpler than global, we only need to check the REGNO is same. */ - if (prev_dem.valid_or_dirty_p () && prev_dem.skip_avl_compatible_p (curr_dem) + if (prev_dem.valid_or_dirty_p () + && prev_dem.skip_avl_compatible_p (curr_dem) && local_avl_compatible_p (prev_avl, curr_avl)) { /* curr_dem and prev_dem is compatible! */ @@ -4234,7 +3921,7 @@ pass_vsetvl::local_eliminate_vsetvl_insn (const bb_info *bb) const compatible before merge. */ prev_dem.set_avl_info (curr_dem.get_avl_info ()); /* Merge both and update into curr_vsetvl. */ - prev_dem = curr_dem.merge (prev_dem, LOCAL_MERGE); + prev_dem = curr_dem.local_merge (prev_dem); change_vsetvl_insn (curr_dem.get_insn (), prev_dem); /* Then we can drop prev_vsetvl. */ eliminate_insn (prev_vsetvl); @@ -4261,8 +3948,11 @@ pass_vsetvl::local_eliminate_vsetvl_insn (const bb_info *bb) const none exists or if a user RVV instruction is enountered prior to any vsetvl. */ static rtx_insn * -get_first_vsetvl_before_rvv_insns (basic_block cfg_bb) +get_first_vsetvl_before_rvv_insns (basic_block cfg_bb, + enum vsetvl_type insn_type) { + gcc_assert (insn_type == VSETVL_DISCARD_RESULT + || insn_type == VSETVL_VTYPE_CHANGE_ONLY); rtx_insn *rinsn; FOR_BB_INSNS (cfg_bb, rinsn) { @@ -4273,7 +3963,11 @@ get_first_vsetvl_before_rvv_insns (basic_block cfg_bb) if (has_vtype_op (rinsn) || vsetvl_insn_p (rinsn)) return nullptr; - if (vsetvl_discard_result_insn_p (rinsn)) + if (insn_type == VSETVL_DISCARD_RESULT + && vsetvl_discard_result_insn_p (rinsn)) + return rinsn; + if (insn_type == VSETVL_VTYPE_CHANGE_ONLY + && vsetvl_vtype_change_only_p (rinsn)) return rinsn; } return nullptr; @@ -4321,16 +4015,15 @@ pass_vsetvl::global_eliminate_vsetvl_insn (const bb_info *bb) const { /* Optimize the local vsetvl. */ dem = block_info.local_dem; - vsetvl_rinsn = get_first_vsetvl_before_rvv_insns (cfg_bb); + vsetvl_rinsn + = get_first_vsetvl_before_rvv_insns (cfg_bb, VSETVL_DISCARD_RESULT); } if (!vsetvl_rinsn) /* Optimize the global vsetvl inserted by LCM. */ vsetvl_rinsn = get_vsetvl_at_end (bb, &dem); /* No need to optimize if block doesn't have vsetvl instructions. */ - if (!dem.valid_or_dirty_p () - || !vsetvl_rinsn - || !dem.get_avl_source () + if (!dem.valid_or_dirty_p () || !vsetvl_rinsn || !dem.get_avl_source () || !dem.has_avl_reg ()) return false; @@ -4345,7 +4038,7 @@ pass_vsetvl::global_eliminate_vsetvl_insn (const bb_info *bb) const unsigned int bb_index; sbitmap_iterator sbi; - rtx avl = get_avl (dem.get_insn ()->rtl ()); + rtx avl = dem.get_avl (); hash_set sets = get_all_sets (dem.get_avl_source (), true, false, false); /* Condition 2: All VL/VTYPE available in are all compatible. */ @@ -4369,7 +4062,10 @@ pass_vsetvl::global_eliminate_vsetvl_insn (const bb_info *bb) const { sbitmap avout = m_vector_manager->vector_avout[e->src->index]; if (e->src == ENTRY_BLOCK_PTR_FOR_FN (cfun) - || e->src == EXIT_BLOCK_PTR_FOR_FN (cfun) || bitmap_empty_p (avout)) + || e->src == EXIT_BLOCK_PTR_FOR_FN (cfun) + || (unsigned int) e->src->index + >= m_vector_manager->vector_block_infos.length () + || bitmap_empty_p (avout)) return false; EXECUTE_IF_SET_IN_BITMAP (avout, 0, bb_index, sbi) @@ -4400,7 +4096,7 @@ pass_vsetvl::global_eliminate_vsetvl_insn (const bb_info *bb) const compatible before merge. */ curr_dem.set_avl_info (prev_dem.get_avl_info ()); /* Merge both and update into curr_vsetvl. */ - prev_dem = curr_dem.merge (prev_dem, LOCAL_MERGE); + prev_dem = curr_dem.local_merge (prev_dem); change_vsetvl_insn (insn, prev_dem); } } @@ -4513,6 +4209,61 @@ has_no_uses (basic_block cfg_bb, rtx_insn *rinsn, int regno) return true; } +/* For many reasons, we failed to elide the redundant vsetvls + in Phase 3 and Phase 4. + + - VLMAX-AVL case: 'vlmax_avl' may locate at some unlucky + point which make us set ANTLOC as false for LCM in 'O1'. + We don't want to complicate phase 3 and phase 4 too much, + so we do the post optimization for redundant VSETVLs here. +*/ +bool +pass_vsetvl::cleanup_earliest_vsetvls (const basic_block cfg_bb) const +{ + bool is_earliest_p = false; + if (cfg_bb->index >= (int) m_vector_manager->vector_block_infos.length ()) + is_earliest_p = true; + + rtx_insn *rinsn + = get_first_vsetvl_before_rvv_insns (cfg_bb, VSETVL_VTYPE_CHANGE_ONLY); + if (!rinsn) + return is_earliest_p; + + sbitmap avail; + if (is_earliest_p) + { + gcc_assert (single_succ_p (cfg_bb) && single_pred_p (cfg_bb)); + const bb_info *pred_bb = crtl->ssa->bb (single_pred (cfg_bb)); + gcc_assert (pred_bb->index () + < m_vector_manager->vector_block_infos.length ()); + avail = m_vector_manager->vector_avout[pred_bb->index ()]; + } + else + avail = m_vector_manager->vector_avin[cfg_bb->index]; + + if (!bitmap_empty_p (avail)) + { + unsigned int bb_index; + sbitmap_iterator sbi; + vector_insn_info strictest_info = vector_insn_info (); + EXECUTE_IF_SET_IN_BITMAP (avail, 0, bb_index, sbi) + { + const auto *expr = m_vector_manager->vector_exprs[bb_index]; + if (strictest_info.uninit_p () + || !expr->compatible_p ( + static_cast (strictest_info))) + strictest_info = *expr; + } + vector_insn_info info; + info.parse_insn (rinsn); + if (!strictest_info.same_vtype_p (info)) + return is_earliest_p; + eliminate_insn (rinsn); + } + + return is_earliest_p; +} + /* This function does the following post optimization base on dataflow analysis: @@ -4532,6 +4283,8 @@ pass_vsetvl::df_post_optimization (void) const rtx_insn *rinsn; FOR_ALL_BB_FN (cfg_bb, cfun) { + if (cleanup_earliest_vsetvls (cfg_bb)) + continue; FOR_BB_INSNS (cfg_bb, rinsn) { if (NONDEBUG_INSN_P (rinsn) && vsetvl_insn_p (rinsn)) @@ -4618,8 +4371,7 @@ pass_vsetvl::compute_probabilities (void) for (const bb_info *bb : crtl->ssa->bbs ()) { basic_block cfg_bb = bb->cfg_bb (); - auto &curr_prob - = get_block_info(cfg_bb).probability; + auto &curr_prob = get_block_info (cfg_bb).probability; /* GCC assume entry block (bb 0) are always so executed so set its probability as "always". */ @@ -4632,9 +4384,15 @@ pass_vsetvl::compute_probabilities (void) gcc_assert (curr_prob.initialized_p ()); FOR_EACH_EDGE (e, ei, cfg_bb->succs) { - auto &new_prob - = get_block_info(e->dest).probability; - if (!new_prob.initialized_p ()) + auto &new_prob = get_block_info (e->dest).probability; + /* Normally, the edge probability should be initialized. + However, some special testing code which is written in + GIMPLE IR style force the edge probility uninitialized, + we conservatively set it as never so that it will not + affect PRE (Phase 3 && Phse 4). */ + if (!e->probability.initialized_p ()) + new_prob = profile_probability::never (); + else if (!new_prob.initialized_p ()) new_prob = curr_prob * e->probability; else if (new_prob == profile_probability::always ()) continue; @@ -4676,9 +4434,7 @@ pass_vsetvl::lazy_vsetvl (void) /* Phase 3 - Propagate demanded info across blocks. */ if (dump_file) fprintf (dump_file, "\nPhase 3: Demands propagation across blocks\n"); - demand_fusion (); - if (dump_file) - m_vector_manager->dump (dump_file); + vsetvl_fusion (); /* Phase 4 - Lazy code motion. */ if (dump_file) diff --git a/gcc/config/riscv/riscv-vsetvl.def b/gcc/config/riscv/riscv-vsetvl.def index 7a73149f1dac..7289c01efcfe 100644 --- a/gcc/config/riscv/riscv-vsetvl.def +++ b/gcc/config/riscv/riscv-vsetvl.def @@ -319,7 +319,7 @@ DEF_SEW_LMUL_FUSE_RULE (/*SEW*/ DEMAND_TRUE, /*LMUL*/ DEMAND_FALSE, /*RATIO*/ DEMAND_TRUE, /*GE_SEW*/ DEMAND_FALSE, /*NEW_DEMAND_SEW*/ true, /*NEW_DEMAND_LMUL*/ false, - /*NEW_DEMAND_RATIO*/ false, + /*NEW_DEMAND_RATIO*/ true, /*NEW_DEMAND_GE_SEW*/ true, first_sew, vlmul_for_first_sew_second_ratio, second_ratio) DEF_SEW_LMUL_FUSE_RULE (/*SEW*/ DEMAND_TRUE, /*LMUL*/ DEMAND_FALSE, diff --git a/gcc/config/riscv/riscv-vsetvl.h b/gcc/config/riscv/riscv-vsetvl.h index 87cdd2e886ee..53549abfac55 100644 --- a/gcc/config/riscv/riscv-vsetvl.h +++ b/gcc/config/riscv/riscv-vsetvl.h @@ -21,8 +21,6 @@ along with GCC; see the file COPYING3. If not see #ifndef GCC_RISCV_VSETVL_H #define GCC_RISCV_VSETVL_H -#define IS_AGNOSTIC(VALUE) (bool) (VALUE & 0x1 || (VALUE >> 1 & 0x1)) - namespace riscv_vector { /* Classification of vsetvl instruction. */ @@ -69,12 +67,6 @@ enum fusion_type KILLED_AVL_FUSION }; -enum merge_type -{ - LOCAL_MERGE, - GLOBAL_MERGE -}; - enum def_type { REAL_SET = 1 << 0, @@ -167,6 +159,7 @@ public: avl_info (rtx, rtl_ssa::set_info *); rtx get_value () const { return m_value; } rtl_ssa::set_info *get_source () const { return m_source; } + void set_source (rtl_ssa::set_info *set) { m_source = set; } bool single_source_equal_p (const avl_info &) const; bool multiple_source_equal_p (const avl_info &) const; avl_info &operator= (const avl_info &); @@ -225,6 +218,7 @@ public: rtx get_avl () const { return m_avl.get_value (); } const avl_info &get_avl_info () const { return m_avl; } rtl_ssa::set_info *get_avl_source () const { return m_avl.get_source (); } + void set_avl_source (rtl_ssa::set_info *set) { m_avl.set_source (set); } void set_avl_info (const avl_info &avl) { m_avl = avl; } uint8_t get_sew () const { return m_sew; } riscv_vector::vlmul_type get_vlmul () const { return m_vlmul; } @@ -246,31 +240,11 @@ private: VALID, UNKNOWN, EMPTY, - /* The empty block can not be polluted as dirty. */ - HARD_EMPTY, /* The block is polluted as containing VSETVL instruction during dem backward propagation to gain better LCM optimization even though such VSETVL instruction is not really emit yet during this time. */ DIRTY, - /* The block is polluted with killed AVL. - We will backward propagate such case: - bb 0: def a5, 55 (empty). - ... - bb 1: vsetvli zero, a5. - ... - bb 2: empty. - ... - bb 3: def a3, 55 (empty). - ... - bb 4: vsetvli zero, a3. - - To elide vsetvli in bb 4, we need to backward pollute bb 3 and bb 2 - as DIRTY block as long as there is a block def AVL which has the same - source with AVL in bb 4. Such polluted block, we call it as - DIRTY_WITH_KILLED_AVL - */ - DIRTY_WITH_KILLED_AVL }; enum state_type m_state; @@ -316,21 +290,11 @@ public: bool uninit_p () const { return m_state == UNINITIALIZED; } bool valid_p () const { return m_state == VALID; } bool unknown_p () const { return m_state == UNKNOWN; } - bool empty_p () const { return m_state == EMPTY || m_state == HARD_EMPTY; } - bool hard_empty_p () const { return m_state == HARD_EMPTY; } - bool dirty_p () const - { - return m_state == DIRTY || m_state == DIRTY_WITH_KILLED_AVL; - } - bool dirty_with_killed_avl_p () const - { - return m_state == DIRTY_WITH_KILLED_AVL; - } - bool real_dirty_p () const { return m_state == DIRTY; } + bool empty_p () const { return m_state == EMPTY; } + bool dirty_p () const { return m_state == DIRTY; } bool valid_or_dirty_p () const { - return m_state == VALID || m_state == DIRTY - || m_state == DIRTY_WITH_KILLED_AVL; + return m_state == VALID || m_state == DIRTY; } bool available_p (const vector_insn_info &) const; @@ -341,32 +305,10 @@ public: return info; } - static vector_insn_info get_hard_empty () - { - vector_insn_info info; - info.set_hard_empty (); - return info; - } - void set_valid () { m_state = VALID; } void set_unknown () { m_state = UNKNOWN; } void set_empty () { m_state = EMPTY; } - void set_hard_empty () { m_state = HARD_EMPTY; } - void set_dirty (enum fusion_type type) - { - gcc_assert (type == VALID_AVL_FUSION || type == KILLED_AVL_FUSION); - if (type == VALID_AVL_FUSION) - m_state = DIRTY; - else - m_state = DIRTY_WITH_KILLED_AVL; - } - void set_dirty (bool dirty_with_killed_avl_p) - { - if (dirty_with_killed_avl_p) - m_state = DIRTY_WITH_KILLED_AVL; - else - m_state = DIRTY; - } + void set_dirty () { m_state = DIRTY; } void set_insn (rtl_ssa::insn_info *insn) { m_insn = insn; } bool demand_p (enum demand_type type) const { return m_demands[type]; } @@ -386,10 +328,12 @@ public: bool compatible_avl_p (const avl_info &) const; bool compatible_vtype_p (const vl_vtype_info &) const; bool compatible_p (const vl_vtype_info &) const; - vector_insn_info merge (const vector_insn_info &, enum merge_type) const; + vector_insn_info local_merge (const vector_insn_info &) const; + vector_insn_info global_merge (const vector_insn_info &, unsigned int) const; rtl_ssa::insn_info *get_insn () const { return m_insn; } const bool *get_demands (void) const { return m_demands; } + rtx get_avl_or_vl_reg (void) const; rtx get_avl_reg_rtx (void) const { return gen_rtx_REG (Pmode, get_avl_source ()->regno ()); @@ -431,6 +375,9 @@ public: sbitmap *vector_comp; sbitmap *vector_avin; sbitmap *vector_avout; + sbitmap *vector_antin; + sbitmap *vector_antout; + sbitmap *vector_earliest; vector_infos_manager (); @@ -452,8 +399,10 @@ public: /* Return true if all expression set in bitmap are same ratio. */ bool all_same_ratio_p (sbitmap) const; - bool all_empty_predecessor_p (const basic_block) const; bool all_avail_in_compatible_p (const basic_block) const; + bool earliest_fusion_worthwhile_p (const basic_block) const; + bool vsetvl_dominated_by_all_preds_p (const basic_block, + const vector_insn_info &) const; bool to_delete_p (rtx_insn *rinsn) { diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc index 5248dd3febe0..8d8f7b4f16ed 100644 --- a/gcc/config/riscv/riscv.cc +++ b/gcc/config/riscv/riscv.cc @@ -65,6 +65,7 @@ along with GCC; see the file COPYING3. If not see #include "cfgloop.h" #include "cfgrtl.h" #include "sel-sched.h" +#include "sched-int.h" #include "fold-const.h" #include "gimple-iterator.h" #include "gimple-expr.h" @@ -73,6 +74,7 @@ along with GCC; see the file COPYING3. If not see /* This file should be included last. */ #include "target-def.h" +#include "riscv-vector-costs.h" /* True if X is an UNSPEC wrapper around a SYMBOL_REF or LABEL_REF. */ #define UNSPEC_ADDRESS_P(X) \ @@ -111,6 +113,14 @@ struct GTY(()) riscv_frame_info { /* How much the GPR save/restore routines adjust sp (or 0 if unused). */ unsigned save_libcall_adjustment; + /* the minimum number of bytes, in multiples of 16-byte address increments, + required to cover the registers in a multi push & pop. */ + unsigned multi_push_adj_base; + + /* the number of additional 16-byte address increments allocated for the stack + frame in a multi push & pop. */ + unsigned multi_push_adj_addi; + /* Offsets of fixed-point and floating-point save areas from frame bottom */ poly_int64 gp_sp_offset; poly_int64 fp_sp_offset; @@ -247,6 +257,9 @@ struct riscv_tune_info { /* Whether unaligned accesses execute very slowly. */ bool riscv_slow_unaligned_access_p; +/* Whether user explicitly passed -mstrict-align. */ +bool riscv_user_wants_strict_align; + /* Stack alignment to assume/maintain. */ unsigned riscv_stack_boundary; @@ -365,6 +378,7 @@ static const struct riscv_tune_param optimize_size_tune_info = { static tree riscv_handle_fndecl_attribute (tree *, tree, tree, int, bool *); static tree riscv_handle_type_attribute (tree *, tree, tree, int, bool *); +static void riscv_legitimize_poly_move (machine_mode, rtx, rtx, rtx); /* Defining target-specific uses of __attribute__. */ static const struct attribute_spec riscv_attribute_table[] = @@ -408,6 +422,17 @@ static const struct riscv_tune_info riscv_tune_info_table[] = { function. */ static bool riscv_save_frame_pointer; +typedef enum +{ + PUSH_IDX = 0, + POP_IDX, + POPRET_IDX, + POPRETZ_IDX, + ZCMP_OP_NUM +} riscv_zcmp_op_t; + +typedef insn_code (*code_for_push_pop_t) (machine_mode); + void riscv_frame_info::reset(void) { total_size = 0; @@ -804,6 +829,138 @@ static int riscv_symbol_insns (enum riscv_symbol_type type) } } +/* Immediate values loaded by the FLI.S instruction in Chapter 25 of the latest RISC-V ISA + Manual draft. For details, please see: + https://github.com/riscv/riscv-isa-manual/releases/tag/isa-449cd0c */ + +static unsigned HOST_WIDE_INT fli_value_hf[32] = +{ + 0xbcp8, 0x4p8, 0x1p8, 0x2p8, 0x1cp8, 0x20p8, 0x2cp8, 0x30p8, + 0x34p8, 0x35p8, 0x36p8, 0x37p8, 0x38p8, 0x39p8, 0x3ap8, 0x3bp8, + 0x3cp8, 0x3dp8, 0x3ep8, 0x3fp8, 0x40p8, 0x41p8, 0x42p8, 0x44p8, + 0x48p8, 0x4cp8, 0x58p8, 0x5cp8, 0x78p8, + /* Only used for filling, ensuring that 29 and 30 of HF are the same. */ + 0x78p8, + 0x7cp8, 0x7ep8 +}; + +static unsigned HOST_WIDE_INT fli_value_sf[32] = +{ + 0xbf8p20, 0x008p20, 0x378p20, 0x380p20, 0x3b8p20, 0x3c0p20, 0x3d8p20, 0x3e0p20, + 0x3e8p20, 0x3eap20, 0x3ecp20, 0x3eep20, 0x3f0p20, 0x3f2p20, 0x3f4p20, 0x3f6p20, + 0x3f8p20, 0x3fap20, 0x3fcp20, 0x3fep20, 0x400p20, 0x402p20, 0x404p20, 0x408p20, + 0x410p20, 0x418p20, 0x430p20, 0x438p20, 0x470p20, 0x478p20, 0x7f8p20, 0x7fcp20 +}; + +static unsigned HOST_WIDE_INT fli_value_df[32] = +{ + 0xbff0p48, 0x10p48, 0x3ef0p48, 0x3f00p48, + 0x3f70p48, 0x3f80p48, 0x3fb0p48, 0x3fc0p48, + 0x3fd0p48, 0x3fd4p48, 0x3fd8p48, 0x3fdcp48, + 0x3fe0p48, 0x3fe4p48, 0x3fe8p48, 0x3fecp48, + 0x3ff0p48, 0x3ff4p48, 0x3ff8p48, 0x3ffcp48, + 0x4000p48, 0x4004p48, 0x4008p48, 0x4010p48, + 0x4020p48, 0x4030p48, 0x4060p48, 0x4070p48, + 0x40e0p48, 0x40f0p48, 0x7ff0p48, 0x7ff8p48 +}; + +/* Display floating-point values at the assembly level, which is consistent + with the zfa extension of llvm: + https://reviews.llvm.org/D145645. */ + +const char *fli_value_print[32] = +{ + "-1.0", "min", "1.52587890625e-05", "3.0517578125e-05", "0.00390625", "0.0078125", "0.0625", "0.125", + "0.25", "0.3125", "0.375", "0.4375", "0.5", "0.625", "0.75", "0.875", + "1.0", "1.25", "1.5", "1.75", "2.0", "2.5", "3.0", "4.0", + "8.0", "16.0", "128.0", "256.0", "32768.0", "65536.0", "inf", "nan" +}; + +/* Return index of the FLI instruction table if rtx X is an immediate constant that can + be moved using a single FLI instruction in zfa extension. Return -1 if not found. */ + +int +riscv_float_const_rtx_index_for_fli (rtx x) +{ + unsigned HOST_WIDE_INT *fli_value_array; + + machine_mode mode = GET_MODE (x); + + if (!TARGET_ZFA + || !CONST_DOUBLE_P(x) + || mode == VOIDmode + || (mode == HFmode && !(TARGET_ZFH || TARGET_ZVFH)) + || (mode == SFmode && !TARGET_HARD_FLOAT) + || (mode == DFmode && !TARGET_DOUBLE_FLOAT)) + return -1; + + if (!SCALAR_FLOAT_MODE_P (mode) + || GET_MODE_BITSIZE (mode).to_constant () > HOST_BITS_PER_WIDE_INT + /* Only support up to DF mode. */ + || GET_MODE_BITSIZE (mode).to_constant () > GET_MODE_BITSIZE (DFmode)) + return -1; + + unsigned HOST_WIDE_INT ival = 0; + + long res[2]; + real_to_target (res, + CONST_DOUBLE_REAL_VALUE (x), + REAL_MODE_FORMAT (mode)); + + if (mode == DFmode) + { + int order = BYTES_BIG_ENDIAN ? 1 : 0; + ival = zext_hwi (res[order], 32); + ival |= (zext_hwi (res[1 - order], 32) << 32); + + /* When the lower 32 bits are not all 0, it is impossible to be in the table. */ + if (ival & (unsigned HOST_WIDE_INT)0xffffffff) + return -1; + } + else + ival = zext_hwi (res[0], 32); + + switch (mode) + { + case E_HFmode: + fli_value_array = fli_value_hf; + break; + case E_SFmode: + fli_value_array = fli_value_sf; + break; + case E_DFmode: + fli_value_array = fli_value_df; + break; + default: + return -1; + } + + if (fli_value_array[0] == ival) + return 0; + + if (fli_value_array[1] == ival) + return 1; + + /* Perform a binary search to find target index. */ + unsigned l, r, m; + + l = 2; + r = 31; + + while (l <= r) + { + m = (l + r) / 2; + if (fli_value_array[m] == ival) + return m; + else if (fli_value_array[m] < ival) + l = m+1; + else + r = m-1; + } + + return -1; +} + /* Implement TARGET_LEGITIMATE_CONSTANT_P. */ static bool @@ -831,6 +988,9 @@ riscv_cannot_force_const_mem (machine_mode mode ATTRIBUTE_UNUSED, rtx x) if (GET_CODE (x) == HIGH) return true; + if (satisfies_constraint_zfli (x)) + return true; + split_const (x, &base, &offset); if (riscv_symbolic_constant_p (base, &type)) { @@ -1213,7 +1373,8 @@ riscv_classify_address (struct riscv_address_info *info, rtx x, /* Implement TARGET_LEGITIMATE_ADDRESS_P. */ static bool -riscv_legitimate_address_p (machine_mode mode, rtx x, bool strict_p) +riscv_legitimate_address_p (machine_mode mode, rtx x, bool strict_p, + code_helper = ERROR_MARK) { struct riscv_address_info addr; @@ -1226,7 +1387,8 @@ static bool riscv_compressed_reg_p (int regno) { /* x8-x15/f8-f15 are compressible registers. */ - return (TARGET_RVC && (IN_RANGE (regno, GP_REG_FIRST + 8, GP_REG_FIRST + 15) + return ((TARGET_RVC || TARGET_ZCA) + && (IN_RANGE (regno, GP_REG_FIRST + 8, GP_REG_FIRST + 15) || IN_RANGE (regno, FP_REG_FIRST + 8, FP_REG_FIRST + 15))); } @@ -1321,6 +1483,10 @@ riscv_const_insns (rtx x) } case CONST_DOUBLE: + /* See if we can use FMV directly. */ + if (satisfies_constraint_zfli (x)) + return 1; + /* We can use x0 to load floating-point zero. */ return x == CONST0_RTX (GET_MODE (x)) ? 1 : 0; case CONST_VECTOR: @@ -1335,7 +1501,7 @@ riscv_const_insns (rtx x) out range of [-16, 15]. - 3. const series vector. ...etc. */ - if (riscv_v_ext_vector_mode_p (GET_MODE (x))) + if (riscv_v_ext_mode_p (GET_MODE (x))) { /* const series vector. */ rtx base, step; @@ -1804,6 +1970,22 @@ riscv_shorten_lw_offset (rtx base, HOST_WIDE_INT offset) return addr; } +/* Helper for riscv_legitimize_address. Given X, return true if it + is a left shift by 1, 2 or 3 positions or a multiply by 2, 4 or 8. + + This respectively represent canonical shift-add rtxs or scaled + memory addresses. */ +static bool +mem_shadd_or_shadd_rtx_p (rtx x) +{ + return ((GET_CODE (x) == ASHIFT + || GET_CODE (x) == MULT) + && CONST_INT_P (XEXP (x, 1)) + && ((GET_CODE (x) == ASHIFT && IN_RANGE (INTVAL (XEXP (x, 1)), 1, 3)) + || (GET_CODE (x) == MULT + && IN_RANGE (exact_log2 (INTVAL (XEXP (x, 1))), 1, 3)))); +} + /* This function is used to implement LEGITIMIZE_ADDRESS. If X can be legitimized in a way that the generic machinery might not expect, return a new address, otherwise return NULL. MODE is the mode of @@ -1829,6 +2011,32 @@ riscv_legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED, rtx base = XEXP (x, 0); HOST_WIDE_INT offset = INTVAL (XEXP (x, 1)); + /* Handle (plus (plus (mult (a) (mem_shadd_constant)) (fp)) (C)) case. */ + if (GET_CODE (base) == PLUS && mem_shadd_or_shadd_rtx_p (XEXP (base, 0)) + && SMALL_OPERAND (offset)) + { + rtx index = XEXP (base, 0); + rtx fp = XEXP (base, 1); + if (REGNO (fp) == VIRTUAL_STACK_VARS_REGNUM) + { + + /* If we were given a MULT, we must fix the constant + as we're going to create the ASHIFT form. */ + int shift_val = INTVAL (XEXP (index, 1)); + if (GET_CODE (index) == MULT) + shift_val = exact_log2 (shift_val); + + rtx reg1 = gen_reg_rtx (Pmode); + rtx reg2 = gen_reg_rtx (Pmode); + rtx reg3 = gen_reg_rtx (Pmode); + riscv_emit_binary (PLUS, reg1, fp, GEN_INT (offset)); + riscv_emit_binary (ASHIFT, reg2, XEXP (index, 0), GEN_INT (shift_val)); + riscv_emit_binary (PLUS, reg3, reg2, reg1); + + return reg3; + } + } + if (!riscv_valid_base_register_p (base, mode, false)) base = copy_to_mode_reg (Pmode, base); if (optimize_function_for_size_p (cfun) @@ -1901,6 +2109,12 @@ riscv_legitimize_const_move (machine_mode mode, rtx dest, rtx src) return; } + if (satisfies_constraint_zfli (src)) + { + riscv_emit_set (dest, src); + return; + } + /* Split moves of symbolic constants into high/low pairs. */ if (riscv_split_symbol (dest, src, MAX_MACHINE_MODE, &src)) { @@ -1928,6 +2142,28 @@ riscv_legitimize_const_move (machine_mode mode, rtx dest, rtx src) return; } + /* Handle below format. + (const:DI + (plus:DI + (symbol_ref:DI ("ic") [flags 0x2] ) <- op_0 + (const_poly_int:DI [16, 16]) // <- op_1 + )) + */ + rtx src_op_0 = XEXP (src, 0); + + if (GET_CODE (src) == CONST && GET_CODE (src_op_0) == PLUS + && CONST_POLY_INT_P (XEXP (src_op_0, 1))) + { + rtx dest_tmp = gen_reg_rtx (mode); + rtx tmp = gen_reg_rtx (mode); + + riscv_emit_move (dest, XEXP (src_op_0, 0)); + riscv_legitimize_poly_move (mode, dest_tmp, tmp, XEXP (src_op_0, 1)); + + emit_insn (gen_rtx_SET (dest, gen_rtx_PLUS (mode, dest, dest_tmp))); + return; + } + src = force_const_mem (mode, src); /* When using explicit relocs, constant pool references are sometimes @@ -2445,6 +2681,8 @@ riscv_rtx_costs (rtx x, machine_mode mode, int outer_code, int opno ATTRIBUTE_UN switch (GET_CODE (x)) { case CONST_INT: + /* trivial constants checked using OUTER_CODE in case they are + encodable in insn itself w/o need for additional insn(s). */ if (riscv_immediate_operand_p (outer_code, INTVAL (x))) { *total = 0; @@ -2462,17 +2700,15 @@ riscv_rtx_costs (rtx x, machine_mode mode, int outer_code, int opno ATTRIBUTE_UN /* Fall through. */ case CONST: + /* Non trivial CONST_INT Fall through: check if need multiple insns. */ if ((cost = riscv_const_insns (x)) > 0) { - /* If the constant is likely to be stored in a GPR, SETs of - single-insn constants are as cheap as register sets; we - never want to CSE them. */ - if (cost == 1 && outer_code == SET) - *total = 0; - /* When we load a constant more than once, it usually is better - to duplicate the last operation in the sequence than to CSE - the constant itself. */ - else if (outer_code == SET || GET_MODE (x) == VOIDmode) + /* 1. Hoist will GCSE constants only if TOTAL returned is non-zero. + 2. For constants loaded more than once, the approach so far has + been to duplicate the operation than to CSE the constant. + 3. TODO: make cost more accurate specially if riscv_const_insns + returns > 1. */ + if (outer_code == SET || GET_MODE (x) == VOIDmode) *total = COSTS_N_INSNS (1); } else /* The instruction will be fetched from the constant pool. */ @@ -2487,7 +2723,8 @@ riscv_rtx_costs (rtx x, machine_mode mode, int outer_code, int opno ATTRIBUTE_UN /* When optimizing for size, make uncompressible 32-bit addresses more expensive so that compressible 32-bit addresses are preferred. */ - if (TARGET_RVC && !speed && riscv_mshorten_memrefs && mode == SImode + if ((TARGET_RVC || TARGET_ZCA) + && !speed && riscv_mshorten_memrefs && mode == SImode && !riscv_compressed_lw_address_p (XEXP (x, 0))) cost++; @@ -2913,7 +3150,8 @@ riscv_address_cost (rtx addr, machine_mode mode, { /* When optimizing for size, make uncompressible 32-bit addresses more * expensive so that compressible 32-bit addresses are preferred. */ - if (TARGET_RVC && !speed && riscv_mshorten_memrefs && mode == SImode + if ((TARGET_RVC || TARGET_ZCA) + && !speed && riscv_mshorten_memrefs && mode == SImode && !riscv_compressed_lw_address_p (addr)) return riscv_address_insns (addr, mode, false) + 1; return riscv_address_insns (addr, mode, false); @@ -2948,6 +3186,10 @@ riscv_split_64bit_move_p (rtx dest, rtx src) if (TARGET_64BIT) return false; + /* There is no need to split if the FLI instruction in the `Zfa` extension can be used. */ + if (satisfies_constraint_zfli (src)) + return false; + /* Allow FPR <-> FPR and FPR <-> MEM moves, and permit the special case of zeroing an FPR with FCVT.D.W. */ if (TARGET_DOUBLE_FLOAT @@ -2967,22 +3209,36 @@ riscv_split_64bit_move_p (rtx dest, rtx src) void riscv_split_doubleword_move (rtx dest, rtx src) { - /* XTheadFmv has instructions for accessing the upper bits of a double. */ - if (!TARGET_64BIT && TARGET_XTHEADFMV) + /* ZFA or XTheadFmv has instructions for accessing the upper bits of a double. */ + if (!TARGET_64BIT && (TARGET_ZFA || TARGET_XTHEADFMV)) { if (FP_REG_RTX_P (dest)) { rtx low_src = riscv_subword (src, false); rtx high_src = riscv_subword (src, true); - emit_insn (gen_th_fmv_hw_w_x (dest, high_src, low_src)); + + if (TARGET_ZFA) + emit_insn (gen_movdfsisi3_rv32 (dest, high_src, low_src)); + else + emit_insn (gen_th_fmv_hw_w_x (dest, high_src, low_src)); return; } if (FP_REG_RTX_P (src)) { rtx low_dest = riscv_subword (dest, false); rtx high_dest = riscv_subword (dest, true); - emit_insn (gen_th_fmv_x_w (low_dest, src)); - emit_insn (gen_th_fmv_x_hw (high_dest, src)); + + if (TARGET_ZFA) + { + emit_insn (gen_movsidf2_low_rv32 (low_dest, src)); + emit_insn (gen_movsidf2_high_rv32 (high_dest, src)); + return; + } + else + { + emit_insn (gen_th_fmv_x_w (low_dest, src)); + emit_insn (gen_th_fmv_x_hw (high_dest, src)); + } return; } } @@ -3146,6 +3402,17 @@ riscv_output_move (rtx dest, rtx src) case 8: return "fld\t%0,%1"; } + + if (src_code == CONST_DOUBLE && satisfies_constraint_zfli (src)) + switch (width) + { + case 2: + return "fli.h\t%0,%1"; + case 4: + return "fli.s\t%0,%1"; + case 8: + return "fli.d\t%0,%1"; + } } if (dest_code == REG && GP_REG_P (REGNO (dest)) && src_code == CONST_POLY_INT) { @@ -3600,7 +3867,7 @@ riscv_expand_conditional_move (rtx dest, rtx op, rtx cons, rtx alt) /* Emit an scc like instruction into a temporary so that we can use an EQ/NE comparison. */ - rtx tmp = gen_reg_rtx (mode); + rtx tmp = gen_reg_rtx (word_mode); /* We can support both FP and integer conditional moves. */ if (INTEGRAL_MODE_P (GET_MODE (XEXP (op, 0)))) @@ -4765,6 +5032,10 @@ riscv_union_memmodels (enum memmodel model1, enum memmodel model2) static bool riscv_memmodel_needs_amo_acquire (enum memmodel model) { + /* ZTSO amo mappings require no annotations. */ + if (TARGET_ZTSO) + return false; + switch (model) { case MEMMODEL_ACQ_REL: @@ -4788,6 +5059,10 @@ riscv_memmodel_needs_amo_acquire (enum memmodel model) static bool riscv_memmodel_needs_amo_release (enum memmodel model) { + /* ZTSO amo mappings require no annotations. */ + if (TARGET_ZTSO) + return false; + switch (model) { case MEMMODEL_ACQ_REL: @@ -4808,7 +5083,7 @@ riscv_memmodel_needs_amo_release (enum memmodel model) /* Get REGNO alignment of vector mode. The alignment = LMUL when the LMUL >= 1. Otherwise, alignment = 1. */ -static int +int riscv_get_v_regno_alignment (machine_mode mode) { /* 3.3.2. LMUL = 2,4,8, register numbers should be multiple of 2,4,8. @@ -4900,7 +5175,8 @@ riscv_print_operand (FILE *file, rtx op, int letter) else if (satisfies_constraint_Wc0 (op)) asm_fprintf (file, "0"); else if (satisfies_constraint_vi (op) - || satisfies_constraint_vj (op)) + || satisfies_constraint_vj (op) + || satisfies_constraint_vk (op)) asm_fprintf (file, "%wd", INTVAL (elt)); else output_operand_lossage ("invalid vector constant"); @@ -4971,8 +5247,7 @@ riscv_print_operand (FILE *file, rtx op, int letter) else if (code == CONST_INT) { /* Tail && Mask policy. */ - bool agnostic_p = UINTVAL (op) & 0x1; - asm_fprintf (file, "%s", agnostic_p ? "a" : "u"); + asm_fprintf (file, "%s", IS_AGNOSTIC (UINTVAL (op)) ? "a" : "u"); } else output_operand_lossage ("invalid vector constant"); @@ -5007,7 +5282,10 @@ riscv_print_operand (FILE *file, rtx op, int letter) case 'I': { const enum memmodel model = memmodel_base (INTVAL (op)); - if (model == MEMMODEL_SEQ_CST) + if (TARGET_ZTSO && model != MEMMODEL_SEQ_CST) + /* LR ops only have an annotation for SEQ_CST in the Ztso mapping. */ + break; + else if (model == MEMMODEL_SEQ_CST) fputs (".aqrl", file); else if (riscv_memmodel_needs_amo_acquire (model)) fputs (".aq", file); @@ -5016,7 +5294,12 @@ riscv_print_operand (FILE *file, rtx op, int letter) case 'J': { const enum memmodel model = memmodel_base (INTVAL (op)); - if (riscv_memmodel_needs_amo_release (model)) + if (TARGET_ZTSO && model == MEMMODEL_SEQ_CST) + /* SC ops only have an annotation for SEQ_CST in the Ztso mapping. */ + fputs (".rl", file); + else if (TARGET_ZTSO) + break; + else if (riscv_memmodel_needs_amo_release (model)) fputs (".rl", file); break; } @@ -5058,6 +5341,24 @@ riscv_print_operand (FILE *file, rtx op, int letter) output_address (mode, XEXP (op, 0)); break; + case CONST_DOUBLE: + { + if (letter == 'z' && op == CONST0_RTX (GET_MODE (op))) + { + fputs (reg_names[GP_REG_FIRST], file); + break; + } + + int fli_index = riscv_float_const_rtx_index_for_fli (op); + if (fli_index == -1 || fli_index > 31) + { + output_operand_lossage ("invalid use of '%%%c'", letter); + break; + } + asm_fprintf (file, "%s", fli_value_print[fli_index]); + break; + } + default: if (letter == 'z' && op == CONST0_RTX (GET_MODE (op))) fputs (reg_names[GP_REG_FIRST], file); @@ -5283,6 +5584,34 @@ riscv_save_reg_p (unsigned int regno) return false; } +/* Return TRUE if Zcmp push and pop insns should be + avoided. FALSE otherwise. + Only use multi push & pop if all GPRs masked can be covered, + and stack access is SP based, + and GPRs are at top of the stack frame, + and no conflicts in stack allocation with other features */ +static bool +riscv_avoid_multi_push (const struct riscv_frame_info *frame) +{ + if (!TARGET_ZCMP || crtl->calls_eh_return || frame_pointer_needed + || cfun->machine->interrupt_handler_p || cfun->machine->varargs_size != 0 + || crtl->args.pretend_args_size != 0 || flag_shrink_wrap_separate + || (frame->mask & ~MULTI_PUSH_GPR_MASK)) + return true; + + return false; +} + +/* Determine whether to use multi push insn. */ +static bool +riscv_use_multi_push (const struct riscv_frame_info *frame) +{ + if (riscv_avoid_multi_push (frame)) + return false; + + return (frame->multi_push_adj_base != 0); +} + /* Return TRUE if a libcall to save/restore GPRs should be avoided. FALSE otherwise. */ static bool @@ -5320,6 +5649,50 @@ riscv_save_libcall_count (unsigned mask) abort (); } +/* calculate number of s regs in multi push and pop. + Note that {s0-s10} is not valid in Zcmp, use {s0-s11} instead. */ +static unsigned +riscv_multi_push_sregs_count (unsigned mask) +{ + unsigned num = riscv_save_libcall_count (mask); + return (num == ZCMP_INVALID_S0S10_SREGS_COUNTS) ? ZCMP_S0S11_SREGS_COUNTS + : num; +} + +/* calculate number of regs(ra, s0-sx) in multi push and pop. */ +static unsigned +riscv_multi_push_regs_count (unsigned mask) +{ + /* 1 is for ra */ + return riscv_multi_push_sregs_count (mask) + 1; +} + +/* Handle 16 bytes align for poly_int. */ +static poly_int64 +riscv_16bytes_align (poly_int64 value) +{ + return aligned_upper_bound (value, 16); +} + +static HOST_WIDE_INT +riscv_16bytes_align (HOST_WIDE_INT value) +{ + return ROUND_UP (value, 16); +} + +/* Handle stack align for poly_int. */ +static poly_int64 +riscv_stack_align (poly_int64 value) +{ + return aligned_upper_bound (value, PREFERRED_STACK_BOUNDARY / 8); +} + +static HOST_WIDE_INT +riscv_stack_align (HOST_WIDE_INT value) +{ + return RISCV_STACK_ALIGN (value); +} + /* Populate the current function's riscv_frame_info structure. RISC-V stack frames grown downward. High addresses are at the top. @@ -5345,7 +5718,7 @@ riscv_save_libcall_count (unsigned mask) | GPR save area | + UNITS_PER_WORD | | +-------------------------------+ <-- stack_pointer_rtx + fp_sp_offset - | | + UNITS_PER_HWVALUE + | | + UNITS_PER_FP_REG | FPR save area | | | +-------------------------------+ <-- frame_pointer_rtx (virtual) @@ -5364,19 +5737,6 @@ riscv_save_libcall_count (unsigned mask) static HOST_WIDE_INT riscv_first_stack_step (struct riscv_frame_info *frame, poly_int64 remaining_size); -/* Handle stack align for poly_int. */ -static poly_int64 -riscv_stack_align (poly_int64 value) -{ - return aligned_upper_bound (value, PREFERRED_STACK_BOUNDARY / 8); -} - -static HOST_WIDE_INT -riscv_stack_align (HOST_WIDE_INT value) -{ - return RISCV_STACK_ALIGN (value); -} - static void riscv_compute_frame_info (void) { @@ -5427,8 +5787,9 @@ riscv_compute_frame_info (void) if (frame->mask) { x_save_size = riscv_stack_align (num_x_saved * UNITS_PER_WORD); - unsigned num_save_restore = 1 + riscv_save_libcall_count (frame->mask); + /* 1 is for ra */ + unsigned num_save_restore = 1 + riscv_save_libcall_count (frame->mask); /* Only use save/restore routines if they don't alter the stack size. */ if (riscv_stack_align (num_save_restore * UNITS_PER_WORD) == x_save_size && !riscv_avoid_save_libcall ()) @@ -5440,6 +5801,14 @@ riscv_compute_frame_info (void) frame->save_libcall_adjustment = x_save_size; } + + if (!riscv_avoid_multi_push (frame)) + { + /* num(ra, s0-sx) */ + unsigned num_multi_push = riscv_multi_push_regs_count (frame->mask); + x_save_size = riscv_stack_align (num_multi_push * UNITS_PER_WORD); + frame->multi_push_adj_base = riscv_16bytes_align (x_save_size); + } } /* In an interrupt function, we need extra space for the initial saves of CSRs. */ @@ -5465,7 +5834,15 @@ riscv_compute_frame_info (void) frame->fp_sp_offset = offset - UNITS_PER_FP_REG; /* Next are the callee-saved GPRs. */ if (frame->mask) - offset += x_save_size; + { + offset += x_save_size; + /* align to 16 bytes and add paddings to GPR part to honor + both stack alignment and zcmp pus/pop size alignment. */ + if (riscv_use_multi_push (frame) + && known_lt (offset, frame->multi_push_adj_base + + ZCMP_SP_INC_STEP * ZCMP_MAX_SPIMM)) + offset = riscv_16bytes_align (offset); + } frame->gp_sp_offset = offset - UNITS_PER_WORD; /* The hard frame pointer points above the callee-saved GPRs. */ frame->hard_frame_pointer_offset = offset; @@ -5644,8 +6021,8 @@ static void riscv_for_each_saved_reg (poly_int64 sp_offset, riscv_save_restore_fn fn, bool epilogue, bool maybe_eh_return) { - HOST_WIDE_INT offset; - unsigned int regno; + HOST_WIDE_INT offset, first_fp_offset; + unsigned int regno, num_masked_fp = 0; unsigned int start = GP_REG_FIRST; unsigned int limit = GP_REG_LAST; @@ -5731,16 +6108,20 @@ riscv_for_each_saved_reg (poly_int64 sp_offset, riscv_save_restore_fn fn, /* This loop must iterate over the same space as its companion in riscv_compute_frame_info. */ - offset = (cfun->machine->frame.fp_sp_offset - sp_offset).to_constant (); + first_fp_offset + = (cfun->machine->frame.fp_sp_offset - sp_offset).to_constant (); for (unsigned int regno = FP_REG_FIRST; regno <= FP_REG_LAST; regno++) if (BITSET_P (cfun->machine->frame.fmask, regno - FP_REG_FIRST)) { bool handle_reg = !cfun->machine->reg_is_wrapped_separately[regno]; machine_mode mode = TARGET_DOUBLE_FLOAT ? DFmode : SFmode; - + unsigned int slot = (riscv_use_multi_push (&cfun->machine->frame)) + ? CALLEE_SAVED_FREG_NUMBER (regno) + : num_masked_fp; + offset = first_fp_offset - slot * GET_MODE_SIZE (mode).to_constant (); if (handle_reg) riscv_save_restore_reg (mode, regno, offset, fn); - offset -= GET_MODE_SIZE (mode).to_constant (); + num_masked_fp++; } } @@ -5780,7 +6161,7 @@ riscv_first_stack_step (struct riscv_frame_info *frame, poly_int64 remaining_siz && remaining_const_size % IMM_REACH >= min_first_step) return remaining_const_size % IMM_REACH; - if (TARGET_RVC) + if (TARGET_RVC || TARGET_ZCA) { /* If we need two subtracts, and one is small enough to allow compressed loads and stores, then put that one first. */ @@ -5837,6 +6218,41 @@ riscv_adjust_libcall_cfi_prologue () return dwarf; } +static rtx +riscv_adjust_multi_push_cfi_prologue (int saved_size) +{ + rtx dwarf = NULL_RTX; + rtx adjust_sp_rtx, reg, mem, insn; + unsigned int mask = cfun->machine->frame.mask; + int offset; + int saved_cnt = 0; + + if (mask & S10_MASK) + mask |= S11_MASK; + + for (int regno = GP_REG_LAST; regno >= GP_REG_FIRST; regno--) + if (BITSET_P (mask & MULTI_PUSH_GPR_MASK, regno - GP_REG_FIRST)) + { + /* The save order is s11-s0, ra + from high to low addr. */ + offset = saved_size - UNITS_PER_WORD * (++saved_cnt); + + reg = gen_rtx_REG (Pmode, regno); + mem = gen_frame_mem (Pmode, + plus_constant (Pmode, stack_pointer_rtx, offset)); + + insn = gen_rtx_SET (mem, reg); + dwarf = alloc_reg_note (REG_CFA_OFFSET, insn, dwarf); + } + + /* Debug info for adjust sp. */ + adjust_sp_rtx + = gen_rtx_SET (stack_pointer_rtx, + plus_constant (Pmode, stack_pointer_rtx, -saved_size)); + dwarf = alloc_reg_note (REG_CFA_ADJUST_CFA, adjust_sp_rtx, dwarf); + return dwarf; +} + static void riscv_emit_stack_tie (void) { @@ -5846,6 +6262,57 @@ riscv_emit_stack_tie (void) emit_insn (gen_stack_tiedi (stack_pointer_rtx, hard_frame_pointer_rtx)); } +/*zcmp multi push and pop code_for_push_pop function ptr array */ +static const code_for_push_pop_t code_for_push_pop[ZCMP_MAX_GRP_SLOTS][ZCMP_OP_NUM] + = {{code_for_gpr_multi_push_up_to_ra, code_for_gpr_multi_pop_up_to_ra, + code_for_gpr_multi_popret_up_to_ra, code_for_gpr_multi_popretz_up_to_ra}, + {code_for_gpr_multi_push_up_to_s0, code_for_gpr_multi_pop_up_to_s0, + code_for_gpr_multi_popret_up_to_s0, code_for_gpr_multi_popretz_up_to_s0}, + {code_for_gpr_multi_push_up_to_s1, code_for_gpr_multi_pop_up_to_s1, + code_for_gpr_multi_popret_up_to_s1, code_for_gpr_multi_popretz_up_to_s1}, + {code_for_gpr_multi_push_up_to_s2, code_for_gpr_multi_pop_up_to_s2, + code_for_gpr_multi_popret_up_to_s2, code_for_gpr_multi_popretz_up_to_s2}, + {code_for_gpr_multi_push_up_to_s3, code_for_gpr_multi_pop_up_to_s3, + code_for_gpr_multi_popret_up_to_s3, code_for_gpr_multi_popretz_up_to_s3}, + {code_for_gpr_multi_push_up_to_s4, code_for_gpr_multi_pop_up_to_s4, + code_for_gpr_multi_popret_up_to_s4, code_for_gpr_multi_popretz_up_to_s4}, + {code_for_gpr_multi_push_up_to_s5, code_for_gpr_multi_pop_up_to_s5, + code_for_gpr_multi_popret_up_to_s5, code_for_gpr_multi_popretz_up_to_s5}, + {code_for_gpr_multi_push_up_to_s6, code_for_gpr_multi_pop_up_to_s6, + code_for_gpr_multi_popret_up_to_s6, code_for_gpr_multi_popretz_up_to_s6}, + {code_for_gpr_multi_push_up_to_s7, code_for_gpr_multi_pop_up_to_s7, + code_for_gpr_multi_popret_up_to_s7, code_for_gpr_multi_popretz_up_to_s7}, + {code_for_gpr_multi_push_up_to_s8, code_for_gpr_multi_pop_up_to_s8, + code_for_gpr_multi_popret_up_to_s8, code_for_gpr_multi_popretz_up_to_s8}, + {code_for_gpr_multi_push_up_to_s9, code_for_gpr_multi_pop_up_to_s9, + code_for_gpr_multi_popret_up_to_s9, code_for_gpr_multi_popretz_up_to_s9}, + {nullptr, nullptr, nullptr, nullptr}, + {code_for_gpr_multi_push_up_to_s11, code_for_gpr_multi_pop_up_to_s11, + code_for_gpr_multi_popret_up_to_s11, + code_for_gpr_multi_popretz_up_to_s11}}; + +static rtx +riscv_gen_multi_push_pop_insn (riscv_zcmp_op_t op, HOST_WIDE_INT adj_size, + unsigned int regs_num) +{ + gcc_assert (op < ZCMP_OP_NUM); + gcc_assert (regs_num <= ZCMP_MAX_GRP_SLOTS + && regs_num != ZCMP_INVALID_S0S10_SREGS_COUNTS + 1); /* 1 for ra*/ + rtx stack_adj = GEN_INT (adj_size); + return GEN_FCN (code_for_push_pop[regs_num - 1][op](Pmode)) (stack_adj); +} + +static unsigned +get_multi_push_fpr_mask (unsigned max_fprs_push) +{ + unsigned mask_fprs_push = 0, num_f_pushed = 0; + for (unsigned regno = FP_REG_FIRST; + regno <= FP_REG_LAST && num_f_pushed < max_fprs_push; regno++) + if (riscv_save_reg_p (regno)) + mask_fprs_push |= 1 << (regno - FP_REG_FIRST), num_f_pushed++; + return mask_fprs_push; +} + /* Expand the "prologue" pattern. */ void @@ -5854,7 +6321,9 @@ riscv_expand_prologue (void) struct riscv_frame_info *frame = &cfun->machine->frame; poly_int64 remaining_size = frame->total_size; unsigned mask = frame->mask; - rtx insn; + unsigned fmask = frame->fmask; + int spimm, multi_push_additional, stack_adj; + rtx insn, dwarf = NULL_RTX; if (flag_stack_usage_info) current_function_static_stack_size = constant_lower_bound (remaining_size); @@ -5862,8 +6331,46 @@ riscv_expand_prologue (void) if (cfun->machine->naked_p) return; + /* prefer muti-push to save-restore libcall. */ + if (riscv_use_multi_push (frame)) + { + remaining_size -= frame->multi_push_adj_base; + if (known_gt (remaining_size, 2 * ZCMP_SP_INC_STEP)) + spimm = 3; + else if (known_gt (remaining_size, ZCMP_SP_INC_STEP)) + spimm = 2; + else if (known_gt (remaining_size, 0)) + spimm = 1; + else + spimm = 0; + multi_push_additional = spimm * ZCMP_SP_INC_STEP; + frame->multi_push_adj_addi = multi_push_additional; + remaining_size -= multi_push_additional; + + /* emit multi push insn & dwarf along with it. */ + stack_adj = frame->multi_push_adj_base + multi_push_additional; + insn = emit_insn (riscv_gen_multi_push_pop_insn ( + PUSH_IDX, -stack_adj, riscv_multi_push_regs_count (frame->mask))); + dwarf = riscv_adjust_multi_push_cfi_prologue (stack_adj); + RTX_FRAME_RELATED_P (insn) = 1; + REG_NOTES (insn) = dwarf; + + /* Temporarily fib that we need not save GPRs. */ + frame->mask = 0; + + /* push FPRs into the addtional reserved space by cm.push. */ + if (fmask) + { + unsigned mask_fprs_push + = get_multi_push_fpr_mask (multi_push_additional / UNITS_PER_WORD); + frame->fmask &= mask_fprs_push; + riscv_for_each_saved_reg (remaining_size, riscv_save_reg, false, + false); + frame->fmask = fmask & ~mask_fprs_push; /* mask for the rest FPRs. */ + } + } /* When optimizing for size, call a subroutine to save the registers. */ - if (riscv_use_save_libcall (frame)) + else if (riscv_use_save_libcall (frame)) { rtx dwarf = NULL_RTX; dwarf = riscv_adjust_libcall_cfi_prologue (); @@ -5879,17 +6386,20 @@ riscv_expand_prologue (void) /* Save the registers. */ if ((frame->mask | frame->fmask) != 0) { - HOST_WIDE_INT step1 = riscv_first_stack_step (frame, remaining_size); - - insn = gen_add3_insn (stack_pointer_rtx, - stack_pointer_rtx, - GEN_INT (-step1)); - RTX_FRAME_RELATED_P (emit_insn (insn)) = 1; - remaining_size -= step1; + if (known_gt (remaining_size, frame->frame_pointer_offset)) + { + HOST_WIDE_INT step1 = riscv_first_stack_step (frame, remaining_size); + remaining_size -= step1; + insn = gen_add3_insn (stack_pointer_rtx, stack_pointer_rtx, + GEN_INT (-step1)); + RTX_FRAME_RELATED_P (emit_insn (insn)) = 1; + } riscv_for_each_saved_reg (remaining_size, riscv_save_reg, false, false); } - frame->mask = mask; /* Undo the above fib. */ + /* Undo the above fib. */ + frame->mask = mask; + frame->fmask = fmask; /* Set up the frame pointer, if we're using one. */ if (frame_pointer_needed) @@ -5942,6 +6452,32 @@ riscv_expand_prologue (void) } } +static rtx +riscv_adjust_multi_pop_cfi_epilogue (int saved_size) +{ + rtx dwarf = NULL_RTX; + rtx adjust_sp_rtx, reg; + unsigned int mask = cfun->machine->frame.mask; + + if (mask & S10_MASK) + mask |= S11_MASK; + + /* Debug info for adjust sp. */ + adjust_sp_rtx + = gen_rtx_SET (stack_pointer_rtx, + plus_constant (Pmode, stack_pointer_rtx, saved_size)); + dwarf = alloc_reg_note (REG_CFA_ADJUST_CFA, adjust_sp_rtx, dwarf); + + for (int regno = GP_REG_FIRST; regno <= GP_REG_LAST; regno++) + if (BITSET_P (mask, regno - GP_REG_FIRST)) + { + reg = gen_rtx_REG (Pmode, regno); + dwarf = alloc_reg_note (REG_CFA_RESTORE, reg, dwarf); + } + + return dwarf; +} + static rtx riscv_adjust_libcall_cfi_epilogue () { @@ -5952,7 +6488,7 @@ riscv_adjust_libcall_cfi_epilogue () /* Debug info for adjust sp. */ adjust_sp_rtx = gen_rtx_SET (stack_pointer_rtx, - gen_rtx_PLUS (GET_MODE(stack_pointer_rtx), stack_pointer_rtx, GEN_INT (saved_size))); + gen_rtx_PLUS (Pmode, stack_pointer_rtx, GEN_INT (saved_size))); dwarf = alloc_reg_note (REG_CFA_ADJUST_CFA, adjust_sp_rtx, dwarf); @@ -5966,6 +6502,78 @@ riscv_adjust_libcall_cfi_epilogue () return dwarf; } +/* return true if popretz pattern can be matched. + set (reg 10 a0) (const_int 0) + use (reg 10 a0) + NOTE_INSN_EPILOGUE_BEG */ +static rtx_insn * +riscv_zcmp_can_use_popretz (void) +{ + rtx_insn *insn = NULL, *use = NULL, *clear = NULL; + + /* sequence stack for NOTE_INSN_EPILOGUE_BEG*/ + struct sequence_stack *outer_seq = get_current_sequence ()->next; + if (!outer_seq) + return NULL; + insn = outer_seq->first; + if (!insn || !NOTE_P (insn) || NOTE_KIND (insn) != NOTE_INSN_EPILOGUE_BEG) + return NULL; + + /* sequence stack for the insn before NOTE_INSN_EPILOGUE_BEG*/ + outer_seq = outer_seq->next; + if (outer_seq) + insn = outer_seq->last; + + /* skip notes */ + while (insn && NOTE_P (insn)) + { + insn = PREV_INSN (insn); + } + use = insn; + + /* match use (reg 10 a0) */ + if (use == NULL || !INSN_P (use) || GET_CODE (PATTERN (use)) != USE + || !REG_P (XEXP (PATTERN (use), 0)) + || REGNO (XEXP (PATTERN (use), 0)) != A0_REGNUM) + return NULL; + + /* match set (reg 10 a0) (const_int 0 [0]) */ + clear = PREV_INSN (use); + if (clear != NULL && INSN_P (clear) && GET_CODE (PATTERN (clear)) == SET + && REG_P (SET_DEST (PATTERN (clear))) + && REGNO (SET_DEST (PATTERN (clear))) == A0_REGNUM + && SET_SRC (PATTERN (clear)) == const0_rtx) + return clear; + + return NULL; +} + +static void +riscv_gen_multi_pop_insn (bool use_multi_pop_normal, unsigned mask, + unsigned multipop_size) +{ + rtx insn; + unsigned regs_count = riscv_multi_push_regs_count (mask); + + if (!use_multi_pop_normal) + insn = emit_insn ( + riscv_gen_multi_push_pop_insn (POP_IDX, multipop_size, regs_count)); + else if (rtx_insn *clear_a0_insn = riscv_zcmp_can_use_popretz ()) + { + delete_insn (NEXT_INSN (clear_a0_insn)); + delete_insn (clear_a0_insn); + insn = emit_jump_insn ( + riscv_gen_multi_push_pop_insn (POPRETZ_IDX, multipop_size, regs_count)); + } + else + insn = emit_jump_insn ( + riscv_gen_multi_push_pop_insn (POPRET_IDX, multipop_size, regs_count)); + + rtx dwarf = riscv_adjust_multi_pop_cfi_epilogue (multipop_size); + RTX_FRAME_RELATED_P (insn) = 1; + REG_NOTES (insn) = dwarf; +} + /* Expand an "epilogue", "sibcall_epilogue", or "eh_return_internal" pattern; style says which. */ @@ -5980,11 +6588,24 @@ riscv_expand_epilogue (int style) Start off by assuming that no registers need to be restored. */ struct riscv_frame_info *frame = &cfun->machine->frame; unsigned mask = frame->mask; + unsigned fmask = frame->fmask; + unsigned mask_fprs_push = 0; HOST_WIDE_INT step2 = 0; - bool use_restore_libcall = ((style == NORMAL_RETURN) - && riscv_use_save_libcall (frame)); - unsigned libcall_size = (use_restore_libcall - ? frame->save_libcall_adjustment : 0); + bool use_multi_pop_normal + = ((style == NORMAL_RETURN) && riscv_use_multi_push (frame)); + bool use_multi_pop_sibcall + = ((style == SIBCALL_RETURN) && riscv_use_multi_push (frame)); + bool use_multi_pop = use_multi_pop_normal || use_multi_pop_sibcall; + + bool use_restore_libcall + = !use_multi_pop + && ((style == NORMAL_RETURN) && riscv_use_save_libcall (frame)); + unsigned libcall_size = use_restore_libcall && !use_multi_pop + ? frame->save_libcall_adjustment + : 0; + unsigned multipop_size + = use_multi_pop ? frame->multi_push_adj_base + frame->multi_push_adj_addi + : 0; rtx ra = gen_rtx_REG (Pmode, RETURN_ADDR_REGNUM); rtx insn; @@ -6055,18 +6676,26 @@ riscv_expand_epilogue (int style) REG_NOTES (insn) = dwarf; } - if (use_restore_libcall) - frame->mask = 0; /* Temporarily fib for GPRs. */ + if (use_restore_libcall || use_multi_pop) + frame->mask = 0; /* Temporarily fib that we need not restore GPRs. */ /* If we need to restore registers, deallocate as much stack as possible in the second step without going out of range. */ - if ((frame->mask | frame->fmask) != 0) + if (use_multi_pop) + { + if (frame->fmask + && known_gt (frame->total_size - multipop_size, + frame->frame_pointer_offset)) + step2 + = riscv_first_stack_step (frame, frame->total_size - multipop_size); + } + else if ((frame->mask | frame->fmask) != 0) step2 = riscv_first_stack_step (frame, frame->total_size - libcall_size); - if (use_restore_libcall) + if (use_restore_libcall || use_multi_pop) frame->mask = mask; /* Undo the above fib. */ - poly_int64 step1 = frame->total_size - step2 - libcall_size; + poly_int64 step1 = frame->total_size - step2 - libcall_size - multipop_size; /* Set TARGET to BASE + STEP1. */ if (known_gt (step1, 0)) @@ -6100,8 +6729,9 @@ riscv_expand_epilogue (int style) stack_pointer_rtx, adjust)); rtx dwarf = NULL_RTX; - rtx cfa_adjust_rtx = gen_rtx_PLUS (Pmode, stack_pointer_rtx, - GEN_INT (step2 + libcall_size)); + rtx cfa_adjust_rtx + = gen_rtx_PLUS (Pmode, stack_pointer_rtx, + GEN_INT (step2 + libcall_size + multipop_size)); dwarf = alloc_reg_note (REG_CFA_DEF_CFA, cfa_adjust_rtx, dwarf); RTX_FRAME_RELATED_P (insn) = 1; @@ -6116,16 +6746,26 @@ riscv_expand_epilogue (int style) epilogue_cfa_sp_offset = step2; } - if (use_restore_libcall) - frame->mask = 0; /* Temporarily fib that we need not save GPRs. */ + if (use_multi_pop) + { + frame->mask = 0; /* Temporarily fib that we need not restore GPRs. */ + if (fmask) + { + mask_fprs_push = get_multi_push_fpr_mask (frame->multi_push_adj_addi + / UNITS_PER_WORD); + frame->fmask &= ~mask_fprs_push; /* FPRs not saved by cm.push */ + } + } + else if (use_restore_libcall) + frame->mask = 0; /* Temporarily fib that we need not restore GPRs. */ /* Restore the registers. */ - riscv_for_each_saved_reg (frame->total_size - step2 - libcall_size, - riscv_restore_reg, - true, style == EXCEPTION_RETURN); + riscv_for_each_saved_reg (frame->total_size - step2 - libcall_size + - multipop_size, + riscv_restore_reg, true, style == EXCEPTION_RETURN); if (use_restore_libcall) - frame->mask = mask; /* Undo the above fib. */ + frame->mask = mask; /* Undo the above fib. */ if (need_barrier_p) riscv_emit_stack_tie (); @@ -6137,15 +6777,33 @@ riscv_expand_epilogue (int style) GEN_INT (step2))); rtx dwarf = NULL_RTX; - rtx cfa_adjust_rtx = gen_rtx_PLUS (Pmode, stack_pointer_rtx, - GEN_INT (libcall_size)); + rtx cfa_adjust_rtx + = gen_rtx_PLUS (Pmode, stack_pointer_rtx, + GEN_INT (libcall_size + multipop_size)); dwarf = alloc_reg_note (REG_CFA_DEF_CFA, cfa_adjust_rtx, dwarf); RTX_FRAME_RELATED_P (insn) = 1; REG_NOTES (insn) = dwarf; } - if (use_restore_libcall) + if (use_multi_pop) + { + /* restore FPRs pushed by cm.push. */ + frame->fmask = fmask & mask_fprs_push; + if (frame->fmask) + riscv_for_each_saved_reg (frame->total_size - libcall_size + - multipop_size, + riscv_restore_reg, true, + style == EXCEPTION_RETURN); + /* Undo the above fib. */ + frame->mask = mask; + frame->fmask = fmask; + riscv_gen_multi_pop_insn (use_multi_pop_normal, frame->mask, + multipop_size); + if (use_multi_pop_normal) + return; + } + else if (use_restore_libcall) { rtx dwarf = riscv_adjust_libcall_cfi_epilogue (); insn = emit_insn (gen_gpr_restore (GEN_INT (riscv_save_libcall_count (mask)))); @@ -6466,7 +7124,8 @@ riscv_secondary_memory_needed (machine_mode mode, reg_class_t class1, return (!riscv_v_ext_mode_p (mode) && GET_MODE_SIZE (mode).to_constant () > UNITS_PER_WORD && (class1 == FP_REGS) != (class2 == FP_REGS) - && !TARGET_XTHEADFMV); + && !TARGET_XTHEADFMV + && !TARGET_ZFA); } /* Implement TARGET_REGISTER_MOVE_COST. */ @@ -6655,6 +7314,31 @@ riscv_issue_rate (void) return tune_param->issue_rate; } +/* Implement TARGET_SCHED_VARIABLE_ISSUE. */ +static int +riscv_sched_variable_issue (FILE *, int, rtx_insn *insn, int more) +{ + if (DEBUG_INSN_P (insn)) + return more; + + rtx_code code = GET_CODE (PATTERN (insn)); + if (code == USE || code == CLOBBER) + return more; + + /* GHOST insns are used for blockage and similar cases which + effectively end a cycle. */ + if (get_attr_type (insn) == TYPE_GHOST) + return 0; + +#if 0 + /* If we ever encounter an insn with an unknown type, trip + an assert so we can find and fix this problem. */ + gcc_assert (get_attr_type (insn) != TYPE_UNKNOWN); +#endif + + return more - 1; +} + /* Auxiliary function to emit RISC-V ELF attribute. */ static void riscv_emit_attribute () @@ -6875,6 +7559,12 @@ riscv_option_override (void) -m[no-]strict-align is left unspecified, heed -mtune's advice. */ riscv_slow_unaligned_access_p = (cpu->tune_param->slow_unaligned_access || TARGET_STRICT_ALIGN); + + /* Make a note if user explicity passed -mstrict-align for later + builtin macro generation. Can't use target_flags_explicitly since + it is set even for -mno-strict-align. */ + riscv_user_wants_strict_align = TARGET_STRICT_ALIGN; + if ((target_flags_explicit & MASK_STRICT_ALIGN) == 0 && cpu->tune_param->slow_unaligned_access) target_flags |= MASK_STRICT_ALIGN; @@ -7008,6 +7698,10 @@ riscv_option_override (void) sorry ( "Current RISC-V GCC cannot support VLEN greater than 4096bit for 'V' Extension"); + SET_OPTION_IF_UNSET (&global_options, &global_options_set, + param_sched_pressure_algorithm, + SCHED_PRESSURE_MODEL); + /* Convert -march to a chunks count. */ riscv_vector_chunks = riscv_convert_vector_bits (); } @@ -7458,6 +8152,27 @@ riscv_gen_gpr_save_insn (struct riscv_frame_info *frame) return gen_rtx_PARALLEL (VOIDmode, vec); } +static HOST_WIDE_INT +zcmp_base_adj (int regs_num) +{ + return riscv_16bytes_align ((regs_num) *GET_MODE_SIZE (word_mode)); +} + +static HOST_WIDE_INT +zcmp_additional_adj (HOST_WIDE_INT total, int regs_num) +{ + return total - zcmp_base_adj (regs_num); +} + +bool +riscv_zcmp_valid_stack_adj_bytes_p (HOST_WIDE_INT total, int regs_num) +{ + HOST_WIDE_INT additioanl_bytes = zcmp_additional_adj (total, regs_num); + return additioanl_bytes == 0 || additioanl_bytes == 1 * ZCMP_SP_INC_STEP + || additioanl_bytes == 2 * ZCMP_SP_INC_STEP + || additioanl_bytes == ZCMP_MAX_SPIMM * ZCMP_SP_INC_STEP; +} + /* Return true if it's valid gpr_save pattern. */ bool @@ -7777,12 +8492,18 @@ riscv_support_vector_misalignment (machine_mode mode, int misalignment, bool is_packed ATTRIBUTE_UNUSED) { - /* TODO: For RVV scalable vector auto-vectorization, we should allow - movmisalign pattern to handle misalign data movement to unblock - possible auto-vectorization. + /* Only enable misalign data movements for VLS modes. */ + if (TARGET_VECTOR_VLS && STRICT_ALIGNMENT) + { + /* Return if movmisalign pattern is not supported for this mode. */ + if (optab_handler (movmisalign_optab, mode) == CODE_FOR_nothing) + return false; - RVV VLS auto-vectorization or SIMD auto-vectorization can be supported here - in the future. */ + /* Misalignment factor is unknown at compile time. */ + if (misalignment == -1) + return false; + } + /* Disable movmisalign for VLA auto-vectorization. */ return default_builtin_support_vector_misalignment (mode, type, misalignment, is_packed); } @@ -7860,8 +8581,8 @@ vector_zero_call_used_regs (HARD_REG_SET need_zeroed_hardregs) } rtx ops[] = {target, CONST0_RTX (mode)}; - riscv_vector::emit_vlmax_insn (code_for_pred_mov (mode), - riscv_vector::RVV_UNOP, ops, vl); + riscv_vector::emit_vlmax_insn_lra (code_for_pred_mov (mode), + riscv_vector::UNARY_OP, ops, vl); SET_HARD_REG_BIT (zeroed_hardregs, regno); } @@ -7986,11 +8707,11 @@ riscv_static_frm_mode_p (int mode) { switch (mode) { - case FRM_MODE_RDN: - case FRM_MODE_RUP: - case FRM_MODE_RTZ: - case FRM_MODE_RMM: - case FRM_MODE_RNE: + case riscv_vector::FRM_RDN: + case riscv_vector::FRM_RUP: + case riscv_vector::FRM_RTZ: + case riscv_vector::FRM_RMM: + case riscv_vector::FRM_RNE: return true; default: return false; @@ -8006,28 +8727,24 @@ riscv_emit_frm_mode_set (int mode, int prev_mode) { rtx backup_reg = DYNAMIC_FRM_RTL (cfun); - if (prev_mode == FRM_MODE_DYN_CALL) + if (prev_mode == riscv_vector::FRM_DYN_CALL) emit_insn (gen_frrmsi (backup_reg)); /* Backup frm when DYN_CALL. */ if (mode != prev_mode) { - /* TODO: By design, FRM_MODE_xxx used by mode switch which is - different from the FRM value like FRM_RTZ defined in - riscv-protos.h. When mode switching we actually need a conversion - function to convert the mode of mode switching to the actual - FRM value like FRM_RTZ. For now, the value between the mode of - mode swith and the FRM value in riscv-protos.h take the same value, - and then we leverage this assumption when emit. */ rtx frm = gen_int_mode (mode, SImode); - if (mode == FRM_MODE_DYN_CALL && prev_mode != FRM_MODE_DYN) + if (mode == riscv_vector::FRM_DYN_CALL + && prev_mode != riscv_vector::FRM_DYN) /* No need to emit when prev mode is DYN already. */ emit_insn (gen_fsrmsi_restore_volatile (backup_reg)); - else if (mode == FRM_MODE_DYN_EXIT && STATIC_FRM_P (cfun) - && prev_mode != FRM_MODE_DYN && prev_mode != FRM_MODE_DYN_CALL) + else if (mode == riscv_vector::FRM_DYN_EXIT && STATIC_FRM_P (cfun) + && prev_mode != riscv_vector::FRM_DYN + && prev_mode != riscv_vector::FRM_DYN_CALL) /* No need to emit when prev mode is DYN or DYN_CALL already. */ emit_insn (gen_fsrmsi_restore_volatile (backup_reg)); - else if (mode == FRM_MODE_DYN && prev_mode != FRM_MODE_DYN_CALL) + else if (mode == riscv_vector::FRM_DYN + && prev_mode != riscv_vector::FRM_DYN_CALL) /* Restore frm value from backup when switch to DYN mode. */ emit_insn (gen_fsrmsi_restore (backup_reg)); else if (riscv_static_frm_mode_p (mode)) @@ -8056,7 +8773,7 @@ riscv_emit_mode_set (int entity, int mode, int prev_mode, } } -/* Adjust the FRM_MODE_NONE insn after a call to FRM_MODE_DYN for the +/* Adjust the FRM_NONE insn after a call to FRM_DYN for the underlying emit. */ static int @@ -8065,7 +8782,7 @@ riscv_frm_adjust_mode_after_call (rtx_insn *cur_insn, int mode) rtx_insn *insn = prev_nonnote_nondebug_insn_bb (cur_insn); if (insn && CALL_P (insn)) - return FRM_MODE_DYN; + return riscv_vector::FRM_DYN; return mode; } @@ -8116,12 +8833,12 @@ riscv_frm_mode_needed (rtx_insn *cur_insn, int code) if (!insn) riscv_frm_emit_after_bb_end (cur_insn); - return FRM_MODE_DYN_CALL; + return riscv_vector::FRM_DYN_CALL; } - int mode = code >= 0 ? get_attr_frm_mode (cur_insn) : FRM_MODE_NONE; + int mode = code >= 0 ? get_attr_frm_mode (cur_insn) : riscv_vector::FRM_NONE; - if (mode == FRM_MODE_NONE) + if (mode == riscv_vector::FRM_NONE) /* After meet a call, we need to backup the frm because it may be updated during the call. Here, for each insn, we will check if the previous insn is a call or not. When previous insn is call, @@ -8229,7 +8946,7 @@ riscv_frm_mode_after (rtx_insn *insn, int mode) return mode; if (frm_unknown_dynamic_p (insn)) - return FRM_MODE_DYN; + return riscv_vector::FRM_DYN; if (recog_memoized (insn) < 0) return mode; @@ -8271,7 +8988,7 @@ riscv_mode_entry (int entity) /* According to RVV 1.0 spec, all vector floating-point operations use the dynamic rounding mode in the frm register. Likewise in other similar places. */ - return FRM_MODE_DYN; + return riscv_vector::FRM_DYN; } default: gcc_unreachable (); @@ -8289,7 +9006,7 @@ riscv_mode_exit (int entity) case RISCV_VXRM: return VXRM_MODE_NONE; case RISCV_FRM: - return FRM_MODE_DYN_EXIT; + return riscv_vector::FRM_DYN_EXIT; default: gcc_unreachable (); } @@ -8336,30 +9053,23 @@ riscv_vectorize_vec_perm_const (machine_mode vmode, machine_mode op_mode, return false; } -/* Implement TARGET_PREFERRED_ELSE_VALUE. For binary operations, - prefer to use the first arithmetic operand as the else value if - the else value doesn't matter, since that exactly matches the RVV - destructive merging form. For ternary operations we could either - pick the first operand and use VMADD-like instructions or the last - operand and use VMACC-like instructions; the latter seems more - natural. - - TODO: Currently, the return value is not ideal for RVV since it will - let VSETVL PASS use MU or TU. We will suport undefine value that allows - VSETVL PASS use TA/MA in the future. */ - -static tree -riscv_preferred_else_value (unsigned, tree, unsigned int nops, tree *ops) -{ - return nops == 3 ? ops[2] : ops[0]; -} - static bool riscv_frame_pointer_required (void) { return riscv_save_frame_pointer && !crtl->is_leaf; } +/* Implement targetm.vectorize.create_costs. */ + +static vector_costs * +riscv_vectorize_create_costs (vec_info *vinfo, bool costing_for_scalar) +{ + if (TARGET_VECTOR) + return new riscv_vector::costs (vinfo, costing_for_scalar); + /* Default vector costs. */ + return new vector_costs (vinfo, costing_for_scalar); +} + /* Initialize the GCC target structure. */ #undef TARGET_ASM_ALIGNED_HI_OP #define TARGET_ASM_ALIGNED_HI_OP "\t.half\t" @@ -8377,6 +9087,9 @@ riscv_frame_pointer_required (void) #undef TARGET_SCHED_ISSUE_RATE #define TARGET_SCHED_ISSUE_RATE riscv_issue_rate +#undef TARGET_SCHED_VARIABLE_ISSUE +#define TARGET_SCHED_VARIABLE_ISSUE riscv_sched_variable_issue + #undef TARGET_FUNCTION_OK_FOR_SIBCALL #define TARGET_FUNCTION_OK_FOR_SIBCALL riscv_function_ok_for_sibcall @@ -8661,12 +9374,12 @@ riscv_frame_pointer_required (void) #undef TARGET_VECTORIZE_VEC_PERM_CONST #define TARGET_VECTORIZE_VEC_PERM_CONST riscv_vectorize_vec_perm_const -#undef TARGET_PREFERRED_ELSE_VALUE -#define TARGET_PREFERRED_ELSE_VALUE riscv_preferred_else_value - #undef TARGET_FRAME_POINTER_REQUIRED #define TARGET_FRAME_POINTER_REQUIRED riscv_frame_pointer_required +#undef TARGET_VECTORIZE_CREATE_COSTS +#define TARGET_VECTORIZE_CREATE_COSTS riscv_vectorize_create_costs + struct gcc_target targetm = TARGET_INITIALIZER; #include "gt-riscv.h" diff --git a/gcc/config/riscv/riscv.h b/gcc/config/riscv/riscv.h index 643e7ea73304..fa0d795168eb 100644 --- a/gcc/config/riscv/riscv.h +++ b/gcc/config/riscv/riscv.h @@ -186,7 +186,7 @@ ASM_MISA_SPEC #define PARM_BOUNDARY BITS_PER_WORD /* Allocation boundary (in *bits*) for the code of a function. */ -#define FUNCTION_BOUNDARY (TARGET_RVC ? 16 : 32) +#define FUNCTION_BOUNDARY ((TARGET_RVC || TARGET_ZCA) ? 16 : 32) /* The smallest supported stack boundary the calling convention supports. */ #define STACK_BOUNDARY \ @@ -420,6 +420,29 @@ ASM_MISA_SPEC #define RISCV_CALL_ADDRESS_TEMP(MODE) \ gen_rtx_REG (MODE, RISCV_CALL_ADDRESS_TEMP_REGNUM) +#define RETURN_ADDR_MASK (1 << RETURN_ADDR_REGNUM) +#define S0_MASK (1 << S0_REGNUM) +#define S1_MASK (1 << S1_REGNUM) +#define S2_MASK (1 << S2_REGNUM) +#define S3_MASK (1 << S3_REGNUM) +#define S4_MASK (1 << S4_REGNUM) +#define S5_MASK (1 << S5_REGNUM) +#define S6_MASK (1 << S6_REGNUM) +#define S7_MASK (1 << S7_REGNUM) +#define S8_MASK (1 << S8_REGNUM) +#define S9_MASK (1 << S9_REGNUM) +#define S10_MASK (1 << S10_REGNUM) +#define S11_MASK (1 << S11_REGNUM) + +#define MULTI_PUSH_GPR_MASK \ + (RETURN_ADDR_MASK | S0_MASK | S1_MASK | S2_MASK | S3_MASK | S4_MASK \ + | S5_MASK | S6_MASK | S7_MASK | S8_MASK | S9_MASK | S10_MASK | S11_MASK) +#define ZCMP_MAX_SPIMM 3 +#define ZCMP_SP_INC_STEP 16 +#define ZCMP_INVALID_S0S10_SREGS_COUNTS 11 +#define ZCMP_S0S11_SREGS_COUNTS 12 +#define ZCMP_MAX_GRP_SLOTS 13 + #define MCOUNT_NAME "_mcount" #define NO_PROFILE_COUNTERS 1 @@ -655,6 +678,8 @@ enum reg_class ((REGNO) >= 8 && (REGNO) <= 9 ? (REGNO) - 8 : \ (REGNO) >= 18 && (REGNO) <= 27 ? (REGNO) - 16 : -1) +#define CALLEE_SAVED_FREG_NUMBER(REGNO) CALLEE_SAVED_REG_NUMBER (REGNO - 32) + #define LIBCALL_VALUE(MODE) \ riscv_function_value (NULL_TREE, NULL_TREE, MODE) @@ -1036,6 +1061,7 @@ while (0) #ifndef USED_FOR_TARGET extern const enum reg_class riscv_regno_to_class[]; extern bool riscv_slow_unaligned_access_p; +extern bool riscv_user_wants_strict_align; extern unsigned riscv_stack_boundary; extern unsigned riscv_bytes_per_vector_chunk; extern poly_uint16 riscv_vector_chunks; @@ -1120,6 +1146,6 @@ extern void riscv_remove_unneeded_save_restore_calls (void); /* Mode switching (Lazy code motion) for RVV rounding mode instructions. */ #define OPTIMIZE_MODE_SWITCHING(ENTITY) (TARGET_VECTOR) -#define NUM_MODES_FOR_MODE_SWITCHING {VXRM_MODE_NONE, FRM_MODE_NONE} +#define NUM_MODES_FOR_MODE_SWITCHING {VXRM_MODE_NONE, riscv_vector::FRM_NONE} #endif /* ! GCC_RISCV_H */ diff --git a/gcc/config/riscv/riscv.md b/gcc/config/riscv/riscv.md index 688fd697255b..4041875e0e35 100644 --- a/gcc/config/riscv/riscv.md +++ b/gcc/config/riscv/riscv.md @@ -55,10 +55,19 @@ UNSPEC_FLT_QUIET UNSPEC_FLE_QUIET UNSPEC_COPYSIGN + UNSPEC_RINT + UNSPEC_ROUND + UNSPEC_FLOOR + UNSPEC_CEIL + UNSPEC_BTRUNC + UNSPEC_ROUNDEVEN + UNSPEC_NEARBYINT UNSPEC_LRINT UNSPEC_LROUND UNSPEC_FMIN UNSPEC_FMAX + UNSPEC_FMINM + UNSPEC_FMAXM ;; Stack tie UNSPEC_TIE @@ -115,12 +124,15 @@ (define_constants [(RETURN_ADDR_REGNUM 1) + (SP_REGNUM 2) (GP_REGNUM 3) (TP_REGNUM 4) (T0_REGNUM 5) (T1_REGNUM 6) (S0_REGNUM 8) (S1_REGNUM 9) + (A0_REGNUM 10) + (A1_REGNUM 11) (S2_REGNUM 18) (S3_REGNUM 19) (S4_REGNUM 20) @@ -401,6 +413,7 @@ ;; vgather vector register gather instructions ;; vcompress vector compress instruction ;; vmov whole vector register move +;; vector unknown vector instruction (define_attr "type" "unknown,branch,jump,call,load,fpload,store,fpstore, mtc,mfc,const,arith,logical,shift,slt,imul,idiv,move,fmove,fadd,fmul, @@ -420,7 +433,7 @@ vired,viwred,vfredu,vfredo,vfwredu,vfwredo, vmalu,vmpop,vmffs,vmsfs,vmiota,vmidx,vimovvx,vimovxv,vfmovvf,vfmovfv, vslideup,vslidedown,vislide1up,vislide1down,vfslide1up,vfslide1down, - vgather,vcompress,vmov" + vgather,vcompress,vmov,vector" (cond [(eq_attr "got" "load") (const_string "load") ;; If a doubleword move uses these expensive instructions, @@ -1434,6 +1447,26 @@ ;; ;; .................... +(define_insn "fminm3" + [(set (match_operand:ANYF 0 "register_operand" "=f") + (unspec:ANYF [(use (match_operand:ANYF 1 "register_operand" " f")) + (use (match_operand:ANYF 2 "register_operand" " f"))] + UNSPEC_FMINM))] + "TARGET_HARD_FLOAT && TARGET_ZFA" + "fminm.\t%0,%1,%2" + [(set_attr "type" "fmove") + (set_attr "mode" "")]) + +(define_insn "fmaxm3" + [(set (match_operand:ANYF 0 "register_operand" "=f") + (unspec:ANYF [(use (match_operand:ANYF 1 "register_operand" " f")) + (use (match_operand:ANYF 2 "register_operand" " f"))] + UNSPEC_FMAXM))] + "TARGET_HARD_FLOAT && TARGET_ZFA" + "fmaxm.\t%0,%1,%2" + [(set_attr "type" "fmove") + (set_attr "mode" "")]) + (define_insn "fmin3" [(set (match_operand:ANYF 0 "register_operand" "=f") (unspec:ANYF [(use (match_operand:ANYF 1 "register_operand" " f")) @@ -1744,13 +1777,13 @@ }) (define_insn "*movhf_hardfloat" - [(set (match_operand:HF 0 "nonimmediate_operand" "=f,f,f,m,m,*f,*r, *r,*r,*m") - (match_operand:HF 1 "move_operand" " f,G,m,f,G,*r,*f,*G*r,*m,*r"))] + [(set (match_operand:HF 0 "nonimmediate_operand" "=f, f,f,f,m,m,*f,*r, *r,*r,*m") + (match_operand:HF 1 "move_operand" " f,zfli,G,m,f,G,*r,*f,*G*r,*m,*r"))] "TARGET_ZFHMIN && (register_operand (operands[0], HFmode) || reg_or_0_operand (operands[1], HFmode))" { return riscv_output_move (operands[0], operands[1]); } - [(set_attr "move_type" "fmove,mtc,fpload,fpstore,store,mtc,mfc,move,load,store") + [(set_attr "move_type" "fmove,fmove,mtc,fpload,fpstore,store,mtc,mfc,move,load,store") (set_attr "mode" "HF")]) (define_insn "*movhf_softfloat" @@ -1816,6 +1849,26 @@ [(set_attr "type" "fcvt") (set_attr "mode" "")]) +(define_insn "2" + [(set (match_operand:ANYF 0 "register_operand" "=f") + (unspec:ANYF + [(match_operand:ANYF 1 "register_operand" " f")] + ROUND))] + "TARGET_HARD_FLOAT && TARGET_ZFA" + "fround.\t%0,%1," + [(set_attr "type" "fcvt") + (set_attr "mode" "")]) + +(define_insn "rint2" + [(set (match_operand:ANYF 0 "register_operand" "=f") + (unspec:ANYF + [(match_operand:ANYF 1 "register_operand" " f")] + UNSPEC_RINT))] + "TARGET_HARD_FLOAT && TARGET_ZFA" + "froundnx.\t%0,%1" + [(set_attr "type" "fcvt") + (set_attr "mode" "")]) + ;; ;; .................... ;; @@ -2075,13 +2128,13 @@ }) (define_insn "*movsf_hardfloat" - [(set (match_operand:SF 0 "nonimmediate_operand" "=f,f,f,m,m,*f,*r, *r,*r,*m") - (match_operand:SF 1 "move_operand" " f,G,m,f,G,*r,*f,*G*r,*m,*r"))] + [(set (match_operand:SF 0 "nonimmediate_operand" "=f, f,f,f,m,m,*f,*r, *r,*r,*m") + (match_operand:SF 1 "move_operand" " f,zfli,G,m,f,G,*r,*f,*G*r,*m,*r"))] "TARGET_HARD_FLOAT && (register_operand (operands[0], SFmode) || reg_or_0_operand (operands[1], SFmode))" { return riscv_output_move (operands[0], operands[1]); } - [(set_attr "move_type" "fmove,mtc,fpload,fpstore,store,mtc,mfc,move,load,store") + [(set_attr "move_type" "fmove,fmove,mtc,fpload,fpstore,store,mtc,mfc,move,load,store") (set_attr "mode" "SF")]) (define_insn "*movsf_softfloat" @@ -2109,23 +2162,23 @@ ;; In RV32, we lack fmv.x.d and fmv.d.x. Go through memory instead. ;; (However, we can still use fcvt.d.w to zero a floating-point register.) (define_insn "*movdf_hardfloat_rv32" - [(set (match_operand:DF 0 "nonimmediate_operand" "=f,f,f,m,m,*th_f_fmv,*th_r_fmv, *r,*r,*m") - (match_operand:DF 1 "move_operand" " f,G,m,f,G,*th_r_fmv,*th_f_fmv,*r*G,*m,*r"))] + [(set (match_operand:DF 0 "nonimmediate_operand" "=f, f,f,f,m,m,*zmvf,*zmvr, *r,*r,*m") + (match_operand:DF 1 "move_operand" " f,zfli,G,m,f,G,*zmvr,*zmvf,*r*G,*m,*r"))] "!TARGET_64BIT && TARGET_DOUBLE_FLOAT && (register_operand (operands[0], DFmode) || reg_or_0_operand (operands[1], DFmode))" { return riscv_output_move (operands[0], operands[1]); } - [(set_attr "move_type" "fmove,mtc,fpload,fpstore,store,mtc,mfc,move,load,store") + [(set_attr "move_type" "fmove,fmove,mtc,fpload,fpstore,store,mtc,mfc,move,load,store") (set_attr "mode" "DF")]) (define_insn "*movdf_hardfloat_rv64" - [(set (match_operand:DF 0 "nonimmediate_operand" "=f,f,f,m,m,*f,*r, *r,*r,*m") - (match_operand:DF 1 "move_operand" " f,G,m,f,G,*r,*f,*r*G,*m,*r"))] + [(set (match_operand:DF 0 "nonimmediate_operand" "=f, f,f,f,m,m,*f,*r, *r,*r,*m") + (match_operand:DF 1 "move_operand" " f,zfli,G,m,f,G,*r,*f,*r*G,*m,*r"))] "TARGET_64BIT && TARGET_DOUBLE_FLOAT && (register_operand (operands[0], DFmode) || reg_or_0_operand (operands[1], DFmode))" { return riscv_output_move (operands[0], operands[1]); } - [(set_attr "move_type" "fmove,mtc,fpload,fpstore,store,mtc,mfc,move,load,store") + [(set_attr "move_type" "fmove,fmove,mtc,fpload,fpstore,store,mtc,mfc,move,load,store") (set_attr "mode" "DF")]) (define_insn "*movdf_softfloat" @@ -2138,6 +2191,39 @@ [(set_attr "move_type" "move,load,store") (set_attr "mode" "DF")]) +(define_insn "movsidf2_low_rv32" + [(set (match_operand:SI 0 "register_operand" "= r") + (truncate:SI + (match_operand:DF 1 "register_operand" "zmvf")))] + "TARGET_HARD_FLOAT && !TARGET_64BIT && TARGET_ZFA" + "fmv.x.w\t%0,%1" + [(set_attr "move_type" "fmove") + (set_attr "mode" "DF")]) + + +(define_insn "movsidf2_high_rv32" + [(set (match_operand:SI 0 "register_operand" "= r") + (truncate:SI + (lshiftrt:DF + (match_operand:DF 1 "register_operand" "zmvf") + (const_int 32))))] + "TARGET_HARD_FLOAT && !TARGET_64BIT && TARGET_ZFA" + "fmvh.x.d\t%0,%1" + [(set_attr "move_type" "fmove") + (set_attr "mode" "DF")]) + +(define_insn "movdfsisi3_rv32" + [(set (match_operand:DF 0 "register_operand" "= f") + (plus:DF + (match_operand:SI 2 "register_operand" "zmvr") + (ashift:SI + (match_operand:SI 1 "register_operand" "zmvr") + (const_int 32))))] + "TARGET_HARD_FLOAT && !TARGET_64BIT && TARGET_ZFA" + "fmvp.d.x\t%0,%2,%1" + [(set_attr "move_type" "fmove") + (set_attr "mode" "DF")]) + (define_split [(set (match_operand:MOVE64 0 "nonimmediate_operand") (match_operand:MOVE64 1 "move_operand"))] @@ -2193,7 +2279,7 @@ (define_insn "riscv_pause" [(unspec_volatile [(const_int 0)] UNSPECV_PAUSE)] "" - "pause") + "* return TARGET_ZIHINTPAUSE ? \"pause\" : \".insn\t0x0100000f\";") ;; ;; .................... @@ -2663,16 +2749,23 @@ rtx op0 = operands[0]; rtx op1 = operands[1]; rtx op2 = operands[2]; - rtx tmp = gen_reg_rtx (SImode); - rtx cmp = gen_rtx_ (mode, op1, op2); - rtx frflags = gen_rtx_UNSPEC_VOLATILE (SImode, gen_rtvec (1, const0_rtx), - UNSPECV_FRFLAGS); - rtx fsflags = gen_rtx_UNSPEC_VOLATILE (SImode, gen_rtvec (1, tmp), - UNSPECV_FSFLAGS); - emit_insn (gen_rtx_SET (tmp, frflags)); - emit_insn (gen_rtx_SET (op0, cmp)); - emit_insn (fsflags); + if (TARGET_ZFA) + emit_insn (gen_f_quiet4_zfa(op0, op1, op2)); + else + { + rtx tmp = gen_reg_rtx (SImode); + rtx cmp = gen_rtx_ (mode, op1, op2); + rtx frflags = gen_rtx_UNSPEC_VOLATILE (SImode, gen_rtvec (1, const0_rtx), + UNSPECV_FRFLAGS); + rtx fsflags = gen_rtx_UNSPEC_VOLATILE (SImode, gen_rtvec (1, tmp), + UNSPECV_FSFLAGS); + + emit_insn (gen_rtx_SET (tmp, frflags)); + emit_insn (gen_rtx_SET (op0, cmp)); + emit_insn (fsflags); + } + if (HONOR_SNANS (mode)) emit_insn (gen_rtx_UNSPEC_VOLATILE (mode, gen_rtvec (2, op1, op2), @@ -2680,6 +2773,18 @@ DONE; }) +(define_insn "f_quiet4_zfa" + [(set (match_operand:X 0 "register_operand" "=r") + (unspec:X + [(match_operand:ANYF 1 "register_operand" " f") + (match_operand:ANYF 2 "register_operand" " f")] + QUIET_COMPARISON))] + "TARGET_HARD_FLOAT && TARGET_ZFA" + "fq.\t%0,%1,%2" + [(set_attr "type" "fcmp") + (set_attr "mode" "") + (set (attr "length") (const_int 16))]) + (define_insn "*seq_zero_" [(set (match_operand:GPR 0 "register_operand" "=r") (eq:GPR (match_operand:X 1 "register_operand" " r") @@ -3321,6 +3426,8 @@ (include "bitmanip.md") (include "crypto.md") (include "sync.md") +(include "sync-rvwmo.md") +(include "sync-ztso.md") (include "peephole.md") (include "pic.md") (include "generic.md") @@ -3328,3 +3435,4 @@ (include "thead.md") (include "vector.md") (include "zicond.md") +(include "zc.md") diff --git a/gcc/config/riscv/riscv.opt b/gcc/config/riscv/riscv.opt index 4dfd8f78ad5e..eca0dda4dd5c 100644 --- a/gcc/config/riscv/riscv.opt +++ b/gcc/config/riscv/riscv.opt @@ -239,12 +239,21 @@ int riscv_zicmo_subext TargetVariable int riscv_zf_subext +TargetVariable +int riscv_zfa_subext + TargetVariable int riscv_zm_subext +TargetVariable +int riscv_zc_subext + TargetVariable int riscv_sv_subext +TargetVariable +int riscv_ztso_subext + TargetVariable int riscv_xthead_subext @@ -271,7 +280,7 @@ Always inline subword atomic operations. Enum Name(riscv_autovec_preference) Type(enum riscv_autovec_preference_enum) -The RISC-V auto-vectorization preference: +Valid arguments to -param=riscv-autovec-preference=: EnumValue Enum(riscv_autovec_preference) String(none) Value(NO_AUTOVEC) @@ -288,7 +297,7 @@ Target RejectNegative Joined Enum(riscv_autovec_preference) Var(riscv_autovec_pr Enum Name(riscv_autovec_lmul) Type(enum riscv_autovec_lmul_enum) -The RVV possible LMUL: +The RVV possible LMUL (-param=riscv-autovec-lmul=): EnumValue Enum(riscv_autovec_lmul) String(m1) Value(RVV_M1) @@ -302,6 +311,9 @@ Enum(riscv_autovec_lmul) String(m4) Value(RVV_M4) EnumValue Enum(riscv_autovec_lmul) String(m8) Value(RVV_M8) +EnumValue +Enum(riscv_autovec_lmul) String(dynamic) Value(RVV_DYNAMIC) + -param=riscv-autovec-lmul= Target RejectNegative Joined Enum(riscv_autovec_lmul) Var(riscv_autovec_lmul) Init(RVV_M1) -param=riscv-autovec-lmul= Set the RVV LMUL of auto-vectorization in the RISC-V port. diff --git a/gcc/config/riscv/sync-rvwmo.md b/gcc/config/riscv/sync-rvwmo.md new file mode 100644 index 000000000000..cb641ea9ec33 --- /dev/null +++ b/gcc/config/riscv/sync-rvwmo.md @@ -0,0 +1,97 @@ +;; Machine description for RISC-V atomic operations. +;; Copyright (C) 2011-2023 Free Software Foundation, Inc. +;; Contributed by Andrew Waterman (andrew@sifive.com). +;; Based on MIPS target for GNU compiler. + +;; This file is part of GCC. + +;; GCC is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 3, or (at your option) +;; any later version. + +;; GCC is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GCC; see the file COPYING3. If not see +;; . + +;; Memory barrier. + +(define_insn "mem_thread_fence_rvwmo" + [(set (match_operand:BLK 0 "" "") + (unspec:BLK [(match_dup 0)] UNSPEC_MEMORY_BARRIER)) + (match_operand:SI 1 "const_int_operand" "")] ;; model + "!TARGET_ZTSO" + { + enum memmodel model = (enum memmodel) INTVAL (operands[1]); + model = memmodel_base (model); + + if (model == MEMMODEL_SEQ_CST) + return "fence\trw,rw"; + else if (model == MEMMODEL_ACQ_REL) + return "fence.tso"; + else if (model == MEMMODEL_ACQUIRE) + return "fence\tr,rw"; + else if (model == MEMMODEL_RELEASE) + return "fence\trw,w"; + else + gcc_unreachable (); + } + [(set_attr "type" "atomic") + (set (attr "length") (const_int 4))]) + +;; Atomic memory operations. + +(define_insn "atomic_load_rvwmo" + [(set (match_operand:GPR 0 "register_operand" "=r") + (unspec_volatile:GPR + [(match_operand:GPR 1 "memory_operand" "A") + (match_operand:SI 2 "const_int_operand")] ;; model + UNSPEC_ATOMIC_LOAD))] + "TARGET_ATOMIC && !TARGET_ZTSO" + { + enum memmodel model = (enum memmodel) INTVAL (operands[2]); + model = memmodel_base (model); + + if (model == MEMMODEL_SEQ_CST) + return "fence\trw,rw\;" + "l\t%0,%1\;" + "fence\tr,rw"; + if (model == MEMMODEL_ACQUIRE) + return "l\t%0,%1\;" + "fence\tr,rw"; + else + return "l\t%0,%1"; + } + [(set_attr "type" "multi") + (set (attr "length") (const_int 12))]) + +;; Implement atomic stores with conservative fences. +;; This allows us to be compatible with the ISA manual Table A.6 and Table A.7. +(define_insn "atomic_store_rvwmo" + [(set (match_operand:GPR 0 "memory_operand" "=A") + (unspec_volatile:GPR + [(match_operand:GPR 1 "reg_or_0_operand" "rJ") + (match_operand:SI 2 "const_int_operand")] ;; model + UNSPEC_ATOMIC_STORE))] + "TARGET_ATOMIC && !TARGET_ZTSO" + { + enum memmodel model = (enum memmodel) INTVAL (operands[2]); + model = memmodel_base (model); + + if (model == MEMMODEL_SEQ_CST) + return "fence\trw,w\;" + "s\t%z1,%0\;" + "fence\trw,rw"; + if (model == MEMMODEL_RELEASE) + return "fence\trw,w\;" + "s\t%z1,%0"; + else + return "s\t%z1,%0"; + } + [(set_attr "type" "multi") + (set (attr "length") (const_int 12))]) diff --git a/gcc/config/riscv/sync-ztso.md b/gcc/config/riscv/sync-ztso.md new file mode 100644 index 000000000000..7bb15b7ab8cd --- /dev/null +++ b/gcc/config/riscv/sync-ztso.md @@ -0,0 +1,81 @@ +;; Machine description for RISC-V atomic operations. +;; Copyright (C) 2011-2023 Free Software Foundation, Inc. +;; Contributed by Andrew Waterman (andrew@sifive.com). +;; Based on MIPS target for GNU compiler. + +;; This file is part of GCC. + +;; GCC is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 3, or (at your option) +;; any later version. + +;; GCC is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GCC; see the file COPYING3. If not see +;; . + +;; Memory barriers. + +(define_insn "mem_thread_fence_ztso" + [(set (match_operand:BLK 0 "" "") + (unspec:BLK [(match_dup 0)] UNSPEC_MEMORY_BARRIER)) + (match_operand:SI 1 "const_int_operand" "")] ;; model + "TARGET_ZTSO" + { + enum memmodel model = (enum memmodel) INTVAL (operands[1]); + model = memmodel_base (model); + + if (model == MEMMODEL_SEQ_CST) + return "fence\trw,rw"; + else + gcc_unreachable (); + } + [(set_attr "type" "atomic") + (set (attr "length") (const_int 4))]) + +;; Atomic memory operations. + +(define_insn "atomic_load_ztso" + [(set (match_operand:GPR 0 "register_operand" "=r") + (unspec_volatile:GPR + [(match_operand:GPR 1 "memory_operand" "A") + (match_operand:SI 2 "const_int_operand")] ;; model + UNSPEC_ATOMIC_LOAD))] + "TARGET_ATOMIC && TARGET_ZTSO" + { + enum memmodel model = (enum memmodel) INTVAL (operands[2]); + model = memmodel_base (model); + + if (model == MEMMODEL_SEQ_CST) + return "fence\trw,rw\;" + "l\t%0,%1"; + else + return "l\t%0,%1"; + } + [(set_attr "type" "multi") + (set (attr "length") (const_int 12))]) + +(define_insn "atomic_store_ztso" + [(set (match_operand:GPR 0 "memory_operand" "=A") + (unspec_volatile:GPR + [(match_operand:GPR 1 "reg_or_0_operand" "rJ") + (match_operand:SI 2 "const_int_operand")] ;; model + UNSPEC_ATOMIC_STORE))] + "TARGET_ATOMIC && TARGET_ZTSO" + { + enum memmodel model = (enum memmodel) INTVAL (operands[2]); + model = memmodel_base (model); + + if (model == MEMMODEL_SEQ_CST) + return "s\t%z1,%0\;" + "fence\trw,rw"; + else + return "s\t%z1,%0"; + } + [(set_attr "type" "multi") + (set (attr "length") (const_int 8))]) diff --git a/gcc/config/riscv/sync.md b/gcc/config/riscv/sync.md index 9fc626267de3..6ff3493b5ced 100644 --- a/gcc/config/riscv/sync.md +++ b/gcc/config/riscv/sync.md @@ -36,88 +36,55 @@ (define_expand "mem_thread_fence" [(match_operand:SI 0 "const_int_operand" "")] ;; model "" -{ - if (INTVAL (operands[0]) != MEMMODEL_RELAXED) - { - rtx mem = gen_rtx_MEM (BLKmode, gen_rtx_SCRATCH (Pmode)); - MEM_VOLATILE_P (mem) = 1; - emit_insn (gen_mem_thread_fence_1 (mem, operands[0])); - } - DONE; -}) - -(define_insn "mem_thread_fence_1" - [(set (match_operand:BLK 0 "" "") - (unspec:BLK [(match_dup 0)] UNSPEC_MEMORY_BARRIER)) - (match_operand:SI 1 "const_int_operand" "")] ;; model - "" { - enum memmodel model = (enum memmodel) INTVAL (operands[1]); - model = memmodel_base (model); - if (model == MEMMODEL_SEQ_CST) - return "fence\trw,rw"; - else if (model == MEMMODEL_ACQ_REL) - return "fence.tso"; - else if (model == MEMMODEL_ACQUIRE) - return "fence\tr,rw"; - else if (model == MEMMODEL_RELEASE) - return "fence\trw,w"; - else - gcc_unreachable (); - } - [(set (attr "length") (const_int 4))]) + enum memmodel model = memmodel_base (INTVAL (operands[0])); + + if (TARGET_ZTSO && model == MEMMODEL_SEQ_CST) + { + rtx mem = gen_rtx_MEM (BLKmode, gen_rtx_SCRATCH (Pmode)); + MEM_VOLATILE_P (mem) = 1; + emit_insn (gen_mem_thread_fence_ztso (mem, operands[0])); + } + else if (!TARGET_ZTSO && model != MEMMODEL_RELAXED) + { + rtx mem = gen_rtx_MEM (BLKmode, gen_rtx_SCRATCH (Pmode)); + MEM_VOLATILE_P (mem) = 1; + emit_insn (gen_mem_thread_fence_rvwmo (mem, operands[0])); + } + DONE; + }) ;; Atomic memory operations. -(define_insn "atomic_load" - [(set (match_operand:GPR 0 "register_operand" "=r") - (unspec_volatile:GPR - [(match_operand:GPR 1 "memory_operand" "A") - (match_operand:SI 2 "const_int_operand")] ;; model - UNSPEC_ATOMIC_LOAD))] +(define_expand "atomic_load" + [(match_operand:GPR 0 "register_operand") + (match_operand:GPR 1 "memory_operand") + (match_operand:SI 2 "const_int_operand")] ;; model "TARGET_ATOMIC" { - enum memmodel model = (enum memmodel) INTVAL (operands[2]); - model = memmodel_base (model); - - if (model == MEMMODEL_SEQ_CST) - return "fence\trw,rw\;" - "l\t%0,%1\;" - "fence\tr,rw"; - if (model == MEMMODEL_ACQUIRE) - return "l\t%0,%1\;" - "fence\tr,rw"; + if (TARGET_ZTSO) + emit_insn (gen_atomic_load_ztso (operands[0], operands[1], + operands[2])); else - return "l\t%0,%1"; - } - [(set_attr "type" "atomic") - (set (attr "length") (const_int 12))]) + emit_insn (gen_atomic_load_rvwmo (operands[0], operands[1], + operands[2])); + DONE; + }) -;; Implement atomic stores with conservative fences. -;; This allows us to be compatible with the ISA manual Table A.6 and Table A.7. -(define_insn "atomic_store" - [(set (match_operand:GPR 0 "memory_operand" "=A") - (unspec_volatile:GPR - [(match_operand:GPR 1 "reg_or_0_operand" "rJ") - (match_operand:SI 2 "const_int_operand")] ;; model - UNSPEC_ATOMIC_STORE))] +(define_expand "atomic_store" + [(match_operand:GPR 0 "memory_operand") + (match_operand:GPR 1 "reg_or_0_operand") + (match_operand:SI 2 "const_int_operand")] ;; model "TARGET_ATOMIC" { - enum memmodel model = (enum memmodel) INTVAL (operands[2]); - model = memmodel_base (model); - - if (model == MEMMODEL_SEQ_CST) - return "fence\trw,w\;" - "s\t%z1,%0\;" - "fence\trw,rw"; - if (model == MEMMODEL_RELEASE) - return "fence\trw,w\;" - "s\t%z1,%0"; + if (TARGET_ZTSO) + emit_insn (gen_atomic_store_ztso (operands[0], operands[1], + operands[2])); else - return "s\t%z1,%0"; - } - [(set_attr "type" "atomic") - (set (attr "length") (const_int 12))]) + emit_insn (gen_atomic_store_rvwmo (operands[0], operands[1], + operands[2])); + DONE; + }) (define_insn "atomic_" [(set (match_operand:GPR 0 "memory_operand" "+A") @@ -169,7 +136,8 @@ "sc.w%J3\t%6, %7, %1\;" "bnez\t%6, 1b"; } - [(set (attr "length") (const_int 28))]) + [(set_attr "type" "multi") + (set (attr "length") (const_int 28))]) (define_expand "atomic_fetch_nand" [(match_operand:SHORT 0 "register_operand") ;; old value at mem @@ -236,7 +204,8 @@ "sc.w%J3\t%6, %7, %1\;" "bnez\t%6, 1b"; } - [(set (attr "length") (const_int 32))]) + [(set_attr "type" "multi") + (set (attr "length") (const_int 32))]) (define_expand "atomic_fetch_" [(match_operand:SHORT 0 "register_operand") ;; old value at mem @@ -343,7 +312,8 @@ "sc.w%J3\t%5, %5, %1\;" "bnez\t%5, 1b"; } - [(set (attr "length") (const_int 20))]) + [(set_attr "type" "multi") + (set (attr "length") (const_int 20))]) (define_insn "atomic_cas_value_strong" [(set (match_operand:GPR 0 "register_operand" "=&r") @@ -369,7 +339,7 @@ "bnez\t%6,1b\;" "1:"; } - [(set_attr "type" "atomic") + [(set_attr "type" "multi") (set (attr "length") (const_int 16))]) (define_expand "atomic_compare_and_swap" @@ -530,7 +500,8 @@ "bnez\t%7, 1b\;" "1:"; } - [(set (attr "length") (const_int 28))]) + [(set_attr "type" "multi") + (set (attr "length") (const_int 28))]) (define_expand "atomic_test_and_set" [(match_operand:QI 0 "register_operand" "") ;; bool output diff --git a/gcc/config/riscv/t-linux b/gcc/config/riscv/t-linux index 216d2776a183..a6f64f88d25c 100644 --- a/gcc/config/riscv/t-linux +++ b/gcc/config/riscv/t-linux @@ -1,3 +1,5 @@ # Only XLEN and ABI affect Linux multilib dir names, e.g. /lib32/ilp32d/ MULTILIB_DIRNAMES := $(patsubst rv32%,lib32,$(patsubst rv64%,lib64,$(MULTILIB_DIRNAMES))) MULTILIB_OSDIRNAMES := $(patsubst lib%,../lib%,$(MULTILIB_DIRNAMES)) + +MULTIARCH_DIRNAME := $(call if_multiarch,$(firstword $(subst -, ,$(target)))-linux-gnu) diff --git a/gcc/config/riscv/t-riscv b/gcc/config/riscv/t-riscv index 1252d6f851ac..b1f80d1d87ca 100644 --- a/gcc/config/riscv/t-riscv +++ b/gcc/config/riscv/t-riscv @@ -62,10 +62,19 @@ riscv-vsetvl.o: $(srcdir)/config/riscv/riscv-vsetvl.cc \ $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) $(REGS_H) \ $(TARGET_H) tree-pass.h df.h rtl-ssa.h cfgcleanup.h insn-config.h \ insn-attr.h insn-opinit.h tm-constrs.h cfgrtl.h cfganal.h lcm.h \ - predict.h profile-count.h $(srcdir)/config/riscv/riscv-vsetvl.h + predict.h profile-count.h $(srcdir)/config/riscv/riscv-vsetvl.h \ + $(srcdir)/config/riscv/riscv-vsetvl.def $(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \ $(srcdir)/config/riscv/riscv-vsetvl.cc +riscv-vector-costs.o: $(srcdir)/config/riscv/riscv-vector-costs.cc \ + $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TARGET_H) $(FUNCTION_H) \ + $(TREE_H) basic-block.h $(RTL_H) gimple.h targhooks.h cfgloop.h \ + fold-const.h $(TM_P_H) tree-vectorizer.h \ + $(srcdir)/config/riscv/riscv-vector-costs.h + $(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \ + $(srcdir)/config/riscv/riscv-vector-costs.cc + riscv-d.o: $(srcdir)/config/riscv/riscv-d.cc \ $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(COMPILE) $< diff --git a/gcc/config/riscv/vector-iterators.md b/gcc/config/riscv/vector-iterators.md index 6a2cfa5bf37e..caef8157e5a6 100644 --- a/gcc/config/riscv/vector-iterators.md +++ b/gcc/config/riscv/vector-iterators.md @@ -81,6 +81,8 @@ UNSPEC_VCOMPRESS UNSPEC_VLEFF UNSPEC_MODIFY_VL + + UNSPEC_VFFMA ]) (define_c_enum "unspecv" [ @@ -445,6 +447,50 @@ (V512DI "TARGET_VECTOR_VLS && TARGET_VECTOR_ELEN_64 && TARGET_MIN_VLEN >= 4096") ]) +(define_mode_iterator V_VLSF [ + (RVVM8HF "TARGET_ZVFH") (RVVM4HF "TARGET_ZVFH") (RVVM2HF "TARGET_ZVFH") + (RVVM1HF "TARGET_ZVFH") (RVVMF2HF "TARGET_ZVFH") + (RVVMF4HF "TARGET_ZVFH && TARGET_MIN_VLEN > 32") + (RVVM8SF "TARGET_VECTOR_ELEN_FP_32") (RVVM4SF "TARGET_VECTOR_ELEN_FP_32") (RVVM2SF "TARGET_VECTOR_ELEN_FP_32") + (RVVM1SF "TARGET_VECTOR_ELEN_FP_32") (RVVMF2SF "TARGET_VECTOR_ELEN_FP_32 && TARGET_MIN_VLEN > 32") + (RVVM8DF "TARGET_VECTOR_ELEN_FP_64") (RVVM4DF "TARGET_VECTOR_ELEN_FP_64") + (RVVM2DF "TARGET_VECTOR_ELEN_FP_64") (RVVM1DF "TARGET_VECTOR_ELEN_FP_64") + + (V1HF "TARGET_VECTOR_VLS && TARGET_VECTOR_ELEN_FP_16") + (V2HF "TARGET_VECTOR_VLS && TARGET_VECTOR_ELEN_FP_16") + (V4HF "TARGET_VECTOR_VLS && TARGET_VECTOR_ELEN_FP_16") + (V8HF "TARGET_VECTOR_VLS && TARGET_VECTOR_ELEN_FP_16") + (V16HF "TARGET_VECTOR_VLS && TARGET_VECTOR_ELEN_FP_16") + (V32HF "TARGET_VECTOR_VLS && TARGET_VECTOR_ELEN_FP_16 && TARGET_MIN_VLEN >= 64") + (V64HF "TARGET_VECTOR_VLS && TARGET_VECTOR_ELEN_FP_16 && TARGET_MIN_VLEN >= 128") + (V128HF "TARGET_VECTOR_VLS && TARGET_VECTOR_ELEN_FP_16 && TARGET_MIN_VLEN >= 256") + (V256HF "TARGET_VECTOR_VLS && TARGET_VECTOR_ELEN_FP_16 && TARGET_MIN_VLEN >= 512") + (V512HF "TARGET_VECTOR_VLS && TARGET_VECTOR_ELEN_FP_16 && TARGET_MIN_VLEN >= 1024") + (V1024HF "TARGET_VECTOR_VLS && TARGET_VECTOR_ELEN_FP_16 && TARGET_MIN_VLEN >= 2048") + (V2048HF "TARGET_VECTOR_VLS && TARGET_VECTOR_ELEN_FP_16 && TARGET_MIN_VLEN >= 4096") + (V1SF "TARGET_VECTOR_VLS && TARGET_VECTOR_ELEN_FP_32") + (V2SF "TARGET_VECTOR_VLS && TARGET_VECTOR_ELEN_FP_32") + (V4SF "TARGET_VECTOR_VLS && TARGET_VECTOR_ELEN_FP_32") + (V8SF "TARGET_VECTOR_VLS && TARGET_VECTOR_ELEN_FP_32") + (V16SF "TARGET_VECTOR_VLS && TARGET_VECTOR_ELEN_FP_32 && TARGET_MIN_VLEN >= 64") + (V32SF "TARGET_VECTOR_VLS && TARGET_VECTOR_ELEN_FP_32 && TARGET_MIN_VLEN >= 128") + (V64SF "TARGET_VECTOR_VLS && TARGET_VECTOR_ELEN_FP_32 && TARGET_MIN_VLEN >= 256") + (V128SF "TARGET_VECTOR_VLS && TARGET_VECTOR_ELEN_FP_32 && TARGET_MIN_VLEN >= 512") + (V256SF "TARGET_VECTOR_VLS && TARGET_VECTOR_ELEN_FP_32 && TARGET_MIN_VLEN >= 1024") + (V512SF "TARGET_VECTOR_VLS && TARGET_VECTOR_ELEN_FP_32 && TARGET_MIN_VLEN >= 2048") + (V1024SF "TARGET_VECTOR_VLS && TARGET_VECTOR_ELEN_FP_32 && TARGET_MIN_VLEN >= 4096") + (V1DF "TARGET_VECTOR_VLS && TARGET_VECTOR_ELEN_FP_64") + (V2DF "TARGET_VECTOR_VLS && TARGET_VECTOR_ELEN_FP_64") + (V4DF "TARGET_VECTOR_VLS && TARGET_VECTOR_ELEN_FP_64") + (V8DF "TARGET_VECTOR_VLS && TARGET_VECTOR_ELEN_FP_64 && TARGET_MIN_VLEN >= 64") + (V16DF "TARGET_VECTOR_VLS && TARGET_VECTOR_ELEN_FP_64 && TARGET_MIN_VLEN >= 128") + (V32DF "TARGET_VECTOR_VLS && TARGET_VECTOR_ELEN_FP_64 && TARGET_MIN_VLEN >= 256") + (V64DF "TARGET_VECTOR_VLS && TARGET_VECTOR_ELEN_FP_64 && TARGET_MIN_VLEN >= 512") + (V128DF "TARGET_VECTOR_VLS && TARGET_VECTOR_ELEN_FP_64 && TARGET_MIN_VLEN >= 1024") + (V256DF "TARGET_VECTOR_VLS && TARGET_VECTOR_ELEN_FP_64 && TARGET_MIN_VLEN >= 2048") + (V512DF "TARGET_VECTOR_VLS && TARGET_VECTOR_ELEN_FP_64 && TARGET_MIN_VLEN >= 4096") +]) + (define_mode_iterator VF_ZVFHMIN [ (RVVM8HF "TARGET_VECTOR_ELEN_FP_16") (RVVM4HF "TARGET_VECTOR_ELEN_FP_16") (RVVM2HF "TARGET_VECTOR_ELEN_FP_16") (RVVM1HF "TARGET_VECTOR_ELEN_FP_16") (RVVMF2HF "TARGET_VECTOR_ELEN_FP_16") @@ -468,6 +514,7 @@ (RVVM8DF "TARGET_VECTOR_ELEN_FP_64") (RVVM4DF "TARGET_VECTOR_ELEN_FP_64") (RVVM2DF "TARGET_VECTOR_ELEN_FP_64") (RVVM1DF "TARGET_VECTOR_ELEN_FP_64") + (V1HF "TARGET_VECTOR_VLS && TARGET_VECTOR_ELEN_FP_16") (V2HF "TARGET_VECTOR_VLS && TARGET_VECTOR_ELEN_FP_16") (V4HF "TARGET_VECTOR_VLS && TARGET_VECTOR_ELEN_FP_16") (V8HF "TARGET_VECTOR_VLS && TARGET_VECTOR_ELEN_FP_16") @@ -479,6 +526,7 @@ (V512HF "TARGET_VECTOR_VLS && TARGET_VECTOR_ELEN_FP_16 && TARGET_MIN_VLEN >= 1024") (V1024HF "TARGET_VECTOR_VLS && TARGET_VECTOR_ELEN_FP_16 && TARGET_MIN_VLEN >= 2048") (V2048HF "TARGET_VECTOR_VLS && TARGET_VECTOR_ELEN_FP_16 && TARGET_MIN_VLEN >= 4096") + (V1SF "TARGET_VECTOR_VLS && TARGET_VECTOR_ELEN_FP_32") (V2SF "TARGET_VECTOR_VLS && TARGET_VECTOR_ELEN_FP_32") (V4SF "TARGET_VECTOR_VLS && TARGET_VECTOR_ELEN_FP_32") (V8SF "TARGET_VECTOR_VLS && TARGET_VECTOR_ELEN_FP_32") @@ -489,6 +537,7 @@ (V256SF "TARGET_VECTOR_VLS && TARGET_VECTOR_ELEN_FP_32 && TARGET_MIN_VLEN >= 1024") (V512SF "TARGET_VECTOR_VLS && TARGET_VECTOR_ELEN_FP_32 && TARGET_MIN_VLEN >= 2048") (V1024SF "TARGET_VECTOR_VLS && TARGET_VECTOR_ELEN_FP_32 && TARGET_MIN_VLEN >= 4096") + (V1DF "TARGET_VECTOR_VLS && TARGET_VECTOR_ELEN_FP_64") (V2DF "TARGET_VECTOR_VLS && TARGET_VECTOR_ELEN_FP_64") (V4DF "TARGET_VECTOR_VLS && TARGET_VECTOR_ELEN_FP_64") (V8DF "TARGET_VECTOR_VLS && TARGET_VECTOR_ELEN_FP_64 && TARGET_MIN_VLEN >= 64") @@ -543,6 +592,51 @@ RVVM8SI RVVM4SI RVVM2SI RVVM1SI (RVVMF2SI "TARGET_MIN_VLEN > 32") ]) +(define_mode_iterator V_VLSI_QHS [ + RVVM8QI RVVM4QI RVVM2QI RVVM1QI RVVMF2QI RVVMF4QI (RVVMF8QI "TARGET_MIN_VLEN > 32") + + RVVM8HI RVVM4HI RVVM2HI RVVM1HI RVVMF2HI (RVVMF4HI "TARGET_MIN_VLEN > 32") + + RVVM8SI RVVM4SI RVVM2SI RVVM1SI (RVVMF2SI "TARGET_MIN_VLEN > 32") + + (V1QI "TARGET_VECTOR_VLS") + (V2QI "TARGET_VECTOR_VLS") + (V4QI "TARGET_VECTOR_VLS") + (V8QI "TARGET_VECTOR_VLS") + (V16QI "TARGET_VECTOR_VLS") + (V32QI "TARGET_VECTOR_VLS") + (V64QI "TARGET_VECTOR_VLS && TARGET_MIN_VLEN >= 64") + (V128QI "TARGET_VECTOR_VLS && TARGET_MIN_VLEN >= 128") + (V256QI "TARGET_VECTOR_VLS && TARGET_MIN_VLEN >= 256") + (V512QI "TARGET_VECTOR_VLS && TARGET_MIN_VLEN >= 512") + (V1024QI "TARGET_VECTOR_VLS && TARGET_MIN_VLEN >= 1024") + (V2048QI "TARGET_VECTOR_VLS && TARGET_MIN_VLEN >= 2048") + (V4096QI "TARGET_VECTOR_VLS && TARGET_MIN_VLEN >= 4096") + (V1HI "TARGET_VECTOR_VLS") + (V2HI "TARGET_VECTOR_VLS") + (V4HI "TARGET_VECTOR_VLS") + (V8HI "TARGET_VECTOR_VLS") + (V16HI "TARGET_VECTOR_VLS") + (V32HI "TARGET_VECTOR_VLS && TARGET_MIN_VLEN >= 64") + (V64HI "TARGET_VECTOR_VLS && TARGET_MIN_VLEN >= 128") + (V128HI "TARGET_VECTOR_VLS && TARGET_MIN_VLEN >= 256") + (V256HI "TARGET_VECTOR_VLS && TARGET_MIN_VLEN >= 512") + (V512HI "TARGET_VECTOR_VLS && TARGET_MIN_VLEN >= 1024") + (V1024HI "TARGET_VECTOR_VLS && TARGET_MIN_VLEN >= 2048") + (V2048HI "TARGET_VECTOR_VLS && TARGET_MIN_VLEN >= 4096") + (V1SI "TARGET_VECTOR_VLS") + (V2SI "TARGET_VECTOR_VLS") + (V4SI "TARGET_VECTOR_VLS") + (V8SI "TARGET_VECTOR_VLS") + (V16SI "TARGET_VECTOR_VLS && TARGET_MIN_VLEN >= 64") + (V32SI "TARGET_VECTOR_VLS && TARGET_MIN_VLEN >= 128") + (V64SI "TARGET_VECTOR_VLS && TARGET_MIN_VLEN >= 256") + (V128SI "TARGET_VECTOR_VLS && TARGET_MIN_VLEN >= 512") + (V256SI "TARGET_VECTOR_VLS && TARGET_MIN_VLEN >= 1024") + (V512SI "TARGET_VECTOR_VLS && TARGET_MIN_VLEN >= 2048") + (V1024SI "TARGET_VECTOR_VLS && TARGET_MIN_VLEN >= 4096") +]) + (define_mode_iterator VI_D [ (RVVM8DI "TARGET_VECTOR_ELEN_64") (RVVM4DI "TARGET_VECTOR_ELEN_64") (RVVM2DI "TARGET_VECTOR_ELEN_64") (RVVM1DI "TARGET_VECTOR_ELEN_64") @@ -1369,6 +1463,101 @@ (V1DF "df") (V2DF "df") (V4DF "df") (V8DF "df") (V16DF "df") (V32DF "df") (V64DF "df") (V128DF "df") (V256DF "df") (V512DF "df") ]) +(define_mode_attr vsingle [ + (RVVM1x8QI "rvvm1qi") (RVVMF2x8QI "rvvmf2qi") (RVVMF4x8QI "rvvmf4qi") (RVVMF8x8QI "rvvmf8qi") + (RVVM1x7QI "rvvm1qi") (RVVMF2x7QI "rvvmf2qi") (RVVMF4x7QI "rvvmf4qi") (RVVMF8x7QI "rvvmf8qi") + (RVVM1x6QI "rvvm1qi") (RVVMF2x6QI "rvvmf2qi") (RVVMF4x6QI "rvvmf4qi") (RVVMF8x6QI "rvvmf8qi") + (RVVM1x5QI "rvvm1qi") (RVVMF2x5QI "rvvmf2qi") (RVVMF4x5QI "rvvmf4qi") (RVVMF8x5QI "rvvmf8qi") + (RVVM2x4QI "rvvm2qi") (RVVM1x4QI "rvvm1qi") (RVVMF2x4QI "rvvmf2qi") (RVVMF4x4QI "rvvmf4qi") (RVVMF8x4QI "rvvmf8qi") + (RVVM2x3QI "rvvm2qi") (RVVM1x3QI "rvvm1qi") (RVVMF2x3QI "rvvmf2qi") (RVVMF4x3QI "rvvmf4qi") (RVVMF8x3QI "rvvmf8qi") + (RVVM4x2QI "rvvm4qi") (RVVM2x2QI "rvvm1qi") (RVVM1x2QI "rvvm1qi") (RVVMF2x2QI "rvvmf2qi") (RVVMF4x2QI "rvvmf4qi") (RVVMF8x2QI "rvvmf8qi") + + (RVVM1x8HI "rvvm1hi") (RVVMF2x8HI "rvvmf2hi") (RVVMF4x8HI "rvvmf4hi") + (RVVM1x7HI "rvvm1hi") (RVVMF2x7HI "rvvmf2hi") (RVVMF4x7HI "rvvmf4hi") + (RVVM1x6HI "rvvm1hi") (RVVMF2x6HI "rvvmf2hi") (RVVMF4x6HI "rvvmf4hi") + (RVVM1x5HI "rvvm1hi") (RVVMF2x5HI "rvvmf2hi") (RVVMF4x5HI "rvvmf4hi") + (RVVM2x4HI "rvvm2hi") (RVVM1x4HI "rvvm1hi") (RVVMF2x4HI "rvvmf2hi") (RVVMF4x4HI "rvvmf4hi") + (RVVM2x3HI "rvvm2hi") (RVVM1x3HI "rvvm1hi") (RVVMF2x3HI "rvvmf2hi") (RVVMF4x3HI "rvvmf4hi") + (RVVM4x2HI "rvvm4hi") (RVVM2x2HI "rvvm2hi") (RVVM1x2HI "rvvm1hi") (RVVMF2x2HI "rvvmf2hi") (RVVMF4x2HI "rvvmf4hi") + + (RVVM1x8HF "rvvm1hf") + (RVVMF2x8HF "rvvmf2hf") + (RVVMF4x8HF "rvvmf4hf") + (RVVM1x7HF "rvvm1hf") + (RVVMF2x7HF "rvvmf2hf") + (RVVMF4x7HF "rvvmf4hf") + (RVVM1x6HF "rvvm1hf") + (RVVMF2x6HF "rvvmf2hf") + (RVVMF4x6HF "rvvmf4hf") + (RVVM1x5HF "rvvm1hf") + (RVVMF2x5HF "rvvmf2hf") + (RVVMF4x5HF "rvvmf4hf") + (RVVM2x4HF "rvvm2hf") + (RVVM1x4HF "rvvm1hf") + (RVVMF2x4HF "rvvmf2hf") + (RVVMF4x4HF "rvvmf4hf") + (RVVM2x3HF "rvvm2hf") + (RVVM1x3HF "rvvm1hf") + (RVVMF2x3HF "rvvmf2hf") + (RVVMF4x3HF "rvvmf4hf") + (RVVM4x2HF "rvvm4hf") + (RVVM2x2HF "rvvm2hf") + (RVVM1x2HF "rvvm1hf") + (RVVMF2x2HF "rvvmf2hf") + (RVVMF4x2HF "rvvmf4hf") + + (RVVM1x8SI "rvvm1si") (RVVMF2x8SI "rvvmf2si") + (RVVM1x7SI "rvvm1si") (RVVMF2x7SI "rvvmf2si") + (RVVM1x6SI "rvvm1si") (RVVMF2x6SI "rvvmf2si") + (RVVM1x5SI "rvvm1si") (RVVMF2x5SI "rvvmf2si") + (RVVM2x4SI "rvvm2si") (RVVM1x4SI "rvvm1si") (RVVMF2x4SI "rvvmf2si") + (RVVM2x3SI "rvvm2si") (RVVM1x3SI "rvvm1si") (RVVMF2x3SI "rvvmf2si") + (RVVM4x2SI "rvvm4si") (RVVM2x2SI "rvvm2si") (RVVM1x2SI "rvvm1si") (RVVMF2x2SI "rvvmf2si") + + (RVVM1x8SF "rvvm1sf") + (RVVMF2x8SF "rvvmf2sf") + (RVVM1x7SF "rvvm1sf") + (RVVMF2x7SF "rvvmf2sf") + (RVVM1x6SF "rvvm1sf") + (RVVMF2x6SF "rvvmf2sf") + (RVVM1x5SF "rvvm1sf") + (RVVMF2x5SF "rvvmf2sf") + (RVVM2x4SF "rvvm2sf") + (RVVM1x4SF "rvvm1sf") + (RVVMF2x4SF "rvvmf2sf") + (RVVM2x3SF "rvvm2sf") + (RVVM1x3SF "rvvm1sf") + (RVVMF2x3SF "rvvmf2sf") + (RVVM4x2SF "rvvm4sf") + (RVVM2x2SF "rvvm2sf") + (RVVM1x2SF "rvvm1sf") + (RVVMF2x2SF "rvvmf2sf") + + (RVVM1x8DI "rvvm1di") + (RVVM1x7DI "rvvm1di") + (RVVM1x6DI "rvvm1di") + (RVVM1x5DI "rvvm1di") + (RVVM2x4DI "rvvm2di") + (RVVM1x4DI "rvvm1di") + (RVVM2x3DI "rvvm2di") + (RVVM1x3DI "rvvm1di") + (RVVM4x2DI "rvvm4di") + (RVVM2x2DI "rvvm2di") + (RVVM1x2DI "rvvm1di") + + (RVVM1x8DF "rvvm1df") + (RVVM1x7DF "rvvm1df") + (RVVM1x6DF "rvvm1df") + (RVVM1x5DF "rvvm1df") + (RVVM2x4DF "rvvm2df") + (RVVM1x4DF "rvvm1df") + (RVVM2x3DF "rvvm2df") + (RVVM1x3DF "rvvm1df") + (RVVM4x2DF "rvvm4df") + (RVVM2x2DF "rvvm2df") + (RVVM1x2DF "rvvm1df") +]) + (define_mode_attr VSUBEL [ (RVVM8HI "QI") (RVVM4HI "QI") (RVVM2HI "QI") (RVVM1HI "QI") (RVVMF2HI "QI") (RVVMF4HI "QI") @@ -1819,7 +2008,9 @@ (define_int_iterator VMISC [UNSPEC_VMSBF UNSPEC_VMSIF UNSPEC_VMSOF]) -(define_int_iterator VFMISC [UNSPEC_VFRSQRT7 UNSPEC_VFREC7]) +(define_int_iterator VFMISC [UNSPEC_VFRSQRT7]) + +(define_int_iterator VFMISC_FRM [UNSPEC_VFREC7]) (define_int_iterator VFCVTS [UNSPEC_VFCVT UNSPEC_UNSIGNED_VFCVT]) @@ -1842,9 +2033,13 @@ (UNSPEC_VNCLIPU "vnclip")]) (define_int_attr misc_op [(UNSPEC_VMSBF "sbf") (UNSPEC_VMSIF "sif") (UNSPEC_VMSOF "sof") - (UNSPEC_VFRSQRT7 "rsqrt7") (UNSPEC_VFREC7 "rec7")]) + (UNSPEC_VFRSQRT7 "rsqrt7")]) -(define_int_attr float_insn_type [(UNSPEC_VFRSQRT7 "vfsqrt") (UNSPEC_VFREC7 "vfrecp")]) +(define_int_attr misc_frm_op [(UNSPEC_VFREC7 "rec7")]) + +(define_int_attr float_insn_type [(UNSPEC_VFRSQRT7 "vfsqrt")]) + +(define_int_attr float_frm_insn_type [(UNSPEC_VFREC7 "vfrecp")]) (define_int_iterator VCOPYSIGNS [UNSPEC_VCOPYSIGN UNSPEC_VXORSIGN]) @@ -1891,6 +2086,11 @@ (define_code_attr nmsub_nmadd [(plus "nmsub") (minus "nmadd")]) (define_code_attr nmsac_nmacc [(plus "nmsac") (minus "nmacc")]) +(define_code_attr ext_to_rshift [(sign_extend "ashiftrt") + (zero_extend "lshiftrt")]) +(define_code_attr EXT_TO_RSHIFT [(sign_extend "ASHIFTRT") + (zero_extend "LSHIFTRT")]) + (define_code_iterator and_ior [and ior]) (define_code_iterator any_float_binop [plus mult minus div]) @@ -2292,3 +2492,87 @@ (V128DF "TARGET_VECTOR_VLS && TARGET_VECTOR_ELEN_FP_64 && TARGET_MIN_VLEN >= 1024") (V256DF "TARGET_VECTOR_VLS && TARGET_VECTOR_ELEN_FP_64 && TARGET_MIN_VLEN >= 2048") (V512DF "TARGET_VECTOR_VLS && TARGET_VECTOR_ELEN_FP_64 && TARGET_MIN_VLEN >= 4096")]) + +(define_mode_iterator VLSI [ + (V1QI "TARGET_VECTOR_VLS") + (V2QI "TARGET_VECTOR_VLS") + (V4QI "TARGET_VECTOR_VLS") + (V8QI "TARGET_VECTOR_VLS") + (V16QI "TARGET_VECTOR_VLS") + (V32QI "TARGET_VECTOR_VLS") + (V64QI "TARGET_VECTOR_VLS && TARGET_MIN_VLEN >= 64") + (V128QI "TARGET_VECTOR_VLS && TARGET_MIN_VLEN >= 128") + (V256QI "TARGET_VECTOR_VLS && TARGET_MIN_VLEN >= 256") + (V512QI "TARGET_VECTOR_VLS && TARGET_MIN_VLEN >= 512") + (V1024QI "TARGET_VECTOR_VLS && TARGET_MIN_VLEN >= 1024") + (V2048QI "TARGET_VECTOR_VLS && TARGET_MIN_VLEN >= 2048") + (V4096QI "TARGET_VECTOR_VLS && TARGET_MIN_VLEN >= 4096") + (V1HI "TARGET_VECTOR_VLS") + (V2HI "TARGET_VECTOR_VLS") + (V4HI "TARGET_VECTOR_VLS") + (V8HI "TARGET_VECTOR_VLS") + (V16HI "TARGET_VECTOR_VLS") + (V32HI "TARGET_VECTOR_VLS && TARGET_MIN_VLEN >= 64") + (V64HI "TARGET_VECTOR_VLS && TARGET_MIN_VLEN >= 128") + (V128HI "TARGET_VECTOR_VLS && TARGET_MIN_VLEN >= 256") + (V256HI "TARGET_VECTOR_VLS && TARGET_MIN_VLEN >= 512") + (V512HI "TARGET_VECTOR_VLS && TARGET_MIN_VLEN >= 1024") + (V1024HI "TARGET_VECTOR_VLS && TARGET_MIN_VLEN >= 2048") + (V2048HI "TARGET_VECTOR_VLS && TARGET_MIN_VLEN >= 4096") + (V1SI "TARGET_VECTOR_VLS") + (V2SI "TARGET_VECTOR_VLS") + (V4SI "TARGET_VECTOR_VLS") + (V8SI "TARGET_VECTOR_VLS") + (V16SI "TARGET_VECTOR_VLS && TARGET_MIN_VLEN >= 64") + (V32SI "TARGET_VECTOR_VLS && TARGET_MIN_VLEN >= 128") + (V64SI "TARGET_VECTOR_VLS && TARGET_MIN_VLEN >= 256") + (V128SI "TARGET_VECTOR_VLS && TARGET_MIN_VLEN >= 512") + (V256SI "TARGET_VECTOR_VLS && TARGET_MIN_VLEN >= 1024") + (V512SI "TARGET_VECTOR_VLS && TARGET_MIN_VLEN >= 2048") + (V1024SI "TARGET_VECTOR_VLS && TARGET_MIN_VLEN >= 4096") + (V1DI "TARGET_VECTOR_VLS && TARGET_VECTOR_ELEN_64") + (V2DI "TARGET_VECTOR_VLS && TARGET_VECTOR_ELEN_64") + (V4DI "TARGET_VECTOR_VLS && TARGET_VECTOR_ELEN_64") + (V8DI "TARGET_VECTOR_VLS && TARGET_VECTOR_ELEN_64 && TARGET_MIN_VLEN >= 64") + (V16DI "TARGET_VECTOR_VLS && TARGET_VECTOR_ELEN_64 && TARGET_MIN_VLEN >= 128") + (V32DI "TARGET_VECTOR_VLS && TARGET_VECTOR_ELEN_64 && TARGET_MIN_VLEN >= 256") + (V64DI "TARGET_VECTOR_VLS && TARGET_VECTOR_ELEN_64 && TARGET_MIN_VLEN >= 512") + (V128DI "TARGET_VECTOR_VLS && TARGET_VECTOR_ELEN_64 && TARGET_MIN_VLEN >= 1024") + (V256DI "TARGET_VECTOR_VLS && TARGET_VECTOR_ELEN_64 && TARGET_MIN_VLEN >= 2048") + (V512DI "TARGET_VECTOR_VLS && TARGET_VECTOR_ELEN_64 && TARGET_MIN_VLEN >= 4096")]) + +(define_mode_iterator VLSF [ + (V1HF "TARGET_VECTOR_VLS && TARGET_VECTOR_ELEN_FP_16") + (V2HF "TARGET_VECTOR_VLS && TARGET_VECTOR_ELEN_FP_16") + (V4HF "TARGET_VECTOR_VLS && TARGET_VECTOR_ELEN_FP_16") + (V8HF "TARGET_VECTOR_VLS && TARGET_VECTOR_ELEN_FP_16") + (V16HF "TARGET_VECTOR_VLS && TARGET_VECTOR_ELEN_FP_16") + (V32HF "TARGET_VECTOR_VLS && TARGET_VECTOR_ELEN_FP_16 && TARGET_MIN_VLEN >= 64") + (V64HF "TARGET_VECTOR_VLS && TARGET_VECTOR_ELEN_FP_16 && TARGET_MIN_VLEN >= 128") + (V128HF "TARGET_VECTOR_VLS && TARGET_VECTOR_ELEN_FP_16 && TARGET_MIN_VLEN >= 256") + (V256HF "TARGET_VECTOR_VLS && TARGET_VECTOR_ELEN_FP_16 && TARGET_MIN_VLEN >= 512") + (V512HF "TARGET_VECTOR_VLS && TARGET_VECTOR_ELEN_FP_16 && TARGET_MIN_VLEN >= 1024") + (V1024HF "TARGET_VECTOR_VLS && TARGET_VECTOR_ELEN_FP_16 && TARGET_MIN_VLEN >= 2048") + (V2048HF "TARGET_VECTOR_VLS && TARGET_VECTOR_ELEN_FP_16 && TARGET_MIN_VLEN >= 4096") + (V1SF "TARGET_VECTOR_VLS && TARGET_VECTOR_ELEN_FP_32") + (V2SF "TARGET_VECTOR_VLS && TARGET_VECTOR_ELEN_FP_32") + (V4SF "TARGET_VECTOR_VLS && TARGET_VECTOR_ELEN_FP_32") + (V8SF "TARGET_VECTOR_VLS && TARGET_VECTOR_ELEN_FP_32") + (V16SF "TARGET_VECTOR_VLS && TARGET_VECTOR_ELEN_FP_32 && TARGET_MIN_VLEN >= 64") + (V32SF "TARGET_VECTOR_VLS && TARGET_VECTOR_ELEN_FP_32 && TARGET_MIN_VLEN >= 128") + (V64SF "TARGET_VECTOR_VLS && TARGET_VECTOR_ELEN_FP_32 && TARGET_MIN_VLEN >= 256") + (V128SF "TARGET_VECTOR_VLS && TARGET_VECTOR_ELEN_FP_32 && TARGET_MIN_VLEN >= 512") + (V256SF "TARGET_VECTOR_VLS && TARGET_VECTOR_ELEN_FP_32 && TARGET_MIN_VLEN >= 1024") + (V512SF "TARGET_VECTOR_VLS && TARGET_VECTOR_ELEN_FP_32 && TARGET_MIN_VLEN >= 2048") + (V1024SF "TARGET_VECTOR_VLS && TARGET_VECTOR_ELEN_FP_32 && TARGET_MIN_VLEN >= 4096") + (V1DF "TARGET_VECTOR_VLS && TARGET_VECTOR_ELEN_FP_64") + (V2DF "TARGET_VECTOR_VLS && TARGET_VECTOR_ELEN_FP_64") + (V4DF "TARGET_VECTOR_VLS && TARGET_VECTOR_ELEN_FP_64") + (V8DF "TARGET_VECTOR_VLS && TARGET_VECTOR_ELEN_FP_64 && TARGET_MIN_VLEN >= 64") + (V16DF "TARGET_VECTOR_VLS && TARGET_VECTOR_ELEN_FP_64 && TARGET_MIN_VLEN >= 128") + (V32DF "TARGET_VECTOR_VLS && TARGET_VECTOR_ELEN_FP_64 && TARGET_MIN_VLEN >= 256") + (V64DF "TARGET_VECTOR_VLS && TARGET_VECTOR_ELEN_FP_64 && TARGET_MIN_VLEN >= 512") + (V128DF "TARGET_VECTOR_VLS && TARGET_VECTOR_ELEN_FP_64 && TARGET_MIN_VLEN >= 1024") + (V256DF "TARGET_VECTOR_VLS && TARGET_VECTOR_ELEN_FP_64 && TARGET_MIN_VLEN >= 2048") + (V512DF "TARGET_VECTOR_VLS && TARGET_VECTOR_ELEN_FP_64 && TARGET_MIN_VLEN >= 4096") +]) diff --git a/gcc/config/riscv/vector.md b/gcc/config/riscv/vector.md index 750b2de8df99..9d7b4bbe1d4f 100644 --- a/gcc/config/riscv/vector.md +++ b/gcc/config/riscv/vector.md @@ -417,7 +417,7 @@ vialu,vshift,vicmp,vimul,vidiv,vsalu,\ vext,viwalu,viwmul,vicalu,vnshift,\ vimuladd,vimerge,vaalu,vsmul,vsshift,\ - vnclip,viminmax,viwmuladd,vmpop,vmffs,vmsfs,\ + vnclip,viminmax,viwmuladd,vmffs,vmsfs,\ vmiota,vmidx,vfalu,vfmul,vfminmax,vfdiv,\ vfwalu,vfwmul,vfsqrt,vfrecp,vfsgnj,vfcmp,\ vfmerge,vfcvtitof,vfcvtftoi,vfwcvtitof,\ @@ -865,28 +865,10 @@ (const_string "none"))) ;; Defines rounding mode of an floating-point operation. -(define_attr "frm_mode" "rne,rtz,rdn,rup,rmm,dyn,dyn_exit,dyn_call,none" +(define_attr "frm_mode" "" (cond [(eq_attr "type" "vfalu,vfwalu,vfmul,vfdiv,vfwmul") - (cond - [(match_test "INTVAL (operands[9]) == riscv_vector::FRM_RNE") - (const_string "rne") - - (match_test "INTVAL (operands[9]) == riscv_vector::FRM_RTZ") - (const_string "rtz") - - (match_test "INTVAL (operands[9]) == riscv_vector::FRM_RDN") - (const_string "rdn") - - (match_test "INTVAL (operands[9]) == riscv_vector::FRM_RUP") - (const_string "rup") - - (match_test "INTVAL (operands[9]) == riscv_vector::FRM_RMM") - (const_string "rmm") - - (match_test "INTVAL (operands[9]) == riscv_vector::FRM_DYN") - (const_string "dyn")] - (const_string "none"))] - (const_string "none"))) + (symbol_ref "riscv_vector::FRM_DYN")] + (symbol_ref "riscv_vector::FRM_NONE"))) ;; ----------------------------------------------------------------- ;; ---- Miscellaneous Operations @@ -896,13 +878,15 @@ [(set (match_operand:V 0 "register_operand" "=vr") (unspec:V [(reg:SI X0_REGNUM)] UNSPEC_VUNDEF))] "TARGET_VECTOR" - "") + "" + [(set_attr "type" "vector")]) (define_insn "@vundefined" [(set (match_operand:VB 0 "register_operand" "=vr") (unspec:VB [(reg:SI X0_REGNUM)] UNSPEC_VUNDEF))] "TARGET_VECTOR" - "") + "" + [(set_attr "type" "vector")]) (define_expand "@vreinterpret" [(set (match_operand:V 0 "register_operand") @@ -953,7 +937,8 @@ [(set (match_operand:P 0 "register_operand" "=r") (unspec:P [(match_operand:P 1 "const_int_operand" "i")] UNSPEC_VLMAX))] "TARGET_VECTOR" - "") + "" + [(set_attr "type" "vector")]) ;; Set VXRM (define_insn "vxrmsi" @@ -1149,11 +1134,13 @@ else { riscv_vector::emit_vlmax_vsetvl (mode, operands[2]); - riscv_vector::emit_vlmax_insn (code_for_pred_mov (mode), - riscv_vector::RVV_UNOP, operands, operands[2]); + riscv_vector::emit_vlmax_insn_lra (code_for_pred_mov (mode), + riscv_vector::UNARY_OP, operands, operands[2]); } DONE; -}) +} +[(set_attr "type" "vector")] +) (define_insn_and_split "*mov_lra" [(set (match_operand:VB 0 "reg_or_mem_operand" "=vr, m,vr") @@ -1169,11 +1156,13 @@ else { riscv_vector::emit_vlmax_vsetvl (mode, operands[2]); - riscv_vector::emit_vlmax_insn (code_for_pred_mov (mode), - riscv_vector::RVV_UNOP, operands, operands[2]); + riscv_vector::emit_vlmax_insn_lra (code_for_pred_mov (mode), + riscv_vector::UNARY_MASK_OP, operands, operands[2]); } DONE; -}) +} +[(set_attr "type" "vector")] +) ;; Define tuple modes data movement. ;; operands[2] is used to save the offset of each subpart. @@ -1234,7 +1223,7 @@ "TARGET_VECTOR" { riscv_vector::emit_vlmax_insn (code_for_pred_broadcast (mode), - riscv_vector::RVV_UNOP, operands); + riscv_vector::UNARY_OP, operands); DONE; } ) @@ -1381,7 +1370,11 @@ "TARGET_VECTOR" "vsetvli\tzero,zero,e%0,%m1,t%p2,m%p3" [(set_attr "type" "vsetvl") - (set_attr "mode" "SI")]) + (set_attr "mode" "SI") + (set (attr "sew") (symbol_ref "INTVAL (operands[0])")) + (set (attr "vlmul") (symbol_ref "INTVAL (operands[1])")) + (set (attr "ta") (symbol_ref "INTVAL (operands[2])")) + (set (attr "ma") (symbol_ref "INTVAL (operands[3])"))]) ;; vsetvl zero,rs1,vtype instruction. ;; The reason we need this pattern since we should avoid setting X0 register @@ -1464,69 +1457,61 @@ ;; - 15.1 Vector Mask-Register Logical Instructions ;; ------------------------------------------------------------------------------- -;; vle.v/vse.v/vmv.v.v/vmv.v.x/vmv.v.i/vfmv.v.f. -;; For vle.v/vmv.v.v/vmv.v.x/vmv.v.i/vfmv.v.f, we may need merge and mask operand. +;; vle.v/vse.v/vmv.v.v. +;; For vle.v/vmv.v.v, we may need merge and mask operand. ;; For vse.v, we don't need merge operand, so it should always match "vu". ;; constraint alternative 0 ~ 1 match vle.v. ;; constraint alternative 2 match vse.v. ;; constraint alternative 3 match vmv.v.v. -;; constraint alternative 4 match vmv.v.i. -;; For vmv.v.i, we allow 2 following cases: -;; 1. (const_vector:RVVMF8QI repeat [ -;; (const_int:QI N)]), -15 <= N < 16. -;; 2. (const_vector:RVVMF2SF repeat [ -;; (const_double:SF 0.0 [0x0.0p+0])]). -;; We add "MEM_P (operands[0]) || MEM_P (operands[3]) || CONST_VECTOR_P (operands[1])" here to -;; make sure we don't want CSE to generate the following pattern: -;; (insn 17 8 19 2 (set (reg:RVVMF4HI 134 [ _1 ]) -;; (if_then_else:RVVMF4HI (unspec:RVVM1BI [ -;; (reg/v:RVVM1BI 137 [ mask ]) -;; (reg:DI 151) -;; (const_int 0 [0]) repeated x3 -;; (reg:SI 66 vl) -;; (reg:SI 67 vtype) -;; ] UNSPEC_VPREDICATE) -;; (const_vector:RVVMF4HI repeat [ -;; (const_int 0 [0]) -;; ]) -;; (reg/v:RVVMF4HI 140 [ merge ]))) "rvv.c":8:12 608 {pred_movvnx1hi} -;; (expr_list:REG_DEAD (reg:DI 151) -;; (expr_list:REG_DEAD (reg/v:RVVMF4HI 140 [ merge ]) -;; (expr_list:REG_DEAD (reg/v:RVVM1BI 137 [ mask ]) -;; (nil))))) -;; Since both vmv.v.v and vmv.v.i doesn't have mask operand. -(define_insn_and_split "@pred_mov" - [(set (match_operand:V_VLS 0 "nonimmediate_operand" "=vr, vr, vd, m, vr, vr, vr, vr") +;; If operand 3 is a const_vector, then it is left to pred_braordcast patterns. +(define_expand "@pred_mov" + [(set (match_operand:V_VLS 0 "nonimmediate_operand") (if_then_else:V_VLS (unspec: - [(match_operand: 1 "vector_mask_operand" "vmWc1, Wc1, vm, vmWc1, Wc1, Wc1, Wc1, Wc1") - (match_operand 4 "vector_length_operand" " rK, rK, rK, rK, rK, rK, rK, rK") - (match_operand 5 "const_int_operand" " i, i, i, i, i, i, i, i") - (match_operand 6 "const_int_operand" " i, i, i, i, i, i, i, i") - (match_operand 7 "const_int_operand" " i, i, i, i, i, i, i, i") + [(match_operand: 1 "vector_mask_operand") + (match_operand 4 "vector_length_operand") + (match_operand 5 "const_int_operand") + (match_operand 6 "const_int_operand") + (match_operand 7 "const_int_operand") (reg:SI VL_REGNUM) (reg:SI VTYPE_REGNUM)] UNSPEC_VPREDICATE) - (match_operand:V_VLS 3 "vector_move_operand" " m, m, m, vr, vr, vr, viWc0, viWc0") - (match_operand:V_VLS 2 "vector_merge_operand" " 0, vu, vu, vu, vu, 0, vu, 0")))] - "TARGET_VECTOR && (MEM_P (operands[0]) || MEM_P (operands[3]) - || CONST_VECTOR_P (operands[1]))" + (match_operand:V_VLS 3 "vector_move_operand") + (match_operand:V_VLS 2 "vector_merge_operand")))] + "TARGET_VECTOR" + {}) + +;; vle.v/vse.v,vmv.v.v +(define_insn_and_split "*pred_mov" + [(set (match_operand:V_VLS 0 "nonimmediate_operand" "=vr, vr, vd, m, vr, vr") + (if_then_else:V_VLS + (unspec: + [(match_operand: 1 "vector_mask_operand" "vmWc1, Wc1, vm, vmWc1, Wc1, Wc1") + (match_operand 4 "vector_length_operand" " rK, rK, rK, rK, rK, rK") + (match_operand 5 "const_int_operand" " i, i, i, i, i, i") + (match_operand 6 "const_int_operand" " i, i, i, i, i, i") + (match_operand 7 "const_int_operand" " i, i, i, i, i, i") + (reg:SI VL_REGNUM) + (reg:SI VTYPE_REGNUM)] UNSPEC_VPREDICATE) + (match_operand:V_VLS 3 "reg_or_mem_operand" " m, m, m, vr, vr, vr") + (match_operand:V_VLS 2 "vector_merge_operand" " 0, vu, vu, vu, vu, 0")))] + "(TARGET_VECTOR + && (register_operand (operands[0], mode) + || register_operand (operands[3], mode)))" "@ vle.v\t%0,%3%p1 vle.v\t%0,%3 vle.v\t%0,%3,%1.t vse.v\t%3,%0%p1 vmv.v.v\t%0,%3 - vmv.v.v\t%0,%3 - vmv.v.i\t%0,%v3 - vmv.v.i\t%0,%v3" + vmv.v.v\t%0,%3" "&& register_operand (operands[0], mode) && register_operand (operands[3], mode) && satisfies_constraint_vu (operands[2]) && INTVAL (operands[7]) == riscv_vector::VLMAX" [(set (match_dup 0) (match_dup 3))] "" - [(set_attr "type" "vlde,vlde,vlde,vste,vimov,vimov,vimov,vimov") + [(set_attr "type" "vlde,vlde,vlde,vste,vimov,vimov") (set_attr "mode" "")]) ;; Dedicated pattern for vse.v instruction since we can't reuse pred_mov pattern to include @@ -1746,23 +1731,24 @@ (match_operand:V_VLS 2 "vector_merge_operand")))] "TARGET_VECTOR" { - /* Handle vmv.s.x instruction which has memory scalar. */ - if (satisfies_constraint_Wdm (operands[3]) || riscv_vector::simm5_p (operands[3]) - || rtx_equal_p (operands[3], CONST0_RTX (mode))) + /* Handle vmv.s.x instruction (Wb1 mask) which has memory scalar. */ + if (satisfies_constraint_Wdm (operands[3])) { if (satisfies_constraint_Wb1 (operands[1])) - { - // Case 1: vmv.s.x (TA) ==> vlse.v (TA) - if (satisfies_constraint_vu (operands[2])) - operands[1] = CONSTM1_RTX (mode); - else if (GET_MODE_BITSIZE (mode) > GET_MODE_BITSIZE (Pmode)) - { - // Case 2: vmv.s.x (TU) ==> andi vl + vlse.v (TU) in RV32 system. + { + /* Case 1: vmv.s.x (TA, x == memory) ==> vlse.v (TA) */ + if (satisfies_constraint_vu (operands[2])) + operands[1] = CONSTM1_RTX (mode); + else if (GET_MODE_BITSIZE (mode) > GET_MODE_BITSIZE (Pmode)) + { + /* Case 2: vmv.s.x (TU, x == memory) ==> + vl = 0 or 1; + vlse.v (TU) in RV32 system */ operands[4] = riscv_vector::gen_avl_for_scalar_move (operands[4]); operands[1] = CONSTM1_RTX (mode); } - else - operands[3] = force_reg (mode, operands[3]); + else + /* Case 3: load x (memory) to register. */ + operands[3] = force_reg (mode, operands[3]); } } else if (GET_MODE_BITSIZE (mode) > GET_MODE_BITSIZE (Pmode) @@ -1892,6 +1878,44 @@ [(set_attr "type" "vimov,vimov,vimovxv,vimovxv") (set_attr "mode" "")]) +(define_insn "*pred_broadcast_zero" + [(set (match_operand:V_VLS 0 "register_operand" "=vr, vr") + (if_then_else:V_VLS + (unspec: + [(match_operand: 1 "vector_least_significant_set_mask_operand" "Wb1, Wb1") + (match_operand 4 "vector_length_operand" " rK, rK") + (match_operand 5 "const_int_operand" " i, i") + (match_operand 6 "const_int_operand" " i, i") + (match_operand 7 "const_int_operand" " i, i") + (reg:SI VL_REGNUM) + (reg:SI VTYPE_REGNUM)] UNSPEC_VPREDICATE) + (match_operand:V_VLS 3 "vector_const_0_operand" "Wc0, Wc0") + (match_operand:V_VLS 2 "vector_merge_operand" " vu, 0")))] + "TARGET_VECTOR" + "vmv.s.x\t%0,zero" + [(set_attr "type" "vimovxv,vimovxv") + (set_attr "mode" "")]) + +;; Because (vec_duplicate imm) will be converted to (const_vector imm), +;; This pattern is used to handle this case. +(define_insn "*pred_broadcast_imm" + [(set (match_operand:V_VLS 0 "register_operand" "=vr, vr") + (if_then_else:V_VLS + (unspec: + [(match_operand: 1 "vector_all_trues_mask_operand" " Wc1, Wc1") + (match_operand 4 "vector_length_operand" " rK, rK") + (match_operand 5 "const_int_operand" " i, i") + (match_operand 6 "const_int_operand" " i, i") + (match_operand 7 "const_int_operand" " i, i") + (reg:SI VL_REGNUM) + (reg:SI VTYPE_REGNUM)] UNSPEC_VPREDICATE) + (match_operand:V_VLS 3 "vector_const_int_or_double_0_operand" "viWc0, viWc0") + (match_operand:V_VLS 2 "vector_merge_operand" " vu, 0")))] + "TARGET_VECTOR" + "vmv.v.i\t%0,%v3" + [(set_attr "type" "vimov,vimov") + (set_attr "mode" "")]) + ;; ------------------------------------------------------------------------------- ;; ---- Predicated Strided loads/stores ;; ------------------------------------------------------------------------------- @@ -2228,8 +2252,8 @@ ;; ------------------------------------------------------------------------------- (define_insn "@pred_" - [(set (match_operand:VI 0 "register_operand" "=vd, vd, vr, vr, vd, vd, vr, vr, vd, vd, vr, vr") - (if_then_else:VI + [(set (match_operand:V_VLSI 0 "register_operand" "=vd, vd, vr, vr, vd, vd, vr, vr, vd, vd, vr, vr") + (if_then_else:V_VLSI (unspec: [(match_operand: 1 "vector_mask_operand" " vm, vm,Wc1, Wc1, vm, vm,Wc1,Wc1, vm, vm,Wc1,Wc1") (match_operand 5 "vector_length_operand" " rK, rK, rK, rK, rK, rK, rK, rK, rK, rK, rK, rK") @@ -2238,10 +2262,10 @@ (match_operand 8 "const_int_operand" " i, i, i, i, i, i, i, i, i, i, i, i") (reg:SI VL_REGNUM) (reg:SI VTYPE_REGNUM)] UNSPEC_VPREDICATE) - (any_int_binop:VI - (match_operand:VI 3 "" "") - (match_operand:VI 4 "" "")) - (match_operand:VI 2 "vector_merge_operand" "vu,0,vu,0,vu,0,vu,0,vu,0,vu,0")))] + (any_int_binop:V_VLSI + (match_operand:V_VLSI 3 "" "") + (match_operand:V_VLSI 4 "" "")) + (match_operand:V_VLSI 2 "vector_merge_operand" "vu,0,vu,0,vu,0,vu,0,vu,0,vu,0")))] "TARGET_VECTOR" "@ v.vv\t%0,%3,%4%p1 @@ -2264,8 +2288,8 @@ ;; For vsll.vx/vsra.vx/vsrl.vx the scalar mode should be Pmode wheras the ;; scalar mode is inner mode of the RVV mode for other vx patterns. (define_insn "@pred__scalar" - [(set (match_operand:VI 0 "register_operand" "=vd,vd, vr, vr,vd,vd, vr, vr") - (if_then_else:VI + [(set (match_operand:V_VLSI 0 "register_operand" "=vd,vd, vr, vr,vd,vd, vr, vr") + (if_then_else:V_VLSI (unspec: [(match_operand: 1 "vector_mask_operand" "vm,vm,Wc1,Wc1,vm,vm,Wc1,Wc1") (match_operand 5 "vector_length_operand" "rK,rK, rK, rK,rK,rK, rK, rK") @@ -2274,10 +2298,10 @@ (match_operand 8 "const_int_operand" " i, i, i, i, i, i, i, i") (reg:SI VL_REGNUM) (reg:SI VTYPE_REGNUM)] UNSPEC_VPREDICATE) - (any_shift:VI - (match_operand:VI 3 "register_operand" "vr,vr, vr, vr,vr,vr, vr, vr") + (any_shift:V_VLSI + (match_operand:V_VLSI 3 "register_operand" "vr,vr, vr, vr,vr,vr, vr, vr") (match_operand 4 "pmode_reg_or_uimm5_operand" " r, r, r, r, K, K, K, K")) - (match_operand:VI 2 "vector_merge_operand" "vu, 0, vu, 0,vu, 0, vu, 0")))] + (match_operand:V_VLSI 2 "vector_merge_operand" "vu, 0, vu, 0,vu, 0, vu, 0")))] "TARGET_VECTOR" "v.v%o4\t%0,%3,%4%p1" [(set_attr "type" "vshift") @@ -2285,8 +2309,8 @@ ;; Handle GET_MODE_INNER (mode) = QImode, HImode, SImode. (define_insn "@pred__scalar" - [(set (match_operand:VI_QHS 0 "register_operand" "=vd,vd, vr, vr") - (if_then_else:VI_QHS + [(set (match_operand:V_VLSI_QHS 0 "register_operand" "=vd,vd, vr, vr") + (if_then_else:V_VLSI_QHS (unspec: [(match_operand: 1 "vector_mask_operand" "vm,vm,Wc1,Wc1") (match_operand 5 "vector_length_operand" "rK,rK, rK, rK") @@ -2295,19 +2319,19 @@ (match_operand 8 "const_int_operand" " i, i, i, i") (reg:SI VL_REGNUM) (reg:SI VTYPE_REGNUM)] UNSPEC_VPREDICATE) - (any_commutative_binop:VI_QHS - (vec_duplicate:VI_QHS + (any_commutative_binop:V_VLSI_QHS + (vec_duplicate:V_VLSI_QHS (match_operand: 4 "reg_or_0_operand" "rJ,rJ, rJ, rJ")) - (match_operand:VI_QHS 3 "register_operand" "vr,vr, vr, vr")) - (match_operand:VI_QHS 2 "vector_merge_operand" "vu, 0, vu, 0")))] + (match_operand:V_VLSI_QHS 3 "register_operand" "vr,vr, vr, vr")) + (match_operand:V_VLSI_QHS 2 "vector_merge_operand" "vu, 0, vu, 0")))] "TARGET_VECTOR" "v.vx\t%0,%3,%z4%p1" [(set_attr "type" "") (set_attr "mode" "")]) (define_insn "@pred__scalar" - [(set (match_operand:VI_QHS 0 "register_operand" "=vd,vd, vr, vr") - (if_then_else:VI_QHS + [(set (match_operand:V_VLSI_QHS 0 "register_operand" "=vd,vd, vr, vr") + (if_then_else:V_VLSI_QHS (unspec: [(match_operand: 1 "vector_mask_operand" "vm,vm,Wc1,Wc1") (match_operand 5 "vector_length_operand" "rK,rK, rK, rK") @@ -2316,19 +2340,19 @@ (match_operand 8 "const_int_operand" " i, i, i, i") (reg:SI VL_REGNUM) (reg:SI VTYPE_REGNUM)] UNSPEC_VPREDICATE) - (any_non_commutative_binop:VI_QHS - (match_operand:VI_QHS 3 "register_operand" "vr,vr, vr, vr") - (vec_duplicate:VI_QHS + (any_non_commutative_binop:V_VLSI_QHS + (match_operand:V_VLSI_QHS 3 "register_operand" "vr,vr, vr, vr") + (vec_duplicate:V_VLSI_QHS (match_operand: 4 "reg_or_0_operand" "rJ,rJ, rJ, rJ"))) - (match_operand:VI_QHS 2 "vector_merge_operand" "vu, 0, vu, 0")))] + (match_operand:V_VLSI_QHS 2 "vector_merge_operand" "vu, 0, vu, 0")))] "TARGET_VECTOR" "v.vx\t%0,%3,%z4%p1" [(set_attr "type" "") (set_attr "mode" "")]) (define_insn "@pred_sub_reverse_scalar" - [(set (match_operand:VI_QHS 0 "register_operand" "=vd,vd, vr, vr") - (if_then_else:VI_QHS + [(set (match_operand:V_VLSI_QHS 0 "register_operand" "=vd,vd, vr, vr") + (if_then_else:V_VLSI_QHS (unspec: [(match_operand: 1 "vector_mask_operand" "vm,vm,Wc1,Wc1") (match_operand 5 "vector_length_operand" "rK,rK, rK, rK") @@ -2337,11 +2361,11 @@ (match_operand 8 "const_int_operand" " i, i, i, i") (reg:SI VL_REGNUM) (reg:SI VTYPE_REGNUM)] UNSPEC_VPREDICATE) - (minus:VI_QHS - (vec_duplicate:VI_QHS + (minus:V_VLSI_QHS + (vec_duplicate:V_VLSI_QHS (match_operand: 4 "reg_or_0_operand" "rJ,rJ, rJ, rJ")) - (match_operand:VI_QHS 3 "register_operand" "vr,vr, vr, vr")) - (match_operand:VI_QHS 2 "vector_merge_operand" "vu, 0, vu, 0")))] + (match_operand:V_VLSI_QHS 3 "register_operand" "vr,vr, vr, vr")) + (match_operand:V_VLSI_QHS 2 "vector_merge_operand" "vu, 0, vu, 0")))] "TARGET_VECTOR" "vrsub.vx\t%0,%3,%z4%p1" [(set_attr "type" "vialu") @@ -2350,8 +2374,8 @@ ;; Handle GET_MODE_INNER (mode) = DImode. We need to split them since ;; we need to deal with SEW = 64 in RV32 system. (define_expand "@pred__scalar" - [(set (match_operand:VI_D 0 "register_operand") - (if_then_else:VI_D + [(set (match_operand:V_VLSI_D 0 "register_operand") + (if_then_else:V_VLSI_D (unspec: [(match_operand: 1 "vector_mask_operand") (match_operand 5 "vector_length_operand") @@ -2360,11 +2384,11 @@ (match_operand 8 "const_int_operand") (reg:SI VL_REGNUM) (reg:SI VTYPE_REGNUM)] UNSPEC_VPREDICATE) - (any_commutative_binop:VI_D - (vec_duplicate:VI_D + (any_commutative_binop:V_VLSI_D + (vec_duplicate:V_VLSI_D (match_operand: 4 "reg_or_int_operand")) - (match_operand:VI_D 3 "register_operand")) - (match_operand:VI_D 2 "vector_merge_operand")))] + (match_operand:V_VLSI_D 3 "register_operand")) + (match_operand:V_VLSI_D 2 "vector_merge_operand")))] "TARGET_VECTOR" { if (riscv_vector::sew64_scalar_helper ( @@ -2382,8 +2406,8 @@ }) (define_insn "*pred__scalar" - [(set (match_operand:VI_D 0 "register_operand" "=vd,vd, vr, vr") - (if_then_else:VI_D + [(set (match_operand:V_VLSI_D 0 "register_operand" "=vd,vd, vr, vr") + (if_then_else:V_VLSI_D (unspec: [(match_operand: 1 "vector_mask_operand" "vm,vm,Wc1,Wc1") (match_operand 5 "vector_length_operand" "rK,rK, rK, rK") @@ -2392,19 +2416,19 @@ (match_operand 8 "const_int_operand" " i, i, i, i") (reg:SI VL_REGNUM) (reg:SI VTYPE_REGNUM)] UNSPEC_VPREDICATE) - (any_commutative_binop:VI_D - (vec_duplicate:VI_D + (any_commutative_binop:V_VLSI_D + (vec_duplicate:V_VLSI_D (match_operand: 4 "reg_or_0_operand" "rJ,rJ, rJ, rJ")) - (match_operand:VI_D 3 "register_operand" "vr,vr, vr, vr")) - (match_operand:VI_D 2 "vector_merge_operand" "vu, 0, vu, 0")))] + (match_operand:V_VLSI_D 3 "register_operand" "vr,vr, vr, vr")) + (match_operand:V_VLSI_D 2 "vector_merge_operand" "vu, 0, vu, 0")))] "TARGET_VECTOR" "v.vx\t%0,%3,%z4%p1" [(set_attr "type" "") (set_attr "mode" "")]) (define_insn "*pred__extended_scalar" - [(set (match_operand:VI_D 0 "register_operand" "=vd,vd, vr, vr") - (if_then_else:VI_D + [(set (match_operand:V_VLSI_D 0 "register_operand" "=vd,vd, vr, vr") + (if_then_else:V_VLSI_D (unspec: [(match_operand: 1 "vector_mask_operand" "vm,vm,Wc1,Wc1") (match_operand 5 "vector_length_operand" "rK,rK, rK, rK") @@ -2413,20 +2437,20 @@ (match_operand 8 "const_int_operand" " i, i, i, i") (reg:SI VL_REGNUM) (reg:SI VTYPE_REGNUM)] UNSPEC_VPREDICATE) - (any_commutative_binop:VI_D - (vec_duplicate:VI_D + (any_commutative_binop:V_VLSI_D + (vec_duplicate:V_VLSI_D (sign_extend: (match_operand: 4 "reg_or_0_operand" "rJ,rJ, rJ, rJ"))) - (match_operand:VI_D 3 "register_operand" "vr,vr, vr, vr")) - (match_operand:VI_D 2 "vector_merge_operand" "vu, 0, vu, 0")))] + (match_operand:V_VLSI_D 3 "register_operand" "vr,vr, vr, vr")) + (match_operand:V_VLSI_D 2 "vector_merge_operand" "vu, 0, vu, 0")))] "TARGET_VECTOR" "v.vx\t%0,%3,%z4%p1" [(set_attr "type" "") (set_attr "mode" "")]) (define_expand "@pred__scalar" - [(set (match_operand:VI_D 0 "register_operand") - (if_then_else:VI_D + [(set (match_operand:V_VLSI_D 0 "register_operand") + (if_then_else:V_VLSI_D (unspec: [(match_operand: 1 "vector_mask_operand") (match_operand 5 "vector_length_operand") @@ -2435,11 +2459,11 @@ (match_operand 8 "const_int_operand") (reg:SI VL_REGNUM) (reg:SI VTYPE_REGNUM)] UNSPEC_VPREDICATE) - (any_non_commutative_binop:VI_D - (match_operand:VI_D 3 "register_operand") - (vec_duplicate:VI_D + (any_non_commutative_binop:V_VLSI_D + (match_operand:V_VLSI_D 3 "register_operand") + (vec_duplicate:V_VLSI_D (match_operand: 4 "reg_or_int_operand"))) - (match_operand:VI_D 2 "vector_merge_operand")))] + (match_operand:V_VLSI_D 2 "vector_merge_operand")))] "TARGET_VECTOR" { if (riscv_vector::sew64_scalar_helper ( @@ -2457,8 +2481,8 @@ }) (define_insn "*pred__scalar" - [(set (match_operand:VI_D 0 "register_operand" "=vd,vd, vr, vr") - (if_then_else:VI_D + [(set (match_operand:V_VLSI_D 0 "register_operand" "=vd,vd, vr, vr") + (if_then_else:V_VLSI_D (unspec: [(match_operand: 1 "vector_mask_operand" "vm,vm,Wc1,Wc1") (match_operand 5 "vector_length_operand" "rK,rK, rK, rK") @@ -2467,19 +2491,19 @@ (match_operand 8 "const_int_operand" " i, i, i, i") (reg:SI VL_REGNUM) (reg:SI VTYPE_REGNUM)] UNSPEC_VPREDICATE) - (any_non_commutative_binop:VI_D - (match_operand:VI_D 3 "register_operand" "vr,vr, vr, vr") - (vec_duplicate:VI_D + (any_non_commutative_binop:V_VLSI_D + (match_operand:V_VLSI_D 3 "register_operand" "vr,vr, vr, vr") + (vec_duplicate:V_VLSI_D (match_operand: 4 "reg_or_0_operand" "rJ,rJ, rJ, rJ"))) - (match_operand:VI_D 2 "vector_merge_operand" "vu, 0, vu, 0")))] + (match_operand:V_VLSI_D 2 "vector_merge_operand" "vu, 0, vu, 0")))] "TARGET_VECTOR" "v.vx\t%0,%3,%z4%p1" [(set_attr "type" "") (set_attr "mode" "")]) (define_insn "*pred__extended_scalar" - [(set (match_operand:VI_D 0 "register_operand" "=vd,vd, vr, vr") - (if_then_else:VI_D + [(set (match_operand:V_VLSI_D 0 "register_operand" "=vd,vd, vr, vr") + (if_then_else:V_VLSI_D (unspec: [(match_operand: 1 "vector_mask_operand" "vm,vm,Wc1,Wc1") (match_operand 5 "vector_length_operand" "rK,rK, rK, rK") @@ -2488,20 +2512,20 @@ (match_operand 8 "const_int_operand" " i, i, i, i") (reg:SI VL_REGNUM) (reg:SI VTYPE_REGNUM)] UNSPEC_VPREDICATE) - (any_non_commutative_binop:VI_D - (match_operand:VI_D 3 "register_operand" "vr,vr, vr, vr") - (vec_duplicate:VI_D + (any_non_commutative_binop:V_VLSI_D + (match_operand:V_VLSI_D 3 "register_operand" "vr,vr, vr, vr") + (vec_duplicate:V_VLSI_D (sign_extend: (match_operand: 4 "reg_or_0_operand" "rJ,rJ, rJ, rJ")))) - (match_operand:VI_D 2 "vector_merge_operand" "vu, 0, vu, 0")))] + (match_operand:V_VLSI_D 2 "vector_merge_operand" "vu, 0, vu, 0")))] "TARGET_VECTOR" "v.vx\t%0,%3,%z4%p1" [(set_attr "type" "") (set_attr "mode" "")]) (define_expand "@pred_sub_reverse_scalar" - [(set (match_operand:VI_D 0 "register_operand") - (if_then_else:VI_D + [(set (match_operand:V_VLSI_D 0 "register_operand") + (if_then_else:V_VLSI_D (unspec: [(match_operand: 1 "vector_mask_operand") (match_operand 5 "vector_length_operand") @@ -2510,11 +2534,11 @@ (match_operand 8 "const_int_operand") (reg:SI VL_REGNUM) (reg:SI VTYPE_REGNUM)] UNSPEC_VPREDICATE) - (minus:VI_D - (vec_duplicate:VI_D + (minus:V_VLSI_D + (vec_duplicate:V_VLSI_D (match_operand: 4 "reg_or_int_operand")) - (match_operand:VI_D 3 "register_operand")) - (match_operand:VI_D 2 "vector_merge_operand")))] + (match_operand:V_VLSI_D 3 "register_operand")) + (match_operand:V_VLSI_D 2 "vector_merge_operand")))] "TARGET_VECTOR" { if (riscv_vector::sew64_scalar_helper ( @@ -2532,8 +2556,8 @@ }) (define_insn "*pred_sub_reverse_scalar" - [(set (match_operand:VI_D 0 "register_operand" "=vd,vd, vr, vr") - (if_then_else:VI_D + [(set (match_operand:V_VLSI_D 0 "register_operand" "=vd,vd, vr, vr") + (if_then_else:V_VLSI_D (unspec: [(match_operand: 1 "vector_mask_operand" "vm,vm,Wc1,Wc1") (match_operand 5 "vector_length_operand" "rK,rK, rK, rK") @@ -2542,19 +2566,19 @@ (match_operand 8 "const_int_operand" " i, i, i, i") (reg:SI VL_REGNUM) (reg:SI VTYPE_REGNUM)] UNSPEC_VPREDICATE) - (minus:VI_D - (vec_duplicate:VI_D + (minus:V_VLSI_D + (vec_duplicate:V_VLSI_D (match_operand: 4 "reg_or_0_operand" "rJ,rJ, rJ, rJ")) - (match_operand:VI_D 3 "register_operand" "vr,vr, vr, vr")) - (match_operand:VI_D 2 "vector_merge_operand" "vu, 0, vu, 0")))] + (match_operand:V_VLSI_D 3 "register_operand" "vr,vr, vr, vr")) + (match_operand:V_VLSI_D 2 "vector_merge_operand" "vu, 0, vu, 0")))] "TARGET_VECTOR" "vrsub.vx\t%0,%3,%z4%p1" [(set_attr "type" "vialu") (set_attr "mode" "")]) (define_insn "*pred_sub_extended_reverse_scalar" - [(set (match_operand:VI_D 0 "register_operand" "=vd,vd, vr, vr") - (if_then_else:VI_D + [(set (match_operand:V_VLSI_D 0 "register_operand" "=vd,vd, vr, vr") + (if_then_else:V_VLSI_D (unspec: [(match_operand: 1 "vector_mask_operand" "vm,vm,Wc1,Wc1") (match_operand 5 "vector_length_operand" "rK,rK, rK, rK") @@ -2563,12 +2587,12 @@ (match_operand 8 "const_int_operand" " i, i, i, i") (reg:SI VL_REGNUM) (reg:SI VTYPE_REGNUM)] UNSPEC_VPREDICATE) - (minus:VI_D - (vec_duplicate:VI_D + (minus:V_VLSI_D + (vec_duplicate:V_VLSI_D (sign_extend: (match_operand: 4 "reg_or_0_operand" "rJ,rJ, rJ, rJ"))) - (match_operand:VI_D 3 "register_operand" "vr,vr, vr, vr")) - (match_operand:VI_D 2 "vector_merge_operand" "vu, 0, vu, 0")))] + (match_operand:V_VLSI_D 3 "register_operand" "vr,vr, vr, vr")) + (match_operand:V_VLSI_D 2 "vector_merge_operand" "vu, 0, vu, 0")))] "TARGET_VECTOR" "vrsub.vx\t%0,%3,%z4%p1" [(set_attr "type" "vialu") @@ -3386,8 +3410,8 @@ ;; ------------------------------------------------------------------------------- (define_insn "@pred_" - [(set (match_operand:VI 0 "register_operand" "=vd,vd, vr, vr") - (if_then_else:VI + [(set (match_operand:V_VLSI 0 "register_operand" "=vd,vd, vr, vr") + (if_then_else:V_VLSI (unspec: [(match_operand: 1 "vector_mask_operand" "vm,vm,Wc1,Wc1") (match_operand 4 "vector_length_operand" "rK,rK, rK, rK") @@ -3396,9 +3420,9 @@ (match_operand 7 "const_int_operand" " i, i, i, i") (reg:SI VL_REGNUM) (reg:SI VTYPE_REGNUM)] UNSPEC_VPREDICATE) - (any_int_unop:VI - (match_operand:VI 3 "register_operand" "vr,vr, vr, vr")) - (match_operand:VI 2 "vector_merge_operand" "vu, 0, vu, 0")))] + (any_int_unop:V_VLSI + (match_operand:V_VLSI 3 "register_operand" "vr,vr, vr, vr")) + (match_operand:V_VLSI 2 "vector_merge_operand" "vu, 0, vu, 0")))] "TARGET_VECTOR" "v.v\t%0,%3%p1" [(set_attr "type" "vialu") @@ -4979,10 +5003,7 @@ (match_operand:VI 5 "register_operand")))] "TARGET_VECTOR" { - /* Swap the multiplication operands if the fallback value is the - second of the two. */ - if (rtx_equal_p (operands[3], operands[5])) - std::swap (operands[2], operands[3]); + riscv_vector::prepare_ternary_operands (operands); }) (define_insn "*pred_madd" @@ -5048,52 +5069,30 @@ (set (attr "avl_type") (symbol_ref "INTVAL (operands[8])"))]) (define_insn_and_rewrite "*pred_mul_plus" - [(set (match_operand:VI 0 "register_operand" "=&vr,?&vr, ?&vr, ?&vr, ?&vr") + [(set (match_operand:VI 0 "register_operand" "=&vr") (if_then_else:VI (unspec: - [(match_operand: 1 "vector_mask_operand" "vmWc1,vmWc1,vmWc1,vmWc1,vmWc1") - (match_operand 6 "vector_length_operand" " rK, rK, rK, rK, rK") - (match_operand 7 "const_int_operand" " i, i, i, i, i") - (match_operand 8 "const_int_operand" " i, i, i, i, i") - (match_operand 9 "const_int_operand" " i, i, i, i, i") + [(match_operand: 1 "vector_mask_operand" "vmWc1") + (match_operand 6 "vector_length_operand" " rK") + (match_operand 7 "const_int_operand" " i") + (match_operand 8 "const_int_operand" " i") + (match_operand 9 "const_int_operand" " i") (reg:SI VL_REGNUM) (reg:SI VTYPE_REGNUM)] UNSPEC_VPREDICATE) (plus:VI (mult:VI - (match_operand:VI 2 "register_operand" " vr, vr, vi, vr, vr") - (match_operand:VI 3 "register_operand" " vr, vr, vr, vi, vr")) - (match_operand:VI 4 "vector_arith_operand" " vr, vi, vr, vr, vr")) - (match_operand:VI 5 "register_operand" " 0, vr, vr, vr, vr")))] + (match_operand:VI 2 "register_operand" " vr") + (match_operand:VI 3 "register_operand" " vr")) + (match_operand:VI 4 "register_operand" " vr")) + (match_operand:VI 5 "register_operand" " vr")))] "TARGET_VECTOR && !rtx_equal_p (operands[2], operands[5]) && !rtx_equal_p (operands[3], operands[5]) && !rtx_equal_p (operands[4], operands[5])" - "@ - vmv.v.v\t%0,%4\;vmacc.vv\t%0,%2,%3%p1 - # - # - # - #" - "&& reload_completed - && !rtx_equal_p (operands[0], operands[5])" + "#" + "&& reload_completed" { - if (satisfies_constraint_vi (operands[3])) - std::swap (operands[2], operands[3]); - - if (satisfies_constraint_vi (operands[2])) - { - emit_insn (gen_pred_merge (operands[0], RVV_VUNDEF (mode), - operands[5], operands[2], operands[1], operands[6], - operands[7], operands[9])); - operands[5] = operands[2] = operands[0]; - } - else - { - emit_insn (gen_pred_merge (operands[0], RVV_VUNDEF (mode), - operands[5], operands[4], operands[1], operands[6], - operands[7], operands[9])); - operands[5] = operands[4] = operands[0]; - } + riscv_vector::prepare_ternary_operands (operands, true); } [(set_attr "type" "vimuladd") (set_attr "mode" "")]) @@ -5112,14 +5111,12 @@ (plus:VI_QHS (mult:VI_QHS (vec_duplicate:VI_QHS - (match_operand: 2 "reg_or_int_operand")) + (match_operand: 2 "register_operand")) (match_operand:VI_QHS 3 "register_operand")) (match_operand:VI_QHS 4 "register_operand")) (match_operand:VI_QHS 5 "register_operand")))] "TARGET_VECTOR" -{ - operands[2] = force_reg (mode, operands[2]); -}) +{}) (define_insn "*pred_madd_scalar" [(set (match_operand:VI 0 "register_operand" "=vd,?&vd, vr,?&vr") @@ -5186,48 +5183,30 @@ (set (attr "avl_type") (symbol_ref "INTVAL (operands[8])"))]) (define_insn_and_rewrite "*pred_mul_plus_scalar" - [(set (match_operand:VI 0 "register_operand" "=&vr, ?&vr, ?&vr, ?&vr") + [(set (match_operand:VI 0 "register_operand" "=&vr") (if_then_else:VI (unspec: - [(match_operand: 1 "vector_mask_operand" "vmWc1,vmWc1,vmWc1,vmWc1") - (match_operand 6 "vector_length_operand" " rK, rK, rK, rK") - (match_operand 7 "const_int_operand" " i, i, i, i") - (match_operand 8 "const_int_operand" " i, i, i, i") - (match_operand 9 "const_int_operand" " i, i, i, i") + [(match_operand: 1 "vector_mask_operand" "vmWc1") + (match_operand 6 "vector_length_operand" " rK") + (match_operand 7 "const_int_operand" " i") + (match_operand 8 "const_int_operand" " i") + (match_operand 9 "const_int_operand" " i") (reg:SI VL_REGNUM) (reg:SI VTYPE_REGNUM)] UNSPEC_VPREDICATE) (plus:VI (mult:VI (vec_duplicate:VI - (match_operand: 2 "register_operand" " r, r, r, r")) - (match_operand:VI 3 "register_operand" " vr, vr, vi, vr")) - (match_operand:VI 4 "vector_arith_operand" " vr, vi, vr, vr")) - (match_operand:VI 5 "register_operand" " 0, vr, vr, vr")))] + (match_operand: 2 "register_operand" " r")) + (match_operand:VI 3 "register_operand" " vr")) + (match_operand:VI 4 "vector_arith_operand" " vr")) + (match_operand:VI 5 "register_operand" " vr")))] "TARGET_VECTOR && !rtx_equal_p (operands[3], operands[5]) && !rtx_equal_p (operands[4], operands[5])" - "@ - vmv.v.v\t%0,%4\;vmacc.vx\t%0,%2,%3%p1 - # - # - #" - "&& reload_completed - && !rtx_equal_p (operands[0], operands[5])" + "#" + "&& reload_completed" { - if (satisfies_constraint_vi (operands[3])) - { - emit_insn (gen_pred_merge (operands[0], RVV_VUNDEF (mode), - operands[5], operands[3], operands[1], operands[6], - operands[7], operands[9])); - operands[5] = operands[3] = operands[0]; - } - else - { - emit_insn (gen_pred_merge (operands[0], RVV_VUNDEF (mode), - operands[5], operands[4], operands[1], operands[6], - operands[7], operands[9])); - operands[5] = operands[4] = operands[0]; - } + riscv_vector::prepare_ternary_operands (operands, true); } [(set_attr "type" "vimuladd") (set_attr "mode" "")]) @@ -5333,49 +5312,31 @@ (set (attr "avl_type") (symbol_ref "INTVAL (operands[8])"))]) (define_insn_and_rewrite "*pred_mul_plus_extended_scalar" - [(set (match_operand:VI_D 0 "register_operand" "=&vr, ?&vr, ?&vr, ?&vr") + [(set (match_operand:VI_D 0 "register_operand" "=&vr") (if_then_else:VI_D (unspec: - [(match_operand: 1 "vector_mask_operand" "vmWc1,vmWc1,vmWc1,vmWc1") - (match_operand 6 "vector_length_operand" " rK, rK, rK, rK") - (match_operand 7 "const_int_operand" " i, i, i, i") - (match_operand 8 "const_int_operand" " i, i, i, i") - (match_operand 9 "const_int_operand" " i, i, i, i") + [(match_operand: 1 "vector_mask_operand" "vmWc1") + (match_operand 6 "vector_length_operand" " rK") + (match_operand 7 "const_int_operand" " i") + (match_operand 8 "const_int_operand" " i") + (match_operand 9 "const_int_operand" " i") (reg:SI VL_REGNUM) (reg:SI VTYPE_REGNUM)] UNSPEC_VPREDICATE) (plus:VI_D (mult:VI_D (vec_duplicate:VI_D (sign_extend: - (match_operand: 2 "register_operand" " r, r, r, r"))) - (match_operand:VI_D 3 "register_operand" " vr, vr, vr, vr")) - (match_operand:VI_D 4 "vector_arith_operand" " vr, vr, vr, vr")) - (match_operand:VI_D 5 "register_operand" " 0, vr, vr, vr")))] + (match_operand: 2 "register_operand" " r"))) + (match_operand:VI_D 3 "register_operand" " vr")) + (match_operand:VI_D 4 "register_operand" " vr")) + (match_operand:VI_D 5 "register_operand" " vr")))] "TARGET_VECTOR && !rtx_equal_p (operands[3], operands[5]) && !rtx_equal_p (operands[4], operands[5])" - "@ - vmv.v.v\t%0,%4\;vmacc.vx\t%0,%2,%3%p1 - # - # - #" - "&& reload_completed - && !rtx_equal_p (operands[0], operands[5])" + "#" + "&& reload_completed" { - if (satisfies_constraint_vi (operands[3])) - { - emit_insn (gen_pred_merge (operands[0], RVV_VUNDEF (mode), - operands[5], operands[3], operands[1], operands[6], - operands[7], operands[9])); - operands[5] = operands[3] = operands[0]; - } - else - { - emit_insn (gen_pred_merge (operands[0], RVV_VUNDEF (mode), - operands[5], operands[4], operands[1], operands[6], - operands[7], operands[9])); - operands[5] = operands[4] = operands[0]; - } + riscv_vector::prepare_ternary_operands (operands, true); } [(set_attr "type" "vimuladd") (set_attr "mode" "")]) @@ -5399,10 +5360,7 @@ (match_operand:VI 5 "register_operand")))] "TARGET_VECTOR" { - /* Swap the multiplication operands if the fallback value is the - second of the two. */ - if (rtx_equal_p (operands[3], operands[5])) - std::swap (operands[2], operands[3]); + riscv_vector::prepare_ternary_operands (operands); }) (define_insn "*pred_nmsub" @@ -5468,52 +5426,30 @@ (set (attr "avl_type") (symbol_ref "INTVAL (operands[8])"))]) (define_insn_and_rewrite "*pred_minus_mul" - [(set (match_operand:VI 0 "register_operand" "=&vr,?&vr, ?&vr, ?&vr, ?&vr") + [(set (match_operand:VI 0 "register_operand" "=&vr") (if_then_else:VI (unspec: - [(match_operand: 1 "vector_mask_operand" "vmWc1,vmWc1,vmWc1,vmWc1,vmWc1") - (match_operand 6 "vector_length_operand" " rK, rK, rK, rK, rK") - (match_operand 7 "const_int_operand" " i, i, i, i, i") - (match_operand 8 "const_int_operand" " i, i, i, i, i") - (match_operand 9 "const_int_operand" " i, i, i, i, i") + [(match_operand: 1 "vector_mask_operand" "vmWc1") + (match_operand 6 "vector_length_operand" " rK") + (match_operand 7 "const_int_operand" " i") + (match_operand 8 "const_int_operand" " i") + (match_operand 9 "const_int_operand" " i") (reg:SI VL_REGNUM) (reg:SI VTYPE_REGNUM)] UNSPEC_VPREDICATE) (minus:VI - (match_operand:VI 4 "vector_arith_operand" " vr, vi, vr, vr, vr") + (match_operand:VI 4 "vector_arith_operand" " vr") (mult:VI - (match_operand:VI 2 "register_operand" " vr, vr, vi, vr, vr") - (match_operand:VI 3 "register_operand" " vr, vr, vr, vi, vr"))) - (match_operand:VI 5 "register_operand" " 0, vr, vr, vr, vr")))] + (match_operand:VI 2 "register_operand" " vr") + (match_operand:VI 3 "register_operand" " vr"))) + (match_operand:VI 5 "register_operand" " vr")))] "TARGET_VECTOR && !rtx_equal_p (operands[2], operands[5]) && !rtx_equal_p (operands[3], operands[5]) && !rtx_equal_p (operands[4], operands[5])" - "@ - vmv.v.v\t%0,%4\;vnmsac.vv\t%0,%2,%3%p1 - # - # - # - #" - "&& reload_completed - && !rtx_equal_p (operands[0], operands[5])" + "#" + "&& reload_completed" { - if (satisfies_constraint_vi (operands[3])) - std::swap (operands[2], operands[3]); - - if (satisfies_constraint_vi (operands[2])) - { - emit_insn (gen_pred_merge (operands[0], RVV_VUNDEF (mode), - operands[5], operands[2], operands[1], operands[6], - operands[7], operands[9])); - operands[5] = operands[2] = operands[0]; - } - else - { - emit_insn (gen_pred_merge (operands[0], RVV_VUNDEF (mode), - operands[5], operands[4], operands[1], operands[6], - operands[7], operands[9])); - operands[5] = operands[4] = operands[0]; - } + riscv_vector::prepare_ternary_operands (operands, true); } [(set_attr "type" "vimuladd") (set_attr "mode" "")]) @@ -5533,13 +5469,11 @@ (match_operand:VI_QHS 4 "register_operand") (mult:VI_QHS (vec_duplicate:VI_QHS - (match_operand: 2 "reg_or_int_operand")) + (match_operand: 2 "register_operand")) (match_operand:VI_QHS 3 "register_operand"))) (match_operand:VI_QHS 5 "register_operand")))] "TARGET_VECTOR" -{ - operands[2] = force_reg (mode, operands[2]); -}) +{}) (define_insn "*pred_nmsub_scalar" [(set (match_operand:VI 0 "register_operand" "=vd,?&vd, vr,?&vr") @@ -5606,48 +5540,30 @@ (set (attr "avl_type") (symbol_ref "INTVAL (operands[8])"))]) (define_insn_and_rewrite "*pred_minus_mul_scalar" - [(set (match_operand:VI 0 "register_operand" "=&vr, ?&vr, ?&vr, ?&vr") + [(set (match_operand:VI 0 "register_operand" "=&vr") (if_then_else:VI (unspec: - [(match_operand: 1 "vector_mask_operand" "vmWc1,vmWc1,vmWc1,vmWc1") - (match_operand 6 "vector_length_operand" " rK, rK, rK, rK") - (match_operand 7 "const_int_operand" " i, i, i, i") - (match_operand 8 "const_int_operand" " i, i, i, i") - (match_operand 9 "const_int_operand" " i, i, i, i") + [(match_operand: 1 "vector_mask_operand" "vmWc1") + (match_operand 6 "vector_length_operand" " rK") + (match_operand 7 "const_int_operand" " i") + (match_operand 8 "const_int_operand" " i") + (match_operand 9 "const_int_operand" " i") (reg:SI VL_REGNUM) (reg:SI VTYPE_REGNUM)] UNSPEC_VPREDICATE) (minus:VI - (match_operand:VI 4 "vector_arith_operand" " vr, vi, vr, vr") + (match_operand:VI 4 "vector_arith_operand" " vr") (mult:VI (vec_duplicate:VI - (match_operand: 2 "register_operand" " r, r, r, r")) - (match_operand:VI 3 "register_operand" " vr, vr, vi, vr"))) - (match_operand:VI 5 "register_operand" " 0, vr, vr, vr")))] + (match_operand: 2 "register_operand" " r")) + (match_operand:VI 3 "register_operand" " vr"))) + (match_operand:VI 5 "register_operand" " vr")))] "TARGET_VECTOR && !rtx_equal_p (operands[3], operands[5]) && !rtx_equal_p (operands[4], operands[5])" - "@ - vmv.v.v\t%0,%4\;vnmsac.vx\t%0,%2,%3%p1 - # - # - #" - "&& reload_completed - && !rtx_equal_p (operands[0], operands[5])" + "#" + "&& reload_completed" { - if (satisfies_constraint_vi (operands[3])) - { - emit_insn (gen_pred_merge (operands[0], RVV_VUNDEF (mode), - operands[5], operands[3], operands[1], operands[6], - operands[7], operands[9])); - operands[5] = operands[3] = operands[0]; - } - else - { - emit_insn (gen_pred_merge (operands[0], RVV_VUNDEF (mode), - operands[5], operands[4], operands[1], operands[6], - operands[7], operands[9])); - operands[5] = operands[4] = operands[0]; - } + riscv_vector::prepare_ternary_operands (operands, true); } [(set_attr "type" "vimuladd") (set_attr "mode" "")]) @@ -5753,49 +5669,31 @@ (set (attr "avl_type") (symbol_ref "INTVAL (operands[8])"))]) (define_insn_and_rewrite "*pred_minus_mul_extended_scalar" - [(set (match_operand:VI_D 0 "register_operand" "=&vr, ?&vr, ?&vr, ?&vr") + [(set (match_operand:VI_D 0 "register_operand" "=&vr") (if_then_else:VI_D (unspec: - [(match_operand: 1 "vector_mask_operand" "vmWc1,vmWc1,vmWc1,vmWc1") - (match_operand 6 "vector_length_operand" " rK, rK, rK, rK") - (match_operand 7 "const_int_operand" " i, i, i, i") - (match_operand 8 "const_int_operand" " i, i, i, i") - (match_operand 9 "const_int_operand" " i, i, i, i") + [(match_operand: 1 "vector_mask_operand" "vmWc1") + (match_operand 6 "vector_length_operand" " rK") + (match_operand 7 "const_int_operand" " i") + (match_operand 8 "const_int_operand" " i") + (match_operand 9 "const_int_operand" " i") (reg:SI VL_REGNUM) (reg:SI VTYPE_REGNUM)] UNSPEC_VPREDICATE) (minus:VI_D - (match_operand:VI_D 4 "vector_arith_operand" " vr, vr, vr, vr") + (match_operand:VI_D 4 "vector_arith_operand" " vr") (mult:VI_D (vec_duplicate:VI_D (sign_extend: - (match_operand: 2 "register_operand" " r, r, r, r"))) - (match_operand:VI_D 3 "register_operand" " vr, vr, vr, vr"))) - (match_operand:VI_D 5 "register_operand" " 0, vr, vr, vr")))] + (match_operand: 2 "register_operand" " r"))) + (match_operand:VI_D 3 "register_operand" " vr"))) + (match_operand:VI_D 5 "register_operand" " vr")))] "TARGET_VECTOR && !rtx_equal_p (operands[3], operands[5]) && !rtx_equal_p (operands[4], operands[5])" - "@ - vmv.v.v\t%0,%4\;vnmsac.vx\t%0,%2,%3%p1 - # - # - #" - "&& reload_completed - && !rtx_equal_p (operands[0], operands[5])" + "#" + "&& reload_completed" { - if (satisfies_constraint_vi (operands[3])) - { - emit_insn (gen_pred_merge (operands[0], RVV_VUNDEF (mode), - operands[5], operands[3], operands[1], operands[6], - operands[7], operands[9])); - operands[5] = operands[3] = operands[0]; - } - else - { - emit_insn (gen_pred_merge (operands[0], RVV_VUNDEF (mode), - operands[5], operands[4], operands[1], operands[6], - operands[7], operands[9])); - operands[5] = operands[4] = operands[0]; - } + riscv_vector::prepare_ternary_operands (operands, true); } [(set_attr "type" "vimuladd") (set_attr "mode" "")]) @@ -6100,8 +5998,8 @@ (set_attr "mode" "")]) (define_insn "@pred_series" - [(set (match_operand:VI 0 "register_operand" "=vd, vd, vr, vr") - (if_then_else:VI + [(set (match_operand:V_VLSI 0 "register_operand" "=vd, vd, vr, vr") + (if_then_else:V_VLSI (unspec: [(match_operand: 1 "vector_mask_operand" " vm, vm,Wc1,Wc1") (match_operand 3 "vector_length_operand" " rK, rK, rK, rK") @@ -6110,8 +6008,8 @@ (match_operand 6 "const_int_operand" " i, i, i, i") (reg:SI VL_REGNUM) (reg:SI VTYPE_REGNUM)] UNSPEC_VPREDICATE) - (vec_series:VI (const_int 0) (const_int 1)) - (match_operand:VI 2 "vector_merge_operand" " vu, 0, vu, 0")))] + (vec_series:V_VLSI (const_int 0) (const_int 1)) + (match_operand:V_VLSI 2 "vector_merge_operand" " vu, 0, vu, 0")))] "TARGET_VECTOR" "vid.v\t%0%p1" [(set_attr "type" "vmidx") @@ -6128,8 +6026,8 @@ ;; ------------------------------------------------------------------------------- (define_insn "@pred_" - [(set (match_operand:VF 0 "register_operand" "=vd, vd, vr, vr") - (if_then_else:VF + [(set (match_operand:V_VLSF 0 "register_operand" "=vd, vd, vr, vr") + (if_then_else:V_VLSF (unspec: [(match_operand: 1 "vector_mask_operand" " vm, vm,Wc1,Wc1") (match_operand 5 "vector_length_operand" " rK, rK, rK, rK") @@ -6140,18 +6038,20 @@ (reg:SI VL_REGNUM) (reg:SI VTYPE_REGNUM) (reg:SI FRM_REGNUM)] UNSPEC_VPREDICATE) - (any_float_binop:VF - (match_operand:VF 3 "register_operand" " vr, vr, vr, vr") - (match_operand:VF 4 "register_operand" " vr, vr, vr, vr")) - (match_operand:VF 2 "vector_merge_operand" " vu, 0, vu, 0")))] + (any_float_binop:V_VLSF + (match_operand:V_VLSF 3 "register_operand" " vr, vr, vr, vr") + (match_operand:V_VLSF 4 "register_operand" " vr, vr, vr, vr")) + (match_operand:V_VLSF 2 "vector_merge_operand" " vu, 0, vu, 0")))] "TARGET_VECTOR" "vf.vv\t%0,%3,%4%p1" [(set_attr "type" "") - (set_attr "mode" "")]) + (set_attr "mode" "") + (set (attr "frm_mode") + (symbol_ref "riscv_vector::get_frm_mode (operands[9])"))]) (define_insn "@pred_" - [(set (match_operand:VF 0 "register_operand" "=vd, vd, vr, vr") - (if_then_else:VF + [(set (match_operand:V_VLSF 0 "register_operand" "=vd, vd, vr, vr") + (if_then_else:V_VLSF (unspec: [(match_operand: 1 "vector_mask_operand" " vm, vm,Wc1,Wc1") (match_operand 5 "vector_length_operand" " rK, rK, rK, rK") @@ -6160,10 +6060,10 @@ (match_operand 8 "const_int_operand" " i, i, i, i") (reg:SI VL_REGNUM) (reg:SI VTYPE_REGNUM)] UNSPEC_VPREDICATE) - (any_float_binop_nofrm:VF - (match_operand:VF 3 "register_operand" " vr, vr, vr, vr") - (match_operand:VF 4 "register_operand" " vr, vr, vr, vr")) - (match_operand:VF 2 "vector_merge_operand" " vu, 0, vu, 0")))] + (any_float_binop_nofrm:V_VLSF + (match_operand:V_VLSF 3 "register_operand" " vr, vr, vr, vr") + (match_operand:V_VLSF 4 "register_operand" " vr, vr, vr, vr")) + (match_operand:V_VLSF 2 "vector_merge_operand" " vu, 0, vu, 0")))] "TARGET_VECTOR" "vf.vv\t%0,%3,%4%p1" [(set_attr "type" "") @@ -6190,7 +6090,9 @@ "TARGET_VECTOR" "vf.vf\t%0,%3,%4%p1" [(set_attr "type" "") - (set_attr "mode" "")]) + (set_attr "mode" "") + (set (attr "frm_mode") + (symbol_ref "riscv_vector::get_frm_mode (operands[9])"))]) (define_insn "@pred__scalar" [(set (match_operand:VF 0 "register_operand" "=vd, vd, vr, vr") @@ -6234,7 +6136,9 @@ "TARGET_VECTOR" "vf.vf\t%0,%3,%4%p1" [(set_attr "type" "") - (set_attr "mode" "")]) + (set_attr "mode" "") + (set (attr "frm_mode") + (symbol_ref "riscv_vector::get_frm_mode (operands[9])"))]) (define_insn "@pred__reverse_scalar" [(set (match_operand:VF 0 "register_operand" "=vd, vd, vr, vr") @@ -6257,7 +6161,9 @@ "TARGET_VECTOR" "vfr.vf\t%0,%3,%4%p1" [(set_attr "type" "") - (set_attr "mode" "")]) + (set_attr "mode" "") + (set (attr "frm_mode") + (symbol_ref "riscv_vector::get_frm_mode (operands[9])"))]) (define_insn "@pred_" [(set (match_operand:VF 0 "register_operand" "=vd, vd, vr, vr") @@ -6371,10 +6277,7 @@ (match_operand:VF 5 "register_operand")))] "TARGET_VECTOR" { - /* Swap the multiplication operands if the fallback value is the - second of the two. */ - if (rtx_equal_p (operands[3], operands[5])) - std::swap (operands[2], operands[3]); + riscv_vector::prepare_ternary_operands (operands); }) (define_insn "*pred_" @@ -6408,7 +6311,9 @@ (set_attr "vl_op_idx" "5") (set (attr "ta") (symbol_ref "riscv_vector::get_ta(operands[6])")) (set (attr "ma") (symbol_ref "riscv_vector::get_ma(operands[7])")) - (set (attr "avl_type") (symbol_ref "INTVAL (operands[8])"))]) + (set (attr "avl_type") (symbol_ref "INTVAL (operands[8])")) + (set (attr "frm_mode") + (symbol_ref "riscv_vector::get_frm_mode (operands[9])"))]) (define_insn "*pred_" [(set (match_operand:VF 0 "register_operand" "=vd, ?&vd, vr, ?&vr") @@ -6441,44 +6346,42 @@ (set_attr "vl_op_idx" "5") (set (attr "ta") (symbol_ref "riscv_vector::get_ta(operands[6])")) (set (attr "ma") (symbol_ref "riscv_vector::get_ma(operands[7])")) - (set (attr "avl_type") (symbol_ref "INTVAL (operands[8])"))]) + (set (attr "avl_type") (symbol_ref "INTVAL (operands[8])")) + (set (attr "frm_mode") + (symbol_ref "riscv_vector::get_frm_mode (operands[9])"))]) (define_insn_and_rewrite "*pred_mul_" - [(set (match_operand:VF 0 "register_operand" "=&vr, ?&vr") + [(set (match_operand:VF 0 "register_operand" "=&vr") (if_then_else:VF (unspec: - [(match_operand: 1 "vector_mask_operand" "vmWc1,vmWc1") - (match_operand 6 "vector_length_operand" " rK, rK") - (match_operand 7 "const_int_operand" " i, i") - (match_operand 8 "const_int_operand" " i, i") - (match_operand 9 "const_int_operand" " i, i") - (match_operand 10 "const_int_operand" " i, i") + [(match_operand: 1 "vector_mask_operand" "vmWc1") + (match_operand 6 "vector_length_operand" " rK") + (match_operand 7 "const_int_operand" " i") + (match_operand 8 "const_int_operand" " i") + (match_operand 9 "const_int_operand" " i") + (match_operand 10 "const_int_operand" " i") (reg:SI VL_REGNUM) (reg:SI VTYPE_REGNUM) (reg:SI FRM_REGNUM)] UNSPEC_VPREDICATE) (plus_minus:VF (mult:VF - (match_operand:VF 2 "register_operand" " vr, vr") - (match_operand:VF 3 "register_operand" " vr, vr")) - (match_operand:VF 4 "vector_arith_operand" " vr, vr")) - (match_operand:VF 5 "register_operand" " 0, vr")))] + (match_operand:VF 2 "register_operand" " vr") + (match_operand:VF 3 "register_operand" " vr")) + (match_operand:VF 4 "register_operand" " vr")) + (match_operand:VF 5 "register_operand" " vr")))] "TARGET_VECTOR && !rtx_equal_p (operands[2], operands[5]) && !rtx_equal_p (operands[3], operands[5]) && !rtx_equal_p (operands[4], operands[5])" - "@ - vmv.v.v\t%0,%4\;vf.vv\t%0,%2,%3%p1 - #" - "&& reload_completed - && !rtx_equal_p (operands[0], operands[5])" + "#" + "&& reload_completed" { - emit_insn (gen_pred_merge (operands[0], RVV_VUNDEF (mode), - operands[5], operands[4], operands[1], operands[6], - operands[7], operands[9])); - operands[5] = operands[4] = operands[0]; + riscv_vector::prepare_ternary_operands (operands, true); } [(set_attr "type" "vfmuladd") - (set_attr "mode" "")]) + (set_attr "mode" "") + (set (attr "frm_mode") + (symbol_ref "riscv_vector::get_frm_mode (operands[10])"))]) (define_expand "@pred_mul__scalar" [(set (match_operand:VF 0 "register_operand") @@ -6535,7 +6438,9 @@ (set_attr "vl_op_idx" "5") (set (attr "ta") (symbol_ref "riscv_vector::get_ta(operands[6])")) (set (attr "ma") (symbol_ref "riscv_vector::get_ma(operands[7])")) - (set (attr "avl_type") (symbol_ref "INTVAL (operands[8])"))]) + (set (attr "avl_type") (symbol_ref "INTVAL (operands[8])")) + (set (attr "frm_mode") + (symbol_ref "riscv_vector::get_frm_mode (operands[9])"))]) (define_insn "*pred__scalar" [(set (match_operand:VF 0 "register_operand" "=vd, ?&vd, vr, ?&vr") @@ -6569,44 +6474,42 @@ (set_attr "vl_op_idx" "5") (set (attr "ta") (symbol_ref "riscv_vector::get_ta(operands[6])")) (set (attr "ma") (symbol_ref "riscv_vector::get_ma(operands[7])")) - (set (attr "avl_type") (symbol_ref "INTVAL (operands[8])"))]) + (set (attr "avl_type") (symbol_ref "INTVAL (operands[8])")) + (set (attr "frm_mode") + (symbol_ref "riscv_vector::get_frm_mode (operands[9])"))]) (define_insn_and_rewrite "*pred_mul__scalar" - [(set (match_operand:VF 0 "register_operand" "=&vr, ?&vr") + [(set (match_operand:VF 0 "register_operand" "=&vr") (if_then_else:VF (unspec: - [(match_operand: 1 "vector_mask_operand" "vmWc1,vmWc1") - (match_operand 6 "vector_length_operand" " rK, rK") - (match_operand 7 "const_int_operand" " i, i") - (match_operand 8 "const_int_operand" " i, i") - (match_operand 9 "const_int_operand" " i, i") - (match_operand 10 "const_int_operand" " i, i") + [(match_operand: 1 "vector_mask_operand" "vmWc1") + (match_operand 6 "vector_length_operand" " rK") + (match_operand 7 "const_int_operand" " i") + (match_operand 8 "const_int_operand" " i") + (match_operand 9 "const_int_operand" " i") + (match_operand 10 "const_int_operand" " i") (reg:SI VL_REGNUM) (reg:SI VTYPE_REGNUM) (reg:SI FRM_REGNUM)] UNSPEC_VPREDICATE) (plus_minus:VF (mult:VF (vec_duplicate:VF - (match_operand: 2 "register_operand" " f, f")) - (match_operand:VF 3 "register_operand" " vr, vr")) - (match_operand:VF 4 "vector_arith_operand" " vr, vr")) - (match_operand:VF 5 "register_operand" " 0, vr")))] + (match_operand: 2 "register_operand" " f")) + (match_operand:VF 3 "register_operand" " vr")) + (match_operand:VF 4 "vector_arith_operand" " vr")) + (match_operand:VF 5 "register_operand" " vr")))] "TARGET_VECTOR && !rtx_equal_p (operands[3], operands[5]) && !rtx_equal_p (operands[4], operands[5])" - "@ - vmv.v.v\t%0,%4\;vf.vf\t%0,%2,%3%p1 - #" - "&& reload_completed - && !rtx_equal_p (operands[0], operands[5])" + "#" + "&& reload_completed" { - emit_insn (gen_pred_merge (operands[0], RVV_VUNDEF (mode), - operands[5], operands[4], operands[1], operands[6], - operands[7], operands[9])); - operands[5] = operands[4] = operands[0]; + riscv_vector::prepare_ternary_operands (operands, true); } [(set_attr "type" "vfmuladd") - (set_attr "mode" "")]) + (set_attr "mode" "") + (set (attr "frm_mode") + (symbol_ref "riscv_vector::get_frm_mode (operands[10])"))]) (define_expand "@pred_mul_neg_" [(set (match_operand:VF 0 "register_operand") @@ -6630,10 +6533,7 @@ (match_operand:VF 5 "register_operand")))] "TARGET_VECTOR" { - /* Swap the multiplication operands if the fallback value is the - second of the two. */ - if (rtx_equal_p (operands[3], operands[5])) - std::swap (operands[2], operands[3]); + riscv_vector::prepare_ternary_operands (operands); }) (define_insn "*pred_" @@ -6668,7 +6568,9 @@ (set_attr "vl_op_idx" "5") (set (attr "ta") (symbol_ref "riscv_vector::get_ta(operands[6])")) (set (attr "ma") (symbol_ref "riscv_vector::get_ma(operands[7])")) - (set (attr "avl_type") (symbol_ref "INTVAL (operands[8])"))]) + (set (attr "avl_type") (symbol_ref "INTVAL (operands[8])")) + (set (attr "frm_mode") + (symbol_ref "riscv_vector::get_frm_mode (operands[9])"))]) (define_insn "*pred_" [(set (match_operand:VF 0 "register_operand" "=vd, ?&vd, vr, ?&vr") @@ -6702,45 +6604,43 @@ (set_attr "vl_op_idx" "5") (set (attr "ta") (symbol_ref "riscv_vector::get_ta(operands[6])")) (set (attr "ma") (symbol_ref "riscv_vector::get_ma(operands[7])")) - (set (attr "avl_type") (symbol_ref "INTVAL (operands[8])"))]) + (set (attr "avl_type") (symbol_ref "INTVAL (operands[8])")) + (set (attr "frm_mode") + (symbol_ref "riscv_vector::get_frm_mode (operands[9])"))]) (define_insn_and_rewrite "*pred_mul_neg_" - [(set (match_operand:VF 0 "register_operand" "=&vr, ?&vr") + [(set (match_operand:VF 0 "register_operand" "=&vr") (if_then_else:VF (unspec: - [(match_operand: 1 "vector_mask_operand" "vmWc1,vmWc1") - (match_operand 6 "vector_length_operand" " rK, rK") - (match_operand 7 "const_int_operand" " i, i") - (match_operand 8 "const_int_operand" " i, i") - (match_operand 9 "const_int_operand" " i, i") - (match_operand 10 "const_int_operand" " i, i") + [(match_operand: 1 "vector_mask_operand" "vmWc1") + (match_operand 6 "vector_length_operand" " rK") + (match_operand 7 "const_int_operand" " i") + (match_operand 8 "const_int_operand" " i") + (match_operand 9 "const_int_operand" " i") + (match_operand 10 "const_int_operand" " i") (reg:SI VL_REGNUM) (reg:SI VTYPE_REGNUM) (reg:SI FRM_REGNUM)] UNSPEC_VPREDICATE) (plus_minus:VF (neg:VF (mult:VF - (match_operand:VF 2 "register_operand" " vr, vr") - (match_operand:VF 3 "register_operand" " vr, vr"))) - (match_operand:VF 4 "vector_arith_operand" " vr, vr")) - (match_operand:VF 5 "register_operand" " 0, vr")))] + (match_operand:VF 2 "register_operand" " vr") + (match_operand:VF 3 "register_operand" " vr"))) + (match_operand:VF 4 "vector_arith_operand" " vr")) + (match_operand:VF 5 "register_operand" " vr")))] "TARGET_VECTOR && !rtx_equal_p (operands[2], operands[5]) && !rtx_equal_p (operands[3], operands[5]) && !rtx_equal_p (operands[4], operands[5])" - "@ - vmv.v.v\t%0,%4\;vf.vv\t%0,%2,%3%p1 - #" - "&& reload_completed - && !rtx_equal_p (operands[0], operands[5])" + "#" + "&& reload_completed" { - emit_insn (gen_pred_merge (operands[0], RVV_VUNDEF (mode), - operands[5], operands[4], operands[1], operands[6], - operands[7], operands[9])); - operands[5] = operands[4] = operands[0]; + riscv_vector::prepare_ternary_operands (operands, true); } [(set_attr "type" "vfmuladd") - (set_attr "mode" "")]) + (set_attr "mode" "") + (set (attr "frm_mode") + (symbol_ref "riscv_vector::get_frm_mode (operands[10])"))]) (define_expand "@pred_mul_neg__scalar" [(set (match_operand:VF 0 "register_operand") @@ -6799,7 +6699,9 @@ (set_attr "vl_op_idx" "5") (set (attr "ta") (symbol_ref "riscv_vector::get_ta(operands[6])")) (set (attr "ma") (symbol_ref "riscv_vector::get_ma(operands[7])")) - (set (attr "avl_type") (symbol_ref "INTVAL (operands[8])"))]) + (set (attr "avl_type") (symbol_ref "INTVAL (operands[8])")) + (set (attr "frm_mode") + (symbol_ref "riscv_vector::get_frm_mode (operands[9])"))]) (define_insn "*pred__scalar" [(set (match_operand:VF 0 "register_operand" "=vd, ?&vd, vr, ?&vr") @@ -6834,18 +6736,20 @@ (set_attr "vl_op_idx" "5") (set (attr "ta") (symbol_ref "riscv_vector::get_ta(operands[6])")) (set (attr "ma") (symbol_ref "riscv_vector::get_ma(operands[7])")) - (set (attr "avl_type") (symbol_ref "INTVAL (operands[8])"))]) + (set (attr "avl_type") (symbol_ref "INTVAL (operands[8])")) + (set (attr "frm_mode") + (symbol_ref "riscv_vector::get_frm_mode (operands[9])"))]) (define_insn_and_rewrite "*pred_mul_neg__scalar" - [(set (match_operand:VF 0 "register_operand" "=&vr, ?&vr") + [(set (match_operand:VF 0 "register_operand" "=&vr") (if_then_else:VF (unspec: - [(match_operand: 1 "vector_mask_operand" "vmWc1,vmWc1") - (match_operand 6 "vector_length_operand" " rK, rK") - (match_operand 7 "const_int_operand" " i, i") - (match_operand 8 "const_int_operand" " i, i") - (match_operand 9 "const_int_operand" " i, i") - (match_operand 10 "const_int_operand" " i, i") + [(match_operand: 1 "vector_mask_operand" "vmWc1") + (match_operand 6 "vector_length_operand" " rK") + (match_operand 7 "const_int_operand" " i") + (match_operand 8 "const_int_operand" " i") + (match_operand 9 "const_int_operand" " i") + (match_operand 10 "const_int_operand" " i") (reg:SI VL_REGNUM) (reg:SI VTYPE_REGNUM) (reg:SI FRM_REGNUM)] UNSPEC_VPREDICATE) @@ -6853,26 +6757,22 @@ (neg:VF (mult:VF (vec_duplicate:VF - (match_operand: 2 "register_operand" " f, f")) - (match_operand:VF 3 "register_operand" " vr, vr"))) - (match_operand:VF 4 "vector_arith_operand" " vr, vr")) - (match_operand:VF 5 "register_operand" " 0, vr")))] + (match_operand: 2 "register_operand" " f")) + (match_operand:VF 3 "register_operand" " vr"))) + (match_operand:VF 4 "vector_arith_operand" " vr")) + (match_operand:VF 5 "register_operand" " vr")))] "TARGET_VECTOR && !rtx_equal_p (operands[3], operands[5]) && !rtx_equal_p (operands[4], operands[5])" - "@ - vmv.v.v\t%0,%4\;vf.vf\t%0,%2,%3%p1 - #" - "&& reload_completed - && !rtx_equal_p (operands[0], operands[5])" + "#" + "&& reload_completed" { - emit_insn (gen_pred_merge (operands[0], RVV_VUNDEF (mode), - operands[5], operands[4], operands[1], operands[6], - operands[7], operands[9])); - operands[5] = operands[4] = operands[0]; + riscv_vector::prepare_ternary_operands (operands, true); } [(set_attr "type" "vfmuladd") - (set_attr "mode" "")]) + (set_attr "mode" "") + (set (attr "frm_mode") + (symbol_ref "riscv_vector::get_frm_mode (operands[10])"))]) ;; ------------------------------------------------------------------------------- ;; ---- Predicated floating-point unary operations @@ -6908,7 +6808,9 @@ (set_attr "vl_op_idx" "4") (set (attr "ta") (symbol_ref "riscv_vector::get_ta(operands[5])")) (set (attr "ma") (symbol_ref "riscv_vector::get_ma(operands[6])")) - (set (attr "avl_type") (symbol_ref "INTVAL (operands[7])"))]) + (set (attr "avl_type") (symbol_ref "INTVAL (operands[7])")) + (set (attr "frm_mode") + (symbol_ref "riscv_vector::get_frm_mode (operands[8])"))]) (define_insn "@pred_" [(set (match_operand:VF 0 "register_operand" "=vd, vd, vr, vr") @@ -6952,6 +6854,29 @@ [(set_attr "type" "") (set_attr "mode" "")]) +(define_insn "@pred_" + [(set (match_operand:VF 0 "register_operand" "=vd, vd, vr, vr") + (if_then_else:VF + (unspec: + [(match_operand: 1 "vector_mask_operand" " vm, vm,Wc1,Wc1") + (match_operand 4 "vector_length_operand" " rK, rK, rK, rK") + (match_operand 5 "const_int_operand" " i, i, i, i") + (match_operand 6 "const_int_operand" " i, i, i, i") + (match_operand 7 "const_int_operand" " i, i, i, i") + (match_operand 8 "const_int_operand" " i, i, i, i") + (reg:SI VL_REGNUM) + (reg:SI VTYPE_REGNUM) + (reg:SI FRM_REGNUM)] UNSPEC_VPREDICATE) + (unspec:VF + [(match_operand:VF 3 "register_operand" " vr, vr, vr, vr")] VFMISC_FRM) + (match_operand:VF 2 "vector_merge_operand" " vu, 0, vu, 0")))] + "TARGET_VECTOR" + "vf.v\t%0,%3%p1" + [(set_attr "type" "") + (set_attr "mode" "") + (set (attr "frm_mode") + (symbol_ref "riscv_vector::get_frm_mode (operands[8])"))]) + (define_insn "@pred_class" [(set (match_operand: 0 "register_operand" "=vd, vd, vr, vr") (if_then_else: @@ -7002,7 +6927,9 @@ "TARGET_VECTOR" "vfw.vv\t%0,%3,%4%p1" [(set_attr "type" "vf") - (set_attr "mode" "")]) + (set_attr "mode" "") + (set (attr "frm_mode") + (symbol_ref "riscv_vector::get_frm_mode (operands[9])"))]) (define_insn "@pred_dual_widen__scalar" [(set (match_operand:VWEXTF 0 "register_operand" "=&vr, &vr") @@ -7027,7 +6954,9 @@ "TARGET_VECTOR" "vfw.vf\t%0,%3,%4%p1" [(set_attr "type" "vf") - (set_attr "mode" "")]) + (set_attr "mode" "") + (set (attr "frm_mode") + (symbol_ref "riscv_vector::get_frm_mode (operands[9])"))]) (define_insn "@pred_single_widen_add" [(set (match_operand:VWEXTF 0 "register_operand" "=&vr, &vr") @@ -7050,7 +6979,9 @@ "TARGET_VECTOR" "vfwadd.wv\t%0,%3,%4%p1" [(set_attr "type" "vfwalu") - (set_attr "mode" "")]) + (set_attr "mode" "") + (set (attr "frm_mode") + (symbol_ref "riscv_vector::get_frm_mode (operands[9])"))]) (define_insn "@pred_single_widen_sub" [(set (match_operand:VWEXTF 0 "register_operand" "=&vr, &vr") @@ -7073,7 +7004,9 @@ "TARGET_VECTOR" "vfwsub.wv\t%0,%3,%4%p1" [(set_attr "type" "vfwalu") - (set_attr "mode" "")]) + (set_attr "mode" "") + (set (attr "frm_mode") + (symbol_ref "riscv_vector::get_frm_mode (operands[9])"))]) (define_insn "@pred_single_widen__scalar" [(set (match_operand:VWEXTF 0 "register_operand" "=&vr, &vr") @@ -7097,7 +7030,9 @@ "TARGET_VECTOR" "vfw.wf\t%0,%3,%4%p1" [(set_attr "type" "vf") - (set_attr "mode" "")]) + (set_attr "mode" "") + (set (attr "frm_mode") + (symbol_ref "riscv_vector::get_frm_mode (operands[9])"))]) ;; ------------------------------------------------------------------------------- ;; ---- Predicated widen floating-point ternary operations @@ -7130,7 +7065,9 @@ "TARGET_VECTOR" "vfw.vv\t%0,%3,%4%p1" [(set_attr "type" "vfwmuladd") - (set_attr "mode" "")]) + (set_attr "mode" "") + (set (attr "frm_mode") + (symbol_ref "riscv_vector::get_frm_mode (operands[9])"))]) (define_insn "@pred_widen_mul__scalar" [(set (match_operand:VWEXTF 0 "register_operand" "=&vr") @@ -7157,7 +7094,9 @@ "TARGET_VECTOR" "vfw.vf\t%0,%3,%4%p1" [(set_attr "type" "vfwmuladd") - (set_attr "mode" "")]) + (set_attr "mode" "") + (set (attr "frm_mode") + (symbol_ref "riscv_vector::get_frm_mode (operands[9])"))]) (define_insn "@pred_widen_mul_neg_" [(set (match_operand:VWEXTF 0 "register_operand" "=&vr") @@ -7184,7 +7123,9 @@ "TARGET_VECTOR" "vfw.vv\t%0,%3,%4%p1" [(set_attr "type" "vfwmuladd") - (set_attr "mode" "")]) + (set_attr "mode" "") + (set (attr "frm_mode") + (symbol_ref "riscv_vector::get_frm_mode (operands[9])"))]) (define_insn "@pred_widen_mul_neg__scalar" [(set (match_operand:VWEXTF 0 "register_operand" "=&vr") @@ -7212,7 +7153,9 @@ "TARGET_VECTOR" "vfw.vf\t%0,%3,%4%p1" [(set_attr "type" "vfwmuladd") - (set_attr "mode" "")]) + (set_attr "mode" "") + (set (attr "frm_mode") + (symbol_ref "riscv_vector::get_frm_mode (operands[9])"))]) ;; ------------------------------------------------------------------------------- ;; ---- Predicated floating-point comparison operations @@ -7522,7 +7465,9 @@ "TARGET_VECTOR" "vfcvt.x.f.v\t%0,%3%p1" [(set_attr "type" "vfcvtftoi") - (set_attr "mode" "")]) + (set_attr "mode" "") + (set (attr "frm_mode") + (symbol_ref "riscv_vector::get_frm_mode (operands[8])"))]) (define_insn "@pred_" [(set (match_operand: 0 "register_operand" "=vd, vd, vr, vr") @@ -7562,7 +7507,9 @@ "TARGET_VECTOR" "vfcvt.f.x.v\t%0,%3%p1" [(set_attr "type" "vfcvtitof") - (set_attr "mode" "")]) + (set_attr "mode" "") + (set (attr "frm_mode") + (symbol_ref "riscv_vector::get_frm_mode (operands[8])"))]) ;; ------------------------------------------------------------------------------- ;; ---- Predicated floating-point widen conversions @@ -7590,7 +7537,9 @@ "TARGET_VECTOR" "vfwcvt.x.f.v\t%0,%3%p1" [(set_attr "type" "vfwcvtftoi") - (set_attr "mode" "")]) + (set_attr "mode" "") + (set (attr "frm_mode") + (symbol_ref "riscv_vector::get_frm_mode (operands[8])"))]) (define_insn "@pred_widen_" [(set (match_operand:VWCONVERTI 0 "register_operand" "=&vr, &vr") @@ -7675,7 +7624,9 @@ "TARGET_VECTOR" "vfncvt.x.f.w\t%0,%3%p1" [(set_attr "type" "vfncvtftoi") - (set_attr "mode" "")]) + (set_attr "mode" "") + (set (attr "frm_mode") + (symbol_ref "riscv_vector::get_frm_mode (operands[8])"))]) (define_insn "@pred_narrow_" [(set (match_operand: 0 "register_operand" "=vd, vd, vr, vr, &vr, &vr") @@ -7715,7 +7666,9 @@ "TARGET_VECTOR" "vfncvt.f.x.w\t%0,%3%p1" [(set_attr "type" "vfncvtitof") - (set_attr "mode" "")]) + (set_attr "mode" "") + (set (attr "frm_mode") + (symbol_ref "riscv_vector::get_frm_mode (operands[8])"))]) (define_insn "@pred_trunc" [(set (match_operand: 0 "register_operand" "=vd, vd, vr, vr, &vr, &vr") @@ -7736,7 +7689,9 @@ "TARGET_VECTOR" "vfncvt.f.f.w\t%0,%3%p1" [(set_attr "type" "vfncvtftof") - (set_attr "mode" "")]) + (set_attr "mode" "") + (set (attr "frm_mode") + (symbol_ref "riscv_vector::get_frm_mode (operands[8])"))]) (define_insn "@pred_rod_trunc" [(set (match_operand: 0 "register_operand" "=vd, vd, vr, vr, &vr, &vr") @@ -8016,7 +7971,9 @@ "TARGET_VECTOR" "vfredsum.vs\t%0,%3,%4%p1" [(set_attr "type" "vfred") - (set_attr "mode" "")]) + (set_attr "mode" "") + (set (attr "frm_mode") + (symbol_ref "riscv_vector::get_frm_mode (operands[8])"))]) ;; Float Ordered Reduction Sum for SF (define_insn "@pred_reduc_plus" @@ -8042,7 +7999,9 @@ "TARGET_VECTOR" "vfredsum.vs\t%0,%3,%4%p1" [(set_attr "type" "vfred") - (set_attr "mode" "")]) + (set_attr "mode" "") + (set (attr "frm_mode") + (symbol_ref "riscv_vector::get_frm_mode (operands[8])"))]) ;; Float Ordered Reduction Sum for DF (define_insn "@pred_reduc_plus" @@ -8068,7 +8027,9 @@ "TARGET_VECTOR" "vfredsum.vs\t%0,%3,%4%p1" [(set_attr "type" "vfred") - (set_attr "mode" "")]) + (set_attr "mode" "") + (set (attr "frm_mode") + (symbol_ref "riscv_vector::get_frm_mode (operands[8])"))]) ;; Float Widen Reduction for HF, aka SF = HF op SF (define_insn "@pred_widen_reduc_plus" @@ -8090,7 +8051,9 @@ "TARGET_VECTOR" "vfwredsum.vs\t%0,%3,%4%p1" [(set_attr "type" "vfwred") - (set_attr "mode" "")]) + (set_attr "mode" "") + (set (attr "frm_mode") + (symbol_ref "riscv_vector::get_frm_mode (operands[8])"))]) ;; Float Widen Reduction for SF, aka DF = SF * DF (define_insn "@pred_widen_reduc_plus" @@ -8112,7 +8075,9 @@ "TARGET_VECTOR" "vfwredsum.vs\t%0,%3,%4%p1" [(set_attr "type" "vfwred") - (set_attr "mode" "")]) + (set_attr "mode" "") + (set (attr "frm_mode") + (symbol_ref "riscv_vector::get_frm_mode (operands[8])"))]) ;; ------------------------------------------------------------------------------- ;; ---- Predicated permutation operations diff --git a/gcc/config/riscv/zc.md b/gcc/config/riscv/zc.md new file mode 100644 index 000000000000..77b28adde955 --- /dev/null +++ b/gcc/config/riscv/zc.md @@ -0,0 +1,1457 @@ +;; Machine description for RISC-V Zc extention. +;; Copyright (C) 2023 Free Software Foundation, Inc. +;; Contributed by Fei Gao (gaofei@eswincomputing.com). + +;; This file is part of GCC. + +;; GCC is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 3, or (at your option) +;; any later version. + +;; GCC is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GCC; see the file COPYING3. If not see +;; . + +(define_insn "@gpr_multi_pop_up_to_ra_" + [(set (reg:X SP_REGNUM) + (plus:X (reg:X SP_REGNUM) + (match_operand 0 "stack_pop_up_to_ra_operand" "I"))) + (set (reg:X RETURN_ADDR_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int ))))] + "TARGET_ZCMP" + "cm.pop {ra}, %0" +) + +(define_insn "@gpr_multi_pop_up_to_s0_" + [(set (reg:X SP_REGNUM) + (plus:X (reg:X SP_REGNUM) + (match_operand 0 "stack_pop_up_to_s0_operand" "I"))) + (set (reg:X S0_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X RETURN_ADDR_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int ))))] + "TARGET_ZCMP" + "cm.pop {ra, s0}, %0" +) + +(define_insn "@gpr_multi_pop_up_to_s1_" + [(set (reg:X SP_REGNUM) + (plus:X (reg:X SP_REGNUM) + (match_operand 0 "stack_pop_up_to_s1_operand" "I"))) + (set (reg:X S1_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S0_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X RETURN_ADDR_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int ))))] + "TARGET_ZCMP" + "cm.pop {ra, s0-s1}, %0" +) + +(define_insn "@gpr_multi_pop_up_to_s2_" + [(set (reg:X SP_REGNUM) + (plus:X (reg:X SP_REGNUM) + (match_operand 0 "stack_pop_up_to_s2_operand" "I"))) + (set (reg:X S2_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S1_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S0_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X RETURN_ADDR_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int ))))] + "TARGET_ZCMP" + "cm.pop {ra, s0-s2}, %0" +) + +(define_insn "@gpr_multi_pop_up_to_s3_" + [(set (reg:X SP_REGNUM) + (plus:X (reg:X SP_REGNUM) + (match_operand 0 "stack_pop_up_to_s3_operand" "I"))) + (set (reg:X S3_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S2_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S1_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S0_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X RETURN_ADDR_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int ))))] + "TARGET_ZCMP" + "cm.pop {ra, s0-s3}, %0" +) + +(define_insn "@gpr_multi_pop_up_to_s4_" + [(set (reg:X SP_REGNUM) + (plus:X (reg:X SP_REGNUM) + (match_operand 0 "stack_pop_up_to_s4_operand" "I"))) + (set (reg:X S4_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S3_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S2_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S1_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S0_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X RETURN_ADDR_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int ))))] + "TARGET_ZCMP" + "cm.pop {ra, s0-s4}, %0" +) + +(define_insn "@gpr_multi_pop_up_to_s5_" + [(set (reg:X SP_REGNUM) + (plus:X (reg:X SP_REGNUM) + (match_operand 0 "stack_pop_up_to_s5_operand" "I"))) + (set (reg:X S5_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S4_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S3_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S2_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S1_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S0_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X RETURN_ADDR_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int ))))] + "TARGET_ZCMP" + "cm.pop {ra, s0-s5}, %0" +) + +(define_insn "@gpr_multi_pop_up_to_s6_" + [(set (reg:X SP_REGNUM) + (plus:X (reg:X SP_REGNUM) + (match_operand 0 "stack_pop_up_to_s6_operand" "I"))) + (set (reg:X S6_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S5_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S4_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S3_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S2_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S1_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S0_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X RETURN_ADDR_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int ))))] + "TARGET_ZCMP" + "cm.pop {ra, s0-s6}, %0" +) + +(define_insn "@gpr_multi_pop_up_to_s7_" + [(set (reg:X SP_REGNUM) + (plus:X (reg:X SP_REGNUM) + (match_operand 0 "stack_pop_up_to_s7_operand" "I"))) + (set (reg:X S7_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S6_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S5_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S4_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S3_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S2_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S1_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S0_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X RETURN_ADDR_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int ))))] + "TARGET_ZCMP" + "cm.pop {ra, s0-s7}, %0" +) + +(define_insn "@gpr_multi_pop_up_to_s8_" + [(set (reg:X SP_REGNUM) + (plus:X (reg:X SP_REGNUM) + (match_operand 0 "stack_pop_up_to_s8_operand" "I"))) + (set (reg:X S8_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S7_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S6_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S5_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S4_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S3_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S2_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S1_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S0_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X RETURN_ADDR_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int ))))] + "TARGET_ZCMP" + "cm.pop {ra, s0-s8}, %0" +) + +(define_insn "@gpr_multi_pop_up_to_s9_" + [(set (reg:X SP_REGNUM) + (plus:X (reg:X SP_REGNUM) + (match_operand 0 "stack_pop_up_to_s9_operand" "I"))) + (set (reg:X S9_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S8_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S7_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S6_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S5_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S4_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S3_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S2_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S1_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S0_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X RETURN_ADDR_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int ))))] + "TARGET_ZCMP" + "cm.pop {ra, s0-s9}, %0" +) + +(define_insn "@gpr_multi_pop_up_to_s11_" + [(set (reg:X SP_REGNUM) + (plus:X (reg:X SP_REGNUM) + (match_operand 0 "stack_pop_up_to_s11_operand" "I"))) + (set (reg:X S11_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S10_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S9_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S8_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S7_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S6_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S5_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S4_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S3_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S2_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S1_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S0_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X RETURN_ADDR_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int ))))] + "TARGET_ZCMP" + "cm.pop {ra, s0-s11}, %0" +) + +(define_insn "@gpr_multi_popret_up_to_ra_" + [(set (reg:X SP_REGNUM) + (plus:X (reg:X SP_REGNUM) + (match_operand 0 "stack_pop_up_to_ra_operand" "I"))) + (set (reg:X RETURN_ADDR_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (return) + (use (reg:SI RETURN_ADDR_REGNUM))] + "TARGET_ZCMP" + "cm.popret {ra}, %0" +) + +(define_insn "@gpr_multi_popret_up_to_s0_" + [(set (reg:X SP_REGNUM) + (plus:X (reg:X SP_REGNUM) + (match_operand 0 "stack_pop_up_to_s0_operand" "I"))) + (set (reg:X S0_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X RETURN_ADDR_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (return) + (use (reg:SI RETURN_ADDR_REGNUM))] + "TARGET_ZCMP" + "cm.popret {ra, s0}, %0" +) + +(define_insn "@gpr_multi_popret_up_to_s1_" + [(set (reg:X SP_REGNUM) + (plus:X (reg:X SP_REGNUM) + (match_operand 0 "stack_pop_up_to_s1_operand" "I"))) + (set (reg:X S1_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S0_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X RETURN_ADDR_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (return) + (use (reg:SI RETURN_ADDR_REGNUM))] + "TARGET_ZCMP" + "cm.popret {ra, s0-s1}, %0" +) + +(define_insn "@gpr_multi_popret_up_to_s2_" + [(set (reg:X SP_REGNUM) + (plus:X (reg:X SP_REGNUM) + (match_operand 0 "stack_pop_up_to_s2_operand" "I"))) + (set (reg:X S2_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S1_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S0_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X RETURN_ADDR_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (return) + (use (reg:SI RETURN_ADDR_REGNUM))] + "TARGET_ZCMP" + "cm.popret {ra, s0-s2}, %0" +) + +(define_insn "@gpr_multi_popret_up_to_s3_" + [(set (reg:X SP_REGNUM) + (plus:X (reg:X SP_REGNUM) + (match_operand 0 "stack_pop_up_to_s3_operand" "I"))) + (set (reg:X S3_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S2_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S1_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S0_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X RETURN_ADDR_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (return) + (use (reg:SI RETURN_ADDR_REGNUM))] + "TARGET_ZCMP" + "cm.popret {ra, s0-s3}, %0" +) + +(define_insn "@gpr_multi_popret_up_to_s4_" + [(set (reg:X SP_REGNUM) + (plus:X (reg:X SP_REGNUM) + (match_operand 0 "stack_pop_up_to_s4_operand" "I"))) + (set (reg:X S4_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S3_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S2_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S1_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S0_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X RETURN_ADDR_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (return) + (use (reg:SI RETURN_ADDR_REGNUM))] + "TARGET_ZCMP" + "cm.popret {ra, s0-s4}, %0" +) + +(define_insn "@gpr_multi_popret_up_to_s5_" + [(set (reg:X SP_REGNUM) + (plus:X (reg:X SP_REGNUM) + (match_operand 0 "stack_pop_up_to_s5_operand" "I"))) + (set (reg:X S5_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S4_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S3_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S2_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S1_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S0_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X RETURN_ADDR_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (return) + (use (reg:SI RETURN_ADDR_REGNUM))] + "TARGET_ZCMP" + "cm.popret {ra, s0-s5}, %0" +) + +(define_insn "@gpr_multi_popret_up_to_s6_" + [(set (reg:X SP_REGNUM) + (plus:X (reg:X SP_REGNUM) + (match_operand 0 "stack_pop_up_to_s6_operand" "I"))) + (set (reg:X S6_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S5_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S4_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S3_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S2_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S1_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S0_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X RETURN_ADDR_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (return) + (use (reg:SI RETURN_ADDR_REGNUM))] + "TARGET_ZCMP" + "cm.popret {ra, s0-s6}, %0" +) + +(define_insn "@gpr_multi_popret_up_to_s7_" + [(set (reg:X SP_REGNUM) + (plus:X (reg:X SP_REGNUM) + (match_operand 0 "stack_pop_up_to_s7_operand" "I"))) + (set (reg:X S7_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S6_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S5_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S4_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S3_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S2_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S1_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S0_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X RETURN_ADDR_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (return) + (use (reg:SI RETURN_ADDR_REGNUM))] + "TARGET_ZCMP" + "cm.popret {ra, s0-s7}, %0" +) + +(define_insn "@gpr_multi_popret_up_to_s8_" + [(set (reg:X SP_REGNUM) + (plus:X (reg:X SP_REGNUM) + (match_operand 0 "stack_pop_up_to_s8_operand" "I"))) + (set (reg:X S8_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S7_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S6_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S5_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S4_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S3_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S2_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S1_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S0_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X RETURN_ADDR_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (return) + (use (reg:SI RETURN_ADDR_REGNUM))] + "TARGET_ZCMP" + "cm.popret {ra, s0-s8}, %0" +) + +(define_insn "@gpr_multi_popret_up_to_s9_" + [(set (reg:X SP_REGNUM) + (plus:X (reg:X SP_REGNUM) + (match_operand 0 "stack_pop_up_to_s9_operand" "I"))) + (set (reg:X S9_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S8_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S7_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S6_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S5_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S4_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S3_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S2_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S1_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S0_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X RETURN_ADDR_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (return) + (use (reg:SI RETURN_ADDR_REGNUM))] + "TARGET_ZCMP" + "cm.popret {ra, s0-s9}, %0" +) + +(define_insn "@gpr_multi_popret_up_to_s11_" + [(set (reg:X SP_REGNUM) + (plus:X (reg:X SP_REGNUM) + (match_operand 0 "stack_pop_up_to_s11_operand" "I"))) + (set (reg:X S11_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S10_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S9_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S8_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S7_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S6_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S5_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S4_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S3_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S2_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S1_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S0_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X RETURN_ADDR_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (return) + (use (reg:SI RETURN_ADDR_REGNUM))] + "TARGET_ZCMP" + "cm.popret {ra, s0-s11}, %0" +) + +(define_insn "@gpr_multi_popretz_up_to_ra_" + [(set (reg:X SP_REGNUM) + (plus:X (reg:X SP_REGNUM) + (match_operand 0 "stack_pop_up_to_ra_operand" "I"))) + (set (reg:X RETURN_ADDR_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X A0_REGNUM) + (const_int 0)) + (use (reg:X A0_REGNUM)) + (return) + (use (reg:SI RETURN_ADDR_REGNUM))] + "TARGET_ZCMP" + "cm.popretz {ra}, %0" +) + +(define_insn "@gpr_multi_popretz_up_to_s0_" + [(set (reg:X SP_REGNUM) + (plus:X (reg:X SP_REGNUM) + (match_operand 0 "stack_pop_up_to_s0_operand" "I"))) + (set (reg:X S0_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X RETURN_ADDR_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X A0_REGNUM) + (const_int 0)) + (use (reg:X A0_REGNUM)) + (return) + (use (reg:SI RETURN_ADDR_REGNUM))] + "TARGET_ZCMP" + "cm.popretz {ra, s0}, %0" +) + +(define_insn "@gpr_multi_popretz_up_to_s1_" + [(set (reg:X SP_REGNUM) + (plus:X (reg:X SP_REGNUM) + (match_operand 0 "stack_pop_up_to_s1_operand" "I"))) + (set (reg:X S1_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S0_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X RETURN_ADDR_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X A0_REGNUM) + (const_int 0)) + (use (reg:X A0_REGNUM)) + (return) + (use (reg:SI RETURN_ADDR_REGNUM))] + "TARGET_ZCMP" + "cm.popretz {ra, s0-s1}, %0" +) + +(define_insn "@gpr_multi_popretz_up_to_s2_" + [(set (reg:X SP_REGNUM) + (plus:X (reg:X SP_REGNUM) + (match_operand 0 "stack_pop_up_to_s2_operand" "I"))) + (set (reg:X S2_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S1_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S0_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X RETURN_ADDR_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X A0_REGNUM) + (const_int 0)) + (use (reg:X A0_REGNUM)) + (return) + (use (reg:SI RETURN_ADDR_REGNUM))] + "TARGET_ZCMP" + "cm.popretz {ra, s0-s2}, %0" +) + +(define_insn "@gpr_multi_popretz_up_to_s3_" + [(set (reg:X SP_REGNUM) + (plus:X (reg:X SP_REGNUM) + (match_operand 0 "stack_pop_up_to_s3_operand" "I"))) + (set (reg:X S3_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S2_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S1_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S0_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X RETURN_ADDR_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X A0_REGNUM) + (const_int 0)) + (use (reg:X A0_REGNUM)) + (return) + (use (reg:SI RETURN_ADDR_REGNUM))] + "TARGET_ZCMP" + "cm.popretz {ra, s0-s3}, %0" +) + +(define_insn "@gpr_multi_popretz_up_to_s4_" + [(set (reg:X SP_REGNUM) + (plus:X (reg:X SP_REGNUM) + (match_operand 0 "stack_pop_up_to_s4_operand" "I"))) + (set (reg:X S4_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S3_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S2_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S1_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S0_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X RETURN_ADDR_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X A0_REGNUM) + (const_int 0)) + (use (reg:X A0_REGNUM)) + (return) + (use (reg:SI RETURN_ADDR_REGNUM))] + "TARGET_ZCMP" + "cm.popretz {ra, s0-s4}, %0" +) + +(define_insn "@gpr_multi_popretz_up_to_s5_" + [(set (reg:X SP_REGNUM) + (plus:X (reg:X SP_REGNUM) + (match_operand 0 "stack_pop_up_to_s5_operand" "I"))) + (set (reg:X S5_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S4_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S3_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S2_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S1_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S0_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X RETURN_ADDR_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X A0_REGNUM) + (const_int 0)) + (use (reg:X A0_REGNUM)) + (return) + (use (reg:SI RETURN_ADDR_REGNUM))] + "TARGET_ZCMP" + "cm.popretz {ra, s0-s5}, %0" +) + +(define_insn "@gpr_multi_popretz_up_to_s6_" + [(set (reg:X SP_REGNUM) + (plus:X (reg:X SP_REGNUM) + (match_operand 0 "stack_pop_up_to_s6_operand" "I"))) + (set (reg:X S6_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S5_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S4_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S3_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S2_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S1_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S0_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X RETURN_ADDR_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X A0_REGNUM) + (const_int 0)) + (use (reg:X A0_REGNUM)) + (return) + (use (reg:SI RETURN_ADDR_REGNUM))] + "TARGET_ZCMP" + "cm.popretz {ra, s0-s6}, %0" +) + +(define_insn "@gpr_multi_popretz_up_to_s7_" + [(set (reg:X SP_REGNUM) + (plus:X (reg:X SP_REGNUM) + (match_operand 0 "stack_pop_up_to_s7_operand" "I"))) + (set (reg:X S7_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S6_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S5_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S4_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S3_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S2_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S1_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S0_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X RETURN_ADDR_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X A0_REGNUM) + (const_int 0)) + (use (reg:X A0_REGNUM)) + (return) + (use (reg:SI RETURN_ADDR_REGNUM))] + "TARGET_ZCMP" + "cm.popretz {ra, s0-s7}, %0" +) + +(define_insn "@gpr_multi_popretz_up_to_s8_" + [(set (reg:X SP_REGNUM) + (plus:X (reg:X SP_REGNUM) + (match_operand 0 "stack_pop_up_to_s8_operand" "I"))) + (set (reg:X S8_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S7_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S6_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S5_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S4_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S3_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S2_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S1_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S0_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X RETURN_ADDR_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X A0_REGNUM) + (const_int 0)) + (use (reg:X A0_REGNUM)) + (return) + (use (reg:SI RETURN_ADDR_REGNUM))] + "TARGET_ZCMP" + "cm.popretz {ra, s0-s8}, %0" +) + +(define_insn "@gpr_multi_popretz_up_to_s9_" + [(set (reg:X SP_REGNUM) + (plus:X (reg:X SP_REGNUM) + (match_operand 0 "stack_pop_up_to_s9_operand" "I"))) + (set (reg:X S9_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S8_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S7_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S6_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S5_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S4_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S3_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S2_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S1_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S0_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X RETURN_ADDR_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X A0_REGNUM) + (const_int 0)) + (use (reg:X A0_REGNUM)) + (return) + (use (reg:SI RETURN_ADDR_REGNUM))] + "TARGET_ZCMP" + "cm.popretz {ra, s0-s9}, %0" +) + +(define_insn "@gpr_multi_popretz_up_to_s11_" + [(set (reg:X SP_REGNUM) + (plus:X (reg:X SP_REGNUM) + (match_operand 0 "stack_pop_up_to_s11_operand" "I"))) + (set (reg:X S11_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S10_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S9_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S8_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S7_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S6_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S5_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S4_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S3_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S2_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S1_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X S0_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X RETURN_ADDR_REGNUM) + (mem:X (plus:X (reg:X SP_REGNUM) + (const_int )))) + (set (reg:X A0_REGNUM) + (const_int 0)) + (use (reg:X A0_REGNUM)) + (return) + (use (reg:SI RETURN_ADDR_REGNUM))] + "TARGET_ZCMP" + "cm.popretz {ra, s0-s11}, %0" +) + +(define_insn "@gpr_multi_push_up_to_ra_" + [(set (mem:X (plus:X (reg:X SP_REGNUM) + (const_int ))) + (reg:X RETURN_ADDR_REGNUM)) + (set (reg:X SP_REGNUM) + (plus:X (reg:X SP_REGNUM) + (match_operand 0 "stack_push_up_to_ra_operand" "I")))] + "TARGET_ZCMP" + "cm.push {ra}, %0" +) + +(define_insn "@gpr_multi_push_up_to_s0_" + [(set (mem:X (plus:X (reg:X SP_REGNUM) + (const_int ))) + (reg:X S0_REGNUM)) + (set (mem:X (plus:X (reg:X SP_REGNUM) + (const_int ))) + (reg:X RETURN_ADDR_REGNUM)) + (set (reg:X SP_REGNUM) + (plus:X (reg:X SP_REGNUM) + (match_operand 0 "stack_push_up_to_s0_operand" "I")))] + "TARGET_ZCMP" + "cm.push {ra, s0}, %0" +) + +(define_insn "@gpr_multi_push_up_to_s1_" + [(set (mem:X (plus:X (reg:X SP_REGNUM) + (const_int ))) + (reg:X S1_REGNUM)) + (set (mem:X (plus:X (reg:X SP_REGNUM) + (const_int ))) + (reg:X S0_REGNUM)) + (set (mem:X (plus:X (reg:X SP_REGNUM) + (const_int ))) + (reg:X RETURN_ADDR_REGNUM)) + (set (reg:X SP_REGNUM) + (plus:X (reg:X SP_REGNUM) + (match_operand 0 "stack_push_up_to_s1_operand" "I")))] + "TARGET_ZCMP" + "cm.push {ra, s0-s1}, %0" +) + +(define_insn "@gpr_multi_push_up_to_s2_" + [(set (mem:X (plus:X (reg:X SP_REGNUM) + (const_int ))) + (reg:X S2_REGNUM)) + (set (mem:X (plus:X (reg:X SP_REGNUM) + (const_int ))) + (reg:X S1_REGNUM)) + (set (mem:X (plus:X (reg:X SP_REGNUM) + (const_int ))) + (reg:X S0_REGNUM)) + (set (mem:X (plus:X (reg:X SP_REGNUM) + (const_int ))) + (reg:X RETURN_ADDR_REGNUM)) + (set (reg:X SP_REGNUM) + (plus:X (reg:X SP_REGNUM) + (match_operand 0 "stack_push_up_to_s2_operand" "I")))] + "TARGET_ZCMP" + "cm.push {ra, s0-s2}, %0" +) + +(define_insn "@gpr_multi_push_up_to_s3_" + [(set (mem:X (plus:X (reg:X SP_REGNUM) + (const_int ))) + (reg:X S3_REGNUM)) + (set (mem:X (plus:X (reg:X SP_REGNUM) + (const_int ))) + (reg:X S2_REGNUM)) + (set (mem:X (plus:X (reg:X SP_REGNUM) + (const_int ))) + (reg:X S1_REGNUM)) + (set (mem:X (plus:X (reg:X SP_REGNUM) + (const_int ))) + (reg:X S0_REGNUM)) + (set (mem:X (plus:X (reg:X SP_REGNUM) + (const_int ))) + (reg:X RETURN_ADDR_REGNUM)) + (set (reg:X SP_REGNUM) + (plus:X (reg:X SP_REGNUM) + (match_operand 0 "stack_push_up_to_s3_operand" "I")))] + "TARGET_ZCMP" + "cm.push {ra, s0-s3}, %0" +) + +(define_insn "@gpr_multi_push_up_to_s4_" + [(set (mem:X (plus:X (reg:X SP_REGNUM) + (const_int ))) + (reg:X S4_REGNUM)) + (set (mem:X (plus:X (reg:X SP_REGNUM) + (const_int ))) + (reg:X S3_REGNUM)) + (set (mem:X (plus:X (reg:X SP_REGNUM) + (const_int ))) + (reg:X S2_REGNUM)) + (set (mem:X (plus:X (reg:X SP_REGNUM) + (const_int ))) + (reg:X S1_REGNUM)) + (set (mem:X (plus:X (reg:X SP_REGNUM) + (const_int ))) + (reg:X S0_REGNUM)) + (set (mem:X (plus:X (reg:X SP_REGNUM) + (const_int ))) + (reg:X RETURN_ADDR_REGNUM)) + (set (reg:X SP_REGNUM) + (plus:X (reg:X SP_REGNUM) + (match_operand 0 "stack_push_up_to_s4_operand" "I")))] + "TARGET_ZCMP" + "cm.push {ra, s0-s4}, %0" +) + +(define_insn "@gpr_multi_push_up_to_s5_" + [(set (mem:X (plus:X (reg:X SP_REGNUM) + (const_int ))) + (reg:X S5_REGNUM)) + (set (mem:X (plus:X (reg:X SP_REGNUM) + (const_int ))) + (reg:X S4_REGNUM)) + (set (mem:X (plus:X (reg:X SP_REGNUM) + (const_int ))) + (reg:X S3_REGNUM)) + (set (mem:X (plus:X (reg:X SP_REGNUM) + (const_int ))) + (reg:X S2_REGNUM)) + (set (mem:X (plus:X (reg:X SP_REGNUM) + (const_int ))) + (reg:X S1_REGNUM)) + (set (mem:X (plus:X (reg:X SP_REGNUM) + (const_int ))) + (reg:X S0_REGNUM)) + (set (mem:X (plus:X (reg:X SP_REGNUM) + (const_int ))) + (reg:X RETURN_ADDR_REGNUM)) + (set (reg:X SP_REGNUM) + (plus:X (reg:X SP_REGNUM) + (match_operand 0 "stack_push_up_to_s5_operand" "I")))] + "TARGET_ZCMP" + "cm.push {ra, s0-s5}, %0" +) + +(define_insn "@gpr_multi_push_up_to_s6_" + [(set (mem:X (plus:X (reg:X SP_REGNUM) + (const_int ))) + (reg:X S6_REGNUM)) + (set (mem:X (plus:X (reg:X SP_REGNUM) + (const_int ))) + (reg:X S5_REGNUM)) + (set (mem:X (plus:X (reg:X SP_REGNUM) + (const_int ))) + (reg:X S4_REGNUM)) + (set (mem:X (plus:X (reg:X SP_REGNUM) + (const_int ))) + (reg:X S3_REGNUM)) + (set (mem:X (plus:X (reg:X SP_REGNUM) + (const_int ))) + (reg:X S2_REGNUM)) + (set (mem:X (plus:X (reg:X SP_REGNUM) + (const_int ))) + (reg:X S1_REGNUM)) + (set (mem:X (plus:X (reg:X SP_REGNUM) + (const_int ))) + (reg:X S0_REGNUM)) + (set (mem:X (plus:X (reg:X SP_REGNUM) + (const_int ))) + (reg:X RETURN_ADDR_REGNUM)) + (set (reg:X SP_REGNUM) + (plus:X (reg:X SP_REGNUM) + (match_operand 0 "stack_push_up_to_s6_operand" "I")))] + "TARGET_ZCMP" + "cm.push {ra, s0-s6}, %0" +) + +(define_insn "@gpr_multi_push_up_to_s7_" + [(set (mem:X (plus:X (reg:X SP_REGNUM) + (const_int ))) + (reg:X S7_REGNUM)) + (set (mem:X (plus:X (reg:X SP_REGNUM) + (const_int ))) + (reg:X S6_REGNUM)) + (set (mem:X (plus:X (reg:X SP_REGNUM) + (const_int ))) + (reg:X S5_REGNUM)) + (set (mem:X (plus:X (reg:X SP_REGNUM) + (const_int ))) + (reg:X S4_REGNUM)) + (set (mem:X (plus:X (reg:X SP_REGNUM) + (const_int ))) + (reg:X S3_REGNUM)) + (set (mem:X (plus:X (reg:X SP_REGNUM) + (const_int ))) + (reg:X S2_REGNUM)) + (set (mem:X (plus:X (reg:X SP_REGNUM) + (const_int ))) + (reg:X S1_REGNUM)) + (set (mem:X (plus:X (reg:X SP_REGNUM) + (const_int ))) + (reg:X S0_REGNUM)) + (set (mem:X (plus:X (reg:X SP_REGNUM) + (const_int ))) + (reg:X RETURN_ADDR_REGNUM)) + (set (reg:X SP_REGNUM) + (plus:X (reg:X SP_REGNUM) + (match_operand 0 "stack_push_up_to_s7_operand" "I")))] + "TARGET_ZCMP" + "cm.push {ra, s0-s7}, %0" +) + +(define_insn "@gpr_multi_push_up_to_s8_" + [(set (mem:X (plus:X (reg:X SP_REGNUM) + (const_int ))) + (reg:X S8_REGNUM)) + (set (mem:X (plus:X (reg:X SP_REGNUM) + (const_int ))) + (reg:X S7_REGNUM)) + (set (mem:X (plus:X (reg:X SP_REGNUM) + (const_int ))) + (reg:X S6_REGNUM)) + (set (mem:X (plus:X (reg:X SP_REGNUM) + (const_int ))) + (reg:X S5_REGNUM)) + (set (mem:X (plus:X (reg:X SP_REGNUM) + (const_int ))) + (reg:X S4_REGNUM)) + (set (mem:X (plus:X (reg:X SP_REGNUM) + (const_int ))) + (reg:X S3_REGNUM)) + (set (mem:X (plus:X (reg:X SP_REGNUM) + (const_int ))) + (reg:X S2_REGNUM)) + (set (mem:X (plus:X (reg:X SP_REGNUM) + (const_int ))) + (reg:X S1_REGNUM)) + (set (mem:X (plus:X (reg:X SP_REGNUM) + (const_int ))) + (reg:X S0_REGNUM)) + (set (mem:X (plus:X (reg:X SP_REGNUM) + (const_int ))) + (reg:X RETURN_ADDR_REGNUM)) + (set (reg:X SP_REGNUM) + (plus:X (reg:X SP_REGNUM) + (match_operand 0 "stack_push_up_to_s8_operand" "I")))] + "TARGET_ZCMP" + "cm.push {ra, s0-s8}, %0" +) + +(define_insn "@gpr_multi_push_up_to_s9_" + [(set (mem:X (plus:X (reg:X SP_REGNUM) + (const_int ))) + (reg:X S9_REGNUM)) + (set (mem:X (plus:X (reg:X SP_REGNUM) + (const_int ))) + (reg:X S8_REGNUM)) + (set (mem:X (plus:X (reg:X SP_REGNUM) + (const_int ))) + (reg:X S7_REGNUM)) + (set (mem:X (plus:X (reg:X SP_REGNUM) + (const_int ))) + (reg:X S6_REGNUM)) + (set (mem:X (plus:X (reg:X SP_REGNUM) + (const_int ))) + (reg:X S5_REGNUM)) + (set (mem:X (plus:X (reg:X SP_REGNUM) + (const_int ))) + (reg:X S4_REGNUM)) + (set (mem:X (plus:X (reg:X SP_REGNUM) + (const_int ))) + (reg:X S3_REGNUM)) + (set (mem:X (plus:X (reg:X SP_REGNUM) + (const_int ))) + (reg:X S2_REGNUM)) + (set (mem:X (plus:X (reg:X SP_REGNUM) + (const_int ))) + (reg:X S1_REGNUM)) + (set (mem:X (plus:X (reg:X SP_REGNUM) + (const_int ))) + (reg:X S0_REGNUM)) + (set (mem:X (plus:X (reg:X SP_REGNUM) + (const_int ))) + (reg:X RETURN_ADDR_REGNUM)) + (set (reg:X SP_REGNUM) + (plus:X (reg:X SP_REGNUM) + (match_operand 0 "stack_push_up_to_s9_operand" "I")))] + "TARGET_ZCMP" + "cm.push {ra, s0-s9}, %0" +) + +(define_insn "@gpr_multi_push_up_to_s11_" + [(set (mem:X (plus:X (reg:X SP_REGNUM) + (const_int ))) + (reg:X S11_REGNUM)) + (set (mem:X (plus:X (reg:X SP_REGNUM) + (const_int ))) + (reg:X S10_REGNUM)) + (set (mem:X (plus:X (reg:X SP_REGNUM) + (const_int ))) + (reg:X S9_REGNUM)) + (set (mem:X (plus:X (reg:X SP_REGNUM) + (const_int ))) + (reg:X S8_REGNUM)) + (set (mem:X (plus:X (reg:X SP_REGNUM) + (const_int ))) + (reg:X S7_REGNUM)) + (set (mem:X (plus:X (reg:X SP_REGNUM) + (const_int ))) + (reg:X S6_REGNUM)) + (set (mem:X (plus:X (reg:X SP_REGNUM) + (const_int ))) + (reg:X S5_REGNUM)) + (set (mem:X (plus:X (reg:X SP_REGNUM) + (const_int ))) + (reg:X S4_REGNUM)) + (set (mem:X (plus:X (reg:X SP_REGNUM) + (const_int ))) + (reg:X S3_REGNUM)) + (set (mem:X (plus:X (reg:X SP_REGNUM) + (const_int ))) + (reg:X S2_REGNUM)) + (set (mem:X (plus:X (reg:X SP_REGNUM) + (const_int ))) + (reg:X S1_REGNUM)) + (set (mem:X (plus:X (reg:X SP_REGNUM) + (const_int ))) + (reg:X S0_REGNUM)) + (set (mem:X (plus:X (reg:X SP_REGNUM) + (const_int ))) + (reg:X RETURN_ADDR_REGNUM)) + (set (reg:X SP_REGNUM) + (plus:X (reg:X SP_REGNUM) + (match_operand 0 "stack_push_up_to_s11_operand" "I")))] + "TARGET_ZCMP" + "cm.push {ra, s0-s11}, %0" +) + +;; ZCMP mv +(define_insn "*mva01s" + [(set (match_operand:X 0 "a0a1_reg_operand" "=r") + (match_operand:X 1 "zcmp_mv_sreg_operand" "r")) + (set (match_operand:X 2 "a0a1_reg_operand" "=r") + (match_operand:X 3 "zcmp_mv_sreg_operand" "r"))] + "TARGET_ZCMP + && (REGNO (operands[2]) != REGNO (operands[0]))" + { return (REGNO (operands[0]) == A0_REGNUM)?"cm.mva01s\t%1,%3":"cm.mva01s\t%3,%1"; } + [(set_attr "mode" "")]) + +(define_insn "*mvsa01" + [(set (match_operand:X 0 "zcmp_mv_sreg_operand" "=r") + (match_operand:X 1 "a0a1_reg_operand" "r")) + (set (match_operand:X 2 "zcmp_mv_sreg_operand" "=r") + (match_operand:X 3 "a0a1_reg_operand" "r"))] + "TARGET_ZCMP + && (REGNO (operands[0]) != REGNO (operands[2])) + && (REGNO (operands[1]) != REGNO (operands[3]))" + { return (REGNO (operands[1]) == A0_REGNUM)?"cm.mvsa01\t%0,%2":"cm.mvsa01\t%2,%0"; } + [(set_attr "mode" "")]) diff --git a/gcc/config/riscv/zicond.md b/gcc/config/riscv/zicond.md index 25f21d33487e..4619220ef8ac 100644 --- a/gcc/config/riscv/zicond.md +++ b/gcc/config/riscv/zicond.md @@ -62,3 +62,34 @@ "TARGET_ZICOND && rtx_equal_p (operands[1], operands[3])" "czero.nez\t%0,%2,%1" ) + +;; Combine creates this form in some cases (particularly the coremark +;; CRC loop. +(define_split + [(set (match_operand:X 0 "register_operand") + (and:X (sign_extract:X (match_operand:X 1 "register_operand") + (const_int 1) + (match_operand 2 "immediate_operand")) + (match_operand:X 3 "register_operand"))) + (clobber (match_operand:X 4 "register_operand"))] + "TARGET_ZICOND && TARGET_ZBS" + [(set (match_dup 4) (zero_extract:X (match_dup 1) (const_int 1) (match_dup 2))) + (set (match_dup 0) (if_then_else:X (eq:X (match_dup 4) (const_int 0)) + (const_int 0) + (match_dup 3)))]) + +(define_split + [(set (match_operand:X 0 "register_operand") + (and:X (sign_extract:X (match_operand:X 1 "register_operand") + (const_int 1) + (match_operand 2 "immediate_operand")) + (match_operand:X 3 "register_operand"))) + (clobber (match_operand:X 4 "register_operand"))] + "TARGET_ZICOND && !TARGET_ZBS && (UINTVAL (operands[2]) < 11)" + [(set (match_dup 4) (and:X (match_dup 1) (match_dup 2))) + (set (match_dup 0) (if_then_else:X (eq:X (match_dup 4) (const_int 0)) + (const_int 0) + (match_dup 3)))] +{ + operands[2] = GEN_INT (1 << UINTVAL(operands[2])); +}) diff --git a/gcc/config/rl78/rl78-protos.h b/gcc/config/rl78/rl78-protos.h index 7d474ffc1301..813459ad8b6d 100644 --- a/gcc/config/rl78/rl78-protos.h +++ b/gcc/config/rl78/rl78-protos.h @@ -18,6 +18,9 @@ along with GCC; see the file COPYING3. If not see . */ + +#include "tree.h" /* For ERROR_MARK. */ + const char * rl78_addsi3_internal (rtx *, unsigned int); void rl78_emit_eh_epilogue (rtx); void rl78_expand_compare (rtx *); @@ -33,7 +36,8 @@ int rl78_far_p (rtx x); bool rl78_hl_b_c_addr_p (rtx); int rl78_initial_elimination_offset (int, int); bool rl78_as_legitimate_address (machine_mode, rtx, - bool, addr_space_t); + bool, addr_space_t, + code_helper = ERROR_MARK); int rl78_legitimize_reload_address (rtx *, machine_mode, int,int, int); enum reg_class rl78_mode_code_base_reg_class (machine_mode, addr_space_t, int, int); bool rl78_peep_movhi_p (rtx *); diff --git a/gcc/config/rl78/rl78.cc b/gcc/config/rl78/rl78.cc index 9083096c4ae9..0cbd6bf780aa 100644 --- a/gcc/config/rl78/rl78.cc +++ b/gcc/config/rl78/rl78.cc @@ -1143,7 +1143,8 @@ rl78_is_legitimate_constant (machine_mode mode ATTRIBUTE_UNUSED, rtx x ATTRIBUTE bool rl78_as_legitimate_address (machine_mode mode ATTRIBUTE_UNUSED, rtx x, - bool strict ATTRIBUTE_UNUSED, addr_space_t as ATTRIBUTE_UNUSED) + bool strict ATTRIBUTE_UNUSED, + addr_space_t as ATTRIBUTE_UNUSED, code_helper) { rtx base, index, addend; bool is_far_addr = false; diff --git a/gcc/config/rs6000/altivec.md b/gcc/config/rs6000/altivec.md index 70db5cfcd9f1..e8a596fb7e9c 100644 --- a/gcc/config/rs6000/altivec.md +++ b/gcc/config/rs6000/altivec.md @@ -2631,6 +2631,18 @@ "vcmpequq. %0,%1,%2" [(set_attr "type" "veccmpfx")]) +;; Expand for builtin vcmpne{b,h,w} +(define_expand "altivec_vcmpne_" + [(set (match_operand:VSX_EXTRACT_I 3 "altivec_register_operand" "=v") + (eq:VSX_EXTRACT_I (match_operand:VSX_EXTRACT_I 1 "altivec_register_operand" "v") + (match_operand:VSX_EXTRACT_I 2 "altivec_register_operand" "v"))) + (set (match_operand:VSX_EXTRACT_I 0 "altivec_register_operand" "=v") + (not:VSX_EXTRACT_I (match_dup 3)))] + "TARGET_ALTIVEC" + { + operands[3] = gen_reg_rtx (GET_MODE (operands[0])); + }) + (define_insn "*altivec_vcmpgts_p" [(set (reg:CC CR6_REGNO) (unspec:CC [(gt:CC (match_operand:VI2 1 "register_operand" "v") diff --git a/gcc/config/rs6000/darwin.h b/gcc/config/rs6000/darwin.h index bf9dfaf2f34b..88a394787029 100644 --- a/gcc/config/rs6000/darwin.h +++ b/gcc/config/rs6000/darwin.h @@ -98,7 +98,7 @@ Include libmx when targeting Darwin 7.0 and above, but before libSystem, since the functions are actually in libSystem but for 7.x compatibility we want them to be looked for in libmx first. - Include libSystemStubs when compiling against 10.3 - 10.5 SDKs (we assume + Include libSystemStubs when compiling against 10.3 - 10.6 SDKs (we assume this is the case when targetting these) - but not for 64-bit long double. Don't do either for m64, the library is either a dummy or non-existent. */ @@ -107,8 +107,8 @@ #define LIB_SPEC \ "%{!static: \ %{!m64:%{!mlong-double-64: \ - %{pg:%:version-compare(>< 10.3 10.5 mmacosx-version-min= -lSystemStubs_profile)} \ - %{!pg:%:version-compare(>< 10.3 10.5 mmacosx-version-min= -lSystemStubs)} \ + %{pg:%:version-compare(>< 10.3 10.7 mmacosx-version-min= -lSystemStubs_profile)} \ + %{!pg:%:version-compare(>< 10.3 10.7 mmacosx-version-min= -lSystemStubs)} \ %:version-compare(>< 10.3 10.4 mmacosx-version-min= -lmx)}} \ -lSystem \ }" diff --git a/gcc/config/rs6000/dfp.md b/gcc/config/rs6000/dfp.md index 5ed8a73ac51d..bf4a227b0eb5 100644 --- a/gcc/config/rs6000/dfp.md +++ b/gcc/config/rs6000/dfp.md @@ -271,7 +271,8 @@ UNSPEC_DIEX UNSPEC_DSCLI UNSPEC_DTSTSFI - UNSPEC_DSCRI]) + UNSPEC_DSCRI + UNSPEC_DQUAN]) (define_code_iterator DFP_TEST [eq lt gt unordered]) @@ -395,3 +396,25 @@ "dscri %0,%1,%2" [(set_attr "type" "dfp") (set_attr "size" "")]) + +(define_insn "dfp_dqua_" + [(set (match_operand:DDTD 0 "gpc_reg_operand" "=d") + (unspec:DDTD [(match_operand:DDTD 1 "gpc_reg_operand" "d") + (match_operand:DDTD 2 "gpc_reg_operand" "d") + (match_operand:SI 3 "const_0_to_3_operand" "n")] + UNSPEC_DQUAN))] + "TARGET_DFP" + "dqua %0,%1,%2,%3" + [(set_attr "type" "dfp") + (set_attr "size" "")]) + +(define_insn "dfp_dquai_" + [(set (match_operand:DDTD 0 "gpc_reg_operand" "=d") + (unspec:DDTD [(match_operand:SI 1 "s5bit_cint_operand" "n") + (match_operand:DDTD 2 "gpc_reg_operand" "d") + (match_operand:SI 3 "const_0_to_3_operand" "n")] + UNSPEC_DQUAN))] + "TARGET_DFP" + "dquai %1,%0,%2,%3" + [(set_attr "type" "dfp") + (set_attr "size" "")]) diff --git a/gcc/config/rs6000/mma.md b/gcc/config/rs6000/mma.md index d36dc13872b4..575751d477e3 100644 --- a/gcc/config/rs6000/mma.md +++ b/gcc/config/rs6000/mma.md @@ -293,8 +293,8 @@ }) (define_insn_and_split "*movoo" - [(set (match_operand:OO 0 "nonimmediate_operand" "=wa,m,wa") - (match_operand:OO 1 "input_operand" "m,wa,wa"))] + [(set (match_operand:OO 0 "nonimmediate_operand" "=wa,ZwO,wa") + (match_operand:OO 1 "input_operand" "ZwO,wa,wa"))] "TARGET_MMA && (gpc_reg_operand (operands[0], OOmode) || gpc_reg_operand (operands[1], OOmode))" @@ -340,8 +340,8 @@ }) (define_insn_and_split "*movxo" - [(set (match_operand:XO 0 "nonimmediate_operand" "=d,m,d") - (match_operand:XO 1 "input_operand" "m,d,d"))] + [(set (match_operand:XO 0 "nonimmediate_operand" "=d,ZwO,d") + (match_operand:XO 1 "input_operand" "ZwO,d,d"))] "TARGET_MMA && (gpc_reg_operand (operands[0], XOmode) || gpc_reg_operand (operands[1], XOmode))" diff --git a/gcc/config/rs6000/predicates.md b/gcc/config/rs6000/predicates.md index 3552d908e9d1..925f69cd3fca 100644 --- a/gcc/config/rs6000/predicates.md +++ b/gcc/config/rs6000/predicates.md @@ -924,7 +924,7 @@ (define_predicate "vsx_quad_dform_memory_operand" (match_code "mem") { - if (!TARGET_P9_VECTOR || GET_MODE_SIZE (mode) != 16) + if (!TARGET_P9_VECTOR) return false; return quad_address_p (XEXP (op, 0), mode, false); diff --git a/gcc/config/rs6000/rs6000-builtins.def b/gcc/config/rs6000/rs6000-builtins.def index 35c4cdf74c5f..ce40600e803b 100644 --- a/gcc/config/rs6000/rs6000-builtins.def +++ b/gcc/config/rs6000/rs6000-builtins.def @@ -641,6 +641,15 @@ const int __builtin_altivec_vcmpgtuw_p (int, vsi, vsi); VCMPGTUW_P vector_gtu_v4si_p {pred} + const vsc __builtin_altivec_vcmpneb (vsc, vsc); + VCMPNEB altivec_vcmpne_v16qi {} + + const vss __builtin_altivec_vcmpneh (vss, vss); + VCMPNEH altivec_vcmpne_v8hi {} + + const vsi __builtin_altivec_vcmpnew (vsi, vsi); + VCMPNEW altivec_vcmpne_v4si {} + const vsi __builtin_altivec_vctsxs (vf, const int<5>); VCTSXS altivec_vctsxs {} @@ -2599,9 +2608,6 @@ const signed int __builtin_altivec_vcmpaew_p (vsi, vsi); VCMPAEW_P vector_ae_v4si_p {} - const vsc __builtin_altivec_vcmpneb (vsc, vsc); - VCMPNEB vcmpneb {} - const signed int __builtin_altivec_vcmpneb_p (vsc, vsc); VCMPNEB_P vector_ne_v16qi_p {} @@ -2614,15 +2620,9 @@ const signed int __builtin_altivec_vcmpnefp_p (vf, vf); VCMPNEFP_P vector_ne_v4sf_p {} - const vss __builtin_altivec_vcmpneh (vss, vss); - VCMPNEH vcmpneh {} - const signed int __builtin_altivec_vcmpneh_p (vss, vss); VCMPNEH_P vector_ne_v8hi_p {} - const vsi __builtin_altivec_vcmpnew (vsi, vsi); - VCMPNEW vcmpnew {} - const signed int __builtin_altivec_vcmpnew_p (vsi, vsi); VCMPNEW_P vector_ne_v4si_p {} @@ -2983,6 +2983,21 @@ const unsigned long long __builtin_unpack_dec128 (_Decimal128, const int<1>); UNPACK_TD unpacktd {} + const _Decimal64 __builtin_dfp_dqua (_Decimal64, _Decimal64, \ + const int<2>); + DFPQUAN_64 dfp_dqua_dd {} + + const _Decimal64 __builtin_dfp_dquai (const int<5>, _Decimal64, \ + const int<2>); + DFPQUAN_64i dfp_dquai_dd {} + + const _Decimal128 __builtin_dfp_dquaq (_Decimal128, _Decimal128, \ + const int<2>); + DFPQUAN_128 dfp_dqua_td {} + + const _Decimal128 __builtin_dfp_dquaqi (const int<5>, _Decimal128, \ + const int<2>); + DFPQUAN_128i dfp_dquai_td {} [crypto] const vull __builtin_crypto_vcipher (vull, vull); diff --git a/gcc/config/rs6000/rs6000-overload.def b/gcc/config/rs6000/rs6000-overload.def index b83946f5ad82..38d92fcf1f04 100644 --- a/gcc/config/rs6000/rs6000-overload.def +++ b/gcc/config/rs6000/rs6000-overload.def @@ -195,6 +195,16 @@ unsigned long long __builtin_cmpb (unsigned long long, unsigned long long); CMPB +[DFPQUAN, dfp_quantize, __builtin_dfp_quantize] + _Decimal64 __builtin_dfp_quantize (_Decimal64, _Decimal64, const int); + DFPQUAN_64 + _Decimal64 __builtin_dfp_quantize (const int, _Decimal64, const int); + DFPQUAN_64i + _Decimal128 __builtin_dfp_quantize (_Decimal128, _Decimal128, const int); + DFPQUAN_128 + _Decimal128 __builtin_dfp_quantize (const int, _Decimal128, const int); + DFPQUAN_128i + [VEC_ABS, vec_abs, __builtin_vec_abs] vsc __builtin_vec_abs (vsc); ABS_V16QI diff --git a/gcc/config/rs6000/rs6000-string.cc b/gcc/config/rs6000/rs6000-string.cc index 75e6f8803a5c..44a946cd4536 100644 --- a/gcc/config/rs6000/rs6000-string.cc +++ b/gcc/config/rs6000/rs6000-string.cc @@ -2811,11 +2811,17 @@ expand_block_move (rtx operands[], bool might_overlap) gen_func.mov = gen_vsx_movv2di_64bit; } else if (TARGET_BLOCK_OPS_UNALIGNED_VSX - && TARGET_POWER10 && bytes < 16 + /* Only use lxvl/stxvl on 64bit POWER10. */ + && TARGET_POWER10 + && TARGET_64BIT + && bytes < 16 && orig_bytes > 16 - && !(bytes == 1 || bytes == 2 - || bytes == 4 || bytes == 8) - && (align >= 128 || !STRICT_ALIGNMENT)) + && !(bytes == 1 + || bytes == 2 + || bytes == 4 + || bytes == 8) + && (align >= 128 + || !STRICT_ALIGNMENT)) { /* Only use lxvl/stxvl if it could replace multiple ordinary loads+stores. Also don't use it unless we likely already diff --git a/gcc/config/rs6000/rs6000.cc b/gcc/config/rs6000/rs6000.cc index 44b448d2ba67..efe9adce1f8b 100644 --- a/gcc/config/rs6000/rs6000.cc +++ b/gcc/config/rs6000/rs6000.cc @@ -1109,7 +1109,8 @@ struct processor_costs ppca2_cost = { static tree (*rs6000_veclib_handler) (combined_fn, tree, tree); -static bool rs6000_debug_legitimate_address_p (machine_mode, rtx, bool); +static bool rs6000_debug_legitimate_address_p (machine_mode, rtx, bool, + code_helper = ERROR_MARK); static tree rs6000_handle_longcall_attribute (tree *, tree, tree, int, bool *); static tree rs6000_handle_altivec_attribute (tree *, tree, tree, int, bool *); static tree rs6000_handle_struct_attribute (tree *, tree, tree, int, bool *); @@ -9883,7 +9884,8 @@ use_toc_relative_ref (rtx sym, machine_mode mode) because adjacent memory cells are accessed by adding word-sized offsets during assembly output. */ static bool -rs6000_legitimate_address_p (machine_mode mode, rtx x, bool reg_ok_strict) +rs6000_legitimate_address_p (machine_mode mode, rtx x, bool reg_ok_strict, + code_helper ch = ERROR_MARK) { bool reg_offset_p = reg_offset_addressing_ok_p (mode); bool quad_offset_p = mode_supports_dq_form (mode); @@ -9891,6 +9893,12 @@ rs6000_legitimate_address_p (machine_mode mode, rtx x, bool reg_ok_strict) if (TARGET_ELF && RS6000_SYMBOL_REF_TLS_P (x)) return 0; + /* lxvl and stxvl doesn't support any addressing modes with PLUS. */ + if (ch.is_internal_fn () + && (ch == IFN_LEN_LOAD || ch == IFN_LEN_STORE) + && GET_CODE (x) == PLUS) + return 0; + /* Handle unaligned altivec lvx/stvx type addresses. */ if (VECTOR_MEM_ALTIVEC_OR_VSX_P (mode) && GET_CODE (x) == AND @@ -9986,10 +9994,10 @@ rs6000_legitimate_address_p (machine_mode mode, rtx x, bool reg_ok_strict) /* Debug version of rs6000_legitimate_address_p. */ static bool -rs6000_debug_legitimate_address_p (machine_mode mode, rtx x, - bool reg_ok_strict) +rs6000_debug_legitimate_address_p (machine_mode mode, rtx x, bool reg_ok_strict, + code_helper ch) { - bool ret = rs6000_legitimate_address_p (mode, x, reg_ok_strict); + bool ret = rs6000_legitimate_address_p (mode, x, reg_ok_strict, ch); fprintf (stderr, "\nrs6000_legitimate_address_p: return = %s, mode = %s, " "strict = %d, reload = %s, code = %s\n", diff --git a/gcc/config/rs6000/vsx.md b/gcc/config/rs6000/vsx.md index 9cd7be23a5fa..19abfeb565a6 100644 --- a/gcc/config/rs6000/vsx.md +++ b/gcc/config/rs6000/vsx.md @@ -3753,9 +3753,9 @@ (define_expand "vsx_extract_" [(parallel [(set (match_operand: 0 "gpc_reg_operand") (vec_select: - (match_operand:VSX_EXTRACT_I 1 "gpc_reg_operand") + (match_operand:VSX_EXTRACT_I2 1 "gpc_reg_operand") (parallel [(match_operand:QI 2 "const_int_operand")]))) - (clobber (match_scratch:VSX_EXTRACT_I 3))])] + (clobber (match_scratch:VSX_EXTRACT_I2 3))])] "VECTOR_MEM_VSX_P (mode) && TARGET_DIRECT_MOVE_64BIT" { /* If we have ISA 3.0, we can do a xxextractuw/vextractu{b,h}. */ @@ -3767,6 +3767,63 @@ } }) +(define_expand "vsx_extract_v4si" + [(parallel [(set (match_operand:SI 0 "gpc_reg_operand") + (vec_select:SI + (match_operand:V4SI 1 "gpc_reg_operand") + (parallel [(match_operand:QI 2 "const_0_to_3_operand")]))) + (clobber (match_scratch:V4SI 3))])] + "TARGET_DIRECT_MOVE_64BIT" +{ + /* The word 1 (BE order) can be extracted by mfvsrwz/stxsiwx. So just + fall through to vsx_extract_v4si_w1. */ + if (TARGET_P9_VECTOR + && INTVAL (operands[2]) != (BYTES_BIG_ENDIAN ? 1 : 2)) + { + emit_insn (gen_vsx_extract_v4si_p9 (operands[0], operands[1], + operands[2])); + DONE; + } +}) + +;; Extract from word 1 (BE order). +(define_insn "vsx_extract_v4si_w1" + [(set (match_operand:SI 0 "nonimmediate_operand" "=r,wa,Z,wa") + (vec_select:SI + (match_operand:V4SI 1 "gpc_reg_operand" "v,v,v,0") + (parallel [(match_operand:QI 2 "const_0_to_3_operand" "n,n,n,n")]))) + (clobber (match_scratch:V4SI 3 "=v,v,v,v"))] + "TARGET_DIRECT_MOVE_64BIT + && INTVAL (operands[2]) == (BYTES_BIG_ENDIAN ? 1 : 2)" +{ + if (which_alternative == 0) + return "mfvsrwz %0,%x1"; + + if (which_alternative == 1) + return "xxlor %x0,%x1,%x1"; + + if (which_alternative == 2) + return "stxsiwx %x1,%y0"; + + return ASM_COMMENT_START " vec_extract to same register"; +} + [(set_attr "type" "mfvsr,veclogical,fpstore,*") + (set_attr "length" "4,4,4,0") + (set_attr "isa" "p8v,*,p8v,*")]) + +(define_insn "*mfvsrwz" + [(set (match_operand:DI 0 "register_operand" "=r") + (zero_extend:DI + (vec_select:SI + (match_operand:V4SI 1 "vsx_register_operand" "wa") + (parallel [(match_operand:QI 2 "const_int_operand" "n")])))) + (clobber (match_scratch:V4SI 3 "=v"))] + "TARGET_DIRECT_MOVE_64BIT + && INTVAL (operands[2]) == (BYTES_BIG_ENDIAN ? 1 : 2)" + "mfvsrwz %0,%x1" + [(set_attr "type" "mfvsr") + (set_attr "isa" "p8v")]) + (define_insn "vsx_extract__p9" [(set (match_operand: 0 "gpc_reg_operand" "=r,") (vec_select: @@ -3838,6 +3895,9 @@ (parallel [(match_dup 2)]))) (clobber (match_dup 3))])] { + gcc_assert (mode != V4SImode + || INTVAL (operands[2]) != (BYTES_BIG_ENDIAN ? 1 : 2)); + operands[4] = gen_rtx_REG (mode, REGNO (operands[0])); } [(set_attr "isa" "p9v,*")]) @@ -3859,60 +3919,58 @@ (parallel [(match_dup 2)]))) (clobber (match_dup 4))]) (set (match_dup 0) - (match_dup 3))]) + (match_dup 3))] +{ + if (which_alternative == 0 + && ((mode == V16QImode + && INTVAL (operands[2]) == (BYTES_BIG_ENDIAN ? 7 : 8)) + || (mode == V8HImode + && INTVAL (operands[2]) == (BYTES_BIG_ENDIAN ? 3 : 4)))) + { + enum machine_mode dest_mode = GET_MODE (operands[0]); + emit_move_insn (operands[0], + gen_rtx_REG (dest_mode, REGNO (operands[3]))); + DONE; + } +}) -(define_insn_and_split "*vsx_extract_si" + +;; Extract from word 0, 2, 3 (BE order). +(define_insn_and_split "*vsx_extract_v4si_w023" [(set (match_operand:SI 0 "nonimmediate_operand" "=r,wa,Z") (vec_select:SI (match_operand:V4SI 1 "gpc_reg_operand" "v,v,v") (parallel [(match_operand:QI 2 "const_0_to_3_operand" "n,n,n")]))) (clobber (match_scratch:V4SI 3 "=v,v,v"))] - "VECTOR_MEM_VSX_P (V4SImode) && TARGET_DIRECT_MOVE_64BIT && !TARGET_P9_VECTOR" + "TARGET_DIRECT_MOVE_64BIT" "#" - "&& reload_completed" + "&& INTVAL (operands[2]) != (BYTES_BIG_ENDIAN ? 1 : 2)" [(const_int 0)] { + gcc_assert (!TARGET_P9_VECTOR); + rtx dest = operands[0]; rtx src = operands[1]; rtx element = operands[2]; - rtx vec_tmp = operands[3]; - int value; + rtx vec_tmp; + + if (GET_CODE (operands[3]) == SCRATCH) + vec_tmp = gen_reg_rtx (V4SImode); + else + vec_tmp = operands[3]; /* Adjust index for LE element ordering, the below minuend 3 is computed by GET_MODE_NUNITS (V4SImode) - 1. */ if (!BYTES_BIG_ENDIAN) element = GEN_INT (3 - INTVAL (element)); - /* If the value is in the correct position, we can avoid doing the VSPLT - instruction. */ - value = INTVAL (element); - if (value != 1) - emit_insn (gen_altivec_vspltw_direct (vec_tmp, src, element)); - else - vec_tmp = src; + emit_insn (gen_altivec_vspltw_direct (vec_tmp, src, element)); - if (MEM_P (operands[0])) - { - if (can_create_pseudo_p ()) - dest = rs6000_force_indexed_or_indirect_mem (dest); - - if (TARGET_P8_VECTOR) - emit_move_insn (dest, gen_rtx_REG (SImode, REGNO (vec_tmp))); - else - emit_insn (gen_stfiwx (dest, gen_rtx_REG (DImode, REGNO (vec_tmp)))); - } - - else if (TARGET_P8_VECTOR) - emit_move_insn (dest, gen_rtx_REG (SImode, REGNO (vec_tmp))); - else - emit_move_insn (gen_rtx_REG (DImode, REGNO (dest)), - gen_rtx_REG (DImode, REGNO (vec_tmp))); + int value = BYTES_BIG_ENDIAN ? 1 : 2; + emit_insn (gen_vsx_extract_v4si_w1 (dest, vec_tmp, GEN_INT (value))); DONE; -} - [(set_attr "type" "mfvsr,vecperm,fpstore") - (set_attr "length" "8") - (set_attr "isa" "*,p8v,*")]) +}) (define_insn_and_split "*vsx_extract__p8" [(set (match_operand: 0 "nonimmediate_operand" "=r") diff --git a/gcc/config/rx/rx.cc b/gcc/config/rx/rx.cc index 726b00a3193b..245c6a4413da 100644 --- a/gcc/config/rx/rx.cc +++ b/gcc/config/rx/rx.cc @@ -179,7 +179,8 @@ rx_small_data_operand (rtx op) static bool rx_is_legitimate_address (machine_mode mode, rtx x, - bool strict ATTRIBUTE_UNUSED) + bool strict ATTRIBUTE_UNUSED, + code_helper = ERROR_MARK) { if (RTX_OK_FOR_BASE (x, strict)) /* Register Indirect. */ diff --git a/gcc/config/rx/rx.md b/gcc/config/rx/rx.md index 6959c6095c66..f6b13b92aa56 100644 --- a/gcc/config/rx/rx.md +++ b/gcc/config/rx/rx.md @@ -1722,7 +1722,7 @@ (minus:SI (match_operand:SI 4 "register_operand" " 1, 1") (match_operand:SI 5 "rx_compare_operand" " rQ,rQ")) - (geu:SI (match_dup 2) (match_dup 3)))) + (gtu:SI (match_dup 3) (match_dup 2)))) (clobber (reg:CC CC_REG))] "" "#" diff --git a/gcc/config/s390/s390.cc b/gcc/config/s390/s390.cc index 6ae81d660e07..49ab4fc7360b 100644 --- a/gcc/config/s390/s390.cc +++ b/gcc/config/s390/s390.cc @@ -4914,7 +4914,8 @@ s390_expand_plus_operand (rtx target, rtx src, STRICT specifies whether strict register checking applies. */ static bool -s390_legitimate_address_p (machine_mode mode, rtx addr, bool strict) +s390_legitimate_address_p (machine_mode mode, rtx addr, bool strict, + code_helper = ERROR_MARK) { struct s390_address ad; diff --git a/gcc/config/sh/sh.cc b/gcc/config/sh/sh.cc index 938f7aa62819..294faf7c0c30 100644 --- a/gcc/config/sh/sh.cc +++ b/gcc/config/sh/sh.cc @@ -266,7 +266,8 @@ static reg_class_t sh_preferred_reload_class (rtx, reg_class_t); static reg_class_t sh_secondary_reload (bool, rtx, reg_class_t, machine_mode, struct secondary_reload_info *); -static bool sh_legitimate_address_p (machine_mode, rtx, bool); +static bool sh_legitimate_address_p (machine_mode, rtx, bool, + code_helper = ERROR_MARK); static rtx sh_legitimize_address (rtx, rtx, machine_mode); static rtx sh_delegitimize_address (rtx); static bool sh_cannot_substitute_mem_equiv_p (rtx); @@ -9038,7 +9039,7 @@ sh_legitimate_index_p (machine_mode mode, rtx op, bool consider_sh2a, GBR GBR+disp */ static bool -sh_legitimate_address_p (machine_mode mode, rtx x, bool strict) +sh_legitimate_address_p (machine_mode mode, rtx x, bool strict, code_helper) { if (REG_P (x) && REGNO (x) == GBR_REG) return true; diff --git a/gcc/config/sparc/sparc.cc b/gcc/config/sparc/sparc.cc index 0aade05faf51..82e579524142 100644 --- a/gcc/config/sparc/sparc.cc +++ b/gcc/config/sparc/sparc.cc @@ -607,7 +607,8 @@ static void sparc_emit_set_const64 (rtx, rtx); static void sparc_output_addr_vec (rtx); static void sparc_output_addr_diff_vec (rtx); static void sparc_output_deferred_case_vectors (void); -static bool sparc_legitimate_address_p (machine_mode, rtx, bool); +static bool sparc_legitimate_address_p (machine_mode, rtx, bool, + code_helper = ERROR_MARK); static bool sparc_legitimate_constant_p (machine_mode, rtx); static rtx sparc_builtin_saveregs (void); static int epilogue_renumber (rtx *, int); @@ -4529,7 +4530,8 @@ sparc_pic_register_p (rtx x) ordinarily. This changes a bit when generating PIC. */ static bool -sparc_legitimate_address_p (machine_mode mode, rtx addr, bool strict) +sparc_legitimate_address_p (machine_mode mode, rtx addr, bool strict, + code_helper) { rtx rs1 = NULL, rs2 = NULL, imm1 = NULL; diff --git a/gcc/config/stormy16/stormy16-protos.h b/gcc/config/stormy16/stormy16-protos.h index f90d88eba6f8..27ae023bcb30 100644 --- a/gcc/config/stormy16/stormy16-protos.h +++ b/gcc/config/stormy16/stormy16-protos.h @@ -18,7 +18,7 @@ You should have received a copy of the GNU General Public License along with GCC; see the file COPYING3. If not see . */ - +#include "tree.h" /* For ERROR_MARK. */ extern struct xstormy16_stack_layout xstormy16_compute_stack_layout (void); extern void xstormy16_expand_prologue (void); @@ -65,6 +65,7 @@ extern const char * xstormy16_output_shift (machine_mode, enum rtx_code, rtx, rtx, rtx); extern bool xstormy16_below100_symbol (rtx, machine_mode); extern bool xstormy16_splittable_below100_operand (rtx, machine_mode); -extern bool xstormy16_legitimate_address_p (machine_mode, rtx, bool); +extern bool xstormy16_legitimate_address_p (machine_mode, rtx, bool, + code_helper = ERROR_MARK); #endif diff --git a/gcc/config/stormy16/stormy16.cc b/gcc/config/stormy16/stormy16.cc index cd453c2a2f70..10887153906e 100644 --- a/gcc/config/stormy16/stormy16.cc +++ b/gcc/config/stormy16/stormy16.cc @@ -795,8 +795,8 @@ xstormy16_expand_andqi3 (rtx *operands) && (INTVAL (X) + (OFFSET) < 0x100 || INTVAL (X) + (OFFSET) >= 0x7F00)) bool -xstormy16_legitimate_address_p (machine_mode mode ATTRIBUTE_UNUSED, - rtx x, bool strict) +xstormy16_legitimate_address_p (machine_mode mode ATTRIBUTE_UNUSED, rtx x, + bool strict, code_helper) { if (LEGITIMATE_ADDRESS_CONST_INT_P (x, 0)) return true; diff --git a/gcc/config/v850/v850.cc b/gcc/config/v850/v850.cc index 0fb72716b174..416c2841a5c0 100644 --- a/gcc/config/v850/v850.cc +++ b/gcc/config/v850/v850.cc @@ -3030,7 +3030,8 @@ v850_rtx_ok_for_base_p (const_rtx x, bool strict_p) static bool v850_legitimate_address_p (machine_mode mode, rtx x, bool strict_p, - addr_space_t as ATTRIBUTE_UNUSED) + addr_space_t as ATTRIBUTE_UNUSED, + code_helper = ERROR_MARK) { gcc_assert (ADDR_SPACE_GENERIC_P (as)); diff --git a/gcc/config/vax/vax.cc b/gcc/config/vax/vax.cc index 82a176d3bfc9..df9478d881ad 100644 --- a/gcc/config/vax/vax.cc +++ b/gcc/config/vax/vax.cc @@ -46,7 +46,8 @@ along with GCC; see the file COPYING3. If not see #include "target-def.h" static void vax_option_override (void); -static bool vax_legitimate_address_p (machine_mode, rtx, bool); +static bool vax_legitimate_address_p (machine_mode, rtx, bool, + code_helper = ERROR_MARK); static void vax_file_start (void); static void vax_init_libfuncs (void); static void vax_output_mi_thunk (FILE *, tree, HOST_WIDE_INT, @@ -1902,7 +1903,7 @@ indexable_address_p (rtx xfoo0, rtx xfoo1, machine_mode mode, bool strict) The MODE argument is the machine mode for the MEM expression that wants to use this address. */ bool -vax_legitimate_address_p (machine_mode mode, rtx x, bool strict) +vax_legitimate_address_p (machine_mode mode, rtx x, bool strict, code_helper) { rtx xfoo0, xfoo1; diff --git a/gcc/config/visium/visium.cc b/gcc/config/visium/visium.cc index 48a61744db64..5fadbc80be06 100644 --- a/gcc/config/visium/visium.cc +++ b/gcc/config/visium/visium.cc @@ -194,7 +194,8 @@ static rtx_insn *visium_md_asm_adjust (vec &, vec &, static bool visium_legitimate_constant_p (machine_mode, rtx); -static bool visium_legitimate_address_p (machine_mode, rtx, bool); +static bool visium_legitimate_address_p (machine_mode, rtx, bool, + code_helper = ERROR_MARK); static bool visium_print_operand_punct_valid_p (unsigned char); static void visium_print_operand (FILE *, rtx, int); @@ -1818,7 +1819,7 @@ rtx_ok_for_offset_p (machine_mode mode, rtx op) kind of register is required. */ static bool -visium_legitimate_address_p (machine_mode mode, rtx x, bool strict) +visium_legitimate_address_p (machine_mode mode, rtx x, bool strict, code_helper) { rtx base; unsigned int regno; diff --git a/gcc/config/xtensa/xtensa.cc b/gcc/config/xtensa/xtensa.cc index 992e80d824db..af71e2179d0c 100644 --- a/gcc/config/xtensa/xtensa.cc +++ b/gcc/config/xtensa/xtensa.cc @@ -123,7 +123,8 @@ static bool xtensa_mode_dependent_address_p (const_rtx, addr_space_t); static bool xtensa_return_in_msb (const_tree); static void printx (FILE *, signed int); static rtx xtensa_builtin_saveregs (void); -static bool xtensa_legitimate_address_p (machine_mode, rtx, bool); +static bool xtensa_legitimate_address_p (machine_mode, rtx, bool, + code_helper = ERROR_MARK); static unsigned int xtensa_multibss_section_type_flags (tree, const char *, int) ATTRIBUTE_UNUSED; static section *xtensa_select_rtx_section (machine_mode, rtx, @@ -2296,9 +2297,9 @@ xtensa_emit_sibcall (int callop, rtx *operands) return result; } - bool -xtensa_legitimate_address_p (machine_mode mode, rtx addr, bool strict) +xtensa_legitimate_address_p (machine_mode mode, rtx addr, bool strict, + code_helper) { /* Allow constant pool addresses. */ if (mode != BLKmode && GET_MODE_SIZE (mode) >= UNITS_PER_WORD diff --git a/gcc/configure b/gcc/configure index 74297d902915..53a32373a188 100755 --- a/gcc/configure +++ b/gcc/configure @@ -30566,7 +30566,8 @@ $as_echo "$gcc_cv_ld64_major" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking linker version" >&5 $as_echo_n "checking linker version... " >&6; } if test x"${gcc_cv_ld64_version}" = x; then - gcc_cv_ld64_version=`$gcc_cv_ld -v 2>&1 | grep ld64 | sed s/.*ld64-// | awk '{print $1}'` + gcc_cv_ld64_version=`$gcc_cv_ld -v 2>&1 | $EGREP 'ld64|dyld' \ + | sed -e 's/.*ld64-//' -e 's/.*dyld-//'| awk '{print $1}'` fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $gcc_cv_ld64_version" >&5 $as_echo "$gcc_cv_ld64_version" >&6; } @@ -31992,7 +31993,7 @@ fi elif test x$host = x$target; then export_sym_check="$gcc_cv_objdump -T" else - export_sym_check= + export_sym_check="$ac_cv_prog_OBJDUMP -T" fi ;; esac diff --git a/gcc/configure.ac b/gcc/configure.ac index 209dd889dec7..c193c96452a8 100644 --- a/gcc/configure.ac +++ b/gcc/configure.ac @@ -4336,7 +4336,7 @@ case "$target_os" in gcc_cv_as_mmacosx_version_min, [-mmacosx-version-min=10.1], [.text],, [AC_DEFINE(HAVE_AS_MMACOSX_VERSION_MIN_OPTION, 1, - [Define if your Mac OS X assembler supports the -mmacos-version-min option.])]) + [Define if your macOS assembler supports the -mmacos-version-min option.])]) ;; esac @@ -4773,7 +4773,7 @@ foo: nop gcc_cv_as_mllvm_x86_pad_for_align, [-mllvm -x86-pad-for-align=false], [.text],, [AC_DEFINE(HAVE_AS_MLLVM_X86_PAD_FOR_ALIGN, 1, - [Define if your Mac OS X assembler supports -mllvm -x86-pad-for-align=false.])]) + [Define if your macOS assembler supports -mllvm -x86-pad-for-align=false.])]) ;; esac @@ -6257,7 +6257,8 @@ if test x"$ld64_flag" = x"yes"; then # If the version was not specified, try to find it. AC_MSG_CHECKING(linker version) if test x"${gcc_cv_ld64_version}" = x; then - gcc_cv_ld64_version=`$gcc_cv_ld -v 2>&1 | grep ld64 | sed s/.*ld64-// | awk '{print $1}'` + gcc_cv_ld64_version=`$gcc_cv_ld -v 2>&1 | $EGREP 'ld64|dyld' \ + | sed -e 's/.*ld64-//' -e 's/.*dyld-//'| awk '{print $1}'` fi AC_MSG_RESULT($gcc_cv_ld64_version) diff --git a/gcc/coretypes.h b/gcc/coretypes.h index ca8837cef67c..f86dc169a40b 100644 --- a/gcc/coretypes.h +++ b/gcc/coretypes.h @@ -99,6 +99,11 @@ typedef const union tree_node *const_tree; struct gimple; typedef gimple *gimple_seq; struct gimple_stmt_iterator; +class code_helper; + +/* Forward declare rtx_code, so that we can use it in target hooks without + needing to pull in rtl.h. */ +enum rtx_code : unsigned; /* Forward decls for leaf gimple subclasses (for individual gimple codes). Keep this in the same order as the corresponding codes in gimple.def. */ diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index d523b0009541..9191726906cb 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,236 @@ +2023-09-01 Jakub Jelinek + + PR c++/111069 + * cp-tree.h (determine_local_discriminator): Add NAME argument with + NULL_TREE default. + (struct cp_decomp): New type. + (cp_finish_decl): Add DECOMP argument defaulted to nullptr. + (cp_maybe_mangle_decomp): Remove declaration. + (cp_finish_decomp): Add cp_decomp * argument, remove tree and unsigned + args. + (cp_convert_range_for): Likewise. + * decl.cc (determine_local_discriminator): Add NAME argument, use it + if non-NULL, otherwise compute it the old way. + (maybe_commonize_var): Don't return early for structured bindings. + (cp_finish_decl): Add DECOMP argument, if non-NULL, call + cp_maybe_mangle_decomp. + (cp_maybe_mangle_decomp): Make it static with a forward declaration. + Call determine_local_discriminator. Replace FIRST and COUNT arguments + with DECOMP argument. + (cp_finish_decomp): Replace FIRST and COUNT arguments with DECOMP + argument. + * mangle.cc (find_decomp_unqualified_name): Remove. + (write_unqualified_name): Don't call find_decomp_unqualified_name. + (mangle_decomp): Handle mangling of static function/block scope + structured bindings. Don't call decl_mangling_context twice. Call + check_abi_tags, call write_abi_tags for abi version >= 19 and emit + -Wabi warnings if needed. + (write_guarded_var_name): Handle structured bindings. + (mangle_ref_init_variable): Use write_guarded_var_name. + * parser.cc (cp_parser_range_for): Adjust do_range_for_auto_deduction + and cp_convert_range_for callers. + (do_range_for_auto_deduction): Replace DECOMP_FIRST_NAME and + DECOMP_CNT arguments with DECOMP. Adjust cp_finish_decomp caller. + (cp_convert_range_for): Replace DECOMP_FIRST_NAME and + DECOMP_CNT arguments with DECOMP. Don't call cp_maybe_mangle_decomp, + adjust cp_finish_decl and cp_finish_decomp callers. + (cp_parser_decomposition_declaration): Don't call + cp_maybe_mangle_decomp, adjust cp_finish_decl and cp_finish_decomp + callers. + (cp_convert_omp_range_for): Adjust do_range_for_auto_deduction + and cp_finish_decomp callers. + (cp_finish_omp_range_for): Don't call cp_maybe_mangle_decomp, + adjust cp_finish_decl and cp_finish_decomp callers. + * pt.cc (tsubst_omp_for_iterator): Adjust tsubst_decomp_names + caller. + (tsubst_decomp_names): Replace FIRST and CNT arguments with DECOMP. + (tsubst_expr): Don't call cp_maybe_mangle_decomp, adjust + tsubst_decomp_names, cp_finish_decl, cp_finish_decomp and + cp_convert_range_for callers. + +2023-08-30 Marek Polacek + + PR c++/91319 + * parser.cc (cp_parser_initializer_list): Set CONSTRUCTOR_IS_DIRECT_INIT + when the designated initializer is of the .x{} form. + +2023-08-30 Marek Polacek + + PR c++/111173 + * decl.cc (grokdeclarator): Disallow constinit on functions. + +2023-08-29 Marek Polacek + + * call.cc (convert_like_internal): Show where the conversion function + was declared. + (maybe_show_nonconverting_candidate): New. + * cp-tree.h (maybe_show_nonconverting_candidate): Declare. + * typeck.cc (convert_for_assignment): Call it. + +2023-08-25 Sandra Loosemore + + * cp-tree.h (cp_convert_omp_range_for): Adjust declaration. + * parser.cc (struct omp_for_parse_data): New. + (cp_parser_postfix_expression): Diagnose calls to OpenMP runtime + in intervening code. + (check_omp_intervening_code): New. + (cp_parser_statement_seq_opt): Special-case nested loops, blocks, + and other constructs for OpenMP loops. + (cp_parser_iteration_statement): Reject loops in intervening code. + (cp_parser_omp_for_loop_init): Expand comments and tweak the + interface slightly to better distinguish input/output parameters. + (cp_convert_omp_range_for): Likewise. + (cp_parser_omp_loop_nest): New, split from cp_parser_omp_for_loop + and largely rewritten. Add more comments. + (insert_structured_blocks): New. + (find_structured_blocks): New. + (struct sit_data, substitute_in_tree_walker, substitute_in_tree): + New. + (fixup_blocks_walker): New. + (cp_parser_omp_for_loop): Rewrite to use recursive descent instead + of a loop. Add logic to reshuffle the bits of code collected + during parsing so intervening code gets moved to the loop body. + (cp_parser_omp_loop): Remove call to finish_omp_for_block, which + is now redundant. + (cp_parser_omp_simd): Likewise. + (cp_parser_omp_for): Likewise. + (cp_parser_omp_distribute): Likewise. + (cp_parser_oacc_loop): Likewise. + (cp_parser_omp_taskloop): Likewise. + (cp_parser_pragma): Reject OpenMP pragmas in intervening code. + * parser.h (struct cp_parser): Add omp_for_parse_state field. + * pt.cc (tsubst_omp_for_iterator): Adjust call to + cp_convert_omp_range_for. + * semantics.cc (finish_omp_for): Try harder to preserve location + of loop variable init expression for use in diagnostics. + (struct fofb_data, finish_omp_for_block_walker): New. + (finish_omp_for_block): Allow variables to be bound in a BIND_EXPR + nested inside BIND instead of directly in BIND itself. + +2023-08-25 Sandra Loosemore + + * constexpr.cc (cxx_eval_constant_expression): Handle + OMP_STRUCTURED_BLOCK. + * pt.cc (tsubst_expr): Likewise. + +2023-08-25 Uros Bizjak + + * call.cc (build_conditional_expr): + Rename TRUE/FALSE to true/false. + (build_new_op): Ditto. + +2023-08-22 Jason Merrill + + * pt.cc (outer_template_args): Handle non-template argument. + * constraint.cc (maybe_substitute_reqs_for): Pass decl to it. + * cp-tree.h (outer_template_args): Adjust. + +2023-08-22 Jason Merrill + + PR c++/109751 + * cp-tree.h (member_like_constrained_friend_p): Declare. + * decl.cc (member_like_constrained_friend_p): New. + (function_requirements_equivalent_p): Check it. + (duplicate_decls): Check it. + (grokfndecl): Check friend template constraints. + * mangle.cc (decl_mangling_context): Check it. + (write_unqualified_name): Check it. + * pt.cc (uses_outer_template_parms_in_constraints): Fix for friends. + (tsubst_friend_function): Don't check satisfaction. + +2023-08-22 Tobias Burnus + + * parser.cc (cp_parser_omp_clause_defaultmap): Parse + 'all' as category. + +2023-08-15 Chung-Lin Tang + Thomas Schwinge + + * parser.cc (OACC_DATA_CLAUSE_MASK): Add PRAGMA_OACC_CLAUSE_DEFAULT. + +2023-08-14 gnaggnoyil + + DR 2386 + PR c++/110216 + * decl.cc (get_tuple_size): Update implementation for DR 2386. + +2023-08-14 Jason Merrill + + * parser.cc (cp_parser_simple_type_specifier): Handle -std=c++14 + -fconcepts. + +2023-08-12 Patrick Palka + Jason Merrill + + PR c++/106604 + * decl.cc (redeclaration_error_message): Remove special handling + for deduction guides. + (grokfndecl): Give deduction guides a dummy DECL_INITIAL. + +2023-08-11 Patrick Palka + + PR c++/110927 + * parser.cc (cp_parser_type_requirement): Pass + check_dependency_p=true instead of =false. + +2023-08-11 Patrick Palka + + PR c++/71954 + * decl.cc (grokdeclarator): Pass 'dname' instead of + 'unqualified_id' as the name when building the VAR_DECL for a + static data member. Call check_explicit_specialization for a + TEMPLATE_ID_EXPR such member. + * pt.cc (finish_member_template_decl): Return NULL_TREE + instead of 'decl' when DECL_TEMPLATE_SPECIALIZATION is not + set. + +2023-08-11 Patrick Palka + + * ptree.cc (cxx_print_decl): Check for DECL_LANG_SPECIFIC and + TS_DECL_COMMON only when necessary. Print DECL_TEMPLATE_INFO + for all decls that have it, not just VAR_DECL or FUNCTION_DECL. + Also print DECL_USE_TEMPLATE. + (cxx_print_type): Print TYPE_TEMPLATE_INFO. + : Don't print TYPE_TI_ARGS + anymore. + : Print TEMPLATE_TYPE_PARM_INDEX + instead of printing the index, level and original level + individually. + +2023-08-08 Marek Polacek + + * parser.cc (cp_parser_postfix_expression): Adjust the call to + cp_parser_braced_list. + (cp_parser_postfix_open_square_expression): Likewise. + (cp_parser_new_initializer): Likewise. + (cp_parser_assignment_expression): Adjust the call to + cp_parser_initializer_clause. + (cp_parser_lambda_introducer): Adjust the call to cp_parser_initializer. + (cp_parser_range_for): Adjust the call to cp_parser_braced_list. + (cp_parser_jump_statement): Likewise. + (cp_parser_mem_initializer): Likewise. + (cp_parser_template_argument): Likewise. + (cp_parser_default_argument): Adjust the call to cp_parser_initializer. + (cp_parser_initializer): Handle null is_direct_init and non_constant_p + arguments. + (cp_parser_initializer_clause): Handle null non_constant_p argument. + (cp_parser_braced_list): Likewise. + (cp_parser_initializer_list): Likewise. + (cp_parser_member_declaration): Adjust the call to + cp_parser_initializer_clause and cp_parser_initializer. + (cp_parser_yield_expression): Adjust the call to cp_parser_braced_list. + (cp_parser_functional_cast): Likewise. + (cp_parser_late_parse_one_default_arg): Adjust the call to + cp_parser_initializer. + (cp_parser_omp_for_loop_init): Likewise. + (cp_parser_omp_declare_reduction_exprs): Likewise. + +2023-08-08 Nathaniel Shead + + PR c++/100482 + * parser.cc (cp_parser_decltype_expr): Report errors raised by + finish_id_expression. + 2023-08-04 Tamar Christina * cp-tree.h (RANGE_FOR_NOVECTOR): New. diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc index 673ec91d60e0..40d9fdc0516a 100644 --- a/gcc/cp/call.cc +++ b/gcc/cp/call.cc @@ -6058,7 +6058,7 @@ build_conditional_expr (const op_location_t &loc, if (complain & tf_error) { auto_diagnostic_group d; - op_error (loc, COND_EXPR, NOP_EXPR, arg1, arg2, arg3, FALSE); + op_error (loc, COND_EXPR, NOP_EXPR, arg1, arg2, arg3, false); print_z_candidates (loc, candidates); } return error_mark_node; @@ -7129,7 +7129,7 @@ build_new_op (const op_location_t &loc, enum tree_code code, int flags, /* ... Otherwise, report the more generic "no matching operator found" error */ auto_diagnostic_group d; - op_error (loc, code, code2, arg1, arg2, arg3, FALSE); + op_error (loc, code, code2, arg1, arg2, arg3, false); print_z_candidates (loc, candidates); } } @@ -7145,7 +7145,7 @@ build_new_op (const op_location_t &loc, enum tree_code code, int flags, if (complain & tf_error) { auto_diagnostic_group d; - op_error (loc, code, code2, arg1, arg2, arg3, TRUE); + op_error (loc, code, code2, arg1, arg2, arg3, true); print_z_candidates (loc, candidates); } result = error_mark_node; @@ -8459,12 +8459,21 @@ convert_like_internal (conversion *convs, tree expr, tree fn, int argnum, if (pedwarn (loc, 0, "converting to %qT from initializer list " "would use explicit constructor %qD", totype, convfn)) - inform (loc, "in C++11 and above a default constructor " - "can be explicit"); + { + inform (DECL_SOURCE_LOCATION (convfn), "%qD declared here", + convfn); + inform (loc, "in C++11 and above a default constructor " + "can be explicit"); + } } else - error ("converting to %qT from initializer list would use " - "explicit constructor %qD", totype, convfn); + { + auto_diagnostic_group d; + error ("converting to %qT from initializer list would use " + "explicit constructor %qD", totype, convfn); + inform (DECL_SOURCE_LOCATION (convfn), "%qD declared here", + convfn); + } } /* If we're initializing from {}, it's value-initialization. */ @@ -14323,4 +14332,28 @@ is_list_ctor (tree decl) return true; } +/* We know that can_convert_arg_bad already said "no" when trying to convert + FROM to TO with ARG and FLAGS. Try to figure out if it was because + an explicit conversion function was skipped when looking for a way to + perform the conversion. At this point we've already printed an error. */ + +void +maybe_show_nonconverting_candidate (tree to, tree from, tree arg, int flags) +{ + if (!(flags & LOOKUP_ONLYCONVERTING)) + return; + + conversion_obstack_sentinel cos; + conversion *c = implicit_conversion (to, from, arg, /*c_cast_p=*/false, + flags & ~LOOKUP_ONLYCONVERTING, tf_none); + if (c && !c->bad_p && c->user_conv_p) + /* Ay, the conversion would have worked in direct-init context. */ + for (; c; c = next_conversion (c)) + if (c->kind == ck_user + && DECL_P (c->cand->fn) + && DECL_NONCONVERTING_P (c->cand->fn)) + inform (DECL_SOURCE_LOCATION (c->cand->fn), "explicit conversion " + "function was not considered"); +} + #include "gt-cp-call.h" diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc index da2c31168105..8bd5c4a47f81 100644 --- a/gcc/cp/constexpr.cc +++ b/gcc/cp/constexpr.cc @@ -8155,6 +8155,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, case OMP_SCAN: case OMP_SCOPE: case OMP_SECTION: + case OMP_STRUCTURED_BLOCK: case OMP_MASTER: case OMP_MASKED: case OMP_TASKGROUP: diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc index 8cf0f2d09746..c9e4e7043cdc 100644 --- a/gcc/cp/constraint.cc +++ b/gcc/cp/constraint.cc @@ -1339,7 +1339,7 @@ maybe_substitute_reqs_for (tree reqs, const_tree decl) if (DECL_UNIQUE_FRIEND_P (decl) && DECL_TEMPLATE_INFO (decl)) { tree tmpl = DECL_TI_TEMPLATE (decl); - tree outer_args = outer_template_args (tmpl); + tree outer_args = outer_template_args (decl); processing_template_decl_sentinel s; if (PRIMARY_TEMPLATE_P (tmpl) || uses_template_parms (outer_args)) diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index d051ee85f701..3ca011c61c8a 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -6727,6 +6727,7 @@ extern bool cp_handle_deprecated_or_unavailable (tree, tsubst_flags_t = tf_warni extern void cp_warn_deprecated_use_scopes (tree); extern tree get_function_version_dispatcher (tree); extern bool any_template_arguments_need_structural_equality_p (tree); +extern void maybe_show_nonconverting_candidate (tree, tree, tree, int); /* in class.cc */ extern tree build_vfield_ref (tree, tree); @@ -6858,7 +6859,8 @@ extern void pop_switch (void); extern void note_break_stmt (void); extern bool note_iteration_stmt_body_start (void); extern void note_iteration_stmt_body_end (bool); -extern void determine_local_discriminator (tree); +extern void determine_local_discriminator (tree, tree = NULL_TREE); +extern bool member_like_constrained_friend_p (tree); extern bool fns_correspond (tree, tree); extern int decls_match (tree, tree, bool = true); extern bool maybe_version_functions (tree, tree, bool); @@ -6890,10 +6892,10 @@ extern tree start_decl (const cp_declarator *, cp_decl_specifier_seq *, int, extern void start_decl_1 (tree, bool); extern bool check_array_initializer (tree, tree, tree); extern void omp_declare_variant_finalize (tree, tree); -extern void cp_finish_decl (tree, tree, bool, tree, int); +struct cp_decomp { tree decl; unsigned int count; }; +extern void cp_finish_decl (tree, tree, bool, tree, int, cp_decomp * = nullptr); extern tree lookup_decomp_type (tree); -extern void cp_maybe_mangle_decomp (tree, tree, unsigned int); -extern void cp_finish_decomp (tree, tree, unsigned int); +extern void cp_finish_decomp (tree, cp_decomp *); extern int cp_complete_array_type (tree *, tree, bool); extern int cp_complete_array_type_or_error (tree *, tree, bool, tsubst_flags_t); extern tree build_ptrmemfunc_type (tree); @@ -7082,7 +7084,7 @@ extern tree maybe_set_retval_sentinel (void); extern tree template_parms_to_args (tree); extern tree template_parms_level_to_args (tree); extern tree generic_targs_for (tree); -extern tree outer_template_args (tree); +extern tree outer_template_args (const_tree); /* in expr.cc */ extern tree cplus_expand_constant (tree); @@ -7310,9 +7312,9 @@ extern tree clone_attrs (tree); extern bool maybe_clone_body (tree); /* In parser.cc */ -extern tree cp_convert_range_for (tree, tree, tree, tree, unsigned int, bool, +extern tree cp_convert_range_for (tree, tree, tree, cp_decomp *, bool, unsigned short, bool); -extern void cp_convert_omp_range_for (tree &, vec *, tree &, +extern void cp_convert_omp_range_for (tree &, tree &, tree &, tree &, tree &, tree &, tree &, tree &); extern void cp_finish_omp_range_for (tree, tree); extern bool parsing_nsdmi (void); @@ -7385,7 +7387,7 @@ extern tree lookup_template_function (tree, tree); extern tree lookup_template_variable (tree, tree, tsubst_flags_t); extern bool uses_template_parms (tree); extern bool uses_template_parms_level (tree, int); -extern bool uses_outer_template_parms_in_constraints (tree); +extern bool uses_outer_template_parms_in_constraints (tree, tree = NULL_TREE); extern bool need_generic_capture (void); extern tree instantiate_class_template (tree); extern tree instantiate_template (tree, tree, tsubst_flags_t); diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc index 792ab330dd05..89e8b85e3f89 100644 --- a/gcc/cp/decl.cc +++ b/gcc/cp/decl.cc @@ -911,15 +911,16 @@ static GTY((deletable)) vec *local_entities; generally very few of these in any particular function. */ void -determine_local_discriminator (tree decl) +determine_local_discriminator (tree decl, tree name) { auto_cond_timevar tv (TV_NAME_LOOKUP); retrofit_lang_decl (decl); tree ctx = DECL_CONTEXT (decl); - tree name = (TREE_CODE (decl) == TYPE_DECL - && TYPE_UNNAMED_P (TREE_TYPE (decl)) - ? NULL_TREE : DECL_NAME (decl)); size_t nelts = vec_safe_length (local_entities); + if (name == NULL_TREE) + name = (TREE_CODE (decl) == TYPE_DECL + && TYPE_UNNAMED_P (TREE_TYPE (decl)) + ? NULL_TREE : DECL_NAME (decl)); for (size_t i = 0; i < nelts; i += 2) { tree *pair = &(*local_entities)[i]; @@ -951,6 +952,30 @@ determine_local_discriminator (tree decl) } +/* True if DECL is a constrained hidden friend as per [temp.friend]/9: + + A non-template friend declaration with a requires-clause shall be a + definition. A friend function template with a constraint that depends on a + template parameter from an enclosing template shall be a definition. Such a + constrained friend function or function template declaration does not + declare the same function or function template as a declaration in any other + scope. + + The ABI calls this a "member-like constrained friend" and mangles it like a + member function to avoid collisions. */ + +bool +member_like_constrained_friend_p (tree decl) +{ + return (TREE_CODE (decl) == FUNCTION_DECL + && DECL_UNIQUE_FRIEND_P (decl) + && DECL_FRIEND_CONTEXT (decl) + && get_constraints (decl) + && (!DECL_TEMPLATE_INFO (decl) + || !PRIMARY_TEMPLATE_P (DECL_TI_TEMPLATE (decl)) + || (uses_outer_template_parms_in_constraints + (most_general_template (decl))))); +} /* Returns true if functions FN1 and FN2 have equivalent trailing requires clauses. */ @@ -968,6 +993,13 @@ function_requirements_equivalent_p (tree newfn, tree oldfn) return cp_tree_equal (req1, req2); } + /* [temp.friend]/9 "Such a constrained friend function does not declare the + same function as a declaration in any other scope." So no need to + actually compare the requirements. */ + if (member_like_constrained_friend_p (newfn) + || member_like_constrained_friend_p (oldfn)) + return false; + /* Compare only trailing requirements. */ tree reqs1 = get_trailing_function_requirements (newfn); tree reqs2 = get_trailing_function_requirements (oldfn); @@ -1936,6 +1968,10 @@ duplicate_decls (tree newdecl, tree olddecl, bool hiding, bool was_hidden) are not ambiguous. */ else if ((!DECL_FUNCTION_VERSIONED (newdecl) && !DECL_FUNCTION_VERSIONED (olddecl)) + /* Let constrained hidden friends coexist for now, we'll + check satisfaction later. */ + && !member_like_constrained_friend_p (newdecl) + && !member_like_constrained_friend_p (olddecl) // The functions have the same parameter types. && compparms (TYPE_ARG_TYPES (TREE_TYPE (newdecl)), TYPE_ARG_TYPES (TREE_TYPE (olddecl))) @@ -3297,10 +3333,6 @@ redeclaration_error_message (tree newdecl, tree olddecl) } } - if (deduction_guide_p (olddecl) - && deduction_guide_p (newdecl)) - return G_("deduction guide %q+D redeclared"); - /* [class.compare.default]: A definition of a comparison operator as defaulted that appears in a class shall be the first declaration of that function. */ @@ -3355,10 +3387,6 @@ redeclaration_error_message (tree newdecl, tree olddecl) } } - if (deduction_guide_p (olddecl) - && deduction_guide_p (newdecl)) - return G_("deduction guide %q+D redeclared"); - /* Core issue #226 (C++11): If a friend function template declaration specifies a @@ -6390,8 +6418,9 @@ layout_var_decl (tree decl) void maybe_commonize_var (tree decl) { - /* Don't mess with __FUNCTION__ and similar. */ - if (DECL_ARTIFICIAL (decl)) + /* Don't mess with __FUNCTION__ and similar. But do handle structured + bindings. */ + if (DECL_ARTIFICIAL (decl) && !DECL_DECOMPOSITION_P (decl)) return; /* Static data in a function with comdat linkage also has comdat @@ -8185,6 +8214,8 @@ omp_declare_variant_finalize (tree decl, tree attr) } } +static void cp_maybe_mangle_decomp (tree, cp_decomp *); + /* Finish processing of a declaration; install its line number and initial value. If the length of an array type is not known before, @@ -8194,11 +8225,14 @@ omp_declare_variant_finalize (tree decl, tree attr) true, then INIT is an integral constant expression. FLAGS is LOOKUP_ONLYCONVERTING if the = init syntax was used, else 0 - if the (init) syntax was used. */ + if the (init) syntax was used. + + DECOMP is first identifier's DECL and identifier count in a structured + bindings, nullptr if not a structured binding. */ void cp_finish_decl (tree decl, tree init, bool init_const_expr_p, - tree asmspec_tree, int flags) + tree asmspec_tree, int flags, cp_decomp *decomp) { vec *cleanups = NULL; const char *asmspec = NULL; @@ -8573,6 +8607,9 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p, return; } + if (decomp) + cp_maybe_mangle_decomp (decl, decomp); + /* If this is a local variable that will need a mangled name, register it now. We must do this before processing the initializer for the variable, since the initialization might @@ -8940,10 +8977,14 @@ get_tuple_size (tree type) /*context*/std_node, /*entering_scope*/false, tf_none); inst = complete_type (inst); - if (inst == error_mark_node || !COMPLETE_TYPE_P (inst)) + if (inst == error_mark_node + || !COMPLETE_TYPE_P (inst) + || !CLASS_TYPE_P (type)) return NULL_TREE; tree val = lookup_qualified_name (inst, value_identifier, LOOK_want::NORMAL, /*complain*/false); + if (val == error_mark_node) + return NULL_TREE; if (VAR_P (val) || TREE_CODE (val) == CONST_DECL) val = maybe_constant_value (val); if (TREE_CODE (val) == INTEGER_CST) @@ -9039,18 +9080,37 @@ lookup_decomp_type (tree v) /* Mangle a decomposition declaration if needed. Arguments like in cp_finish_decomp. */ -void -cp_maybe_mangle_decomp (tree decl, tree first, unsigned int count) +static void +cp_maybe_mangle_decomp (tree decl, cp_decomp *decomp) { if (!processing_template_decl && !error_operand_p (decl) && TREE_STATIC (decl)) { auto_vec v; - v.safe_grow (count, true); - tree d = first; - for (unsigned int i = 0; i < count; i++, d = DECL_CHAIN (d)) - v[count - i - 1] = d; + v.safe_grow (decomp->count, true); + tree d = decomp->decl; + for (unsigned int i = 0; i < decomp->count; i++, d = DECL_CHAIN (d)) + v[decomp->count - i - 1] = d; + if (DECL_FUNCTION_SCOPE_P (decl)) + { + size_t sz = 3; + for (unsigned int i = 0; i < decomp->count; ++i) + sz += IDENTIFIER_LENGTH (DECL_NAME (v[i])) + 1; + char *name = XALLOCAVEC (char, sz); + name[0] = 'D'; + name[1] = 'C'; + char *p = name + 2; + for (unsigned int i = 0; i < decomp->count; ++i) + { + size_t len = IDENTIFIER_LENGTH (DECL_NAME (v[i])); + *p++ = ' '; + memcpy (p, IDENTIFIER_POINTER (DECL_NAME (v[i])), len); + p += len; + } + *p = '\0'; + determine_local_discriminator (decl, get_identifier (name)); + } SET_DECL_ASSEMBLER_NAME (decl, mangle_decomp (decl, v)); maybe_apply_pragma_weak (decl); } @@ -9062,8 +9122,10 @@ cp_maybe_mangle_decomp (tree decl, tree first, unsigned int count) those decls. */ void -cp_finish_decomp (tree decl, tree first, unsigned int count) +cp_finish_decomp (tree decl, cp_decomp *decomp) { + tree first = decomp->decl; + unsigned count = decomp->count; if (error_operand_p (decl)) { error_out: @@ -10309,16 +10371,28 @@ grokfndecl (tree ctype, ci = NULL_TREE; } /* C++20 CA378: Remove non-templated constrained functions. */ + /* [temp.friend]/9 A non-template friend declaration with a + requires-clause shall be a definition. A friend function template with + a constraint that depends on a template parameter from an enclosing + template shall be a definition. */ if (ci && (block_local || (!flag_concepts_ts && (!processing_template_decl || (friendp && !memtmpl && !funcdef_flag))))) { - error_at (location, "constraints on a non-templated function"); + if (!friendp || !processing_template_decl) + error_at (location, "constraints on a non-templated function"); + else + error_at (location, "constrained non-template friend declaration" + " must be a definition"); ci = NULL_TREE; } set_constraints (decl, ci); + if (ci && friendp && memtmpl && !funcdef_flag + && uses_outer_template_parms_in_constraints (decl, ctx)) + error_at (location, "friend function template with constraints that " + "depend on outer template parameters must be a definition"); } if (TREE_CODE (type) == METHOD_TYPE) @@ -10352,6 +10426,12 @@ grokfndecl (tree ctype, DECL_CXX_DESTRUCTOR_P (decl) = 1; DECL_NAME (decl) = dtor_identifier; break; + case sfk_deduction_guide: + /* Give deduction guides a definition even though they don't really + have one: the restriction that you can't repeat a deduction guide + makes them more like a definition anyway. */ + DECL_INITIAL (decl) = void_node; + break; default: break; } @@ -14439,7 +14519,16 @@ grokdeclarator (const cp_declarator *declarator, /* C++ allows static class members. All other work for this is done by grokfield. */ decl = build_lang_decl_loc (id_loc, VAR_DECL, - unqualified_id, type); + dname, type); + if (unqualified_id + && TREE_CODE (unqualified_id) == TEMPLATE_ID_EXPR) + { + decl = check_explicit_specialization (unqualified_id, decl, + template_count, + concept_p * 8); + if (decl == error_mark_node) + return error_mark_node; + } set_linkage_for_static_data_member (decl); if (concept_p) error_at (declspecs->locations[ds_concept], @@ -14581,6 +14670,9 @@ grokdeclarator (const cp_declarator *declarator, "storage class % invalid for " "function %qs", name); } + else if (constinit_p) + error_at (declspecs->locations[ds_constinit], + "% specifier invalid for function %qs", name); if (virt_specifiers) error ("virt-specifiers in %qs not allowed outside a class " diff --git a/gcc/cp/mangle.cc b/gcc/cp/mangle.cc index bef0fda6d229..d88c779bfa2e 100644 --- a/gcc/cp/mangle.cc +++ b/gcc/cp/mangle.cc @@ -963,6 +963,9 @@ decl_mangling_context (tree decl) tcontext = CP_DECL_CONTEXT (decl); + if (member_like_constrained_friend_p (decl)) + tcontext = DECL_FRIEND_CONTEXT (decl); + /* Ignore the artificial declare reduction functions. */ if (tcontext && TREE_CODE (tcontext) == FUNCTION_DECL @@ -1344,51 +1347,6 @@ write_template_prefix (const tree node) add_substitution (substitution); } -/* As the list of identifiers for the structured binding declaration - DECL is likely gone, try to recover the DC + E portion - from its mangled name. Return pointer to the DC and set len to - the length up to and including the terminating E. On failure - return NULL. */ - -static const char * -find_decomp_unqualified_name (tree decl, size_t *len) -{ - const char *p = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)); - const char *end = p + IDENTIFIER_LENGTH (DECL_ASSEMBLER_NAME (decl)); - bool nested = false; - if (!startswith (p, "_Z")) - return NULL; - p += 2; - if (startswith (p, "St")) - p += 2; - else if (*p == 'N') - { - nested = true; - ++p; - while (ISDIGIT (p[0])) - { - char *e; - long num = strtol (p, &e, 10); - if (num >= 1 && num < end - e) - p = e + num; - else - break; - } - } - if (!startswith (p, "DC")) - return NULL; - if (nested) - { - if (end[-1] != 'E') - return NULL; - --end; - } - if (end[-1] != 'E') - return NULL; - *len = end - p; - return p; -} - /* "For the purposes of mangling, the name of an anonymous union is considered to be the name of the first named data member found by a pre-order, depth-first, declaration-order walk of the data members of the anonymous @@ -1419,6 +1377,7 @@ anon_aggr_naming_decl (tree type) ::= [] ::= [] ::= + ::= F # member-like constrained friend ::= L */ @@ -1461,21 +1420,17 @@ write_unqualified_name (tree decl) { found = true; gcc_assert (DECL_ASSEMBLER_NAME_SET_P (decl)); - const char *decomp_str = NULL; - size_t decomp_len = 0; - if (VAR_P (decl) - && DECL_DECOMPOSITION_P (decl) - && DECL_NAME (decl) == NULL_TREE - && DECL_NAMESPACE_SCOPE_P (decl)) - decomp_str = find_decomp_unqualified_name (decl, &decomp_len); - if (decomp_str) - write_chars (decomp_str, decomp_len); - else - write_source_name (DECL_ASSEMBLER_NAME (decl)); + write_source_name (DECL_ASSEMBLER_NAME (decl)); } else if (DECL_DECLARES_FUNCTION_P (decl)) { found = true; + + /* A constrained hidden friend is mangled like a member function, with + the name prefixed by 'F'. */ + if (member_like_constrained_friend_p (decl)) + write_char ('F'); + if (DECL_CONSTRUCTOR_P (decl)) write_special_name_constructor (decl); else if (DECL_DESTRUCTOR_P (decl)) @@ -4363,6 +4318,7 @@ mangle_decomp (const tree decl, vec &decls) location_t saved_loc = input_location; input_location = DECL_SOURCE_LOCATION (decl); + check_abi_tags (decl); start_mangling (decl); write_string ("_Z"); @@ -4370,13 +4326,21 @@ mangle_decomp (const tree decl, vec &decls) gcc_assert (context != NULL_TREE); bool nested = false; + bool local = false; if (DECL_NAMESPACE_STD_P (context)) write_string ("St"); + else if (TREE_CODE (context) == FUNCTION_DECL) + { + local = true; + write_char ('Z'); + write_encoding (context); + write_char ('E'); + } else if (context != global_namespace) { nested = true; write_char ('N'); - write_prefix (decl_mangling_context (decl)); + write_prefix (context); } write_string ("DC"); @@ -4386,8 +4350,22 @@ mangle_decomp (const tree decl, vec &decls) write_unqualified_name (d); write_char ('E'); + if (tree tags = get_abi_tags (decl)) + { + /* We didn't emit ABI tags for structured bindings before ABI 19. */ + if (!G.need_abi_warning + && TREE_PUBLIC (decl) + && abi_warn_or_compat_version_crosses (19)) + G.need_abi_warning = 1; + + if (abi_version_at_least (19)) + write_abi_tags (tags); + } + if (nested) write_char ('E'); + else if (local && DECL_DISCRIMINATOR_P (decl)) + write_discriminator (discriminator_for_local_entity (decl)); tree id = finish_mangling_get_identifier (); if (DEBUG_MANGLE) @@ -4395,6 +4373,37 @@ mangle_decomp (const tree decl, vec &decls) IDENTIFIER_POINTER (id)); input_location = saved_loc; + + if (warn_abi && G.need_abi_warning) + { + const char fabi_version[] = "-fabi-version"; + tree id2 = id; + int save_ver = flag_abi_version; + + if (flag_abi_version != warn_abi_version) + { + flag_abi_version = warn_abi_version; + id2 = mangle_decomp (decl, decls); + flag_abi_version = save_ver; + } + + if (id2 == id) + /* OK. */; + else if (warn_abi_version != 0 + && abi_version_at_least (warn_abi_version)) + warning_at (DECL_SOURCE_LOCATION (G.entity), OPT_Wabi, + "the mangled name of %qD changed between " + "%<%s=%d%> (%qD) and %<%s=%d%> (%qD)", + G.entity, fabi_version, warn_abi_version, id2, + fabi_version, save_ver, id); + else + warning_at (DECL_SOURCE_LOCATION (G.entity), OPT_Wabi, + "the mangled name of %qD changes between " + "%<%s=%d%> (%qD) and %<%s=%d%> (%qD)", + G.entity, fabi_version, save_ver, id, + fabi_version, warn_abi_version, id2); + } + return id; } @@ -4564,6 +4573,13 @@ write_guarded_var_name (const tree variable) /* The name of a guard variable for a reference temporary should refer to the reference, not the temporary. */ write_string (IDENTIFIER_POINTER (DECL_NAME (variable)) + 4); + else if (DECL_DECOMPOSITION_P (variable) + && DECL_NAME (variable) == NULL_TREE + && startswith (IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (variable)), + "_Z")) + /* The name of a guard variable for a structured binding needs special + casing. */ + write_string (IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (variable)) + 2); else write_name (variable, /*ignore_local_scope=*/0); } @@ -4630,7 +4646,7 @@ mangle_ref_init_variable (const tree variable) start_mangling (variable); write_string ("_ZGR"); check_abi_tags (variable); - write_name (variable, /*ignore_local_scope=*/0); + write_guarded_var_name (variable); /* Avoid name clashes with aggregate initialization of multiple references at once. */ write_compact_number (current_ref_temp_count++); diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc index ba15a095e83e..7811d582b072 100644 --- a/gcc/cp/parser.cc +++ b/gcc/cp/parser.cc @@ -261,6 +261,10 @@ static bool cp_parser_omp_declare_reduction_exprs static void cp_finalize_oacc_routine (cp_parser *, tree, bool); +static void check_omp_intervening_code + (cp_parser *); + + /* Manifest constants. */ #define CP_LEXER_BUFFER_SIZE ((256 * 1024) / sizeof (cp_token)) #define CP_SAVED_TOKEN_STACK 5 @@ -2100,6 +2104,52 @@ struct cp_parser_expression_stack_entry typedef struct cp_parser_expression_stack_entry cp_parser_expression_stack[NUM_PREC_VALUES]; +/* Used for parsing OMP for loops. + + Some notes on flags used for context: + parser->omp_for_parse_state is non-null anywhere inside the OMP FOR + construct, except for the final-loop-body. + The want_nested_loop flag is true if inside a {} sequence where + a loop-nest (or another {} sequence containing a loop-nest) is expected, + but has not yet been seen. It's false when parsing intervening code + statements or their substatements that cannot contain a loop-nest. + The in_intervening_code flag is true when parsing any intervening code, + including substatements, and whether or not want_nested_loop is true. + + And, about error handling: + The saw_intervening_code flag is set if the loop is not perfectly + nested, even in the usual case where this is not an error. + perfect_nesting_fail is set if an error has been diagnosed because an + imperfectly-nested loop was found where a perfectly-nested one is + required (we diagnose this only once). + fail is set if any kind of structural error in the loop nest + has been found and diagnosed. + */ +struct omp_for_parse_data { + enum tree_code code; + tree declv, condv, incrv, initv; + tree pre_body; + tree orig_declv; + auto_vec orig_inits; + int count; /* Expected nesting depth. */ + int depth; /* Current nesting depth. */ + location_t for_loc; + releasing_vec init_blockv; + releasing_vec body_blockv; + releasing_vec init_placeholderv; + releasing_vec body_placeholderv; + bool ordered : 1; + bool inscan : 1; + bool want_nested_loop : 1; + bool in_intervening_code : 1; + bool saw_intervening_code : 1; + bool perfect_nesting_fail : 1; + bool fail : 1; + tree clauses; + tree *cclauses; + tree ordered_cl; +}; + /* Prototypes. */ /* Constructors and destructors. */ @@ -2343,7 +2393,7 @@ static tree cp_parser_c_for static tree cp_parser_range_for (cp_parser *, tree, tree, tree, bool, unsigned short, bool, bool); static void do_range_for_auto_deduction - (tree, tree, tree, unsigned int); + (tree, tree, cp_decomp *); static tree cp_parser_perform_range_for_lookup (tree, tree *, tree *); static tree cp_parser_range_for_member_function @@ -2492,11 +2542,11 @@ static tree cp_parser_default_argument static void cp_parser_function_body (cp_parser *, bool); static tree cp_parser_initializer - (cp_parser *, bool *, bool *, bool = false); + (cp_parser *, bool * = nullptr, bool * = nullptr, bool = false); static cp_expr cp_parser_initializer_clause - (cp_parser *, bool *); + (cp_parser *, bool * = nullptr); static cp_expr cp_parser_braced_list - (cp_parser*, bool*); + (cp_parser*, bool * = nullptr); static vec *cp_parser_initializer_list (cp_parser *, bool *, bool *); @@ -2921,6 +2971,7 @@ static bool cp_parser_skip_up_to_closing_square_bracket static bool cp_parser_skip_to_closing_square_bracket (cp_parser *); static size_t cp_parser_skip_balanced_tokens (cp_parser *, size_t); +static tree cp_parser_omp_loop_nest (cp_parser *, bool *); // -------------------------------------------------------------------------- // // Unevaluated Operand Guard @@ -7743,12 +7794,8 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p, /* If things aren't going well, there's no need to keep going. */ if (!cp_parser_error_occurred (parser)) - { - bool non_constant_p; - /* Parse the brace-enclosed initializer list. */ - initializer = cp_parser_braced_list (parser, - &non_constant_p); - } + /* Parse the brace-enclosed initializer list. */ + initializer = cp_parser_braced_list (parser); /* If that worked, we're definitely looking at a compound-literal expression. */ if (cp_parser_parse_definitely (parser)) @@ -8008,12 +8055,22 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p, complain); else /* All other function calls. */ - postfix_expression - = finish_call_expr (postfix_expression, &args, - /*disallow_virtual=*/false, - koenig_p, - complain); - + { + if (DECL_P (postfix_expression) + && parser->omp_for_parse_state + && parser->omp_for_parse_state->in_intervening_code + && omp_runtime_api_call (postfix_expression)) + { + error_at (loc, "calls to the OpenMP runtime API are " + "not permitted in intervening code"); + parser->omp_for_parse_state->fail = true; + } + postfix_expression + = finish_call_expr (postfix_expression, &args, + /*disallow_virtual=*/false, + koenig_p, + complain); + } if (close_paren_loc != UNKNOWN_LOCATION) postfix_expression.set_location (combined_loc); @@ -8212,10 +8269,9 @@ cp_parser_postfix_open_square_expression (cp_parser *parser, } else if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE)) { - bool expr_nonconst_p; cp_lexer_set_source_position (parser->lexer); maybe_warn_cpp0x (CPP0X_INITIALIZER_LISTS); - index = cp_parser_braced_list (parser, &expr_nonconst_p); + index = cp_parser_braced_list (parser); } else index = cp_parser_expression (parser, NULL, /*cast_p=*/false, @@ -9649,12 +9705,10 @@ cp_parser_new_initializer (cp_parser* parser) if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE)) { - tree t; - bool expr_non_constant_p; cp_lexer_set_source_position (parser->lexer); maybe_warn_cpp0x (CPP0X_INITIALIZER_LISTS); - t = cp_parser_braced_list (parser, &expr_non_constant_p); - CONSTRUCTOR_IS_DIRECT_INIT (t) = 1; + tree t = cp_parser_braced_list (parser); + CONSTRUCTOR_IS_DIRECT_INIT (t) = true; expression_list = make_tree_vector_single (t); } else @@ -10514,11 +10568,8 @@ cp_parser_assignment_expression (cp_parser* parser, cp_id_kind * pidk, = cp_parser_assignment_operator_opt (parser); if (assignment_operator != ERROR_MARK) { - bool non_constant_p; - /* Parse the right-hand side of the assignment. */ - cp_expr rhs = cp_parser_initializer_clause (parser, - &non_constant_p); + cp_expr rhs = cp_parser_initializer_clause (parser); if (BRACE_ENCLOSED_INITIALIZER_P (rhs)) maybe_warn_cpp0x (CPP0X_INITIALIZER_LISTS); @@ -11422,14 +11473,15 @@ cp_parser_lambda_introducer (cp_parser* parser, tree lambda_expr) || cp_lexer_next_token_is (parser->lexer, CPP_OPEN_PAREN) || cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE)) { - bool direct, non_constant; /* An explicit initializer exists. */ if (cxx_dialect < cxx14) pedwarn (input_location, OPT_Wc__14_extensions, "lambda capture initializers " "only available with %<-std=c++14%> or %<-std=gnu++14%>"); - capture_init_expr = cp_parser_initializer (parser, &direct, - &non_constant, true); + capture_init_expr = cp_parser_initializer (parser, + /*direct_init=*/nullptr, + /*non_constant=*/nullptr, + /*subexpression_p=*/true); explicit_init_p = true; if (capture_init_expr == NULL_TREE) { @@ -12531,9 +12583,15 @@ cp_parser_statement (cp_parser* parser, tree in_statement_expr, return so that we can check for a close brace. Otherwise we require a real statement and must go back and read one. */ if (in_compound_for_pragma) - cp_parser_pragma (parser, pragma_compound, if_p); + { + if (cp_parser_pragma (parser, pragma_compound, if_p) + && parser->omp_for_parse_state) + check_omp_intervening_code (parser); + } else if (!cp_parser_pragma (parser, pragma_stmt, if_p)) do_restart = true; + else if (parser->omp_for_parse_state) + check_omp_intervening_code (parser); if (parser->lexer != lexer && lexer->in_omp_attribute_pragma && (!in_omp_attribute_pragma || lexer->orphan_p)) @@ -12969,6 +13027,55 @@ cp_parser_compound_statement (cp_parser *parser, tree in_statement_expr, return compound_stmt; } +/* Diagnose errors related to imperfectly nested loops in an OMP + loop construct. This function is called when such code is seen. + Only issue one such diagnostic no matter how much invalid + intervening code there is in the loop. + FIXME: maybe the location associated with the diagnostic should + be the current parser token instead of the location of the outer loop + nest. */ + +static void +check_omp_intervening_code (cp_parser *parser) +{ + struct omp_for_parse_data *omp_for_parse_state + = parser->omp_for_parse_state; + gcc_assert (omp_for_parse_state); + + if (!omp_for_parse_state->in_intervening_code) + return; + omp_for_parse_state->saw_intervening_code = true; + + /* Only diagnose errors related to perfect nesting once. */ + if (!omp_for_parse_state->perfect_nesting_fail) + { + if (omp_for_parse_state->code == OACC_LOOP) + { + error_at (omp_for_parse_state->for_loc, + "inner loops must be perfectly nested in " + "%<#pragma acc loop%>"); + omp_for_parse_state->perfect_nesting_fail = true; + } + else if (omp_for_parse_state->ordered) + { + error_at (omp_for_parse_state->for_loc, + "inner loops must be perfectly nested with " + "% clause"); + omp_for_parse_state->perfect_nesting_fail = true; + } + else if (omp_for_parse_state->inscan) + { + error_at (omp_for_parse_state->for_loc, + "inner loops must be perfectly nested with " + "% % clause"); + omp_for_parse_state->perfect_nesting_fail = true; + } + /* TODO: Also reject loops with TILE directive. */ + if (omp_for_parse_state->perfect_nesting_fail) + omp_for_parse_state->fail = true; + } +} + /* Parse an (optional) statement-seq. statement-seq: @@ -12978,6 +13085,11 @@ cp_parser_compound_statement (cp_parser *parser, tree in_statement_expr, static void cp_parser_statement_seq_opt (cp_parser* parser, tree in_statement_expr) { + struct omp_for_parse_data *omp_for_parse_state + = parser->omp_for_parse_state; + bool in_omp_loop_block + = omp_for_parse_state ? omp_for_parse_state->want_nested_loop : false; + /* Scan statements until there aren't any more. */ while (true) { @@ -13005,6 +13117,50 @@ cp_parser_statement_seq_opt (cp_parser* parser, tree in_statement_expr) } } + /* Handle special cases for OMP FOR canonical loop syntax. */ + else if (in_omp_loop_block) + { + bool want_nested_loop = omp_for_parse_state->want_nested_loop; + if (want_nested_loop + && token->type == CPP_KEYWORD && token->keyword == RID_FOR) + { + /* Found the nested loop. */ + omp_for_parse_state->depth++; + add_stmt (cp_parser_omp_loop_nest (parser, NULL)); + omp_for_parse_state->depth--; + } + else if (token->type == CPP_SEMICOLON) + { + /* Prior to implementing the OpenMP 5.1 syntax for canonical + loop form, GCC used to accept an empty statements as not + being intervening code. Continue to do that, as an + extension. */ + /* FIXME: Maybe issue a warning or something here? */ + cp_lexer_consume_token (parser->lexer); + } + else if (want_nested_loop && token->type == CPP_OPEN_BRACE) + /* The nested compound statement may contain the next loop, or + it might just be intervening code. */ + { + cp_parser_statement (parser, in_statement_expr, true, NULL); + if (omp_for_parse_state->want_nested_loop) + check_omp_intervening_code (parser); + } + else + { + /* This must be intervening code. */ + omp_for_parse_state->want_nested_loop = false; + /* Defer calling check_omp_intervening_code on pragmas until + cp_parser_statement, because we can't know until we parse + it whether or not the pragma is a statement. */ + if (token->type != CPP_PRAGMA) + check_omp_intervening_code (parser); + cp_parser_statement (parser, in_statement_expr, true, NULL); + omp_for_parse_state->want_nested_loop = want_nested_loop; + } + continue; + } + /* Parse the statement. */ cp_parser_statement (parser, in_statement_expr, true, NULL); } @@ -13698,8 +13854,7 @@ cp_parser_range_for (cp_parser *parser, tree scope, tree init, tree range_decl, tree stmt, range_expr; auto_vec bindings; auto_vec names; - tree decomp_first_name = NULL_TREE; - unsigned int decomp_cnt = 0; + cp_decomp decomp_d, *decomp = NULL; /* Get the range declaration momentarily out of the way so that the range expression doesn't clash with it. */ @@ -13716,9 +13871,11 @@ cp_parser_range_for (cp_parser *parser, tree scope, tree init, tree range_decl, { tree d = range_decl; range_decl = TREE_OPERAND (v, 0); - decomp_cnt = tree_to_uhwi (TREE_OPERAND (v, 1)) + 1; - decomp_first_name = d; - for (unsigned int i = 0; i < decomp_cnt; i++, d = DECL_CHAIN (d)) + decomp = &decomp_d; + decomp->count = tree_to_uhwi (TREE_OPERAND (v, 1)) + 1; + decomp->decl = d; + for (unsigned int i = 0; i < decomp->count; + i++, d = DECL_CHAIN (d)) { tree name = DECL_NAME (d); names.safe_push (name); @@ -13738,10 +13895,7 @@ cp_parser_range_for (cp_parser *parser, tree scope, tree init, tree range_decl, } if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE)) - { - bool expr_non_constant_p; - range_expr = cp_parser_braced_list (parser, &expr_non_constant_p); - } + range_expr = cp_parser_braced_list (parser); else range_expr = cp_parser_expression (parser); @@ -13775,15 +13929,13 @@ cp_parser_range_for (cp_parser *parser, tree scope, tree init, tree range_decl, if (!type_dependent_expression_p (range_expr) /* do_auto_deduction doesn't mess with template init-lists. */ && !BRACE_ENCLOSED_INITIALIZER_P (range_expr)) - do_range_for_auto_deduction (range_decl, range_expr, decomp_first_name, - decomp_cnt); + do_range_for_auto_deduction (range_decl, range_expr, decomp); } else { stmt = begin_for_stmt (scope, init); - stmt = cp_convert_range_for (stmt, range_decl, range_expr, - decomp_first_name, decomp_cnt, ivdep, - unroll, novector); + stmt = cp_convert_range_for (stmt, range_decl, range_expr, decomp, + ivdep, unroll, novector); } return stmt; } @@ -13815,8 +13967,7 @@ build_range_temp (tree range_expr) a shortcut version of cp_convert_range_for. */ static void -do_range_for_auto_deduction (tree decl, tree range_expr, - tree decomp_first_name, unsigned int decomp_cnt) +do_range_for_auto_deduction (tree decl, tree range_expr, cp_decomp *decomp) { tree auto_node = type_uses_auto (TREE_TYPE (decl)); if (auto_node) @@ -13837,7 +13988,7 @@ do_range_for_auto_deduction (tree decl, tree range_expr, tf_warning_or_error, adc_variable_type); if (VAR_P (decl) && DECL_DECOMPOSITION_P (decl)) - cp_finish_decomp (decl, decomp_first_name, decomp_cnt); + cp_finish_decomp (decl, decomp); } } } @@ -13960,8 +14111,8 @@ warn_for_range_copy (tree decl, tree expr) tree cp_convert_range_for (tree statement, tree range_decl, tree range_expr, - tree decomp_first_name, unsigned int decomp_cnt, - bool ivdep, unsigned short unroll, bool novector) + cp_decomp *decomp, bool ivdep, unsigned short unroll, + bool novector) { tree begin, end; tree iter_type, begin_expr, end_expr; @@ -14029,17 +14180,14 @@ cp_convert_range_for (tree statement, tree range_decl, tree range_expr, tf_warning_or_error); finish_for_expr (expression, statement); - if (VAR_P (range_decl) && DECL_DECOMPOSITION_P (range_decl)) - cp_maybe_mangle_decomp (range_decl, decomp_first_name, decomp_cnt); - /* The declaration is initialized with *__begin inside the loop body. */ tree deref_begin = build_x_indirect_ref (input_location, begin, RO_UNARY_STAR, NULL_TREE, tf_warning_or_error); cp_finish_decl (range_decl, deref_begin, /*is_constant_init*/false, NULL_TREE, - LOOKUP_ONLYCONVERTING); + LOOKUP_ONLYCONVERTING, decomp); if (VAR_P (range_decl) && DECL_DECOMPOSITION_P (range_decl)) - cp_finish_decomp (range_decl, decomp_first_name, decomp_cnt); + cp_finish_decomp (range_decl, decomp); warn_for_range_copy (range_decl, deref_begin); @@ -14207,6 +14355,15 @@ cp_parser_iteration_statement (cp_parser* parser, bool *if_p, bool ivdep, statement. */ in_statement = parser->in_statement; + /* Special case for OMP loop intervening code. Parsing of permitted + collapsed loop nests is handled elsewhere. */ + if (parser->omp_for_parse_state) + { + error_at (token->location, + "loop not permitted in intervening code in OpenMP loop body"); + parser->omp_for_parse_state->fail = true; + } + /* See what kind of keyword it is. */ keyword = token->keyword; switch (keyword) @@ -14451,13 +14608,12 @@ cp_parser_jump_statement (cp_parser* parser) case RID_RETURN: { tree expr; - bool expr_non_constant_p; if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE)) { cp_lexer_set_source_position (parser->lexer); maybe_warn_cpp0x (CPP0X_INITIALIZER_LISTS); - expr = cp_parser_braced_list (parser, &expr_non_constant_p); + expr = cp_parser_braced_list (parser); } else if (cp_lexer_next_token_is_not (parser->lexer, CPP_SEMICOLON)) expr = cp_parser_expression (parser); @@ -15729,18 +15885,20 @@ cp_parser_decomposition_declaration (cp_parser *parser, if (decl != error_mark_node) { - cp_maybe_mangle_decomp (decl, prev, v.length ()); + cp_decomp decomp = { prev, v.length () }; cp_finish_decl (decl, initializer, non_constant_p, NULL_TREE, - (is_direct_init ? LOOKUP_NORMAL : LOOKUP_IMPLICIT)); - cp_finish_decomp (decl, prev, v.length ()); + (is_direct_init ? LOOKUP_NORMAL : LOOKUP_IMPLICIT), + &decomp); + cp_finish_decomp (decl, &decomp); } } else if (decl != error_mark_node) { *maybe_range_for_decl = prev; + cp_decomp decomp = { prev, v.length () }; /* Ensure DECL_VALUE_EXPR is created for all the decls but the underlying DECL. */ - cp_finish_decomp (decl, prev, v.length ()); + cp_finish_decomp (decl, &decomp); } if (pushed_scope) @@ -16520,10 +16678,6 @@ cp_parser_decltype_expr (cp_parser *parser, expr = cp_parser_lookup_name_simple (parser, expr, id_expr_start_token->location); - if (expr && TREE_CODE (expr) == TEMPLATE_DECL) - /* A template without args is not a complete id-expression. */ - expr = error_mark_node; - if (expr && expr != error_mark_node && TREE_CODE (expr) != TYPE_DECL @@ -16544,13 +16698,17 @@ cp_parser_decltype_expr (cp_parser *parser, &error_msg, id_expr_start_token->location)); - if (expr == error_mark_node) - /* We found an id-expression, but it was something that we - should not have found. This is an error, not something - we can recover from, so note that we found an - id-expression and we'll recover as gracefully as - possible. */ - id_expression_or_member_access_p = true; + if (error_msg) + { + /* We found an id-expression, but it was something that we + should not have found. This is an error, not something + we can recover from, so report the error we found and + we'll recover as gracefully as possible. */ + cp_parser_parse_definitely (parser); + cp_parser_error (parser, error_msg); + id_expression_or_member_access_p = true; + return error_mark_node; + } } if (expr @@ -17070,10 +17228,9 @@ cp_parser_mem_initializer (cp_parser* parser) if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE)) { - bool expr_non_constant_p; cp_lexer_set_source_position (parser->lexer); maybe_warn_cpp0x (CPP0X_INITIALIZER_LISTS); - expression_list = cp_parser_braced_list (parser, &expr_non_constant_p); + expression_list = cp_parser_braced_list (parser); CONSTRUCTOR_IS_DIRECT_INIT (expression_list) = 1; expression_list = build_tree_list (NULL_TREE, expression_list); } @@ -19211,10 +19368,7 @@ cp_parser_template_argument (cp_parser* parser) /* In C++20, we can encounter a braced-init-list. */ if (cxx_dialect >= cxx20 && cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE)) - { - bool expr_non_constant_p; - return cp_parser_braced_list (parser, &expr_non_constant_p); - } + return cp_parser_braced_list (parser); /* With C++17 generalized non-type template arguments we need to handle lvalue constant expressions, too. */ @@ -20034,12 +20188,13 @@ cp_parser_simple_type_specifier (cp_parser* parser, /* Otherwise, look for a type-name. */ if (!type) { - if (cxx_dialect >= cxx17) + if (cxx_dialect >= cxx17 || flag_concepts) cp_parser_parse_tentatively (parser); type = cp_parser_type_name (parser, (qualified_p && typename_p)); - if (cxx_dialect >= cxx17 && !cp_parser_parse_definitely (parser)) + if ((cxx_dialect >= cxx17 || flag_concepts) + && !cp_parser_parse_definitely (parser)) type = NULL_TREE; } @@ -25328,7 +25483,6 @@ cp_parser_default_argument (cp_parser *parser, bool template_parm_p) tree default_argument = NULL_TREE; bool saved_greater_than_is_operator_p; unsigned char saved_local_variables_forbidden_p; - bool non_constant_p, is_direct_init; /* Make sure that PARSER->GREATER_THAN_IS_OPERATOR_P is set correctly. */ @@ -25355,8 +25509,7 @@ cp_parser_default_argument (cp_parser *parser, bool template_parm_p) saved_class_ref = current_class_ref; cp_function_chain->x_current_class_ref = NULL_TREE; } - default_argument - = cp_parser_initializer (parser, &is_direct_init, &non_constant_p); + default_argument = cp_parser_initializer (parser); /* Restore the "this" pointer. */ if (cfun) { @@ -25455,8 +25608,8 @@ cp_parser_ctor_initializer_opt_and_function_body (cp_parser *parser, is set to true; otherwise it is set to false. */ static tree -cp_parser_initializer (cp_parser* parser, bool* is_direct_init, - bool* non_constant_p, bool subexpression_p) +cp_parser_initializer (cp_parser *parser, bool *is_direct_init /*=nullptr*/, + bool *non_constant_p /*=nullptr*/, bool subexpression_p) { cp_token *token; tree init; @@ -25466,9 +25619,11 @@ cp_parser_initializer (cp_parser* parser, bool* is_direct_init, /* Let our caller know whether or not this initializer was parenthesized. */ - *is_direct_init = (token->type != CPP_EQ); + if (is_direct_init) + *is_direct_init = (token->type != CPP_EQ); /* Assume that the initializer is constant. */ - *non_constant_p = false; + if (non_constant_p) + *non_constant_p = false; if (token->type == CPP_EQ) { @@ -25528,7 +25683,8 @@ cp_parser_initializer_clause (cp_parser* parser, bool* non_constant_p) cp_expr initializer; /* Assume the expression is constant. */ - *non_constant_p = false; + if (non_constant_p) + *non_constant_p = false; /* If it is not a `{', then we are looking at an assignment-expression. */ @@ -25560,7 +25716,7 @@ cp_parser_initializer_clause (cp_parser* parser, bool* non_constant_p) cp_parser_initializer. */ static cp_expr -cp_parser_braced_list (cp_parser* parser, bool* non_constant_p) +cp_parser_braced_list (cp_parser *parser, bool *non_constant_p /*=nullptr*/) { tree initializer; location_t start_loc = cp_lexer_peek_token (parser->lexer)->location; @@ -25582,7 +25738,7 @@ cp_parser_braced_list (cp_parser* parser, bool* non_constant_p) if (cp_lexer_next_token_is (parser->lexer, CPP_COMMA)) cp_lexer_consume_token (parser->lexer); } - else + else if (non_constant_p) *non_constant_p = false; /* Now, there should be a trailing `}'. */ location_t finish_loc = cp_lexer_peek_token (parser->lexer)->location; @@ -25720,7 +25876,8 @@ cp_parser_initializer_list (cp_parser* parser, bool* non_constant_p, tree first_designator = NULL_TREE; /* Assume all of the expressions are constant. */ - *non_constant_p = false; + if (non_constant_p) + *non_constant_p = false; unsigned nelts = 0; int suppress = suppress_location_wrappers; @@ -25732,6 +25889,7 @@ cp_parser_initializer_list (cp_parser* parser, bool* non_constant_p, tree designator; tree initializer; bool clause_non_constant_p; + bool direct_p = false; location_t loc = cp_lexer_peek_token (parser->lexer)->location; /* Handle the C++20 syntax, '. id ='. */ @@ -25754,6 +25912,8 @@ cp_parser_initializer_list (cp_parser* parser, bool* non_constant_p, if (cp_lexer_next_token_is (parser->lexer, CPP_EQ)) /* Consume the `='. */ cp_lexer_consume_token (parser->lexer); + else + direct_p = true; } /* Also, if the next token is an identifier and the following one is a colon, we are looking at the GNU designated-initializer @@ -25828,9 +25988,15 @@ cp_parser_initializer_list (cp_parser* parser, bool* non_constant_p, initializer = cp_parser_initializer_clause (parser, &clause_non_constant_p); /* If any clause is non-constant, so is the entire initializer. */ - if (clause_non_constant_p) + if (clause_non_constant_p && non_constant_p) *non_constant_p = true; + if (TREE_CODE (initializer) == CONSTRUCTOR) + /* This uses |= rather than = because C_I_D_I could have been set in + cp_parser_functional_cast so we must be careful not to clear the + flag. */ + CONSTRUCTOR_IS_DIRECT_INIT (initializer) |= direct_p; + /* If we have an ellipsis, this is an initializer pack expansion. */ if (cp_lexer_next_token_is (parser->lexer, CPP_ELLIPSIS)) @@ -27703,14 +27869,12 @@ cp_parser_member_declaration (cp_parser* parser) initializer = cp_parser_save_nsdmi (parser); else if (cxx_dialect >= cxx11) { - bool nonconst; /* Don't require a constant rvalue in C++11, since we might want a reference constant. We'll enforce constancy later. */ cp_lexer_consume_token (parser->lexer); /* Parse the initializer. */ - initializer = cp_parser_initializer_clause (parser, - &nonconst); + initializer = cp_parser_initializer_clause (parser); } else /* Parse the initializer. */ @@ -27719,13 +27883,12 @@ cp_parser_member_declaration (cp_parser* parser) else if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE) && !function_declarator_p (declarator)) { - bool x; declarator->init_loc = cp_lexer_peek_token (parser->lexer)->location; if (decl_specifiers.storage_class != sc_static) initializer = cp_parser_save_nsdmi (parser); else - initializer = cp_parser_initializer (parser, &x, &x); + initializer = cp_parser_initializer (parser); } /* Detect invalid bit-field cases such as @@ -28735,11 +28898,10 @@ cp_parser_yield_expression (cp_parser* parser) if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE)) { - bool expr_non_constant_p; cp_lexer_set_source_position (parser->lexer); /* ??? : probably a moot point? */ maybe_warn_cpp0x (CPP0X_INITIALIZER_LISTS); - expr = cp_parser_braced_list (parser, &expr_non_constant_p); + expr = cp_parser_braced_list (parser); } else expr = cp_parser_assignment_expression (parser); @@ -30996,7 +31158,7 @@ cp_parser_type_requirement (cp_parser *parser) cp_parser_global_scope_opt (parser, /*current_scope_valid_p=*/false); cp_parser_nested_name_specifier_opt (parser, /*typename_keyword_p=*/true, - /*check_dependency_p=*/false, + /*check_dependency_p=*/true, /*type_p=*/true, /*is_declaration=*/false); @@ -31006,7 +31168,7 @@ cp_parser_type_requirement (cp_parser *parser) cp_lexer_consume_token (parser->lexer); type = cp_parser_template_id (parser, /*template_keyword_p=*/true, - /*check_dependency=*/false, + /*check_dependency_p=*/true, /*tag_type=*/none_type, /*is_declaration=*/false); type = make_typename_type (parser->scope, type, typename_type, @@ -32655,7 +32817,6 @@ cp_parser_functional_cast (cp_parser* parser, tree type) vec *vec; tree expression_list; cp_expr cast; - bool nonconst_p; location_t start_loc = input_location; @@ -32666,7 +32827,7 @@ cp_parser_functional_cast (cp_parser* parser, tree type) { cp_lexer_set_source_position (parser->lexer); maybe_warn_cpp0x (CPP0X_INITIALIZER_LISTS); - expression_list = cp_parser_braced_list (parser, &nonconst_p); + expression_list = cp_parser_braced_list (parser); CONSTRUCTOR_IS_DIRECT_INIT (expression_list) = 1; if (TREE_CODE (type) == TYPE_DECL) type = TREE_TYPE (type); @@ -33101,7 +33262,6 @@ cp_parser_late_parse_one_default_arg (cp_parser *parser, tree decl, { cp_token_cache *tokens; tree parsed_arg; - bool dummy; if (default_arg == error_mark_node) return error_mark_node; @@ -33114,7 +33274,7 @@ cp_parser_late_parse_one_default_arg (cp_parser *parser, tree decl, start_lambda_scope (decl); /* Parse the default argument. */ - parsed_arg = cp_parser_initializer (parser, &dummy, &dummy); + parsed_arg = cp_parser_initializer (parser); if (BRACE_ENCLOSED_INITIALIZER_P (parsed_arg)) maybe_warn_cpp0x (CPP0X_INITIALIZER_LISTS); @@ -38830,8 +38990,8 @@ cp_parser_omp_clause_defaultmap (cp_parser *parser, tree list, if (!cp_lexer_next_token_is (parser->lexer, CPP_NAME)) { invalid_category: - cp_parser_error (parser, "expected %, % or " - "%"); + cp_parser_error (parser, "expected %, %, " + "%"); goto out_err; } id = cp_lexer_peek_token (parser->lexer)->u.value; @@ -38842,6 +39002,8 @@ cp_parser_omp_clause_defaultmap (cp_parser *parser, tree list, case 'a': if (strcmp ("aggregate", p) == 0) category = OMP_CLAUSE_DEFAULTMAP_CATEGORY_AGGREGATE; + else if (strcmp ("all", p) == 0) + category = OMP_CLAUSE_DEFAULTMAP_CATEGORY_ALL; else goto invalid_category; break; @@ -38872,13 +39034,19 @@ cp_parser_omp_clause_defaultmap (cp_parser *parser, tree list, for (c = list; c ; c = OMP_CLAUSE_CHAIN (c)) if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEFAULTMAP && (category == OMP_CLAUSE_DEFAULTMAP_CATEGORY_UNSPECIFIED + || category == OMP_CLAUSE_DEFAULTMAP_CATEGORY_ALL || OMP_CLAUSE_DEFAULTMAP_CATEGORY (c) == category || (OMP_CLAUSE_DEFAULTMAP_CATEGORY (c) - == OMP_CLAUSE_DEFAULTMAP_CATEGORY_UNSPECIFIED))) + == OMP_CLAUSE_DEFAULTMAP_CATEGORY_UNSPECIFIED) + || (OMP_CLAUSE_DEFAULTMAP_CATEGORY (c) + == OMP_CLAUSE_DEFAULTMAP_CATEGORY_ALL))) { enum omp_clause_defaultmap_kind cat = category; location_t loc = OMP_CLAUSE_LOCATION (c); - if (cat == OMP_CLAUSE_DEFAULTMAP_CATEGORY_UNSPECIFIED) + if (cat == OMP_CLAUSE_DEFAULTMAP_CATEGORY_UNSPECIFIED + || (cat == OMP_CLAUSE_DEFAULTMAP_CATEGORY_ALL + && (OMP_CLAUSE_DEFAULTMAP_CATEGORY (c) + != OMP_CLAUSE_DEFAULTMAP_CATEGORY_UNSPECIFIED))) cat = OMP_CLAUSE_DEFAULTMAP_CATEGORY (c); p = NULL; switch (cat) @@ -38886,6 +39054,9 @@ cp_parser_omp_clause_defaultmap (cp_parser *parser, tree list, case OMP_CLAUSE_DEFAULTMAP_CATEGORY_UNSPECIFIED: p = NULL; break; + case OMP_CLAUSE_DEFAULTMAP_CATEGORY_ALL: + p = "all"; + break; case OMP_CLAUSE_DEFAULTMAP_CATEGORY_AGGREGATE: p = "aggregate"; break; @@ -43071,7 +43242,19 @@ cp_parser_omp_for_incr (cp_parser *parser, tree decl) return build2 (MODIFY_EXPR, TREE_TYPE (decl), decl, rhs); } -/* Parse the initialization statement of an OpenMP for loop. +/* Parse the initialization statement of an OpenMP for loop. Range-for + is handled separately in cp_convert_omp_range_for. + + On entry SL is the current statement list. Parsing of some forms + of initialization pops this list and stores its contents in either INIT + or THIS_PRE_BODY, and sets SL to null. Initialization for class + iterators is added directly to SL and it is not popped until later. + + On return, DECL is set if the initialization is by binding the + iteration variable. If the initialization is by assignment, REAL_DECL + is set to point to a variable in an outer scope. ORIG_INIT is set + if the iteration variable is of class type; this is a copy saved for + error checking in finish_omp_for. Return true if the resulting construct should have an OMP_CLAUSE_PRIVATE added to it. */ @@ -43079,7 +43262,7 @@ cp_parser_omp_for_incr (cp_parser *parser, tree decl) static tree cp_parser_omp_for_loop_init (cp_parser *parser, tree &this_pre_body, - releasing_vec &for_block, + tree &sl, tree &init, tree &orig_init, tree &decl, @@ -43156,10 +43339,10 @@ cp_parser_omp_for_loop_init (cp_parser *parser, || type_dependent_expression_p (decl) || auto_node) { - bool is_direct_init, is_non_constant_init; + bool is_non_constant_init; init = cp_parser_initializer (parser, - &is_direct_init, + /*is_direct_init=*/nullptr, &is_non_constant_init); if (auto_node) @@ -43177,18 +43360,22 @@ cp_parser_omp_for_loop_init (cp_parser *parser, asm_specification, LOOKUP_ONLYCONVERTING); orig_init = init; + + /* In the case of a class iterator, do not pop sl here. + Both class initialization and finalization must happen in + the enclosing init block scope. For now set the init + expression to null; it'll be filled in properly in + finish_omp_for before stuffing it in the OMP_FOR. */ if (CLASS_TYPE_P (TREE_TYPE (decl))) + init = NULL_TREE; + else /* It is a parameterized type. */ { - vec_safe_push (for_block, this_pre_body); - init = NULL_TREE; - } - else - { - init = pop_stmt_list (this_pre_body); + init = pop_stmt_list (sl); + sl = NULL_TREE; if (init && TREE_CODE (init) == STATEMENT_LIST) { tree_stmt_iterator i = tsi_start (init); - /* Move lambda DECL_EXPRs to FOR_BLOCK. */ + /* Move lambda DECL_EXPRs to the enclosing block. */ while (!tsi_end_p (i)) { tree t = tsi_stmt (i); @@ -43196,7 +43383,7 @@ cp_parser_omp_for_loop_init (cp_parser *parser, && TREE_CODE (DECL_EXPR_DECL (t)) == TYPE_DECL) { tsi_delink (&i); - vec_safe_push (for_block, t); + add_stmt (t); continue; } break; @@ -43210,9 +43397,10 @@ cp_parser_omp_for_loop_init (cp_parser *parser, } } } - this_pre_body = NULL_TREE; } else + /* This is an initialized declaration of non-class, + non-parameterized type iteration variable. */ { /* Consume '='. */ cp_lexer_consume_token (parser->lexer); @@ -43226,6 +43414,8 @@ cp_parser_omp_for_loop_init (cp_parser *parser, /*init_const_expr_p=*/false, asm_specification, LOOKUP_ONLYCONVERTING); + this_pre_body = pop_stmt_list (sl); + sl = NULL_TREE; } if (pushed_scope) @@ -43297,14 +43487,21 @@ cp_parser_omp_for_loop_init (cp_parser *parser, real_decl = TREE_OPERAND (init, 0); } } + this_pre_body = pop_stmt_list (sl); + sl = NULL_TREE; } return add_private_clause; } -/* Helper for cp_parser_omp_for_loop, handle one range-for loop. */ +/* Helper for cp_parser_omp_loop_nest, handle one range-for loop + including introducing new temporaries for the range start and end, + doing auto deduction, and processing decomposition variables. + This function is also called from pt.cc during template instantiation. + In that case SL is NULL_TREE, otherwise it is the current statement + list. */ void -cp_convert_omp_range_for (tree &this_pre_body, vec *for_block, +cp_convert_omp_range_for (tree &this_pre_body, tree &sl, tree &decl, tree &orig_decl, tree &init, tree &orig_init, tree &cond, tree &incr) { @@ -43321,8 +43518,7 @@ cp_convert_omp_range_for (tree &this_pre_body, vec *for_block, && !BRACE_ENCLOSED_INITIALIZER_P (init)) { tree d = decl; - tree decomp_first_name = NULL_TREE; - unsigned decomp_cnt = 0; + cp_decomp decomp_d, *decomp = NULL; if (decl != error_mark_node && DECL_HAS_VALUE_EXPR_P (decl)) { tree v = DECL_VALUE_EXPR (decl); @@ -43331,17 +43527,21 @@ cp_convert_omp_range_for (tree &this_pre_body, vec *for_block, && DECL_DECOMPOSITION_P (TREE_OPERAND (v, 0))) { d = TREE_OPERAND (v, 0); - decomp_cnt = tree_to_uhwi (TREE_OPERAND (v, 1)) + 1; - decomp_first_name = decl; + decomp = &decomp_d; + decomp->count = tree_to_uhwi (TREE_OPERAND (v, 1)) + 1; + decomp->decl = decl; } } - do_range_for_auto_deduction (d, init, decomp_first_name, decomp_cnt); + do_range_for_auto_deduction (d, init, decomp); } cond = global_namespace; incr = NULL_TREE; orig_init = init; - if (this_pre_body) - this_pre_body = pop_stmt_list (this_pre_body); + if (sl) + { + this_pre_body = pop_stmt_list (sl); + sl = NULL_TREE; + } return; } @@ -43421,14 +43621,9 @@ cp_convert_omp_range_for (tree &this_pre_body, vec *for_block, orig_decl = decl; decl = begin; - if (for_block) - { - vec_safe_push (for_block, this_pre_body); - this_pre_body = NULL_TREE; - } + /* Defer popping sl here. */ - tree decomp_first_name = NULL_TREE; - unsigned decomp_cnt = 0; + cp_decomp decomp_d, *decomp = NULL; if (orig_decl != error_mark_node && DECL_HAS_VALUE_EXPR_P (orig_decl)) { tree v = DECL_VALUE_EXPR (orig_decl); @@ -43438,8 +43633,9 @@ cp_convert_omp_range_for (tree &this_pre_body, vec *for_block, { tree d = orig_decl; orig_decl = TREE_OPERAND (v, 0); - decomp_cnt = tree_to_uhwi (TREE_OPERAND (v, 1)) + 1; - decomp_first_name = d; + decomp = &decomp_d; + decomp->count = tree_to_uhwi (TREE_OPERAND (v, 1)) + 1; + decomp->decl = d; } } @@ -43452,10 +43648,10 @@ cp_convert_omp_range_for (tree &this_pre_body, vec *for_block, { TREE_TYPE (orig_decl) = do_auto_deduction (TREE_TYPE (orig_decl), t, auto_node); - if (decomp_first_name) + if (decomp) { ++processing_template_decl; - cp_finish_decomp (orig_decl, decomp_first_name, decomp_cnt); + cp_finish_decomp (orig_decl, decomp); --processing_template_decl; if (!processing_template_decl) clear_has_value_expr = true; @@ -43463,6 +43659,16 @@ cp_convert_omp_range_for (tree &this_pre_body, vec *for_block, } } + /* The output ORIG_DECL is not a decl. Instead, it is a tree structure + that holds decls for variables implementing the iterator, represented + as a TREE_LIST whose TREE_CHAIN is a vector. The first two elements + of the vector are decls of scratch variables for the range start and + end that will eventually be bound in the implicit scope surrounding + the whole loop nest. The remaining elements are decls of derived + decomposition variables that are bound inside the loop body. This + structure is further mangled by finish_omp_for into the form required + for the OMP_FOR_ORIG_DECLS field of the OMP_FOR tree node. */\ + unsigned decomp_cnt = decomp ? decomp->count : 0; tree v = make_tree_vec (decomp_cnt + 3); TREE_VEC_ELT (v, 0) = range_temp_decl; TREE_VEC_ELT (v, 1) = end; @@ -43478,13 +43684,13 @@ cp_convert_omp_range_for (tree &this_pre_body, vec *for_block, name but the DECL_VALUE_EXPR will be dependent. Hide those from folding of other loop initializers e.g. for warning purposes until cp_finish_omp_range_for. */ - gcc_checking_assert (DECL_HAS_VALUE_EXPR_P (decomp_first_name) - || (TREE_TYPE (decomp_first_name) + gcc_checking_assert (DECL_HAS_VALUE_EXPR_P (decomp->decl) + || (TREE_TYPE (decomp->decl) == error_mark_node)); - DECL_HAS_VALUE_EXPR_P (decomp_first_name) = 0; + DECL_HAS_VALUE_EXPR_P (decomp->decl) = 0; } - TREE_VEC_ELT (v, i + 3) = decomp_first_name; - decomp_first_name = DECL_CHAIN (decomp_first_name); + TREE_VEC_ELT (v, i + 3) = decomp->decl; + decomp->decl = DECL_CHAIN (decomp->decl); } orig_decl = tree_cons (NULL_TREE, NULL_TREE, v); } @@ -43498,27 +43704,26 @@ cp_finish_omp_range_for (tree orig, tree begin) gcc_assert (TREE_CODE (orig) == TREE_LIST && TREE_CODE (TREE_CHAIN (orig)) == TREE_VEC); tree decl = TREE_VEC_ELT (TREE_CHAIN (orig), 2); - tree decomp_first_name = NULL_TREE; - unsigned int decomp_cnt = 0; + cp_decomp decomp_d, *decomp = NULL; if (VAR_P (decl) && DECL_DECOMPOSITION_P (decl)) { - decomp_first_name = TREE_VEC_ELT (TREE_CHAIN (orig), 3); - decomp_cnt = TREE_VEC_LENGTH (TREE_CHAIN (orig)) - 3; + decomp = &decomp_d; + decomp_d.decl = TREE_VEC_ELT (TREE_CHAIN (orig), 3); + decomp_d.count = TREE_VEC_LENGTH (TREE_CHAIN (orig)) - 3; if (TREE_PUBLIC (TREE_CHAIN (orig))) { /* Undo temporary clearing of DECL_HAS_VALUE_EXPR_P done by cp_convert_omp_range_for above. */ TREE_PUBLIC (TREE_CHAIN (orig)) = 0; - tree d = decomp_first_name; - for (unsigned i = 0; i < decomp_cnt; i++) + tree d = decomp_d.decl; + for (unsigned i = 0; i < decomp_d.count; i++) { if (TREE_TYPE (d) != error_mark_node) DECL_HAS_VALUE_EXPR_P (d) = 1; d = DECL_CHAIN (d); } } - cp_maybe_mangle_decomp (decl, decomp_first_name, decomp_cnt); } /* The declaration is initialized with *__begin inside the loop body. */ @@ -43526,9 +43731,9 @@ cp_finish_omp_range_for (tree orig, tree begin) build_x_indirect_ref (input_location, begin, RO_UNARY_STAR, NULL_TREE, tf_warning_or_error), /*is_constant_init*/false, NULL_TREE, - LOOKUP_ONLYCONVERTING); + LOOKUP_ONLYCONVERTING, decomp); if (VAR_P (decl) && DECL_DECOMPOSITION_P (decl)) - cp_finish_decomp (decl, decomp_first_name, decomp_cnt); + cp_finish_decomp (decl, decomp); } /* Return true if next tokens contain a standard attribute that contains @@ -43717,23 +43922,603 @@ cp_parser_omp_scan_loop_body (cp_parser *parser) braces.require_close (parser); } + +/* This function parses a single level of a loop nest, invoking itself + recursively if necessary. + + loop-nest :: for (...) loop-body + loop-body :: loop-nest + | { [intervening-code] loop-body [intervening-code] } + | final-loop-body + intervening-code :: structured-block-sequence + final-loop-body :: structured-block + + For a collapsed loop nest, only a single OMP_FOR is built, pulling out + all the iterator information from the inner loops into vectors in the + parser->omp_for_parse_state structure. + + In the "range for" case, it is transformed into a regular "for" iterator + by introducing some temporary variables for the begin/end, + as well as bindings of the actual iteration variables which are + injected into the body of the loop. + + Initialization code for iterator variables may end up either in the + init vector (simple assignments), in omp_for_parse_state->pre_body + (decl_exprs for iterators bound in the for statement), or in the + scope surrounding this level of loop initialization. + + The scopes of class iterator variables and their finalizers need to + be adjusted after parsing so that all of the initialization happens + in a scope surrounding all of the intervening and body code. For + this reason we separately store the initialization and body blocks + for each level of loops in the omp_for_parse_state structure and + reassemble/reorder them in cp_parser_omp_for. See additional + comments there about the use of placeholders, etc. */ + +static tree +cp_parser_omp_loop_nest (cp_parser *parser, bool *if_p) +{ + tree decl, cond, incr, init; + tree orig_init, real_decl, orig_decl; + tree init_block, body_block; + tree init_placeholder, body_placeholder; + tree init_scope; + tree this_pre_body = NULL_TREE; + bool moreloops; + unsigned char save_in_statement; + tree add_private_clause = NULL_TREE; + location_t loc; + bool is_range_for = false; + tree sl = NULL_TREE; + struct omp_for_parse_data *omp_for_parse_state + = parser->omp_for_parse_state; + gcc_assert (omp_for_parse_state); + int depth = omp_for_parse_state->depth; + + /* We have already matched the FOR token but not consumed it yet. */ + gcc_assert (cp_lexer_next_token_is_keyword (parser->lexer, RID_FOR)); + loc = cp_lexer_consume_token (parser->lexer)->location; + + /* Forbid break/continue in the loop initializer, condition, and + increment expressions. */ + save_in_statement = parser->in_statement; + parser->in_statement = IN_OMP_BLOCK; + + /* We are not in intervening code now. */ + omp_for_parse_state->in_intervening_code = false; + + /* Don't create location wrapper nodes within an OpenMP "for" + statement. */ + auto_suppress_location_wrappers sentinel; + + matching_parens parens; + if (!parens.require_open (parser)) + return NULL; + + init = orig_init = decl = real_decl = orig_decl = NULL_TREE; + + init_placeholder = build_stmt (input_location, EXPR_STMT, + integer_zero_node); + vec_safe_push (omp_for_parse_state->init_placeholderv, init_placeholder); + + /* The init_block acts as a container for this level of loop goo. */ + init_block = push_stmt_list (); + vec_safe_push (omp_for_parse_state->init_blockv, init_block); + + /* Wrap a scope around this entire level of loop to hold bindings + of loop iteration variables. We can't insert them directly + in the containing scope because that would cause their visibility to + be incorrect with respect to intervening code after this loop. + We will combine the nested init_scopes in postprocessing after the + entire loop is parsed. */ + init_scope = begin_compound_stmt (0); + + /* Now we need another level of statement list container to capture the + initialization (and possible finalization) bits. In some cases this + container may be popped off during initializer parsing to store code in + INIT or THIS_PRE_BODY, depending on the form of initialization. If + we have a class iterator we will pop it at the end of parsing this + level, so the cleanups are handled correctly. */ + sl = push_stmt_list (); + + if (omp_for_parse_state->code != OACC_LOOP && cxx_dialect >= cxx11) + { + /* Save tokens so that we can put them back. */ + cp_lexer_save_tokens (parser->lexer); + + /* Look for ':' that is not nested in () or {}. */ + is_range_for + = (cp_parser_skip_to_closing_parenthesis_1 (parser, + /*recovering=*/false, + CPP_COLON, + /*consume_paren=*/ + false) == -1); + + /* Roll back the tokens we skipped. */ + cp_lexer_rollback_tokens (parser->lexer); + + if (is_range_for) + { + bool saved_colon_corrects_to_scope_p + = parser->colon_corrects_to_scope_p; + + /* A colon is used in range-based for. */ + parser->colon_corrects_to_scope_p = false; + + /* Parse the declaration. */ + cp_parser_simple_declaration (parser, + /*function_definition_allowed_p=*/ + false, &decl); + parser->colon_corrects_to_scope_p + = saved_colon_corrects_to_scope_p; + + cp_parser_require (parser, CPP_COLON, RT_COLON); + + init = cp_parser_range_for (parser, NULL_TREE, NULL_TREE, decl, + false, 0, false, true); + + cp_convert_omp_range_for (this_pre_body, sl, decl, + orig_decl, init, orig_init, + cond, incr); + + if (omp_for_parse_state->ordered_cl) + error_at (OMP_CLAUSE_LOCATION (omp_for_parse_state->ordered_cl), + "% clause with parameter on " + "range-based % loop"); + + goto parse_close_paren; + } + } + + add_private_clause + = cp_parser_omp_for_loop_init (parser, this_pre_body, sl, + init, orig_init, decl, real_decl); + + cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON); + + /* If the iteration variable was introduced via a declaration in the + for statement, DECL points at it. Otherwise DECL is null and + REAL_DECL is a variable previously declared in an outer scope. + Make REAL_DECL point at the iteration variable no matter where it + was introduced. */ + if (decl) + real_decl = decl; + + /* Some clauses treat iterator variables specially. */ + if (omp_for_parse_state->cclauses != NULL + && omp_for_parse_state->cclauses[C_OMP_CLAUSE_SPLIT_PARALLEL] != NULL + && real_decl != NULL_TREE + && omp_for_parse_state->code != OMP_LOOP) + { + tree *c; + for (c = &(omp_for_parse_state->cclauses[C_OMP_CLAUSE_SPLIT_PARALLEL]); + *c ; ) + if (OMP_CLAUSE_CODE (*c) == OMP_CLAUSE_FIRSTPRIVATE + && OMP_CLAUSE_DECL (*c) == real_decl) + { + error_at (loc, "iteration variable %qD" + " should not be firstprivate", real_decl); + *c = OMP_CLAUSE_CHAIN (*c); + } + else if (OMP_CLAUSE_CODE (*c) == OMP_CLAUSE_LASTPRIVATE + && OMP_CLAUSE_DECL (*c) == real_decl) + { + /* Move lastprivate (decl) clause to OMP_FOR_CLAUSES. */ + tree l = *c; + *c = OMP_CLAUSE_CHAIN (*c); + if (omp_for_parse_state->code == OMP_SIMD) + { + OMP_CLAUSE_CHAIN (l) + = omp_for_parse_state->cclauses[C_OMP_CLAUSE_SPLIT_FOR]; + omp_for_parse_state->cclauses[C_OMP_CLAUSE_SPLIT_FOR] = l; + } + else + { + OMP_CLAUSE_CHAIN (l) = omp_for_parse_state->clauses; + omp_for_parse_state->clauses = l; + } + add_private_clause = NULL_TREE; + } + else + { + if (OMP_CLAUSE_CODE (*c) == OMP_CLAUSE_PRIVATE + && OMP_CLAUSE_DECL (*c) == real_decl) + add_private_clause = NULL_TREE; + c = &OMP_CLAUSE_CHAIN (*c); + } + } + + if (add_private_clause) + { + tree c; + for (c = omp_for_parse_state->clauses; c ; c = OMP_CLAUSE_CHAIN (c)) + { + if ((OMP_CLAUSE_CODE (c) == OMP_CLAUSE_PRIVATE + || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LASTPRIVATE) + && OMP_CLAUSE_DECL (c) == decl) + break; + else if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_FIRSTPRIVATE + && OMP_CLAUSE_DECL (c) == decl) + error_at (loc, "iteration variable %qD " + "should not be firstprivate", + decl); + else if ((OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION + || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_IN_REDUCTION) + && OMP_CLAUSE_DECL (c) == decl) + error_at (loc, "iteration variable %qD should not be reduction", + decl); + } + if (c == NULL) + { + if ((omp_for_parse_state->code == OMP_SIMD + && omp_for_parse_state->count != 1) + || omp_for_parse_state->code == OMP_LOOP) + c = build_omp_clause (loc, OMP_CLAUSE_LASTPRIVATE); + else if (omp_for_parse_state->code != OMP_SIMD) + c = build_omp_clause (loc, OMP_CLAUSE_PRIVATE); + else + c = build_omp_clause (loc, OMP_CLAUSE_LINEAR); + OMP_CLAUSE_DECL (c) = add_private_clause; + c = finish_omp_clauses (c, C_ORT_OMP); + if (c) + { + OMP_CLAUSE_CHAIN (c) = omp_for_parse_state->clauses; + omp_for_parse_state->clauses = c; + /* For linear, signal that we need to fill up + the so far unknown linear step. */ + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LINEAR) + OMP_CLAUSE_LINEAR_STEP (c) = NULL_TREE; + } + } + } + + cond = NULL; + if (cp_lexer_next_token_is_not (parser->lexer, CPP_SEMICOLON)) + cond = cp_parser_omp_for_cond (parser, decl, omp_for_parse_state->code); + cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON); + + incr = NULL; + if (cp_lexer_next_token_is_not (parser->lexer, CPP_CLOSE_PAREN)) + { + /* If decl is an iterator, preserve the operator on decl + until finish_omp_for. */ + if (real_decl + && ((processing_template_decl + && (TREE_TYPE (real_decl) == NULL_TREE + || !INDIRECT_TYPE_P (TREE_TYPE (real_decl)))) + || CLASS_TYPE_P (TREE_TYPE (real_decl)))) + incr = cp_parser_omp_for_incr (parser, real_decl); + else + incr = cp_parser_expression (parser); + protected_set_expr_location_if_unset (incr, input_location); + } + + parse_close_paren: + if (!parens.require_close (parser)) + cp_parser_skip_to_closing_parenthesis (parser, /*recovering=*/true, + /*or_comma=*/false, + /*consume_paren=*/true); + + /* We've parsed all the for (...) stuff now. Store the bits. */ + TREE_VEC_ELT (omp_for_parse_state->declv, depth) = decl; + TREE_VEC_ELT (omp_for_parse_state->initv, depth) = init; + TREE_VEC_ELT (omp_for_parse_state->condv, depth) = cond; + TREE_VEC_ELT (omp_for_parse_state->incrv, depth) = incr; + if (orig_init) + { + omp_for_parse_state->orig_inits.safe_grow_cleared (depth + 1, true); + omp_for_parse_state->orig_inits[depth] = orig_init; + } + if (orig_decl) + { + if (!omp_for_parse_state->orig_declv) + omp_for_parse_state->orig_declv + = copy_node (omp_for_parse_state->declv); + TREE_VEC_ELT (omp_for_parse_state->orig_declv, depth) = orig_decl; + } + else if (omp_for_parse_state->orig_declv) + TREE_VEC_ELT (omp_for_parse_state->orig_declv, depth) = decl; + if (this_pre_body) + append_to_statement_list_force (this_pre_body, + &(omp_for_parse_state->pre_body)); + + /* Start a nested block for the loop body. */ + body_placeholder = build_stmt (input_location, EXPR_STMT, + integer_zero_node); + vec_safe_push (omp_for_parse_state->body_placeholderv, body_placeholder); + body_block = push_stmt_list (); + vec_safe_push (omp_for_parse_state->body_blockv, body_block); + + moreloops = depth < omp_for_parse_state->count - 1; + omp_for_parse_state->want_nested_loop = moreloops; + if (moreloops && cp_lexer_next_token_is_keyword (parser->lexer, RID_FOR)) + { + omp_for_parse_state->depth++; + add_stmt (cp_parser_omp_loop_nest (parser, if_p)); + omp_for_parse_state->depth--; + } + else if (moreloops + && cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE)) + { + /* This is the open brace in the loop-body grammar production. Rather + than trying to special-case braces, just parse it as a compound + statement and handle the nested loop-body case there. Note that + when we see a further open brace inside the compound statement + loop-body, we don't know whether it is the start of intervening + code that is a compound statement, or a level of braces + surrounding a nested loop-body. Use the WANT_NESTED_LOOP state + bit to ensure we have only one nested loop at each level. */ + + omp_for_parse_state->in_intervening_code = true; + cp_parser_compound_statement (parser, NULL, BCS_NORMAL, false); + omp_for_parse_state->in_intervening_code = false; + + if (omp_for_parse_state->want_nested_loop) + { + /* We have already parsed the whole loop body and not found a + nested loop. */ + error_at (omp_for_parse_state->for_loc, + "not enough nested loops"); + omp_for_parse_state->fail = true; + } + if_p = NULL; + } + else + { + /* This is the final-loop-body case in the grammar: we have something + that is not a FOR and not an open brace. */ + if (moreloops) + { + /* If we were expecting a nested loop, give an error and mark + that parsing has failed, and try to recover by parsing the + body as regular code without further collapsing. */ + error_at (omp_for_parse_state->for_loc, + "not enough nested loops"); + omp_for_parse_state->fail = true; + } + parser->in_statement = IN_OMP_FOR; + + /* Generate the parts of range for that belong in the loop body, + to be executed on every iteration. This includes setting the + user-declared decomposition variables from the compiler-generated + temporaries that are the real iteration variables for OMP_FOR. + FIXME: Not sure if this is correct with respect to visibility + of the variables from intervening code. However, putting this + code in each level of loop instead of all around the innermost + body also makes the decomposition variables visible to the + inner for init/bound/step exressions, which is not supposed to + happen and causes test failures. */ + if (omp_for_parse_state->orig_declv) + for (int i = 0; i < omp_for_parse_state->count; i++) + { + tree o = TREE_VEC_ELT (omp_for_parse_state->orig_declv, i); + tree d = TREE_VEC_ELT (omp_for_parse_state->declv, i); + if (o != d) + cp_finish_omp_range_for (o, d); + } + + /* Now parse the final-loop-body for the innermost loop. */ + parser->omp_for_parse_state = NULL; + if (omp_for_parse_state->inscan) + cp_parser_omp_scan_loop_body (parser); + else + cp_parser_statement (parser, NULL_TREE, false, if_p); + parser->omp_for_parse_state = omp_for_parse_state; + } + parser->in_statement = save_in_statement; + omp_for_parse_state->want_nested_loop = false; + omp_for_parse_state->in_intervening_code = true; + + /* Pop and remember the body block. Add the body placeholder + to the surrounding statement list instead. This is just a unique + token that will be replaced when we reassemble the generated + code for the entire omp for statement. */ + body_block = pop_stmt_list (body_block); + omp_for_parse_state->body_blockv[depth] = body_block; + add_stmt (body_placeholder); + + /* Pop and remember the init block. */ + if (sl) + add_stmt (pop_stmt_list (sl)); + finish_compound_stmt (init_scope); + init_block = pop_stmt_list (init_block); + omp_for_parse_state->init_blockv[depth] = init_block; + + /* Return the init placeholder rather than the remembered init block. + Again, this is just a unique cookie that will be used to reassemble + code pieces when the entire omp for statement has been parsed. */ + return init_placeholder; +} + +/* Worker for find_structured_blocks. *TP points to a STATEMENT_LIST + and ITER is the element that is or contains a nested loop. This + function moves the statements before and after ITER into + OMP_STRUCTURED_BLOCKs and modifies *TP. */ +static void +insert_structured_blocks (tree *tp, tree_stmt_iterator iter) +{ + tree sl = push_stmt_list (); + for (tree_stmt_iterator i = tsi_start (*tp); !tsi_end_p (i); ) + if (i == iter) + { + sl = pop_stmt_list (sl); + if (TREE_CODE (sl) != STATEMENT_LIST || !tsi_end_p (tsi_start (sl))) + tsi_link_before (&i, + build1 (OMP_STRUCTURED_BLOCK, void_type_node, sl), + TSI_SAME_STMT); + i++; + sl = push_stmt_list (); + } + else + { + tree s = tsi_stmt (i); + tsi_delink (&i); /* Advances i to next statement. */ + add_stmt (s); + } + sl = pop_stmt_list (sl); + if (TREE_CODE (sl) != STATEMENT_LIST || !tsi_end_p (tsi_start (sl))) + tsi_link_after (&iter, + build1 (OMP_STRUCTURED_BLOCK, void_type_node, sl), + TSI_SAME_STMT); +} + +/* Helper to find and mark structured blocks in intervening code for a + single loop level with markers for later error checking. *TP is the + piece of code to be marked and INNER is the inner loop placeholder. + Returns true if INNER was found (recursively) in *TP. */ +static bool +find_structured_blocks (tree *tp, tree inner) +{ + if (*tp == inner) + return true; + else if (TREE_CODE (*tp) == BIND_EXPR) + return find_structured_blocks (&(BIND_EXPR_BODY (*tp)), inner); + else if (TREE_CODE (*tp) == STATEMENT_LIST) + { + for (tree_stmt_iterator i = tsi_start (*tp); !tsi_end_p (i); ++i) + { + tree *p = tsi_stmt_ptr (i); + /* The normal case is that there is no intervening code and we + do not have to insert any OMP_STRUCTURED_BLOCK markers. */ + if (find_structured_blocks (p, inner)) + { + if (!(i == tsi_start (*tp) && i == tsi_last (*tp))) + insert_structured_blocks (tp, i); + return true; + } + } + return false; + } + else if (TREE_CODE (*tp) == TRY_FINALLY_EXPR) + return find_structured_blocks (&(TREE_OPERAND (*tp, 0)), inner); + else if (TREE_CODE (*tp) == CLEANUP_STMT) + return find_structured_blocks (&(CLEANUP_BODY (*tp)), inner); + else + return false; +} + +/* Helpers used for relinking tree structures: In tree rooted at + CONTEXT, replace ORIG with REPLACEMENT. If FLATTEN is true, try to combine + nested BIND_EXPRs. Gives an assertion if it fails to find ORIG. */ + +struct sit_data { + tree orig; + tree repl; + bool flatten; +}; + +static tree +substitute_in_tree_walker (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED, + void *dp) +{ + struct sit_data *sit = (struct sit_data *)dp; + if (*tp == sit->orig) + { + *tp = sit->repl; + return *tp; + } + /* Remove redundant BIND_EXPRs with no bindings even when not specifically + trying to flatten. */ + else if (TREE_CODE (*tp) == BIND_EXPR + && BIND_EXPR_BODY (*tp) == sit->orig + && !BIND_EXPR_VARS (*tp) + && (sit->flatten || TREE_CODE (sit->repl) == BIND_EXPR)) + { + *tp = sit->repl; + return *tp; + } + else if (sit->flatten + && TREE_CODE (*tp) == BIND_EXPR + && TREE_CODE (sit->repl) == BIND_EXPR) + { + if (BIND_EXPR_BODY (*tp) == sit->orig) + { + /* Merge binding lists for two directly nested BIND_EXPRs, + keeping the outer one. */ + BIND_EXPR_VARS (*tp) = chainon (BIND_EXPR_VARS (*tp), + BIND_EXPR_VARS (sit->repl)); + BIND_EXPR_BODY (*tp) = BIND_EXPR_BODY (sit->repl); + return *tp; + } + else if (TREE_CODE (BIND_EXPR_BODY (*tp)) == STATEMENT_LIST) + /* There might be a statement list containing cleanup_points + etc between the two levels of BIND_EXPR. We can still merge + them, again keeping the outer BIND_EXPR. */ + for (tree_stmt_iterator i = tsi_start (BIND_EXPR_BODY (*tp)); + !tsi_end_p (i); ++i) + { + tree *p = tsi_stmt_ptr (i); + if (*p == sit->orig) + { + BIND_EXPR_VARS (*tp) = chainon (BIND_EXPR_VARS (*tp), + BIND_EXPR_VARS (sit->repl)); + *p = BIND_EXPR_BODY (sit->repl); + return *tp; + } + } + } + return NULL; +} + +static void +substitute_in_tree (tree *context, tree orig, tree repl, bool flatten) +{ + struct sit_data data; + + gcc_assert (*context && orig && repl); + if (TREE_CODE (repl) == BIND_EXPR && !BIND_EXPR_VARS (repl)) + repl = BIND_EXPR_BODY (repl); + data.orig = orig; + data.repl = repl; + data.flatten = flatten; + + tree result = cp_walk_tree (context, substitute_in_tree_walker, + (void *)&data, NULL); + gcc_assert (result != NULL_TREE); +} + +/* Walker to patch up the BLOCK_NODE hierarchy after the above surgery. + *DP is is the parent block. */ + +static tree +fixup_blocks_walker (tree *tp, int *walk_subtrees, void *dp) +{ + tree superblock = *(tree *)dp; + + if (TREE_CODE (*tp) == BIND_EXPR) + { + tree block = BIND_EXPR_BLOCK (*tp); + if (superblock) + { + BLOCK_SUPERCONTEXT (block) = superblock; + BLOCK_CHAIN (block) = BLOCK_SUBBLOCKS (superblock); + BLOCK_SUBBLOCKS (superblock) = block; + } + BLOCK_SUBBLOCKS (block) = NULL_TREE; + cp_walk_tree (&BIND_EXPR_BODY (*tp), fixup_blocks_walker, + (void *)&block, NULL); + *walk_subtrees = 0; + } + + return NULL; +} + /* Parse the restricted form of the for statement allowed by OpenMP. */ static tree cp_parser_omp_for_loop (cp_parser *parser, enum tree_code code, tree clauses, tree *cclauses, bool *if_p) { - tree init, orig_init, cond, incr, body, decl, pre_body = NULL_TREE, ret; - tree orig_decl; - tree real_decl, initv, condv, incrv, declv, orig_declv; - tree this_pre_body, cl, ordered_cl = NULL_TREE; - location_t loc_first; - bool collapse_err = false; - int i, collapse = 1, ordered = 0, count, nbraces = 0; - releasing_vec for_block; - auto_vec orig_inits; + tree ret; + tree cl, ordered_cl = NULL_TREE; + int collapse = 1, ordered = 0; + unsigned int count; bool tiling = false; bool inscan = false; + struct omp_for_parse_data data; + struct omp_for_parse_data *save_data = parser->omp_for_parse_state; + tree result; + location_t loc_first = cp_lexer_peek_token (parser->lexer)->location; for (cl = clauses; cl; cl = OMP_CLAUSE_CHAIN (cl)) if (OMP_CLAUSE_CODE (cl) == OMP_CLAUSE_COLLAPSE) @@ -43766,355 +44551,133 @@ cp_parser_omp_for_loop (cp_parser *parser, enum tree_code code, tree clauses, gcc_assert (tiling || (collapse >= 1 && ordered >= 0)); count = ordered ? ordered : collapse; - declv = make_tree_vec (count); - initv = make_tree_vec (count); - condv = make_tree_vec (count); - incrv = make_tree_vec (count); - orig_declv = NULL_TREE; - - loc_first = cp_lexer_peek_token (parser->lexer)->location; - - for (i = 0; i < count; i++) + if (!cp_lexer_next_token_is_keyword (parser->lexer, RID_FOR)) { - int bracecount = 0; - tree add_private_clause = NULL_TREE; - location_t loc; - - if (!cp_lexer_next_token_is_keyword (parser->lexer, RID_FOR)) - { - if (!collapse_err) - cp_parser_error (parser, "for statement expected"); - return NULL; - } - loc = cp_lexer_consume_token (parser->lexer)->location; - - /* Don't create location wrapper nodes within an OpenMP "for" - statement. */ - auto_suppress_location_wrappers sentinel; - - matching_parens parens; - if (!parens.require_open (parser)) - return NULL; - - init = orig_init = decl = real_decl = orig_decl = NULL_TREE; - this_pre_body = push_stmt_list (); - - if (code != OACC_LOOP && cxx_dialect >= cxx11) - { - /* Save tokens so that we can put them back. */ - cp_lexer_save_tokens (parser->lexer); - - /* Look for ':' that is not nested in () or {}. */ - bool is_range_for - = (cp_parser_skip_to_closing_parenthesis_1 (parser, - /*recovering=*/false, - CPP_COLON, - /*consume_paren=*/ - false) == -1); - - /* Roll back the tokens we skipped. */ - cp_lexer_rollback_tokens (parser->lexer); - - if (is_range_for) - { - bool saved_colon_corrects_to_scope_p - = parser->colon_corrects_to_scope_p; - - /* A colon is used in range-based for. */ - parser->colon_corrects_to_scope_p = false; - - /* Parse the declaration. */ - cp_parser_simple_declaration (parser, - /*function_definition_allowed_p=*/ - false, &decl); - parser->colon_corrects_to_scope_p - = saved_colon_corrects_to_scope_p; - - cp_parser_require (parser, CPP_COLON, RT_COLON); - - init = cp_parser_range_for (parser, NULL_TREE, NULL_TREE, decl, - false, 0, false, true); - - cp_convert_omp_range_for (this_pre_body, for_block, decl, - orig_decl, init, orig_init, - cond, incr); - if (this_pre_body) - { - if (pre_body) - { - tree t = pre_body; - pre_body = push_stmt_list (); - add_stmt (t); - add_stmt (this_pre_body); - pre_body = pop_stmt_list (pre_body); - } - else - pre_body = this_pre_body; - } - - if (ordered_cl) - error_at (OMP_CLAUSE_LOCATION (ordered_cl), - "% clause with parameter on " - "range-based % loop"); - - goto parse_close_paren; - } - } - - add_private_clause - = cp_parser_omp_for_loop_init (parser, this_pre_body, for_block, - init, orig_init, decl, real_decl); - - cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON); - if (this_pre_body) - { - this_pre_body = pop_stmt_list (this_pre_body); - if (pre_body) - { - tree t = pre_body; - pre_body = push_stmt_list (); - add_stmt (t); - add_stmt (this_pre_body); - pre_body = pop_stmt_list (pre_body); - } - else - pre_body = this_pre_body; - } - - if (decl) - real_decl = decl; - if (cclauses != NULL - && cclauses[C_OMP_CLAUSE_SPLIT_PARALLEL] != NULL - && real_decl != NULL_TREE - && code != OMP_LOOP) - { - tree *c; - for (c = &cclauses[C_OMP_CLAUSE_SPLIT_PARALLEL]; *c ; ) - if (OMP_CLAUSE_CODE (*c) == OMP_CLAUSE_FIRSTPRIVATE - && OMP_CLAUSE_DECL (*c) == real_decl) - { - error_at (loc, "iteration variable %qD" - " should not be firstprivate", real_decl); - *c = OMP_CLAUSE_CHAIN (*c); - } - else if (OMP_CLAUSE_CODE (*c) == OMP_CLAUSE_LASTPRIVATE - && OMP_CLAUSE_DECL (*c) == real_decl) - { - /* Move lastprivate (decl) clause to OMP_FOR_CLAUSES. */ - tree l = *c; - *c = OMP_CLAUSE_CHAIN (*c); - if (code == OMP_SIMD) - { - OMP_CLAUSE_CHAIN (l) = cclauses[C_OMP_CLAUSE_SPLIT_FOR]; - cclauses[C_OMP_CLAUSE_SPLIT_FOR] = l; - } - else - { - OMP_CLAUSE_CHAIN (l) = clauses; - clauses = l; - } - add_private_clause = NULL_TREE; - } - else - { - if (OMP_CLAUSE_CODE (*c) == OMP_CLAUSE_PRIVATE - && OMP_CLAUSE_DECL (*c) == real_decl) - add_private_clause = NULL_TREE; - c = &OMP_CLAUSE_CHAIN (*c); - } - } - - if (add_private_clause) - { - tree c; - for (c = clauses; c ; c = OMP_CLAUSE_CHAIN (c)) - { - if ((OMP_CLAUSE_CODE (c) == OMP_CLAUSE_PRIVATE - || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LASTPRIVATE) - && OMP_CLAUSE_DECL (c) == decl) - break; - else if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_FIRSTPRIVATE - && OMP_CLAUSE_DECL (c) == decl) - error_at (loc, "iteration variable %qD " - "should not be firstprivate", - decl); - else if ((OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION - || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_IN_REDUCTION) - && OMP_CLAUSE_DECL (c) == decl) - error_at (loc, "iteration variable %qD should not be reduction", - decl); - } - if (c == NULL) - { - if ((code == OMP_SIMD && collapse != 1) || code == OMP_LOOP) - c = build_omp_clause (loc, OMP_CLAUSE_LASTPRIVATE); - else if (code != OMP_SIMD) - c = build_omp_clause (loc, OMP_CLAUSE_PRIVATE); - else - c = build_omp_clause (loc, OMP_CLAUSE_LINEAR); - OMP_CLAUSE_DECL (c) = add_private_clause; - c = finish_omp_clauses (c, C_ORT_OMP); - if (c) - { - OMP_CLAUSE_CHAIN (c) = clauses; - clauses = c; - /* For linear, signal that we need to fill up - the so far unknown linear step. */ - if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LINEAR) - OMP_CLAUSE_LINEAR_STEP (c) = NULL_TREE; - } - } - } - - cond = NULL; - if (cp_lexer_next_token_is_not (parser->lexer, CPP_SEMICOLON)) - cond = cp_parser_omp_for_cond (parser, decl, code); - cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON); - - incr = NULL; - if (cp_lexer_next_token_is_not (parser->lexer, CPP_CLOSE_PAREN)) - { - /* If decl is an iterator, preserve the operator on decl - until finish_omp_for. */ - if (real_decl - && ((processing_template_decl - && (TREE_TYPE (real_decl) == NULL_TREE - || !INDIRECT_TYPE_P (TREE_TYPE (real_decl)))) - || CLASS_TYPE_P (TREE_TYPE (real_decl)))) - incr = cp_parser_omp_for_incr (parser, real_decl); - else - incr = cp_parser_expression (parser); - protected_set_expr_location_if_unset (incr, input_location); - } - - parse_close_paren: - if (!parens.require_close (parser)) - cp_parser_skip_to_closing_parenthesis (parser, /*recovering=*/true, - /*or_comma=*/false, - /*consume_paren=*/true); - - TREE_VEC_ELT (declv, i) = decl; - TREE_VEC_ELT (initv, i) = init; - TREE_VEC_ELT (condv, i) = cond; - TREE_VEC_ELT (incrv, i) = incr; - if (orig_init) - { - orig_inits.safe_grow_cleared (i + 1, true); - orig_inits[i] = orig_init; - } - if (orig_decl) - { - if (!orig_declv) - orig_declv = copy_node (declv); - TREE_VEC_ELT (orig_declv, i) = orig_decl; - } - else if (orig_declv) - TREE_VEC_ELT (orig_declv, i) = decl; - - if (i == count - 1) - break; - - /* FIXME: OpenMP 3.0 draft isn't very clear on what exactly is allowed - in between the collapsed for loops to be still considered perfectly - nested. Hopefully the final version clarifies this. - For now handle (multiple) {'s and empty statements. */ - cp_parser_parse_tentatively (parser); - for (;;) - { - if (cp_lexer_next_token_is_keyword (parser->lexer, RID_FOR)) - break; - else if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE)) - { - cp_lexer_consume_token (parser->lexer); - bracecount++; - } - else if (bracecount - && cp_lexer_next_token_is (parser->lexer, CPP_SEMICOLON)) - cp_lexer_consume_token (parser->lexer); - else - { - loc = cp_lexer_peek_token (parser->lexer)->location; - error_at (loc, "not enough for loops to collapse"); - collapse_err = true; - cp_parser_abort_tentative_parse (parser); - declv = NULL_TREE; - break; - } - } - - if (declv) - { - cp_parser_parse_definitely (parser); - nbraces += bracecount; - } + cp_parser_error (parser, "for statement expected"); + return NULL; } - if (nbraces) - if_p = NULL; + /* Initialize parse state for recursive descent. */ + data.declv = make_tree_vec (count); + data.initv = make_tree_vec (count); + data.condv = make_tree_vec (count); + data.incrv = make_tree_vec (count); + data.pre_body = NULL_TREE; + data.for_loc = cp_lexer_peek_token (parser->lexer)->location; + data.count = count; + data.depth = 0; + data.want_nested_loop = true; + data.ordered = ordered > 0; + data.in_intervening_code = false; + data.perfect_nesting_fail = false; + data.fail = false; + data.inscan = inscan; + data.saw_intervening_code = false; + data.code = code; + data.orig_declv = NULL_TREE; + data.clauses = clauses; + data.cclauses = cclauses; + data.ordered_cl = ordered_cl; + parser->omp_for_parse_state = &data; - /* Note that we saved the original contents of this flag when we entered - the structured block, and so we don't need to re-save it here. */ - parser->in_statement = IN_OMP_FOR; + cp_parser_omp_loop_nest (parser, if_p); - /* Note that the grammar doesn't call for a structured block here, - though the loop as a whole is a structured block. */ - if (orig_declv) + /* Bomb out early if there was an error (not enough loops, etc). */ + if (data.fail || data.declv == NULL_TREE) { - body = begin_omp_structured_block (); - for (i = 0; i < count; i++) - if (TREE_VEC_ELT (orig_declv, i) != TREE_VEC_ELT (declv, i)) - cp_finish_omp_range_for (TREE_VEC_ELT (orig_declv, i), - TREE_VEC_ELT (declv, i)); + parser->omp_for_parse_state = save_data; + return NULL_TREE; } - else - body = push_stmt_list (); - if (inscan) - cp_parser_omp_scan_loop_body (parser); - else - cp_parser_statement (parser, NULL_TREE, false, if_p); - if (orig_declv) - body = finish_omp_structured_block (body); - else - body = pop_stmt_list (body); - if (declv == NULL_TREE) + /* Relink the init and body blocks that were built during parsing. At + this point we have a structure nested like + init 0 + body 0 + init 1 + body 1 + init 2 + body 2 + and we want to turn it into + init 0 + init 1 + init 2 + omp_for + body 0 + body 1 + body 2 + We also need to flatten the init blocks, as some code for later + processing of combined directives gets confused otherwise. */ + + gcc_assert (vec_safe_length (data.init_blockv) == count); + gcc_assert (vec_safe_length (data.body_blockv) == count); + gcc_assert (vec_safe_length (data.init_placeholderv) == count); + gcc_assert (vec_safe_length (data.body_placeholderv) == count); + + /* First insert markers for structured blocks for intervening code in + the loop bodies. */ + for (unsigned int i = 0; i < count - 1; i++) + { + bool good = find_structured_blocks (&(data.body_blockv[i]), + data.init_placeholderv[i+1]); + gcc_assert (good); + } + + /* Do the substitution from the inside out. */ + for (unsigned int i = count - 1; i > 0; i--) + { + substitute_in_tree (&(data.body_blockv[i-1]), + data.init_placeholderv[i], + data.body_blockv[i], false); + substitute_in_tree (&(data.init_blockv[i-1]), + data.body_placeholderv[i-1], + data.init_blockv[i], true); + } + + /* Generate the OMP_FOR. Note finish_omp_for adds the OMP_FOR + (and possibly other stuff) to the current statement list but + returns a pointer to the OMP_FOR itself, or null in case of error. */ + result = push_stmt_list (); + ret = finish_omp_for (loc_first, code, data.declv, data.orig_declv, + data.initv, data.condv, data.incrv, + data.body_blockv[0], + data.pre_body, &data.orig_inits, data.clauses); + result = pop_stmt_list (result); + + /* Check for errors involving lb/ub/incr expressions referencing + variables declared in intervening code. */ + if (data.saw_intervening_code + && !c_omp_check_loop_binding_exprs (ret, &data.orig_inits)) ret = NULL_TREE; - else - ret = finish_omp_for (loc_first, code, declv, orig_declv, initv, condv, - incrv, body, pre_body, &orig_inits, clauses); - while (nbraces) + if (ret) { - if (cp_lexer_next_token_is (parser->lexer, CPP_CLOSE_BRACE)) + /* Splice the omp_for into the nest of init blocks. */ + substitute_in_tree (&(data.init_blockv[0]), + data.body_placeholderv[count - 1], + result, true); + + /* Some later processing for combined directives assumes + that the BIND_EXPR containing range for variables appears + at top level in the OMP_FOR body. Fix that up if it's + not the case, e.g. because there is intervening code. */ + if (code != OACC_LOOP) + finish_omp_for_block (data.init_blockv[0], ret); + + /* Clean up the block subblock/superblock links. Per comment in + begin_compound_stmt, "we don't build BLOCK nodes when processing + templates", so skip this step in that case. */ + if (!processing_template_decl) { - cp_lexer_consume_token (parser->lexer); - nbraces--; - } - else if (cp_lexer_next_token_is (parser->lexer, CPP_SEMICOLON)) - cp_lexer_consume_token (parser->lexer); - else - { - if (!collapse_err) - { - error_at (cp_lexer_peek_token (parser->lexer)->location, - "collapsed loops not perfectly nested"); - } - collapse_err = true; - cp_parser_statement_seq_opt (parser, NULL); - if (cp_lexer_next_token_is (parser->lexer, CPP_EOF)) - break; + tree superblock = NULL_TREE; + cp_walk_tree (&data.init_blockv[0], fixup_blocks_walker, + (void *)&superblock, NULL); } + + /* Finally record the result. */ + add_stmt (data.init_blockv[0]); } - while (!for_block->is_empty ()) - { - tree t = for_block->pop (); - if (TREE_CODE (t) == STATEMENT_LIST) - add_stmt (pop_stmt_list (t)); - else - add_stmt (t); - } - + parser->omp_for_parse_state = save_data; return ret; } @@ -44173,7 +44736,7 @@ cp_parser_omp_loop (cp_parser *parser, cp_token *pragma_tok, ret = cp_parser_omp_for_loop (parser, OMP_LOOP, clauses, cclauses, if_p); cp_parser_end_omp_structured_block (parser, save); - add_stmt (finish_omp_for_block (finish_omp_structured_block (sb), ret)); + add_stmt (finish_omp_structured_block (sb)); return ret; } @@ -44222,7 +44785,7 @@ cp_parser_omp_simd (cp_parser *parser, cp_token *pragma_tok, ret = cp_parser_omp_for_loop (parser, OMP_SIMD, clauses, cclauses, if_p); cp_parser_end_omp_structured_block (parser, save); - add_stmt (finish_omp_for_block (finish_omp_structured_block (sb), ret)); + add_stmt (finish_omp_structured_block (sb)); return ret; } @@ -44324,7 +44887,7 @@ cp_parser_omp_for (cp_parser *parser, cp_token *pragma_tok, ret = cp_parser_omp_for_loop (parser, OMP_FOR, clauses, cclauses, if_p); cp_parser_end_omp_structured_block (parser, save); - add_stmt (finish_omp_for_block (finish_omp_structured_block (sb), ret)); + add_stmt (finish_omp_structured_block (sb)); return ret; } @@ -45172,7 +45735,7 @@ cp_parser_omp_distribute (cp_parser *parser, cp_token *pragma_tok, ret = cp_parser_omp_for_loop (parser, OMP_DISTRIBUTE, clauses, NULL, if_p); cp_parser_end_omp_structured_block (parser, save); - add_stmt (finish_omp_for_block (finish_omp_structured_block (sb), ret)); + add_stmt (finish_omp_structured_block (sb)); return ret; } @@ -45874,6 +46437,7 @@ cp_parser_oacc_cache (cp_parser *parser, cp_token *pragma_tok) | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_COPYIN) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_COPYOUT) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_CREATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_DEFAULT) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_DETACH) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_DEVICEPTR) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_IF) \ @@ -46214,7 +46778,15 @@ cp_parser_oacc_loop (cp_parser *parser, cp_token *pragma_tok, char *p_name, int save = cp_parser_begin_omp_structured_block (parser); tree stmt = cp_parser_omp_for_loop (parser, OACC_LOOP, clauses, NULL, if_p); cp_parser_end_omp_structured_block (parser, save); - add_stmt (finish_omp_structured_block (block)); + + /* Later processing of combined acc loop constructs gets confused + by an extra level of empty nested BIND_EXPRs, so flatten them. */ + block = finish_omp_structured_block (block); + if (TREE_CODE (block) == BIND_EXPR + && TREE_CODE (BIND_EXPR_BODY (block)) == BIND_EXPR + && !BIND_EXPR_VARS (block)) + block = BIND_EXPR_BODY (block); + add_stmt (block); return stmt; } @@ -47753,7 +48325,7 @@ cp_parser_omp_declare_reduction_exprs (tree fndecl, cp_parser *parser) bool ctor = false; if (strcmp (p, "omp_priv") == 0) { - bool is_direct_init, is_non_constant_init; + bool is_non_constant_init; ctor = true; cp_lexer_consume_token (parser->lexer); /* Reject initializer (omp_priv) and initializer (omp_priv ()). */ @@ -47768,7 +48340,8 @@ cp_parser_omp_declare_reduction_exprs (tree fndecl, cp_parser *parser) error ("invalid initializer clause"); return false; } - initializer = cp_parser_initializer (parser, &is_direct_init, + initializer = cp_parser_initializer (parser, + /*is_direct_init=*/nullptr, &is_non_constant_init); cp_finish_decl (omp_priv, initializer, !is_non_constant_init, NULL_TREE, LOOKUP_ONLYCONVERTING); @@ -48566,7 +49139,7 @@ cp_parser_omp_taskloop (cp_parser *parser, cp_token *pragma_tok, if_p); cp_parser_end_omp_structured_block (parser, save); - add_stmt (finish_omp_for_block (finish_omp_structured_block (sb), ret)); + add_stmt (finish_omp_structured_block (sb)); return ret; } @@ -49350,6 +49923,17 @@ cp_parser_pragma (cp_parser *parser, enum pragma_context context, bool *if_p) parser->lexer->in_pragma = true; id = cp_parser_pragma_kind (pragma_tok); + if (parser->omp_for_parse_state + && parser->omp_for_parse_state->in_intervening_code + && id >= PRAGMA_OMP__START_ + && id <= PRAGMA_OMP__LAST_) + { + error_at (pragma_tok->location, + "intervening code must not contain OpenMP directives"); + parser->omp_for_parse_state->fail = true; + cp_parser_skip_to_pragma_eol (parser, pragma_tok); + return false; + } if (id != PRAGMA_OMP_DECLARE && id != PRAGMA_OACC_ROUTINE) cp_ensure_no_omp_declare_simd (parser); switch (id) diff --git a/gcc/cp/parser.h b/gcc/cp/parser.h index e261d7e16e48..6cbb9a8e0314 100644 --- a/gcc/cp/parser.h +++ b/gcc/cp/parser.h @@ -435,6 +435,9 @@ struct GTY(()) cp_parser { specification, if any, or UNKNOWN_LOCATION otherwise. */ location_t innermost_linkage_specification_location; + /* Pointer to state for parsing omp_loops. Managed by + cp_parser_omp_for_loop in parser.cc and not used outside that file. */ + struct omp_for_parse_data * GTY((skip)) omp_for_parse_state; }; /* In parser.cc */ diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc index 2706fa619bf8..0790bbf948ff 100644 --- a/gcc/cp/pt.cc +++ b/gcc/cp/pt.cc @@ -314,7 +314,7 @@ finish_member_template_decl (tree decl) return DECL_TI_TEMPLATE (decl); } else - return decl; + return NULL_TREE; } else error_at (DECL_SOURCE_LOCATION (decl), @@ -4966,19 +4966,21 @@ generic_targs_for (tree tmpl) } /* Return the template arguments corresponding to the template parameters of - TMPL's enclosing scope. When TMPL is a member of a partial specialization, + DECL's enclosing scope. When DECL is a member of a partial specialization, this returns the arguments for the partial specialization as opposed to those for the primary template, which is the main difference between this function - and simply using e.g. the TYPE_TI_ARGS of TMPL's DECL_CONTEXT. */ + and simply using e.g. the TYPE_TI_ARGS of DECL's DECL_CONTEXT. */ tree -outer_template_args (tree tmpl) +outer_template_args (const_tree decl) { - tree ti = get_template_info (DECL_TEMPLATE_RESULT (tmpl)); + if (TREE_CODE (decl) == TEMPLATE_DECL) + decl = DECL_TEMPLATE_RESULT (decl); + tree ti = get_template_info (decl); if (!ti) return NULL_TREE; tree args = TI_ARGS (ti); - if (!PRIMARY_TEMPLATE_P (tmpl)) + if (!PRIMARY_TEMPLATE_P (TI_TEMPLATE (ti))) return args; if (TMPL_ARGS_DEPTH (args) == 1) return NULL_TREE; @@ -11049,14 +11051,21 @@ uses_outer_template_parms (tree decl) from its enclosing scope. */ bool -uses_outer_template_parms_in_constraints (tree decl) +uses_outer_template_parms_in_constraints (tree decl, tree ctx/*=NULL_TREE*/) { tree ci = get_constraints (decl); if (ci) ci = CI_ASSOCIATED_CONSTRAINTS (ci); if (!ci) return false; - int depth = template_class_depth (CP_DECL_CONTEXT (decl)); + if (!ctx) + { + if (tree fc = DECL_FRIEND_CONTEXT (decl)) + ctx = fc; + else + ctx = CP_DECL_CONTEXT (decl); + } + int depth = template_class_depth (ctx); if (depth == 0) return false; return for_each_template_parm (ci, template_parm_outer_level, @@ -11393,9 +11402,6 @@ tsubst_friend_function (tree decl, tree args) not_tmpl = DECL_TEMPLATE_RESULT (new_friend); new_friend_result_template_info = DECL_TEMPLATE_INFO (not_tmpl); } - else if (!constraints_satisfied_p (new_friend)) - /* Only define a constrained hidden friend when satisfied. */ - return error_mark_node; /* Inside pushdecl_namespace_level, we will push into the current namespace. However, the friend function should go @@ -18346,7 +18352,7 @@ tsubst_copy_asm_operands (tree t, tree args, tsubst_flags_t complain, static tree *omp_parallel_combined_clauses; static tree tsubst_decomp_names (tree, tree, tree, tsubst_flags_t, tree, - tree *, unsigned int *); + cp_decomp *); /* Substitute one OMP_FOR iterator. */ @@ -18377,28 +18383,27 @@ tsubst_omp_for_iterator (tree t, int i, tree declv, tree &orig_declv, && VAR_P (TREE_OPERAND (v, 0)) && DECL_DECOMPOSITION_P (TREE_OPERAND (v, 0))) { - tree decomp_first = NULL_TREE; - unsigned decomp_cnt = 0; + cp_decomp decomp_d = { NULL_TREE, 0 }; tree d = tsubst_decl (TREE_OPERAND (v, 0), args, complain); maybe_push_decl (d); d = tsubst_decomp_names (d, TREE_OPERAND (v, 0), args, complain, - in_decl, &decomp_first, &decomp_cnt); + in_decl, &decomp_d); decomp = true; if (d == error_mark_node) decl = error_mark_node; else - for (unsigned int i = 0; i < decomp_cnt; i++) + for (unsigned int i = 0; i < decomp_d.count; i++) { - if (!DECL_HAS_VALUE_EXPR_P (decomp_first)) + if (!DECL_HAS_VALUE_EXPR_P (decomp_d.decl)) { tree v = build_nt (ARRAY_REF, d, - size_int (decomp_cnt - i - 1), + size_int (decomp_d.count - i - 1), NULL_TREE, NULL_TREE); - SET_DECL_VALUE_EXPR (decomp_first, v); - DECL_HAS_VALUE_EXPR_P (decomp_first) = 1; + SET_DECL_VALUE_EXPR (decomp_d.decl, v); + DECL_HAS_VALUE_EXPR_P (decomp_d.decl) = 1; } - fit_decomposition_lang_decl (decomp_first, d); - decomp_first = DECL_CHAIN (decomp_first); + fit_decomposition_lang_decl (decomp_d.decl, d); + decomp_d.decl = DECL_CHAIN (decomp_d.decl); } } } @@ -18479,7 +18484,8 @@ tsubst_omp_for_iterator (tree t, int i, tree declv, tree &orig_declv, tree this_pre_body = NULL_TREE; tree orig_init = NULL_TREE; tree orig_decl = NULL_TREE; - cp_convert_omp_range_for (this_pre_body, NULL, decl, orig_decl, init, + tree init_sl = NULL_TREE; + cp_convert_omp_range_for (this_pre_body, init_sl, decl, orig_decl, init, orig_init, cond, incr); if (orig_decl) { @@ -18716,11 +18722,10 @@ tsubst_find_omp_teams (tree *tp, int *walk_subtrees, void *) static tree tsubst_decomp_names (tree decl, tree pattern_decl, tree args, - tsubst_flags_t complain, tree in_decl, tree *first, - unsigned int *cnt) + tsubst_flags_t complain, tree in_decl, cp_decomp *decomp) { tree decl2, decl3, prev = decl; - *cnt = 0; + decomp->count = 0; gcc_assert (DECL_NAME (decl) == NULL_TREE); for (decl2 = DECL_CHAIN (pattern_decl); decl2 @@ -18729,12 +18734,12 @@ tsubst_decomp_names (tree decl, tree pattern_decl, tree args, && DECL_NAME (decl2); decl2 = DECL_CHAIN (decl2)) { - if (TREE_TYPE (decl2) == error_mark_node && *cnt == 0) + if (TREE_TYPE (decl2) == error_mark_node && decomp->count == 0) { gcc_assert (errorcount); return error_mark_node; } - (*cnt)++; + decomp->count++; gcc_assert (DECL_DECOMP_BASE (decl2) == pattern_decl); gcc_assert (DECL_HAS_VALUE_EXPR_P (decl2)); tree v = DECL_VALUE_EXPR (decl2); @@ -18764,7 +18769,7 @@ tsubst_decomp_names (tree decl, tree pattern_decl, tree args, else prev = decl3; } - *first = prev; + decomp->decl = prev; return decl; } @@ -19036,8 +19041,8 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl) else { bool const_init = false; - unsigned int cnt = 0; - tree first = NULL_TREE, ndecl = error_mark_node; + cp_decomp decomp_d, *decomp = NULL; + tree ndecl = error_mark_node; tree asmspec_tree = NULL_TREE; maybe_push_decl (decl); @@ -19049,9 +19054,11 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl) if (VAR_P (decl) && DECL_DECOMPOSITION_P (decl) && TREE_TYPE (pattern_decl) != error_mark_node) - ndecl = tsubst_decomp_names (decl, pattern_decl, args, - complain, in_decl, &first, - &cnt); + { + decomp = &decomp_d; + ndecl = tsubst_decomp_names (decl, pattern_decl, args, + complain, in_decl, decomp); + } init = tsubst_init (init, decl, args, complain, in_decl); @@ -19059,9 +19066,6 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl) const_init = (DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (pattern_decl)); - if (ndecl != error_mark_node) - cp_maybe_mangle_decomp (ndecl, first, cnt); - /* In a non-template function, VLA type declarations are handled in grokdeclarator; for templates, handle them now. */ @@ -19078,10 +19082,11 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl) TREE_TYPE (asmspec_tree) = char_array_type_node; } - cp_finish_decl (decl, init, const_init, asmspec_tree, 0); + cp_finish_decl (decl, init, const_init, asmspec_tree, 0, + decomp); if (ndecl != error_mark_node) - cp_finish_decomp (ndecl, first, cnt); + cp_finish_decomp (ndecl, decomp); } } } @@ -19120,12 +19125,13 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl) maybe_push_decl (decl); expr = RECUR (RANGE_FOR_EXPR (t)); - tree decomp_first = NULL_TREE; - unsigned decomp_cnt = 0; + cp_decomp decomp_d, *decomp = NULL; if (VAR_P (decl) && DECL_DECOMPOSITION_P (decl)) - decl = tsubst_decomp_names (decl, RANGE_FOR_DECL (t), args, - complain, in_decl, - &decomp_first, &decomp_cnt); + { + decomp = &decomp_d; + decl = tsubst_decomp_names (decl, RANGE_FOR_DECL (t), args, + complain, in_decl, decomp); + } if (processing_template_decl) { @@ -19133,15 +19139,14 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl) RANGE_FOR_UNROLL (stmt) = RANGE_FOR_UNROLL (t); RANGE_FOR_NOVECTOR (stmt) = RANGE_FOR_NOVECTOR (t); finish_range_for_decl (stmt, decl, expr); - if (decomp_first && decl != error_mark_node) - cp_finish_decomp (decl, decomp_first, decomp_cnt); + if (decomp && decl != error_mark_node) + cp_finish_decomp (decl, decomp); } else { unsigned short unroll = (RANGE_FOR_UNROLL (t) ? tree_to_uhwi (RANGE_FOR_UNROLL (t)) : 0); - stmt = cp_convert_range_for (stmt, decl, expr, - decomp_first, decomp_cnt, + stmt = cp_convert_range_for (stmt, decl, expr, decomp, RANGE_FOR_IVDEP (t), unroll, RANGE_FOR_NOVECTOR (t)); } @@ -19741,6 +19746,7 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl) break; case OMP_MASTER: + case OMP_STRUCTURED_BLOCK: omp_parallel_combined_clauses = NULL; /* FALLTHRU */ case OMP_SECTION: diff --git a/gcc/cp/ptree.cc b/gcc/cp/ptree.cc index 33af7b81f587..b4001486701f 100644 --- a/gcc/cp/ptree.cc +++ b/gcc/cp/ptree.cc @@ -38,10 +38,6 @@ cxx_print_decl (FILE *file, tree node, int indent) return; } - if (!CODE_CONTAINS_STRUCT (TREE_CODE (node), TS_DECL_COMMON) - || !DECL_LANG_SPECIFIC (node)) - return; - if (TREE_CODE (node) == FUNCTION_DECL) { int flags = TFF_DECL_SPECIFIERS|TFF_RETURN_TYPE @@ -106,6 +102,10 @@ cxx_print_decl (FILE *file, tree node, int indent) need_indent = false; } + if (!CODE_CONTAINS_STRUCT (TREE_CODE (node), TS_DECL_COMMON) + || !DECL_LANG_SPECIFIC (node)) + return; + if (DECL_EXTERNAL (node) && DECL_NOT_REALLY_EXTERN (node)) { if (need_indent) @@ -124,27 +124,33 @@ cxx_print_decl (FILE *file, tree node, int indent) need_indent = false; } - if (VAR_OR_FUNCTION_DECL_P (node) + if ((VAR_OR_FUNCTION_DECL_P (node) + || TREE_CODE (node) == FIELD_DECL + || TREE_CODE (node) == TYPE_DECL + || TREE_CODE (node) == CONCEPT_DECL + || TREE_CODE (node) == TEMPLATE_DECL) && DECL_TEMPLATE_INFO (node)) - print_node (file, "template-info", DECL_TEMPLATE_INFO (node), - indent + 4); + { + print_node (file, "template-info", DECL_TEMPLATE_INFO (node), + indent + 4); + indent_to (file, indent + 3); + fprintf (file, " use_template=%d", DECL_USE_TEMPLATE (node)); + } } void cxx_print_type (FILE *file, tree node, int indent) { + if (TYPE_LANG_SPECIFIC (node) + && TYPE_TEMPLATE_INFO (node)) + print_node (file, "template-info", TYPE_TEMPLATE_INFO (node), indent + 4); + switch (TREE_CODE (node)) { case BOUND_TEMPLATE_TEMPLATE_PARM: - print_node (file, "args", TYPE_TI_ARGS (node), indent + 4); - gcc_fallthrough (); - case TEMPLATE_TYPE_PARM: case TEMPLATE_TEMPLATE_PARM: - indent_to (file, indent + 3); - fprintf (file, "index %d level %d orig_level %d", - TEMPLATE_TYPE_IDX (node), TEMPLATE_TYPE_LEVEL (node), - TEMPLATE_TYPE_ORIG_LEVEL (node)); + print_node (file, "tpi", TEMPLATE_TYPE_PARM_INDEX (node), indent + 4); return; case FUNCTION_TYPE: diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc index e810bc41fc8e..5b539ceefbf7 100644 --- a/gcc/cp/semantics.cc +++ b/gcc/cp/semantics.cc @@ -10541,6 +10541,7 @@ finish_omp_for (location_t locus, enum tree_code code, tree declv, int i; int collapse = 1; int ordered = 0; + auto_vec init_locv; gcc_assert (TREE_VEC_LENGTH (declv) == TREE_VEC_LENGTH (initv)); gcc_assert (TREE_VEC_LENGTH (declv) == TREE_VEC_LENGTH (condv)); @@ -10569,6 +10570,28 @@ finish_omp_for (location_t locus, enum tree_code code, tree declv, incr = TREE_VEC_ELT (incrv, i); elocus = locus; + /* We are going to throw out the init's original MODIFY_EXPR or + MODOP_EXPR below. Save its location so we can use it when + reconstructing the expression farther down. Alternatively, if the + initializer is a binding of the iteration variable, save + that location. Any of these locations in the initialization clause + for the current nested loop are better than using the argument locus, + that points to the "for" of the the outermost loop in the nest. */ + if (init && EXPR_HAS_LOCATION (init)) + elocus = EXPR_LOCATION (init); + else if (decl && INDIRECT_REF_P (decl) && EXPR_HAS_LOCATION (decl)) + /* This can happen for class iterators. */ + elocus = EXPR_LOCATION (decl); + else if (decl && DECL_P (decl)) + { + if (DECL_SOURCE_LOCATION (decl) != UNKNOWN_LOCATION) + elocus = DECL_SOURCE_LOCATION (decl); + else if (DECL_INITIAL (decl) + && EXPR_HAS_LOCATION (DECL_INITIAL (decl))) + elocus = EXPR_LOCATION (DECL_INITIAL (decl)); + } + init_locv.safe_push (elocus); + if (decl == NULL) { if (init != NULL) @@ -10597,9 +10620,6 @@ finish_omp_for (location_t locus, enum tree_code code, tree declv, } } - if (init && EXPR_HAS_LOCATION (init)) - elocus = EXPR_LOCATION (init); - if (cond == global_namespace) continue; @@ -10646,8 +10666,8 @@ finish_omp_for (location_t locus, enum tree_code code, tree declv, again and going through the cp_build_modify_expr path below when we instantiate the thing. */ TREE_VEC_ELT (initv, i) - = build2 (MODIFY_EXPR, void_type_node, TREE_VEC_ELT (declv, i), - TREE_VEC_ELT (initv, i)); + = build2_loc (init_locv[i], MODIFY_EXPR, void_type_node, + TREE_VEC_ELT (declv, i), TREE_VEC_ELT (initv, i)); } TREE_TYPE (stmt) = void_type_node; @@ -10676,10 +10696,7 @@ finish_omp_for (location_t locus, enum tree_code code, tree declv, incr = TREE_VEC_ELT (incrv, i); if (orig_incr) TREE_VEC_ELT (orig_incr, i) = incr; - elocus = locus; - - if (init && EXPR_HAS_LOCATION (init)) - elocus = EXPR_LOCATION (init); + elocus = init_locv[i]; if (!DECL_P (decl)) { @@ -10724,7 +10741,7 @@ finish_omp_for (location_t locus, enum tree_code code, tree declv, init = cp_build_modify_expr (elocus, decl, NOP_EXPR, init, tf_warning_or_error); else - init = build2 (MODIFY_EXPR, void_type_node, decl, init); + init = build2_loc (elocus, MODIFY_EXPR, void_type_node, decl, init); if (decl == error_mark_node || init == error_mark_node) return NULL; @@ -10896,47 +10913,71 @@ finish_omp_for (location_t locus, enum tree_code code, tree declv, return omp_for; } -/* Fix up range for decls. Those decls were pushed into BIND's BIND_EXPR_VARS - and need to be moved into the BIND_EXPR inside of the OMP_FOR's body. */ +/* Code walker for finish_omp_for_block: extract binding of DP->var + from its current block and move it to a new BIND_EXPR DP->b + surrounding the body of DP->omp_for. */ +struct fofb_data { + tree var; + tree b; + tree omp_for; +}; + +static tree +finish_omp_for_block_walker (tree *tp, int *walk_subtrees, void *dp) +{ + struct fofb_data *fofb = (struct fofb_data *)dp; + if (TREE_CODE (*tp) == BIND_EXPR) + for (tree *p = &BIND_EXPR_VARS (*tp); *p; p = &DECL_CHAIN (*p)) + { + if (*p == fofb->var) + { + *p = DECL_CHAIN (*p); + if (fofb->b == NULL_TREE) + { + fofb->b = make_node (BLOCK); + fofb->b = build3 (BIND_EXPR, void_type_node, NULL_TREE, + OMP_FOR_BODY (fofb->omp_for), fofb->b); + TREE_SIDE_EFFECTS (fofb->b) = 1; + OMP_FOR_BODY (fofb->omp_for) = fofb->b; + } + DECL_CHAIN (fofb->var) = BIND_EXPR_VARS (fofb->b); + BIND_EXPR_VARS (fofb->b) = fofb->var; + BLOCK_VARS (BIND_EXPR_BLOCK (fofb->b)) = fofb->var; + BLOCK_VARS (BIND_EXPR_BLOCK (*tp)) = BIND_EXPR_VARS (*tp); + return *tp; + } + } + if (TREE_CODE (*tp) != BIND_EXPR && TREE_CODE (*tp) != STATEMENT_LIST) + *walk_subtrees = false; + return NULL_TREE; +} + +/* Fix up range for decls. Those decls were pushed into BIND's + BIND_EXPR_VARS, or that of a nested BIND_EXPR inside its body, + and need to be moved into a new BIND_EXPR surrounding OMP_FOR's body + so that processing of combined loop directives can find them. */ tree finish_omp_for_block (tree bind, tree omp_for) { if (omp_for == NULL_TREE || !OMP_FOR_ORIG_DECLS (omp_for) - || bind == NULL_TREE - || TREE_CODE (bind) != BIND_EXPR) + || bind == NULL_TREE) return bind; - tree b = NULL_TREE; + struct fofb_data fofb; + fofb.b = NULL_TREE; + fofb.omp_for = omp_for; for (int i = 0; i < TREE_VEC_LENGTH (OMP_FOR_INIT (omp_for)); i++) if (TREE_CODE (TREE_VEC_ELT (OMP_FOR_ORIG_DECLS (omp_for), i)) == TREE_LIST && TREE_CHAIN (TREE_VEC_ELT (OMP_FOR_ORIG_DECLS (omp_for), i))) { tree v = TREE_CHAIN (TREE_VEC_ELT (OMP_FOR_ORIG_DECLS (omp_for), i)); - gcc_assert (BIND_EXPR_BLOCK (bind) - && (BIND_EXPR_VARS (bind) - == BLOCK_VARS (BIND_EXPR_BLOCK (bind)))); for (int j = 2; j < TREE_VEC_LENGTH (v); j++) - for (tree *p = &BIND_EXPR_VARS (bind); *p; p = &DECL_CHAIN (*p)) - { - if (*p == TREE_VEC_ELT (v, j)) - { - tree var = *p; - *p = DECL_CHAIN (*p); - if (b == NULL_TREE) - { - b = make_node (BLOCK); - b = build3 (BIND_EXPR, void_type_node, NULL_TREE, - OMP_FOR_BODY (omp_for), b); - TREE_SIDE_EFFECTS (b) = 1; - OMP_FOR_BODY (omp_for) = b; - } - DECL_CHAIN (var) = BIND_EXPR_VARS (b); - BIND_EXPR_VARS (b) = var; - BLOCK_VARS (BIND_EXPR_BLOCK (b)) = var; - } - } - BLOCK_VARS (BIND_EXPR_BLOCK (bind)) = BIND_EXPR_VARS (bind); + { + fofb.var = TREE_VEC_ELT (v, j); + cp_walk_tree (&bind, finish_omp_for_block_walker, + (void *)&fofb, NULL); + } } return bind; } diff --git a/gcc/cp/typeck.cc b/gcc/cp/typeck.cc index d5c0c85ed51b..459739d5866b 100644 --- a/gcc/cp/typeck.cc +++ b/gcc/cp/typeck.cc @@ -10262,6 +10262,8 @@ convert_for_assignment (tree type, tree rhs, { range_label_for_type_mismatch label (rhstype, type); gcc_rich_location richloc (rhs_loc, has_loc ? &label : NULL); + auto_diagnostic_group d; + switch (errtype) { case ICR_DEFAULT_ARGUMENT: @@ -10296,6 +10298,10 @@ convert_for_assignment (tree type, tree rhs, gcc_unreachable(); } } + + /* See if we can be more helpful. */ + maybe_show_nonconverting_candidate (type, rhstype, rhs, flags); + if (TYPE_PTR_P (rhstype) && TYPE_PTR_P (type) && CLASS_TYPE_P (TREE_TYPE (rhstype)) diff --git a/gcc/d/ChangeLog b/gcc/d/ChangeLog index 50750bb45405..23b391cd77a6 100644 --- a/gcc/d/ChangeLog +++ b/gcc/d/ChangeLog @@ -1,3 +1,14 @@ +2023-08-20 Iain Buclaw + + * dmd/MERGE: Merge upstream dmd 26f049fb26. + * dmd/VERSION: Bump version to v2.105.0-beta.1. + * d-codegen.cc (get_frameinfo): Check useGC in condition. + * d-lang.cc (d_handle_option): Set obsolete parameter when compiling + with -Wall. + (d_post_options): Set useGC to false when compiling with + -fno-druntime. Propagate obsolete flag to compileEnv. + * expr.cc (ExprVisitor::visit (CatExp *)): Check useGC in condition. + 2023-07-10 Iain Buclaw * dmd/MERGE: Merge upstream dmd a88e1335f7. diff --git a/gcc/d/d-codegen.cc b/gcc/d/d-codegen.cc index 2738958fde12..155f5d0d6188 100644 --- a/gcc/d/d-codegen.cc +++ b/gcc/d/d-codegen.cc @@ -2850,7 +2850,7 @@ get_frameinfo (FuncDeclaration *fd) /* This can shift due to templates being expanded that access alias symbols, give it a decent error for now. */ if (requiresClosure != fd->requiresClosure - && (fd->nrvo_var || global.params.betterC)) + && (fd->nrvo_var || !global.params.useGC)) fd->checkClosure (); /* Set-up a closure frame, this will be allocated on the heap. */ diff --git a/gcc/d/d-lang.cc b/gcc/d/d-lang.cc index 7cb86bf268ff..10b9000119ec 100644 --- a/gcc/d/d-lang.cc +++ b/gcc/d/d-lang.cc @@ -779,6 +779,7 @@ d_handle_option (size_t scode, const char *arg, HOST_WIDE_INT value, case OPT_Wall: if (value) global.params.warnings = DIAGNOSTICinform; + global.params.obsolete = value; break; case OPT_Wdeprecated: @@ -894,6 +895,7 @@ d_post_options (const char ** fn) flag_exceptions = false; } + global.params.useGC = false; global.params.checkAction = CHECKACTION_C; } @@ -939,6 +941,7 @@ d_post_options (const char ** fn) global.compileEnv.previewIn = global.params.previewIn; global.compileEnv.ddocOutput = global.params.ddoc.doOutput; global.compileEnv.shortenedMethods = global.params.shortenedMethods; + global.compileEnv.obsolete = global.params.obsolete; /* Add in versions given on the command line. */ if (global.params.versionids) diff --git a/gcc/d/dmd/MERGE b/gcc/d/dmd/MERGE index 308d51b55d08..a02a8cbaba5f 100644 --- a/gcc/d/dmd/MERGE +++ b/gcc/d/dmd/MERGE @@ -1,4 +1,4 @@ -a88e1335f7ea767ef438c34998f5d1f26008c586 +26f049fb26e755096dea3f1474decea7c0fef187 The first line of this file holds the git revision number of the last merge done from the dlang/dmd repository. diff --git a/gcc/d/dmd/VERSION b/gcc/d/dmd/VERSION index 9c46eea2d8ca..6faa8d801e6c 100644 --- a/gcc/d/dmd/VERSION +++ b/gcc/d/dmd/VERSION @@ -1 +1 @@ -v2.104.1 +v2.105.0-beta.1 diff --git a/gcc/d/dmd/clone.d b/gcc/d/dmd/clone.d index 3586f20ddbed..4cff1ecf49c0 100644 --- a/gcc/d/dmd/clone.d +++ b/gcc/d/dmd/clone.d @@ -1263,7 +1263,7 @@ FuncDeclaration buildPostBlit(StructDeclaration sd, Scope* sc) // block to destroy any prior successfully postblitted fields should // this field's postblit fail. // Don't generate it for betterC code since it cannot throw exceptions. - if (fieldsToDestroy.length > 0 && !(cast(TypeFunction)sdv.postblit.type).isnothrow && !global.params.betterC) + if (fieldsToDestroy.length > 0 && !(cast(TypeFunction)sdv.postblit.type).isnothrow && global.params.useExceptions) { // create a list of destructors that need to be called Expression[] dtorCalls; diff --git a/gcc/d/dmd/common/string.d b/gcc/d/dmd/common/string.d index a1614fd907c8..6de921e3d7a1 100644 --- a/gcc/d/dmd/common/string.d +++ b/gcc/d/dmd/common/string.d @@ -48,7 +48,7 @@ struct SmallBuffer(Element) } else { - assert(len < sizeof.max / Element.sizeof); + assert(len < sizeof.max / (2 * Element.sizeof)); _extent = (cast(typeof(_extent.ptr)) malloc(len * Element.sizeof))[0 .. len]; _extent.ptr || assert(0, "Out of memory."); needsFree = true; diff --git a/gcc/d/dmd/cond.d b/gcc/d/dmd/cond.d index fcb50e0a648c..467f9f1a9901 100644 --- a/gcc/d/dmd/cond.d +++ b/gcc/d/dmd/cond.d @@ -733,6 +733,7 @@ extern (C++) final class VersionCondition : DVCondition case "SysV4": case "TVOS": case "unittest": + case "VisionOS": case "WASI": case "WatchOS": case "WebAssembly": diff --git a/gcc/d/dmd/cparse.d b/gcc/d/dmd/cparse.d index 1b6b2bb4b1b2..03383d13fd59 100644 --- a/gcc/d/dmd/cparse.d +++ b/gcc/d/dmd/cparse.d @@ -1911,14 +1911,12 @@ final class CParser(AST) : Parser!AST if (tt.id || tt.tok == TOK.enum_) { if (!tt.id && id) + /* This applies for enums declared as + * typedef enum {A} E; + */ tt.id = id; Specifier spec; - auto stag = declareTag(tt, spec); - if (tt.tok == TOK.enum_) - { - isalias = false; - s = new AST.AliasDeclaration(token.loc, id, stag); - } + declareTag(tt, spec); } } if (isalias) diff --git a/gcc/d/dmd/dsymbolsem.d b/gcc/d/dmd/dsymbolsem.d index 622e28691a63..7a800bddd02f 100644 --- a/gcc/d/dmd/dsymbolsem.d +++ b/gcc/d/dmd/dsymbolsem.d @@ -1459,9 +1459,12 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor if (sym) { import dmd.access : symbolIsVisible; - if (!symbolIsVisible(sc, sym)) + if (!symbolIsVisible(sc, sym) && !sym.errors) + { imp.mod.error(imp.loc, "member `%s` is not visible from module `%s`", imp.names[i].toChars(), sc._module.toChars()); + sym.errors = true; + } ad.dsymbolSemantic(sc); // If the import declaration is in non-root module, // analysis of the aliased symbol is deferred. @@ -2231,11 +2234,14 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor if (!(sc.flags & SCOPE.Cfile)) // C enum remains incomplete until members are done ed.semanticRun = PASS.semanticdone; - // @@@DEPRECATED_2.110@@@ https://dlang.org/deprecate.html#scope%20as%20a%20type%20constraint - // Deprecated in 2.100 - // Make an error in 2.110 - if (sc.stc & STC.scope_) - deprecation(ed.loc, "`scope` as a type constraint is deprecated. Use `scope` at the usage site."); + version (none) + { + // @@@DEPRECATED_2.110@@@ https://dlang.org/deprecate.html#scope%20as%20a%20type%20constraint + // Deprecated in 2.100 + // Make an error in 2.110 + if (sc.stc & STC.scope_) + deprecation(ed.loc, "`scope` as a type constraint is deprecated. Use `scope` at the usage site."); + } Scope* sce; if (ed.isAnonymous()) @@ -3176,6 +3182,9 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor funcdecl.skipCodegen = true; funcdecl._linkage = sc.linkage; + if (sc.flags & SCOPE.Cfile && funcdecl.isFuncLiteralDeclaration()) + funcdecl._linkage = LINK.d; // so they are uniquely mangled + if (auto fld = funcdecl.isFuncLiteralDeclaration()) { if (fld.treq) @@ -3460,77 +3469,10 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor if (funcdecl.isAbstract() && funcdecl.isFinalFunc()) funcdecl.error("cannot be both `final` and `abstract`"); - version (none) - { - if (funcdecl.isAbstract() && funcdecl.fbody) - funcdecl.error("`abstract` functions cannot have bodies"); - } - - version (none) - { - if (funcdecl.isStaticConstructor() || funcdecl.isStaticDestructor()) - { - if (!funcdecl.isStatic() || funcdecl.type.nextOf().ty != Tvoid) - funcdecl.error("static constructors / destructors must be `static void`"); - if (f.arguments && f.arguments.length) - funcdecl.error("static constructors / destructors must have empty parameter list"); - // BUG: check for invalid storage classes - } - } if (funcdecl.printf || funcdecl.scanf) { - /* printf/scanf-like functions must be of the form: - * extern (C/C++) T printf([parameters...], const(char)* format, ...); - * or: - * extern (C/C++) T vprintf([parameters...], const(char)* format, va_list); - */ - - static bool isPointerToChar(Parameter p) - { - if (auto tptr = p.type.isTypePointer()) - { - return tptr.next.ty == Tchar; - } - return false; - } - - bool isVa_list(Parameter p) - { - return p.type.equals(target.va_listType(funcdecl.loc, sc)); - } - - const nparams = f.parameterList.length; - if ((f.linkage == LINK.c || f.linkage == LINK.cpp) && - - (f.parameterList.varargs == VarArg.variadic && - nparams >= 1 && - isPointerToChar(f.parameterList[nparams - 1]) || - - f.parameterList.varargs == VarArg.none && - nparams >= 2 && - isPointerToChar(f.parameterList[nparams - 2]) && - isVa_list(f.parameterList[nparams - 1]) - ) - ) - { - // the signature is valid for printf/scanf, no error - } - else - { - const p = (funcdecl.printf ? Id.printf : Id.scanf).toChars(); - if (f.parameterList.varargs == VarArg.variadic) - { - funcdecl.error("`pragma(%s)` functions must be `extern(C) %s %s([parameters...], const(char)*, ...)`" - ~ " not `%s`", - p, f.next.toChars(), funcdecl.toChars(), funcdecl.type.toChars()); - } - else - { - funcdecl.error("`pragma(%s)` functions must be `extern(C) %s %s([parameters...], const(char)*, va_list)`", - p, f.next.toChars(), funcdecl.toChars()); - } - } + checkPrintfScanfSignature(funcdecl, f, sc); } if (auto id = parent.isInterfaceDeclaration()) @@ -4869,11 +4811,14 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor sd.deferred.semantic3(sc); } - // @@@DEPRECATED_2.110@@@ https://dlang.org/deprecate.html#scope%20as%20a%20type%20constraint - // Deprecated in 2.100 - // Make an error in 2.110 - if (sd.storage_class & STC.scope_) - deprecation(sd.loc, "`scope` as a type constraint is deprecated. Use `scope` at the usage site."); + version (none) + { + // @@@DEPRECATED_2.110@@@ https://dlang.org/deprecate.html#scope%20as%20a%20type%20constraint + // Deprecated in 2.100 + // Make an error in 2.110 + if (sd.storage_class & STC.scope_) + deprecation(sd.loc, "`scope` as a type constraint is deprecated. Use `scope` at the usage site."); + } //printf("-StructDeclaration::semantic(this=%p, '%s', sizeok = %d)\n", sd, sd.toPrettyChars(), sd.sizeok); } @@ -5538,12 +5483,15 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor } //printf("-ClassDeclaration.dsymbolSemantic(%s), type = %p, sizeok = %d, this = %p\n", toChars(), type, sizeok, this); - // @@@DEPRECATED_2.110@@@ https://dlang.org/deprecate.html#scope%20as%20a%20type%20constraint - // Deprecated in 2.100 - // Make an error in 2.110 - // Don't forget to remove code at https://github.com/dlang/dmd/blob/b2f8274ba76358607fc3297a1e9f361480f9bcf9/src/dmd/dsymbolsem.d#L1032-L1036 - if (cldec.storage_class & STC.scope_) - deprecation(cldec.loc, "`scope` as a type constraint is deprecated. Use `scope` at the usage site."); + version (none) + { + // @@@DEPRECATED_2.110@@@ https://dlang.org/deprecate.html#scope%20as%20a%20type%20constraint + // Deprecated in 2.100 + // Make an error in 2.110 + // Don't forget to remove code at https://github.com/dlang/dmd/blob/b2f8274ba76358607fc3297a1e9f361480f9bcf9/src/dmd/dsymbolsem.d#L1032-L1036 + if (cldec.storage_class & STC.scope_) + deprecation(cldec.loc, "`scope` as a type constraint is deprecated. Use `scope` at the usage site."); + } } override void visit(InterfaceDeclaration idec) @@ -5844,12 +5792,15 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor } assert(idec.type.ty != Tclass || (cast(TypeClass)idec.type).sym == idec); - // @@@DEPRECATED_2.120@@@ https://dlang.org/deprecate.html#scope%20as%20a%20type%20constraint - // Deprecated in 2.087 - // Made an error in 2.100, but removal depends on `scope class` being removed too - // Don't forget to remove code at https://github.com/dlang/dmd/blob/b2f8274ba76358607fc3297a1e9f361480f9bcf9/src/dmd/dsymbolsem.d#L1032-L1036 - if (idec.storage_class & STC.scope_) - error(idec.loc, "`scope` as a type constraint is obsolete. Use `scope` at the usage site."); + version (none) + { + // @@@DEPRECATED_2.120@@@ https://dlang.org/deprecate.html#scope%20as%20a%20type%20constraint + // Deprecated in 2.087 + // Made an error in 2.100, but removal depends on `scope class` being removed too + // Don't forget to remove code at https://github.com/dlang/dmd/blob/b2f8274ba76358607fc3297a1e9f361480f9bcf9/src/dmd/dsymbolsem.d#L1032-L1036 + if (idec.storage_class & STC.scope_) + error(idec.loc, "`scope` as a type constraint is obsolete. Use `scope` at the usage site."); + } } } @@ -7386,3 +7337,64 @@ private void writeMixin(const(char)[] s, ref const Loc loc, ref int lines, ref O buf.writenl(); ++lines; } + +/** + * Check signature of `pragma(printf)` function, print error if invalid. + * + * printf/scanf-like functions must be of the form: + * extern (C/C++) T printf([parameters...], const(char)* format, ...); + * or: + * extern (C/C++) T vprintf([parameters...], const(char)* format, va_list); + * + * Params: + * funcdecl = function to check + * f = function type + * sc = scope + */ +void checkPrintfScanfSignature(FuncDeclaration funcdecl, TypeFunction f, Scope* sc) +{ + static bool isPointerToChar(Parameter p) + { + if (auto tptr = p.type.isTypePointer()) + { + return tptr.next.ty == Tchar; + } + return false; + } + + bool isVa_list(Parameter p) + { + return p.type.equals(target.va_listType(funcdecl.loc, sc)); + } + + const nparams = f.parameterList.length; + const p = (funcdecl.printf ? Id.printf : Id.scanf).toChars(); + if (!(f.linkage == LINK.c || f.linkage == LINK.cpp)) + { + .error(funcdecl.loc, "`pragma(%s)` function `%s` must have `extern(C)` or `extern(C++)` linkage," + ~" not `extern(%s)`", + p, funcdecl.toChars(), f.linkage.linkageToChars()); + } + if (f.parameterList.varargs == VarArg.variadic) + { + if (!(nparams >= 1 && isPointerToChar(f.parameterList[nparams - 1]))) + { + .error(funcdecl.loc, "`pragma(%s)` function `%s` must have" + ~ " signature `%s %s([parameters...], const(char)*, ...)` not `%s`", + p, funcdecl.toChars(), f.next.toChars(), funcdecl.toChars(), funcdecl.type.toChars()); + } + } + else if (f.parameterList.varargs == VarArg.none) + { + if(!(nparams >= 2 && isPointerToChar(f.parameterList[nparams - 2]) && + isVa_list(f.parameterList[nparams - 1]))) + .error(funcdecl.loc, "`pragma(%s)` function `%s` must have"~ + " signature `%s %s([parameters...], const(char)*, va_list)`", + p, funcdecl.toChars(), f.next.toChars(), funcdecl.toChars()); + } + else + { + .error(funcdecl.loc, "`pragma(%s)` function `%s` must have C-style variadic `...` or `va_list` parameter", + p, funcdecl.toChars()); + } +} diff --git a/gcc/d/dmd/errors.d b/gcc/d/dmd/errors.d index 287dc4963e9e..1f7a78eb6a23 100644 --- a/gcc/d/dmd/errors.d +++ b/gcc/d/dmd/errors.d @@ -119,22 +119,32 @@ else package auto previewErrorFunc(bool isDeprecated, FeatureState featureState) @safe @nogc pure nothrow { - if (featureState == FeatureState.enabled) - return &error; - else if (featureState == FeatureState.disabled || isDeprecated) - return &noop; - else - return &deprecation; + with (FeatureState) final switch (featureState) + { + case enabled: + return &error; + + case disabled: + return &noop; + + case default_: + return isDeprecated ? &noop : &deprecation; + } } package auto previewSupplementalFunc(bool isDeprecated, FeatureState featureState) @safe @nogc pure nothrow { - if (featureState == FeatureState.enabled) - return &errorSupplemental; - else if (featureState == FeatureState.disabled || isDeprecated) - return &noop; - else - return &deprecationSupplemental; + with (FeatureState) final switch (featureState) + { + case enabled: + return &errorSupplemental; + + case disabled: + return &noop; + + case default_: + return isDeprecated ? &noop : &deprecationSupplemental; + } } diff --git a/gcc/d/dmd/expression.d b/gcc/d/dmd/expression.d index 35f11afdc93b..9477867e9294 100644 --- a/gcc/d/dmd/expression.d +++ b/gcc/d/dmd/expression.d @@ -2468,19 +2468,13 @@ extern (C++) class ThisExp : Expression return typeof(return)(true); } - override final bool isLvalue() + override bool isLvalue() { - // Class `this` should be an rvalue; struct `this` should be an lvalue. - return type.toBasetype().ty != Tclass; + return true; } - override final Expression toLvalue(Scope* sc, Expression e) + override Expression toLvalue(Scope* sc, Expression e) { - if (type.toBasetype().ty == Tclass) - { - // Class `this` is an rvalue; struct `this` is an lvalue. - return Expression.toLvalue(sc, e); - } return this; } @@ -2500,6 +2494,18 @@ extern (C++) final class SuperExp : ThisExp super(loc, EXP.super_); } + override bool isLvalue() + { + // Class `super` should be an rvalue + return false; + } + + override Expression toLvalue(Scope* sc, Expression e) + { + // Class `super` is an rvalue + return Expression.toLvalue(sc, e); + } + override void accept(Visitor v) { v.visit(this); diff --git a/gcc/d/dmd/expression.h b/gcc/d/dmd/expression.h index 770c3e7ae3d8..8c6393fb6e18 100644 --- a/gcc/d/dmd/expression.h +++ b/gcc/d/dmd/expression.h @@ -348,8 +348,8 @@ public: ThisExp *syntaxCopy() override; Optional toBool() override; - bool isLvalue() override final; - Expression *toLvalue(Scope *sc, Expression *e) override final; + bool isLvalue() override; + Expression *toLvalue(Scope *sc, Expression *e) override; void accept(Visitor *v) override { v->visit(this); } }; @@ -357,6 +357,8 @@ public: class SuperExp final : public ThisExp { public: + bool isLvalue() override; + Expression* toLvalue(Scope* sc, Expression* e) final override; void accept(Visitor *v) override { v->visit(this); } }; diff --git a/gcc/d/dmd/expressionsem.d b/gcc/d/dmd/expressionsem.d index be597dfa90f1..25f755bdf0ed 100644 --- a/gcc/d/dmd/expressionsem.d +++ b/gcc/d/dmd/expressionsem.d @@ -3556,7 +3556,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor */ private void tryLowerToNewItem(NewExp ne) { - if (global.params.betterC || !sc.needsCodegen()) + if (!global.params.useGC || !sc.needsCodegen()) return; auto hook = global.params.tracegc ? Id._d_newitemTTrace : Id._d_newitemT; @@ -11069,7 +11069,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor /* `_d_arraycatnTX` canot be used with `-betterC`, but `CatExp`s may be * used with `-betterC`, but only during CTFE. */ - if (global.params.betterC || !sc.needsCodegen()) + if (!global.params.useGC || !sc.needsCodegen()) return; if (auto ce = exp.isCatExp()) diff --git a/gcc/d/dmd/func.d b/gcc/d/dmd/func.d index a714d2d281a9..60457351af6a 100644 --- a/gcc/d/dmd/func.d +++ b/gcc/d/dmd/func.d @@ -2019,7 +2019,8 @@ extern (C++) class FuncDeclaration : Declaration overloadApply(cast() this, (Dsymbol s) { auto f = s.isFuncDeclaration(); - if (!f) + auto td = s.isTemplateDeclaration(); + if (!f && !td) return 0; if (result) { @@ -2243,7 +2244,7 @@ extern (C++) class FuncDeclaration : Declaration if (global.gag) // need not report supplemental errors return true; } - else if (global.params.betterC) + else if (!global.params.useGC) { error("is `-betterC` yet allocates closure for `%s()` with the GC", toChars()); if (global.gag) // need not report supplemental errors @@ -4605,16 +4606,15 @@ bool setUnsafe(Scope* sc, bool setUnsafePreview(Scope* sc, FeatureState fs, bool gag, Loc loc, const(char)* msg, RootObject arg0 = null, RootObject arg1 = null, RootObject arg2 = null) { - if (fs == FeatureState.disabled) + with (FeatureState) final switch (fs) { + case disabled: return false; - } - else if (fs == FeatureState.enabled) - { + + case enabled: return sc.setUnsafe(gag, loc, msg, arg0, arg1, arg2); - } - else - { + + case default_: if (!sc.func) return false; if (sc.func.isSafeBypassingInference()) diff --git a/gcc/d/dmd/globals.d b/gcc/d/dmd/globals.d index 0ac60420ef7b..9071e6a58ca6 100644 --- a/gcc/d/dmd/globals.d +++ b/gcc/d/dmd/globals.d @@ -81,11 +81,11 @@ enum CppStdRevision : uint } /// Trivalent boolean to represent the state of a `revert`able change -enum FeatureState : byte +enum FeatureState : ubyte { - default_ = -1, /// Not specified by the user - disabled = 0, /// Specified as `-revert=` - enabled = 1 /// Specified as `-preview=` + default_ = 0, /// Not specified by the user + disabled = 1, /// Specified as `-revert=` + enabled = 2, /// Specified as `-preview=` } extern(C++) struct Output @@ -124,6 +124,7 @@ extern (C++) struct Param bool release; // build release version bool preservePaths; // true means don't strip path from source file DiagnosticReporting warnings = DiagnosticReporting.off; // how compiler warnings are handled + bool obsolete; // enable warnings about use of obsolete messages bool color; // use ANSI colors in console output bool cov; // generate code coverage data ubyte covPercent; // 0..100 code coverage percentage required @@ -132,6 +133,7 @@ extern (C++) struct Param bool useModuleInfo = true; // generate runtime module information bool useTypeInfo = true; // generate runtime type information bool useExceptions = true; // support exception handling + bool useGC = true; // support features that require the GC bool betterC; // be a "better C" compiler; no dependency on D runtime bool addMain; // add a default main() function bool allInst; // generate code for all template instantiations diff --git a/gcc/d/dmd/globals.h b/gcc/d/dmd/globals.h index 66345acc88b4..0dad5dd12e78 100644 --- a/gcc/d/dmd/globals.h +++ b/gcc/d/dmd/globals.h @@ -75,11 +75,11 @@ enum CppStdRevision }; /// Trivalent boolean to represent the state of a `revert`able change -enum class FeatureState : signed char +enum class FeatureState : unsigned char { - default_ = -1, /// Not specified by the user - disabled = 0, /// Specified as `-revert=` - enabled = 1 /// Specified as `-preview=` + default_ = 0, /// Not specified by the user + disabled = 1, /// Specified as `-revert=` + enabled = 2, /// Specified as `-preview=` }; struct Output @@ -119,6 +119,7 @@ struct Param d_bool release; // build release version d_bool preservePaths; // true means don't strip path from source file Diagnostic warnings; + d_bool obsolete; // warn about use of obsolete features d_bool color; // use ANSI colors in console output d_bool cov; // generate code coverage data unsigned char covPercent; // 0..100 code coverage percentage required @@ -127,6 +128,7 @@ struct Param d_bool useModuleInfo; // generate runtime module information d_bool useTypeInfo; // generate runtime type information d_bool useExceptions; // support exception handling + d_bool useGC; // support features that require the GC d_bool betterC; // be a "better C" compiler; no dependency on D runtime d_bool addMain; // add a default main() function d_bool allInst; // generate code for all template instantiations @@ -263,6 +265,7 @@ struct CompileEnv bool previewIn; bool ddocOutput; bool shortenedMethods; + bool obsolete; }; struct Global diff --git a/gcc/d/dmd/initsem.d b/gcc/d/dmd/initsem.d index ee288d1e4748..c60b4311ff53 100644 --- a/gcc/d/dmd/initsem.d +++ b/gcc/d/dmd/initsem.d @@ -772,10 +772,13 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ const nfields = sd.fields.length; size_t fieldi = 0; + Loop1: for (size_t index = 0; index < ci.initializerList.length; ) { - auto di = ci.initializerList[index]; - auto dlist = di.designatorList; + CInitializer cprev; + L1: + DesigInit di = ci.initializerList[index]; + Designators* dlist = di.designatorList; if (dlist) { const length = (*dlist).length; @@ -798,9 +801,19 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ si.addInit(id, di.initializer); ++fieldi; ++index; - break; + continue Loop1; } } + if (cprev) + { + /* The peeling didn't work, so unpeel it + */ + ci = cprev; + di = ci.initializerList[index]; + goto L2; + } + error(ci.loc, "`.%s` is not a field of `%s`\n", id.toChars(), sd.toChars()); + return err(); } else { @@ -808,10 +821,14 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ break; if (index == 0 && ci.initializerList.length == 1 && di.initializer.isCInitializer()) { + /* Try peeling off this set of { } and see if it works + */ + cprev = ci; ci = di.initializer.isCInitializer(); - continue; + goto L1; } + L2: VarDeclaration field; while (1) // skip field if it overlaps with previously seen fields { diff --git a/gcc/d/dmd/lexer.d b/gcc/d/dmd/lexer.d index add1ce684684..9cce7c567234 100644 --- a/gcc/d/dmd/lexer.d +++ b/gcc/d/dmd/lexer.d @@ -51,6 +51,7 @@ struct CompileEnv bool previewIn; /// `in` means `[ref] scope const`, accepts rvalues bool ddocOutput; /// collect embedded documentation comments bool shortenedMethods = true; /// allow => in normal function declarations + bool obsolete; /// warn on use of legacy code } /*********************************************************** diff --git a/gcc/d/dmd/nogc.d b/gcc/d/dmd/nogc.d index 9a8f24227467..d7a28209b3eb 100644 --- a/gcc/d/dmd/nogc.d +++ b/gcc/d/dmd/nogc.d @@ -219,7 +219,7 @@ Expression checkGC(Scope* sc, Expression e) * Just don't generate code for it. * Detect non-CTFE use of the GC in betterC code. */ - const betterC = global.params.betterC; + const betterC = !global.params.useGC; FuncDeclaration f = sc.func; if (e && e.op != EXP.error && f && sc.intypeof != 1 && (!(sc.flags & SCOPE.ctfe) || betterC) && diff --git a/gcc/d/dmd/parse.d b/gcc/d/dmd/parse.d index eeaef8d7d8b2..d15e448150fa 100644 --- a/gcc/d/dmd/parse.d +++ b/gcc/d/dmd/parse.d @@ -718,13 +718,8 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer tk.value == TOK.out_ || tk.value == TOK.do_ || tk.value == TOK.goesTo || tk.value == TOK.identifier && tk.ident == Id._body)) { - // @@@DEPRECATED_2.117@@@ - // https://github.com/dlang/DIPs/blob/1f5959abe482b1f9094f6484a7d0a3ade77fc2fc/DIPs/accepted/DIP1003.md - // Deprecated in 2.097 - Can be removed from 2.117 - // The deprecation period is longer than usual as `body` - // was quite widely used. if (tk.value == TOK.identifier && tk.ident == Id._body) - deprecation("usage of the `body` keyword is deprecated. Use `do` instead."); + usageOfBodyKeyword(); a = parseDeclarations(true, pAttrs, pAttrs.comment); if (a && a.length) @@ -1163,7 +1158,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer a = parseDeclDefs(0, pLastDecl); if (token.value != TOK.rightCurly) { - /* { */ + /* left curly brace */ error("matching `}` expected, not `%s`", token.toChars()); eSink.errorSupplemental(lcLoc, "unmatched `{`"); } @@ -1505,7 +1500,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer if (token.value != TOK.leftCurly) { - error("`{` expected after template parameter list, not `%s`", token.toChars()); + error("`{` expected after template parameter list, not `%s`", token.toChars()); /* } */ goto Lerr; } decldefs = parseBlock(null); @@ -2724,7 +2719,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer nextToken(); - const(char)* begPtr = token.ptr + 1; // skip '{' + const(char)* begPtr = token.ptr + 1; // skip left curly brace const(char)* endPtr = null; AST.Statement sbody = parseStatement(ParseStatementFlags.curly, &endPtr); @@ -3041,6 +3036,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer } e = new AST.EnumDeclaration(loc, id, memtype); + // opaque type if (token.value == TOK.semicolon && id) nextToken(); else if (token.value == TOK.leftCurly) @@ -3073,7 +3069,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer && token.value != TOK.comma && token.value != TOK.assign) { - switch(token.value) + switch (token.value) { case TOK.at: if (StorageClass _stc = parseAttribute(udas)) @@ -3109,12 +3105,23 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer } else { - goto default; + if (isAnonymousEnum) + goto default; // maybe `Type identifier` + + prevTOK = token.value; + nextToken(); + error("expected `,` or `=` after identifier, not `%s`", token.toChars()); } break; default: if (isAnonymousEnum) { + if (type) + { + error("expected identifier after type, not `%s`", token.toChars()); + type = null; + break; + } type = parseType(&ident, null); if (type == AST.Type.terror) { @@ -3125,6 +3132,11 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer else { prevTOK = TOK.identifier; + const tv = token.value; + if (ident && tv != TOK.assign && tv != TOK.comma && tv != TOK.rightCurly) + { + error("expected `,` or `=` after identifier, not `%s`", token.toChars()); + } } } else @@ -3166,7 +3178,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer { value = null; if (type && type != AST.Type.terror && isAnonymousEnum) - error("if type, there must be an initializer"); + error("initializer required after `%s` when type is specified", ident.toChars()); } AST.DeprecatedDeclaration dd; @@ -3471,6 +3483,11 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer return decldefs; } + /* Parse a type and optional identifier + * Params: + * pident = set to Identifier if there is one, null if not + * ptpl = if !null, then set to TemplateParameterList + */ AST.Type parseType(Identifier* pident = null, AST.TemplateParameters** ptpl = null) { /* Take care of the storage class prefixes that @@ -4450,13 +4467,8 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer (tk.value == TOK.leftParenthesis || tk.value == TOK.leftCurly || tk.value == TOK.in_ || tk.value == TOK.out_ || tk.value == TOK.goesTo || tk.value == TOK.do_ || tk.value == TOK.identifier && tk.ident == Id._body)) { - // @@@DEPRECATED_2.117@@@ - // https://github.com/dlang/DIPs/blob/1f5959abe482b1f9094f6484a7d0a3ade77fc2fc/DIPs/accepted/DIP1003.md - // Deprecated in 2.097 - Can be removed from 2.117 - // The deprecation period is longer than usual as `body` - // was quite widely used. if (tk.value == TOK.identifier && tk.ident == Id._body) - deprecation("usage of the `body` keyword is deprecated. Use `do` instead."); + usageOfBodyKeyword(); ts = null; } @@ -4569,6 +4581,9 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer } else if (t.ty == Tfunction) { + if (storage_class & STC.manifest) + error("function cannot have enum storage class"); + AST.Expression constraint = null; //printf("%s funcdecl t = %s, storage_class = x%lx\n", loc.toChars(), t.toChars(), storage_class); auto f = new AST.FuncDeclaration(loc, Loc.initial, ident, storage_class | (disable ? STC.disable : 0), t); @@ -5193,12 +5208,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer case TOK.identifier: if (token.ident == Id._body) { - // @@@DEPRECATED_2.117@@@ - // https://github.com/dlang/DIPs/blob/1f5959abe482b1f9094f6484a7d0a3ade77fc2fc/DIPs/accepted/DIP1003.md - // Deprecated in 2.097 - Can be removed from 2.117 - // The deprecation period is longer than usual as `body` - // was quite widely used. - deprecation("usage of the `body` keyword is deprecated. Use `do` instead."); + usageOfBodyKeyword(); goto case TOK.do_; } goto default; @@ -6027,7 +6037,7 @@ LagainStc: auto statements = new AST.Statements(); while (token.value != TOK.rightCurly && token.value != TOK.endOfFile) { - statements.push(parseStatement(ParseStatementFlags.curlyScope)); + statements.push(parseStatement(ParseStatementFlags.curlyScope | ParseStatementFlags.semiOk)); } if (endPtr) *endPtr = token.ptr; @@ -7572,12 +7582,7 @@ LagainStc: case TOK.identifier: if (t.ident == Id._body) { - // @@@DEPRECATED_2.117@@@ - // https://github.com/dlang/DIPs/blob/1f5959abe482b1f9094f6484a7d0a3ade77fc2fc/DIPs/accepted/DIP1003.md - // Deprecated in 2.097 - Can be removed from 2.117 - // The deprecation period is longer than usual as `body` - // was quite widely used. - deprecation("usage of the `body` keyword is deprecated. Use `do` instead."); + usageOfBodyKeyword(); goto case TOK.do_; } goto default; @@ -8806,6 +8811,7 @@ LagainStc: { // (type) una_exp nextToken(); + // Note: `t` may be an expression that looks like a type auto t = parseType(); check(TOK.rightParenthesis); @@ -8823,6 +8829,16 @@ LagainStc: te.parens = true; e = parsePostExp(te); } + else if (token.value == TOK.leftParenthesis || + token.value == TOK.plusPlus || token.value == TOK.minusMinus) + { + // (type)(expr) + // (callable)(args) + // (expr)++ + auto te = new AST.TypeExp(loc, t); + te.parens = true; + e = parsePostExp(te); + } else { e = parseUnaryExp(); @@ -9526,6 +9542,14 @@ LagainStc: STC.live | /*STC.future |*/ // probably should be included STC.disable; + + void usageOfBodyKeyword() + { + if (compileEnv.obsolete) + { + eSink.warning(token.loc, "usage of identifer `body` as a keyword is obsolete. Use `do` instead."); + } + } } enum PREC : int diff --git a/gcc/d/dmd/semantic3.d b/gcc/d/dmd/semantic3.d index e4ca22a98b5b..c7d121948203 100644 --- a/gcc/d/dmd/semantic3.d +++ b/gcc/d/dmd/semantic3.d @@ -1422,7 +1422,8 @@ private extern(C++) final class Semantic3Visitor : Visitor * https://issues.dlang.org/show_bug.cgi?id=14246 */ AggregateDeclaration ad = ctor.isMemberDecl(); - if (!ctor.fbody || !ad || !ad.fieldDtor || !global.params.dtorFields || !global.params.useExceptions || ctor.type.toTypeFunction.isnothrow) + if (!ctor.fbody || !ad || !ad.fieldDtor || + global.params.dtorFields == FeatureState.disabled || !global.params.useExceptions || ctor.type.toTypeFunction.isnothrow) return visit(cast(FuncDeclaration)ctor); /* Generate: diff --git a/gcc/d/dmd/target.d b/gcc/d/dmd/target.d index fddfd546742d..81ff84f361e1 100644 --- a/gcc/d/dmd/target.d +++ b/gcc/d/dmd/target.d @@ -25,7 +25,7 @@ module dmd.target; -import dmd.globals : Param; +import dmd.globals : Param, CHECKENABLE; enum CPU : ubyte { @@ -111,7 +111,7 @@ extern (C++) struct Target /// Architecture name const(char)[] architectureName; CPU cpu = CPU.baseline; // CPU instruction set to target - bool is64bit; // generate 64 bit code for x86_64; true by default for 64 bit dmd + bool isX86_64; // generate 64 bit code for x86_64; true by default for 64 bit dmd bool isLP64; // pointers are 64 bits // Environmental diff --git a/gcc/d/dmd/target.h b/gcc/d/dmd/target.h index 561afa18d42d..ca0e09c88e04 100644 --- a/gcc/d/dmd/target.h +++ b/gcc/d/dmd/target.h @@ -156,7 +156,7 @@ struct Target DString architectureName; // name of the platform architecture (e.g. X86_64) CPU cpu; // CPU instruction set to target - d_bool is64bit; // generate 64 bit code for x86_64; true by default for 64 bit dmd + d_bool isX86_64; // generate 64 bit code for x86_64; true by default for 64 bit dmd d_bool isLP64; // pointers are 64 bits // Environmental diff --git a/gcc/d/dmd/traits.d b/gcc/d/dmd/traits.d index caebf1cee259..0d9c95ff173e 100644 --- a/gcc/d/dmd/traits.d +++ b/gcc/d/dmd/traits.d @@ -947,15 +947,24 @@ Expression semanticTraits(TraitsExp e, Scope* sc) */ Dsymbol sym = getDsymbol(o); + + if (sym && e.ident == Id.hasMember) + { + if (auto sm = sym.search(e.loc, id)) + return True(); + + // https://issues.dlang.org/show_bug.cgi?id=23951 + if (auto decl = sym.isDeclaration()) + { + ex = typeDotIdExp(e.loc, decl.type, id); + goto doSemantic; + } + } + if (auto t = isType(o)) ex = typeDotIdExp(e.loc, t, id); else if (sym) { - if (e.ident == Id.hasMember) - { - if (auto sm = sym.search(e.loc, id)) - return True(); - } ex = new DsymbolExp(e.loc, sym); ex = new DotIdExp(e.loc, ex, id); } @@ -966,7 +975,7 @@ Expression semanticTraits(TraitsExp e, Scope* sc) e.error("invalid first argument"); return ErrorExp.get(); } - + doSemantic: // ignore symbol visibility and disable access checks for these traits Scope* scx = sc.push(); scx.flags |= SCOPE.ignoresymbolvisibility | SCOPE.noaccesscheck; @@ -1223,7 +1232,7 @@ Expression semanticTraits(TraitsExp e, Scope* sc) // @@@DEPRECATION 2.100.2 if (auto td = s.isTemplateDeclaration()) { - if (td.overnext || td.funcroot) + if (td.overnext || td.overroot) { deprecation(e.loc, "`__traits(getAttributes)` may only be used for individual functions, not the overload set `%s`", td.ident.toChars()); deprecationSupplemental(e.loc, "the result of `__traits(getOverloads)` may be used to select the desired function to extract attributes from"); diff --git a/gcc/d/expr.cc b/gcc/d/expr.cc index 8fb1eea65a6f..7038655bc94f 100644 --- a/gcc/d/expr.cc +++ b/gcc/d/expr.cc @@ -695,7 +695,7 @@ public: { /* This error is only emitted during the code generation pass because concatentation is allowed in CTFE. */ - if (global.params.betterC) + if (!global.params.useGC) { error_at (make_location_t (e->loc), "array concatenation of expression %qs requires the GC and " diff --git a/gcc/doc/analyzer.texi b/gcc/doc/analyzer.texi index 2692b0e3ece5..c50d7eb0ce84 100644 --- a/gcc/doc/analyzer.texi +++ b/gcc/doc/analyzer.texi @@ -652,6 +652,14 @@ __analyzer_get_unknown_ptr (); @end smallexample will obtain an unknown @code{void *}. +@item __analyzer_get_strlen +@smallexample +__analyzer_get_strlen (buf); +@end smallexample +will emit a warning if PTR doesn't point to a null-terminated string. +TODO: eventually get the strlen of the buffer (without the +optimizer touching it). + @end table @subsection Other Debugging Techniques diff --git a/gcc/doc/contrib.texi b/gcc/doc/contrib.texi index d7b73e179a5c..031c4ec44ce2 100644 --- a/gcc/doc/contrib.texi +++ b/gcc/doc/contrib.texi @@ -1515,7 +1515,7 @@ Gael Thomas for @code{VMClassLoader} boot packages support suggestions. @item Andreas Tobler for Darwin and Solaris testing and fixing, @code{Qt4} -support for Darwin/OS X, @code{Graphics2D} support, @code{gtk+} +support for Darwin / macOS, @code{Graphics2D} support, @code{gtk+} updates. @item diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi index 89c5b4ea2b20..947c05babc9e 100644 --- a/gcc/doc/extend.texi +++ b/gcc/doc/extend.texi @@ -843,6 +843,13 @@ Thus, @code{array (pointer (char), 4)} is the type of arrays of 4 pointers to @code{char}. @end itemize +The ISO C2X operator @code{typeof_unqual} is available in ISO C2X mode +and its result is the non-atomic unqualified version of what @code{typeof} +operator returns. Alternate spelling @code{__typeof_unqual__} is +available in all C modes and provides non-atomic unqualified version of +what @code{__typeof__} operator returns. +@xref{Alternate Keywords}. + @cindex @code{__auto_type} in GNU C In GNU C, but not GNU C++, you may also declare the type of a variable as @code{__auto_type}. In that case, the declaration must declare @@ -1077,7 +1084,7 @@ infinities, NaNs and negative zeros are involved. ISO/IEC TS 18661-3:2015 defines C support for additional floating types @code{_Float@var{n}} and @code{_Float@var{n}x}, and GCC supports these type names; the set of types supported depends on the target -architecture. These types are not supported when compiling C++. +architecture. Constants with these types use suffixes @code{f@var{n}} or @code{F@var{n}} and @code{f@var{n}x} or @code{F@var{n}x}. These type names can be used together with @code{_Complex} to declare complex @@ -1086,10 +1093,10 @@ types. As an extension, GNU C and GNU C++ support additional floating types, which are not supported by all targets. @itemize @bullet -@item @code{__float128} is available on i386, x86_64, IA-64, and -hppa HP-UX, as well as on PowerPC GNU/Linux targets that enable +@item @code{__float128} is available on i386, x86_64, IA-64, LoongArch +and hppa HP-UX, as well as on PowerPC GNU/Linux targets that enable the vector scalar (VSX) instruction set. @code{__float128} supports -the 128-bit floating type. On i386, x86_64, PowerPC, and IA-64 +the 128-bit floating type. On i386, x86_64, PowerPC, LoongArch and IA-64, other than HP-UX, @code{__float128} is an alias for @code{_Float128}. On hppa and IA-64 HP-UX, @code{__float128} is an alias for @code{long double}. @@ -5165,6 +5172,17 @@ attribute. Example: int bpf_probe_read (void *dst, int size, const void *unsafe_ptr) __attribute__ ((kernel_helper (4))); @end smallexample + +@cindex @code{naked} function attribute, BPF +@item naked +This attribute allows the compiler to construct the requisite function +declaration, while allowing the body of the function to be assembly +code. The specified function will not have prologue/epilogue +sequences generated by the compiler. Only basic @code{asm} statements +can safely be included in naked functions (@pxref{Basic Asm}). While +using extended @code{asm} or a mixture of basic @code{asm} and C code +may appear to work, they cannot be depended upon to work reliably and +are not supported. @end table @node C-SKY Function Attributes @@ -11907,10 +11925,29 @@ macros to replace them with the customary keywords. It looks like this: @findex __extension__ @opindex pedantic @option{-pedantic} and other options cause warnings for many GNU C extensions. -You can -prevent such warnings within one expression by writing -@code{__extension__} before the expression. @code{__extension__} has no -effect aside from this. +You can suppress such warnings using the keyword @code{__extension__}. +Specifically: + +@itemize @bullet +@item +Writing @code{__extension__} before an expression prevents warnings +about extensions within that expression. + +@item +In C, writing: + +@smallexample +[[__extension__ @dots{}]] +@end smallexample + +suppresses warnings about using @samp{[[]]} attributes in C versions +that predate C2X@. Since the scope token @samp{::} is not a single +lexing token in earlier versions of C, this construct also allows two colons +to be used in place of @code{::}. GCC does not check whether the two +colons are immediately adjacent. +@end itemize + +@code{__extension__} has no effect aside from this. @node Incomplete Enums @section Incomplete @code{enum} Types @@ -16620,6 +16657,20 @@ function you need to include @code{larchintrin.h}. void __break (imm0_32767) @end smallexample +Additional built-in functions are available for LoongArch family +processors to efficiently use 128-bit floating-point (__float128) +values. + +The following are the basic built-in functions supported. +@smallexample +__float128 __builtin_fabsq (__float128); +__float128 __builtin_copysignq (__float128, __float128); +__float128 __builtin_infq (void); +__float128 __builtin_huge_valq (void); +__float128 __builtin_nanq (void); +__float128 __builtin_nansq (void); +@end smallexample + @node MIPS DSP Built-in Functions @subsection MIPS DSP Built-in Functions @@ -18559,6 +18610,23 @@ The builtin uses the ISA 3.0 instruction @code{mffscdrn} if available. Otherwise the builtin reads the FPSCR, masks the current decimal rounding mode bits out and OR's in the new value. +_Decimal64 __builtin_dfp_quantize (_Decimal64, _Decimal64, const int); +_Decimal64 __builtin_dfp_quantize (const int, _Decimal64, const int); +_Decimal128 __builtin_dfp_quantize (_Decimal128, _Decimal128, const int); +_Decimal128 __builtin_dfp_quantize (const int, _Decimal128, const int); + +The @code{__builtin_dfp_quantize} built-in, converts and rounds the second +argument to the form with the exponent as specified by the first +argument based on the rounding mode specified by the third argument. +If the first argument is a decimal floating point value, its exponent is used +for converting and rounding of the second argument. If the first argument is a +5-bit constant integer value, then the value specifies the exponent to be used +when rounding and converting the second argument. The third argument is a +two bit constant integer that specifies the rounding mode. The possible modes +are: 00 Round to nearest, ties to even; 01 Round toward 0; 10 Round to nearest, +ties away from 0; 11 Round according to DRN where DRN is the Decimal Floating +point field of the FPSCR. + @end smallexample The following functions require @option{-mhard-float}, @@ -21570,9 +21638,9 @@ Returns the value that is currently set in the @samp{tp} register. @enddefbuiltin @defbuiltin{void __builtin_riscv_pause (void)} -Generates the @code{pause} (hint) machine instruction. This implies the -Xgnuzihintpausestate extension, which redefines the @code{pause} instruction to -change architectural state. +Generates the @code{pause} (hint) machine instruction. If the target implements +the Zihintpause extension, it indicates that the current hart should be +temporarily paused or slowed down. @enddefbuiltin @node RISC-V Vector Intrinsics @@ -24124,7 +24192,7 @@ attribute, do change the value of preprocessor macros like The following pragmas are available for all architectures running the Darwin operating system. These are useful for compatibility with other -Mac OS compilers. +macOS compilers. @table @code @cindex pragma, mark @@ -25322,7 +25390,7 @@ compiled separately. @end table G++ implements the Borland model on targets where the linker supports it, -including ELF targets (such as GNU/Linux), Mac OS X and Microsoft Windows. +including ELF targets (such as GNU/Linux), macOS and Microsoft Windows. Otherwise G++ implements neither automatic model. You have the following options for dealing with template instantiations: diff --git a/gcc/doc/generic.texi b/gcc/doc/generic.texi index 3f9bddd7eae3..c8d6ef062f64 100644 --- a/gcc/doc/generic.texi +++ b/gcc/doc/generic.texi @@ -2488,6 +2488,20 @@ In some cases, @code{OMP_CONTINUE} is placed right before occur right after the looping body, it will be emitted between @code{OMP_CONTINUE} and @code{OMP_RETURN}. +@item OMP_STRUCTURED_BLOCK + +This is another statement that doesn't correspond to an OpenMP directive. +It is used to mark sections of code in another directive that must +be structured block sequences, in particular for sequences of intervening code +in the body of an @code{OMP_FOR}. It is not necessary to use this when the +entire body of a directive is required to be a structured block sequence, +since that is implicit in the representation of the corresponding node. + +This tree node is used only to allow error checking transfers of control +in/out of the structured block sequence after gimplification. +It has a single operand (@code{OMP_STRUCTURED_BLOCK_BODY}) that is +the code within the structured block sequence. + @item OMP_ATOMIC Represents @code{#pragma omp atomic}. diff --git a/gcc/doc/gimple.texi b/gcc/doc/gimple.texi index 322c7609cf31..a3ade15afc9b 100644 --- a/gcc/doc/gimple.texi +++ b/gcc/doc/gimple.texi @@ -468,6 +468,7 @@ The following table briefly describes the GIMPLE instruction set. @item @code{GIMPLE_OMP_SECTIONS_SWITCH} @tab x @tab x @item @code{GIMPLE_OMP_SINGLE} @tab x @tab x @item @code{GIMPLE_PHI} @tab @tab x +@item @code{GIMPLE_OMP_STRUCTURED_BLOCK} @tab x @tab @item @code{GIMPLE_RESX} @tab @tab x @item @code{GIMPLE_RETURN} @tab x @tab x @item @code{GIMPLE_SWITCH} @tab x @tab x @@ -1040,6 +1041,7 @@ Return a deep copy of statement @code{STMT}. * @code{GIMPLE_OMP_SECTION}:: * @code{GIMPLE_OMP_SECTIONS}:: * @code{GIMPLE_OMP_SINGLE}:: +* @code{GIMPLE_OMP_STRUCTURED_BLOCK}:: * @code{GIMPLE_PHI}:: * @code{GIMPLE_RESX}:: * @code{GIMPLE_RETURN}:: @@ -2160,6 +2162,23 @@ Set @code{CLAUSES} to be the clauses associated with @code{OMP_SINGLE} @code{G}. @end deftypefn +@node @code{GIMPLE_OMP_STRUCTURED_BLOCK} +@subsection @code{GIMPLE_OMP_STRUCTURED_BLOCK} +@cindex @code{GIMPLE_OMP_STRUCTURED_BLOCK} + +Like the GENERIC equivalent @code{OMP_STRUCTURED_BLOCK}, this GIMPLE +statement does not correspond directly to an OpenMP directive, and +exists only to permit error checking of transfers of control +in/out of structured block sequences (the @code{diagnose_omp_blocks} pass +in @file{omp-low.cc}). All @code{GIMPLE_OMP_STRUCTURED_BLOCK} +nodes are eliminated during OpenMP lowering. + +@deftypefn {GIMPLE function} gimple gimple_build_omp_structured_block (gimple_seq body) +Build a @code{GIMPLE_OMP_STRUCTURED_BLOCK} statement. +@code{BODY} is the sequence of statements in the structured block sequence. +@end deftypefn + + @node @code{GIMPLE_PHI} @subsection @code{GIMPLE_PHI} @cindex @code{GIMPLE_PHI} diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index 674f956f4b8f..02de0f657e85 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -345,6 +345,7 @@ Objective-C and Objective-C++ Dialects}. -Wcast-align -Wcast-align=strict -Wcast-function-type -Wcast-qual -Wchar-subscripts -Wclobbered -Wcomment +-Wcompare-distinct-pointer-types -Wno-complain-wrong-lang -Wconversion -Wno-coverage-mismatch -Wno-cpp -Wdangling-else -Wdangling-pointer -Wdangling-pointer=@var{n} @@ -430,6 +431,7 @@ Objective-C and Objective-C++ Dialects}. -fanalyzer-checker=@var{name} -fno-analyzer-feasibility -fanalyzer-fine-grained +-fanalyzer-show-events-in-system-headers -fno-analyzer-state-merge -fno-analyzer-state-purge -fno-analyzer-suppress-followups @@ -472,6 +474,7 @@ Objective-C and Objective-C++ Dialects}. -Wno-analyzer-null-argument -Wno-analyzer-null-dereference -Wno-analyzer-out-of-bounds +-Wno-analyzer-overlapping-buffers -Wno-analyzer-possible-null-argument -Wno-analyzer-possible-null-dereference -Wno-analyzer-putenv-of-auto-var @@ -1419,6 +1422,7 @@ See RS/6000 and PowerPC Options. -mcld -mcx16 -msahf -mmovbe -mcrc32 -mmwait -mrecip -mrecip=@var{opt} -mvzeroupper -mprefer-avx128 -mprefer-vector-width=@var{opt} +-mpartial-vector-fp-math -mmove-max=@var{bits} -mstore-max=@var{bits} -mmmx -msse -msse2 -msse3 -mssse3 -msse4.1 -msse4.2 -msse4 -mavx -mavx2 -mavx512f -mavx512pf -mavx512er -mavx512cd -mavx512vl @@ -3013,6 +3017,9 @@ in C++14 and up. Version 18, which first appeard in G++ 13, fixes manglings of lambdas that have additional context. +Version 19, which first appeard in G++ 14, fixes manglings of structured +bindings to include ABI tags. + See also @option{-Wabi}. @opindex fabi-compat-version @@ -4772,7 +4779,7 @@ pointers after reallocation. @opindex Wuseless-cast @opindex Wno-useless-cast -@item -Wuseless-cast @r{(C++ and Objective-C++ only)} +@item -Wuseless-cast @r{(C, Objective-C, C++ and Objective-C++ only)} Warn when an expression is cast to its own type. This warning does not occur when a class object is converted to a non-reference type as that is a way to create a temporary: @@ -4833,7 +4840,7 @@ Use @var{class-name} as the name of the class to instantiate for each literal string specified with the syntax @code{@@"@dots{}"}. The default class name is @code{NXConstantString} if the GNU runtime is being used, and @code{NSConstantString} if the NeXT runtime is being used (see below). On -Darwin (macOS, MacOS X) platforms, the @option{-fconstant-cfstrings} option, if +Darwin / macOS platforms, the @option{-fconstant-cfstrings} option, if also present, overrides the @option{-fconstant-string-class} setting and cause @code{@@"@dots{}"} literals to be laid out as constant CoreFoundation strings. Note that @option{-fconstant-cfstrings} is an alias for the target-specific @@ -4847,7 +4854,7 @@ runtime. This is the default for most types of systems. @opindex fnext-runtime @item -fnext-runtime Generate output compatible with the NeXT runtime. This is the default -for NeXT-based systems, including Darwin and Mac OS X@. The macro +for NeXT-based systems, including Darwin / macOS. The macro @code{__NEXT_RUNTIME__} is predefined if (and only if) this option is used. @@ -9102,6 +9109,11 @@ The latter front end diagnoses @samp{f951: Warning: command-line option '-fno-rtti' is valid for C++/D/ObjC++ but not for Fortran}, which may be disabled with @option{-Wno-complain-wrong-lang}. +@opindex Wcompare-distinct-pointer-types +@item -Wcompare-distinct-pointer-types @r{(C and Objective-C only)} +Warn if pointers of distinct types are compared without a cast. This +warning is enabled by default. + @opindex Wconversion @opindex Wno-conversion @item -Wconversion @@ -10311,6 +10323,7 @@ Enabling this option effectively enables the following warnings: -Wanalyzer-null-argument -Wanalyzer-null-dereference -Wanalyzer-out-of-bounds +-Wanalyzer-overlapping-buffers -Wanalyzer-possible-null-argument -Wanalyzer-possible-null-dereference -Wanalyzer-putenv-of-auto-var @@ -10656,6 +10669,24 @@ involved, the direction of the access (read vs write), and, in some cases, the values of data involved. This diagram can be suppressed using @option{-fdiagnostics-text-art-charset=none}. +@opindex Wanalyzer-overlapping-buffers +@opindex Wno-analyzer-overlapping-buffers +@item -Wno-analyzer-overlapping-buffers +This warning requires @option{-fanalyzer}, which enables it; use +@option{-Wno-analyzer-overlapping-buffers} to disable it. + +This diagnostic warns for paths through the code in which overlapping +buffers are passed to an API for which the behavior on such buffers +is undefined. + +Specifically, the diagnostic occurs on calls to the following functions +@itemize @bullet +@item @code{memcpy} +@item @code{strcat} +@item @code{strcpy} +@end itemize +for cases where the buffers are known to overlap. + @opindex Wanalyzer-possible-null-argument @opindex Wno-analyzer-possible-null-argument @item -Wno-analyzer-possible-null-argument @@ -11100,6 +11131,7 @@ and of the following functions: @item @code{siglongjmp} @item @code{signal} @item @code{sigsetjmp} +@item @code{strcat} @item @code{strchr} @item @code{strlen} @end itemize @@ -11203,6 +11235,14 @@ have been detected as being duplicates of each other, it emits a note when reporting the best diagnostic, giving the number of additional diagnostics that were suppressed by the deduplication logic. +@opindex fanalyzer-show-events-in-system-headers +@opindex fno-analyzer-show-events-in-system-headers +@item -fanalyzer-show-events-in-system-headers +By default the analyzer emits simplified diagnostics paths by hiding +events fully located within a system header. +With @option{-fanalyzer-show-events-in-system-headers} such +events are no longer suppressed. + @opindex fanalyzer-state-merge @opindex fno-analyzer-state-merge @item -fno-analyzer-state-merge @@ -11449,7 +11489,7 @@ possible. Produce debugging information in DWARF format (if that is supported). The value of @var{version} may be either 2, 3, 4 or 5; the default version for most targets is 5 (with the exception of VxWorks, TPF and -Darwin/Mac OS X, which default to version 2, and AIX, which defaults +Darwin / macOS, which default to version 2, and AIX, which defaults to version 4). Note that with DWARF Version 2, some ports require and always @@ -12622,8 +12662,8 @@ Attempt to remove redundant extension instructions. This is especially helpful for the x86-64 architecture, which implicitly zero-extends in 64-bit registers after writing to their lower 32-bit half. -Enabled for Alpha, AArch64, PowerPC, RISC-V, SPARC, h83000 and x86 at levels -@option{-O2}, @option{-O3}, @option{-Os}. +Enabled for Alpha, AArch64, LoongArch, PowerPC, RISC-V, SPARC, h83000 and x86 at +levels @option{-O2}, @option{-O3}, @option{-Os}. @opindex fno-lifetime-dse @opindex flifetime-dse @@ -20529,8 +20569,9 @@ performance of the code. Permissible values for this option are: @samp{cortex-a73.cortex-a35}, @samp{cortex-a73.cortex-a53}, @samp{cortex-a75.cortex-a55}, @samp{cortex-a76.cortex-a55}, @samp{cortex-r82}, @samp{cortex-x1}, @samp{cortex-x1c}, @samp{cortex-x2}, -@samp{cortex-x3}, @samp{cortex-a510}, @samp{cortex-a710}, @samp{cortex-a715}, -@samp{ampere1}, @samp{ampere1a}, and @samp{native}. +@samp{cortex-x3}, @samp{cortex-a510}, @samp{cortex-a520}, @samp{cortex-a710}, +@samp{cortex-a715}, @samp{cortex-a720}, @samp{ampere1}, @samp{ampere1a}, +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}, @@ -30031,7 +30072,7 @@ the same as @option{-mbig}. @opindex mdynamic-no-pic @item -mdynamic-no-pic -On Darwin and Mac OS X systems, compile code so that it is not +On Darwin / macOS systems, compile code so that it is not relocatable, but that its external references are relocatable. The resulting code is suitable for applications, but not shared libraries. @@ -33754,6 +33795,23 @@ This option instructs GCC to use 128-bit AVX instructions instead of This option instructs GCC to use @var{opt}-bit vector width in instructions instead of default on the selected platform. +@opindex mpartial-vector-fp-math +@item -mpartial-vector-fp-math +This option enables GCC to generate floating-point operations that might +affect the set of floating-point status flags on partial vectors, where +vector elements reside in the low part of the 128-bit SSE register. Unless +@option{-fno-trapping-math} is specified, the compiler guarantees correct +behavior by sanitizing all input operands to have zeroes in the unused +upper part of the vector register. Note that by using built-in functions +or inline assembly with partial vector arguments, NaNs, denormal or invalid +values can leak into the upper part of the vector, causing possible +performance issues when @option{-fno-trapping-math} is in effect. These +issues can be mitigated by manually sanitizing the upper part of the partial +vector argument register or by using @option{-mdaz-ftz} to set +denormals-are-zero (DAZ) flag in the MXCSR register. + +This option is enabled by default. + @opindex mmove-max @item -mmove-max=@var{bits} This option instructs GCC to set the maximum number of bits can be diff --git a/gcc/doc/md.texi b/gcc/doc/md.texi index 9693b6bfe798..24453693d89e 100644 --- a/gcc/doc/md.texi +++ b/gcc/doc/md.texi @@ -4978,6 +4978,23 @@ for (j = 0; j < GET_MODE_NUNITS (@var{n}); j++) This pattern is not allowed to @code{FAIL}. +@cindex @code{vec_mask_len_load_lanes@var{m}@var{n}} instruction pattern +@item @samp{vec_mask_len_load_lanes@var{m}@var{n}} +Like @samp{vec_load_lanes@var{m}@var{n}}, but takes an additional +mask operand (operand 2), length operand (operand 3) as well as bias operand (operand 4) +that specifies which elements of the destination vectors should be loaded. +Other elements of the destination vectors are undefined. The operation is equivalent to: + +@smallexample +int c = GET_MODE_SIZE (@var{m}) / GET_MODE_SIZE (@var{n}); +for (j = 0; j < operand3 + operand4; j++) + if (operand2[j]) + for (i = 0; i < c; i++) + operand0[i][j] = operand1[j * c + i]; +@end smallexample + +This pattern is not allowed to @code{FAIL}. + @cindex @code{vec_store_lanes@var{m}@var{n}} instruction pattern @item @samp{vec_store_lanes@var{m}@var{n}} Equivalent to @samp{vec_load_lanes@var{m}@var{n}}, with the memory @@ -5011,6 +5028,23 @@ for (j = 0; j < GET_MODE_NUNITS (@var{n}); j++) This pattern is not allowed to @code{FAIL}. +@cindex @code{vec_mask_len_store_lanes@var{m}@var{n}} instruction pattern +@item @samp{vec_mask_len_store_lanes@var{m}@var{n}} +Like @samp{vec_store_lanes@var{m}@var{n}}, but takes an additional +mask operand (operand 2), length operand (operand 3) as well as bias operand (operand 4) +that specifies which elements of the source vectors should be stored. +The operation is equivalent to: + +@smallexample +int c = GET_MODE_SIZE (@var{m}) / GET_MODE_SIZE (@var{n}); +for (j = 0; j < operand3 + operand4; j++) + if (operand2[j]) + for (i = 0; i < c; i++) + operand0[j * c + i] = operand1[i][j]; +@end smallexample + +This pattern is not allowed to @code{FAIL}. + @cindex @code{gather_load@var{m}@var{n}} instruction pattern @item @samp{gather_load@var{m}@var{n}} Load several separate memory locations into a vector of mode @var{m}. @@ -5602,6 +5636,12 @@ has mode @var{m} and operands 0 and 1 have the mode appropriate for one element of @var{m}. Operand 2 has the usual mask mode for vectors of mode @var{m}; see @code{TARGET_VECTORIZE_GET_MASK_MODE}. +@cindex @code{len_fold_extract_last_@var{m}} instruction pattern +@item @code{len_fold_extract_last_@var{m}} +Like @samp{fold_extract_last_@var{m}}, but takes an extra length operand as +operand 4 and an extra bias operand as operand 5. The last associated element +is extracted should have the index i < len (operand 4) + bias (operand 5). + @cindex @code{fold_left_plus_@var{m}} instruction pattern @item @code{fold_left_plus_@var{m}} Take scalar operand 1 and successively add each element from vector @@ -7160,6 +7200,40 @@ move operand 2 or (operands 2 + operand 3) into operand 0 according to the comparison in operand 1. If the comparison is false, operand 2 is moved into operand 0, otherwise (operand 2 + operand 3) is moved. +@cindex @code{cond_neg@var{mode}} instruction pattern +@cindex @code{cond_one_cmpl@var{mode}} instruction pattern +@item @samp{cond_neg@var{mode}} +@itemx @samp{cond_one_cmpl@var{mode}} +When operand 1 is true, perform an operation on operands 2 and +store the result in operand 0, otherwise store operand 3 in operand 0. +The operation works elementwise if the operands are vectors. + +The scalar case is equivalent to: + +@smallexample +op0 = op1 ? @var{op} op2 : op3; +@end smallexample + +while the vector case is equivalent to: + +@smallexample +for (i = 0; i < GET_MODE_NUNITS (@var{m}); i++) + op0[i] = op1[i] ? @var{op} op2[i] : op3[i]; +@end smallexample + +where, for example, @var{op} is @code{~} for @samp{cond_one_cmpl@var{mode}}. + +When defined for floating-point modes, the contents of @samp{op2[i]} +are not interpreted if @samp{op1[i]} is false, just like they would not +be in a normal C @samp{?:} condition. + +Operands 0, 2, and 3 all have mode @var{m}. Operand 1 is a scalar +integer if @var{m} is scalar, otherwise it has the mode returned by +@code{TARGET_VECTORIZE_GET_MASK_MODE}. + +@samp{cond_@var{op}@var{mode}} generally corresponds to a conditional +form of @samp{@var{op}@var{mode}2}. + @cindex @code{cond_add@var{mode}} instruction pattern @cindex @code{cond_sub@var{mode}} instruction pattern @cindex @code{cond_mul@var{mode}} instruction pattern @@ -7247,6 +7321,34 @@ for (i = 0; i < GET_MODE_NUNITS (@var{m}); i++) op0[i] = op1[i] ? fma (op2[i], op3[i], op4[i]) : op5[i]; @end smallexample +@cindex @code{cond_len_neg@var{mode}} instruction pattern +@cindex @code{cond_len_one_cmpl@var{mode}} instruction pattern +@item @samp{cond_len_neg@var{mode}} +@itemx @samp{cond_len_one_cmpl@var{mode}} +When operand 1 is true and element index < operand 4 + operand 5, perform an operation on operands 1 and +store the result in operand 0, otherwise store operand 2 in operand 0. +The operation only works for the operands are vectors. + +@smallexample +for (i = 0; i < ops[4] + ops[5]; i++) + op0[i] = op1[i] ? @var{op} op2[i] : op3[i]; +@end smallexample + +where, for example, @var{op} is @code{~} for @samp{cond_len_one_cmpl@var{mode}}. + +When defined for floating-point modes, the contents of @samp{op2[i]} +are not interpreted if @samp{op1[i]} is false, just like they would not +be in a normal C @samp{?:} condition. + +Operands 0, 2, and 3 all have mode @var{m}. Operand 1 is a scalar +integer if @var{m} is scalar, otherwise it has the mode returned by +@code{TARGET_VECTORIZE_GET_MASK_MODE}. Operand 4 has whichever +integer mode the target prefers. + +@samp{cond_len_@var{op}@var{mode}} generally corresponds to a conditional +form of @samp{@var{op}@var{mode}2}. + + @cindex @code{cond_len_add@var{mode}} instruction pattern @cindex @code{cond_len_sub@var{mode}} instruction pattern @cindex @code{cond_len_mul@var{mode}} instruction pattern diff --git a/gcc/doc/plugins.texi b/gcc/doc/plugins.texi index 26df8b490df9..f9a23180ed88 100644 --- a/gcc/doc/plugins.texi +++ b/gcc/doc/plugins.texi @@ -44,7 +44,7 @@ Plugins are loaded with Where @var{name} is the plugin name and @var{ext} is the platform-specific dynamic library extension. It should be @code{dll} on Windows/MinGW, -@code{dylib} on Darwin/Mac OS X, and @code{so} on all other platforms. +@code{dylib} on Darwin/macOS, and @code{so} on all other platforms. The plugin arguments are parsed by GCC and passed to respective plugins as key-value pairs. Multiple plugins can be invoked by specifying multiple @option{-fplugin} arguments. diff --git a/gcc/doc/rtl.texi b/gcc/doc/rtl.texi index 76aeafb8f155..0ed88f58821e 100644 --- a/gcc/doc/rtl.texi +++ b/gcc/doc/rtl.texi @@ -4964,7 +4964,7 @@ the pass should check whether the new pattern matches a target instruction or satisfies the requirements of an inline asm: @smallexample -if (!rtl_ssa::recog (change)) +if (!rtl_ssa::recog (attempt, change)) return false; @end smallexample @@ -5015,7 +5015,7 @@ if (!rtl_ssa::restrict_movement (change)) insn_change_watermark watermark; // Use validate_change etc. to change INSN's pattern. @dots{} -if (!rtl_ssa::recog (change) +if (!rtl_ssa::recog (attempt, change) || !rtl_ssa::change_is_worthwhile (change)) return false; @@ -5048,7 +5048,7 @@ For example, if a pass is changing exactly two instructions, it might do: @smallexample -rtl_ssa::insn_change *changes[] = @{ &change1, change2 @}; +rtl_ssa::insn_change *changes[] = @{ &change1, &change2 @}; @end smallexample where @code{change1}'s instruction must come before @code{change2}'s. @@ -5066,7 +5066,7 @@ in the correct order with respect to each other. The way to do this is: @smallexample -if (!rtl_ssa::restrict_movement (change, insn_is_changing (changes))) +if (!rtl_ssa::restrict_movement_ignoring (change, insn_is_changing (changes))) return false; @end smallexample @@ -5078,7 +5078,7 @@ changing instructions (which might, for example, no longer need to clobber the flags register). The way to do this is: @smallexample -if (!rtl_ssa::recog (change, insn_is_changing (changes))) +if (!rtl_ssa::recog_ignoring (attempt, change, insn_is_changing (changes))) return false; @end smallexample @@ -5118,28 +5118,28 @@ Putting all this together, the process for a two-instruction change is: @smallexample auto attempt = crtl->ssa->new_change_attempt (); -rtl_ssa::insn_change change (insn1); +rtl_ssa::insn_change change1 (insn1); change1.new_defs = @dots{}; change1.new_uses = @dots{}; change1.move_range = @dots{}; -rtl_ssa::insn_change change (insn2); +rtl_ssa::insn_change change2 (insn2); change2.new_defs = @dots{}; change2.new_uses = @dots{}; change2.move_range = @dots{}; -rtl_ssa::insn_change *changes[] = @{ &change1, change2 @}; +rtl_ssa::insn_change *changes[] = @{ &change1, &change2 @}; auto is_changing = insn_is_changing (changes); -if (!rtl_ssa::restrict_movement (change1, is_changing) - || !rtl_ssa::restrict_movement (change2, is_changing)) +if (!rtl_ssa::restrict_movement_ignoring (change1, is_changing) + || !rtl_ssa::restrict_movement_ignoring (change2, is_changing)) return false; insn_change_watermark watermark; // Use validate_change etc. to change INSN1's and INSN2's patterns. @dots{} -if (!rtl_ssa::recog (change1, is_changing) - || !rtl_ssa::recog (change2, is_changing) +if (!rtl_ssa::recog_ignoring (attempt, change1, is_changing) + || !rtl_ssa::recog_ignoring (attempt, change2, is_changing) || !rtl_ssa::changes_are_worthwhile (changes) || !crtl->ssa->verify_insn_changes (changes)) return false; diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi index c0ca98ab5e0f..defa4ac3a7f9 100644 --- a/gcc/doc/tm.texi +++ b/gcc/doc/tm.texi @@ -5800,7 +5800,7 @@ many ulps below or above those boundaries result could be. Set this macro to 1 to use the "NeXT" Objective-C message sending conventions by default. This calling convention involves passing the object, the selector and the method arguments all at once to the method-lookup library function. -This is the usual setting when targeting Darwin/Mac OS X systems, which have +This is the usual setting when targeting Darwin / macOS systems, which have the NeXT runtime installed. If the macro is set to 0, the "GNU" Objective-C message sending convention @@ -5862,9 +5862,16 @@ the maximum number that @code{TARGET_LEGITIMATE_ADDRESS_P} would ever accept. @end defmac -@deftypefn {Target Hook} bool TARGET_LEGITIMATE_ADDRESS_P (machine_mode @var{mode}, rtx @var{x}, bool @var{strict}) +@deftypefn {Target Hook} bool TARGET_LEGITIMATE_ADDRESS_P (machine_mode @var{mode}, rtx @var{x}, bool @var{strict}, code_helper @var{ch}) A function that returns whether @var{x} (an RTX) is a legitimate memory address on the target machine for a memory operand of mode @var{mode}. +If @var{ch} is not @code{ERROR_MARK}, it can be called from middle-end to +determine if it is valid to use @var{x} as a memory operand for RTX insn +which is generated for the given code_helper @var{ch}. For example, +assuming the given @var{ch} is IFN_LEN_LOAD, on some target its underlying +hardware instructions support fewer addressing modes than what are for the +normal vector load and store, then with this @var{ch} target can know the +actual use context and return more exact result. Legitimate addresses are defined in two variants: a strict variant and a non-strict one. The @var{strict} parameter chooses which variant is @@ -11018,11 +11025,12 @@ version of this hook returns true for the modes returned by either the target hooks for the given address space. @end deftypefn -@deftypefn {Target Hook} bool TARGET_ADDR_SPACE_LEGITIMATE_ADDRESS_P (machine_mode @var{mode}, rtx @var{exp}, bool @var{strict}, addr_space_t @var{as}) +@deftypefn {Target Hook} bool TARGET_ADDR_SPACE_LEGITIMATE_ADDRESS_P (machine_mode @var{mode}, rtx @var{exp}, bool @var{strict}, addr_space_t @var{as}, code_helper @var{ch}) Define this to return true if @var{exp} is a valid address for mode -@var{mode} in the named address space @var{as}. The @var{strict} -parameter says whether strict addressing is in effect after reload has -finished. This target hook is the same as the +@var{mode} in the named address space @var{as} with the use context +@var{ch}. The @var{strict} parameter says whether strict addressing +is in effect after reload has finished. The @var{ch} indicates what +context @var{exp} will be used for. This target hook is the same as the @code{TARGET_LEGITIMATE_ADDRESS_P} target hook, except that it includes explicit named address space support. @end deftypefn @@ -12031,7 +12039,7 @@ This target hook is required only when the target has several different modes and they have different conditional execution capability, such as ARM. @end deftypefn -@deftypefn {Target Hook} rtx TARGET_GEN_CCMP_FIRST (rtx_insn **@var{prep_seq}, rtx_insn **@var{gen_seq}, int @var{code}, tree @var{op0}, tree @var{op1}) +@deftypefn {Target Hook} rtx TARGET_GEN_CCMP_FIRST (rtx_insn **@var{prep_seq}, rtx_insn **@var{gen_seq}, rtx_code @var{code}, tree @var{op0}, tree @var{op1}) This function prepares to emit a comparison insn for the first compare in a sequence of conditional comparisions. It returns an appropriate comparison with @code{CC} for passing to @code{gen_ccmp_next} or @code{cbranch_optab}. @@ -12041,7 +12049,7 @@ This function prepares to emit a comparison insn for the first compare in a @var{code} is the @code{rtx_code} of the compare for @var{op0} and @var{op1}. @end deftypefn -@deftypefn {Target Hook} rtx TARGET_GEN_CCMP_NEXT (rtx_insn **@var{prep_seq}, rtx_insn **@var{gen_seq}, rtx @var{prev}, int @var{cmp_code}, tree @var{op0}, tree @var{op1}, int @var{bit_code}) +@deftypefn {Target Hook} rtx TARGET_GEN_CCMP_NEXT (rtx_insn **@var{prep_seq}, rtx_insn **@var{gen_seq}, rtx @var{prev}, rtx_code @var{cmp_code}, tree @var{op0}, tree @var{op1}, rtx_code @var{bit_code}) This function prepares to emit a conditional comparison within a sequence of conditional comparisons. It returns an appropriate comparison with @code{CC} for passing to @code{gen_ccmp_next} or @code{cbranch_optab}. diff --git a/gcc/doc/tm.texi.in b/gcc/doc/tm.texi.in index 3186fbf50295..0e48714b77c2 100644 --- a/gcc/doc/tm.texi.in +++ b/gcc/doc/tm.texi.in @@ -4021,7 +4021,7 @@ macro, a reasonable default is used. Set this macro to 1 to use the "NeXT" Objective-C message sending conventions by default. This calling convention involves passing the object, the selector and the method arguments all at once to the method-lookup library function. -This is the usual setting when targeting Darwin/Mac OS X systems, which have +This is the usual setting when targeting Darwin / macOS systems, which have the NeXT runtime installed. If the macro is set to 0, the "GNU" Objective-C message sending convention diff --git a/gcc/dwarf2out.cc b/gcc/dwarf2out.cc index fa0fe4c41bbd..69018bde2383 100644 --- a/gcc/dwarf2out.cc +++ b/gcc/dwarf2out.cc @@ -30141,8 +30141,13 @@ prune_unused_types_walk (dw_die_ref die) case DW_TAG_reference_type: case DW_TAG_rvalue_reference_type: case DW_TAG_volatile_type: + case DW_TAG_restrict_type: + case DW_TAG_shared_type: + case DW_TAG_atomic_type: + case DW_TAG_immutable_type: case DW_TAG_typedef: case DW_TAG_array_type: + case DW_TAG_coarray_type: case DW_TAG_friend: case DW_TAG_enumeration_type: case DW_TAG_subroutine_type: @@ -30151,6 +30156,8 @@ prune_unused_types_walk (dw_die_ref die) case DW_TAG_subrange_type: case DW_TAG_ptr_to_member_type: case DW_TAG_file_type: + case DW_TAG_unspecified_type: + case DW_TAG_dynamic_type: /* Type nodes are useful only when other DIEs reference them --- don't mark them. */ /* FALLTHROUGH */ diff --git a/gcc/expr.cc b/gcc/expr.cc index 174f8acb269a..9a37bff1fdd3 100644 --- a/gcc/expr.cc +++ b/gcc/expr.cc @@ -11248,17 +11248,15 @@ expand_expr_real_1 (tree exp, rtx target, machine_mode tmode, set_mem_addr_space (temp, as); if (TREE_THIS_VOLATILE (exp)) MEM_VOLATILE_P (temp) = 1; - if (modifier != EXPAND_WRITE - && modifier != EXPAND_MEMORY - && !inner_reference_p + if (modifier == EXPAND_WRITE || modifier == EXPAND_MEMORY) + return temp; + if (!inner_reference_p && mode != BLKmode && align < GET_MODE_ALIGNMENT (mode)) temp = expand_misaligned_mem_ref (temp, mode, unsignedp, align, modifier == EXPAND_STACK_PARM ? NULL_RTX : target, alt_rtl); - if (reverse - && modifier != EXPAND_MEMORY - && modifier != EXPAND_WRITE) + if (reverse) temp = flip_storage_order (mode, temp); return temp; } diff --git a/gcc/flag-types.h b/gcc/flag-types.h index 36305de589ea..7466c1106f2b 100644 --- a/gcc/flag-types.h +++ b/gcc/flag-types.h @@ -478,13 +478,6 @@ enum threader_debug THREADER_DEBUG_ALL = 1 }; -/* VRP modes. */ -enum vrp_mode -{ - VRP_MODE_VRP, - VRP_MODE_RANGER -}; - /* Modes of OpenACC 'kernels' constructs handling. */ enum openacc_kernels { diff --git a/gcc/fold-const.cc b/gcc/fold-const.cc index 7e5494dfd392..fa1d5834bc30 100644 --- a/gcc/fold-const.cc +++ b/gcc/fold-const.cc @@ -40,6 +40,7 @@ along with GCC; see the file COPYING3. If not see gimple code, we need to handle GIMPLE tuples as well as their corresponding tree equivalents. */ +#define INCLUDE_ALGORITHM #include "config.h" #include "system.h" #include "coretypes.h" @@ -10520,6 +10521,181 @@ vec_cst_ctor_to_array (tree arg, unsigned int nelts, tree *elts) return true; } +/* Helper routine for fold_vec_perm_cst to check if SEL is a suitable + mask for VLA vec_perm folding. + REASON if specified, will contain the reason why SEL is not suitable. + Used only for debugging and unit-testing. */ + +static bool +valid_mask_for_fold_vec_perm_cst_p (tree arg0, tree arg1, + const vec_perm_indices &sel, + const char **reason = NULL) +{ + unsigned sel_npatterns = sel.encoding ().npatterns (); + unsigned sel_nelts_per_pattern = sel.encoding ().nelts_per_pattern (); + + if (!(pow2p_hwi (sel_npatterns) + && pow2p_hwi (VECTOR_CST_NPATTERNS (arg0)) + && pow2p_hwi (VECTOR_CST_NPATTERNS (arg1)))) + { + if (reason) + *reason = "npatterns is not power of 2"; + return false; + } + + /* We want to avoid cases where sel.length is not a multiple of npatterns. + For eg: sel.length = 2 + 2x, and sel npatterns = 4. */ + poly_uint64 esel; + if (!multiple_p (sel.length (), sel_npatterns, &esel)) + { + if (reason) + *reason = "sel.length is not multiple of sel_npatterns"; + return false; + } + + if (sel_nelts_per_pattern < 3) + return true; + + for (unsigned pattern = 0; pattern < sel_npatterns; pattern++) + { + poly_uint64 a1 = sel[pattern + sel_npatterns]; + poly_uint64 a2 = sel[pattern + 2 * sel_npatterns]; + HOST_WIDE_INT step; + if (!poly_int64 (a2 - a1).is_constant (&step)) + { + if (reason) + *reason = "step is not constant"; + return false; + } + // FIXME: Punt on step < 0 for now, revisit later. + if (step < 0) + return false; + if (step == 0) + continue; + + if (!pow2p_hwi (step)) + { + if (reason) + *reason = "step is not power of 2"; + return false; + } + + /* Ensure that stepped sequence of the pattern selects elements + only from the same input vector. */ + uint64_t q1, qe; + poly_uint64 r1, re; + poly_uint64 ae = a1 + (esel - 2) * step; + poly_uint64 arg_len = TYPE_VECTOR_SUBPARTS (TREE_TYPE (arg0)); + + if (!(can_div_trunc_p (a1, arg_len, &q1, &r1) + && can_div_trunc_p (ae, arg_len, &qe, &re) + && q1 == qe)) + { + if (reason) + *reason = "crossed input vectors"; + return false; + } + + /* Ensure that the stepped sequence always selects from the same + input pattern. */ + unsigned arg_npatterns + = ((q1 & 1) == 0) ? VECTOR_CST_NPATTERNS (arg0) + : VECTOR_CST_NPATTERNS (arg1); + + if (!multiple_p (step, arg_npatterns)) + { + if (reason) + *reason = "step is not multiple of npatterns"; + return false; + } + } + + return true; +} + +/* Try to fold permutation of ARG0 and ARG1 with SEL selector when + the input vectors are VECTOR_CST. Return NULL_TREE otherwise. + REASON has same purpose as described in + valid_mask_for_fold_vec_perm_cst_p. */ + +static tree +fold_vec_perm_cst (tree type, tree arg0, tree arg1, const vec_perm_indices &sel, + const char **reason = NULL) +{ + unsigned res_npatterns, res_nelts_per_pattern; + unsigned HOST_WIDE_INT res_nelts; + + /* (1) If SEL is a suitable mask as determined by + valid_mask_for_fold_vec_perm_cst_p, then: + res_npatterns = max of npatterns between ARG0, ARG1, and SEL + res_nelts_per_pattern = max of nelts_per_pattern between + ARG0, ARG1 and SEL. + (2) If SEL is not a suitable mask, and TYPE is VLS then: + res_npatterns = nelts in result vector. + res_nelts_per_pattern = 1. + This exception is made so that VLS ARG0, ARG1 and SEL work as before. */ + if (valid_mask_for_fold_vec_perm_cst_p (arg0, arg1, sel, reason)) + { + res_npatterns + = std::max (VECTOR_CST_NPATTERNS (arg0), + std::max (VECTOR_CST_NPATTERNS (arg1), + sel.encoding ().npatterns ())); + + res_nelts_per_pattern + = std::max (VECTOR_CST_NELTS_PER_PATTERN (arg0), + std::max (VECTOR_CST_NELTS_PER_PATTERN (arg1), + sel.encoding ().nelts_per_pattern ())); + + res_nelts = res_npatterns * res_nelts_per_pattern; + } + else if (TYPE_VECTOR_SUBPARTS (type).is_constant (&res_nelts)) + { + res_npatterns = res_nelts; + res_nelts_per_pattern = 1; + } + else + return NULL_TREE; + + tree_vector_builder out_elts (type, res_npatterns, res_nelts_per_pattern); + for (unsigned i = 0; i < res_nelts; i++) + { + poly_uint64 len = TYPE_VECTOR_SUBPARTS (TREE_TYPE (arg0)); + uint64_t q; + poly_uint64 r; + unsigned HOST_WIDE_INT index; + + /* Punt if sel[i] /trunc_div len cannot be determined, + because the input vector to be chosen will depend on + runtime vector length. + For example if len == 4 + 4x, and sel[i] == 4, + If len at runtime equals 4, we choose arg1[0]. + For any other value of len > 4 at runtime, we choose arg0[4]. + which makes the element choice dependent on runtime vector length. */ + if (!can_div_trunc_p (sel[i], len, &q, &r)) + { + if (reason) + *reason = "cannot divide selector element by arg len"; + return NULL_TREE; + } + + /* sel[i] % len will give the index of element in the chosen input + vector. For example if sel[i] == 5 + 4x and len == 4 + 4x, + we will choose arg1[1] since (5 + 4x) % (4 + 4x) == 1. */ + if (!r.is_constant (&index)) + { + if (reason) + *reason = "remainder is not constant"; + return NULL_TREE; + } + + tree arg = ((q & 1) == 0) ? arg0 : arg1; + tree elem = vector_cst_elt (arg, index); + out_elts.quick_push (elem); + } + + return out_elts.build (); +} + /* Attempt to fold vector permutation of ARG0 and ARG1 vectors using SEL selector. Return the folded VECTOR_CST or CONSTRUCTOR if successful, NULL_TREE otherwise. */ @@ -10529,43 +10705,41 @@ fold_vec_perm (tree type, tree arg0, tree arg1, const vec_perm_indices &sel) { unsigned int i; unsigned HOST_WIDE_INT nelts; - bool need_ctor = false; - if (!sel.length ().is_constant (&nelts)) - return NULL_TREE; - gcc_assert (known_eq (TYPE_VECTOR_SUBPARTS (type), nelts) - && known_eq (TYPE_VECTOR_SUBPARTS (TREE_TYPE (arg0)), nelts) - && known_eq (TYPE_VECTOR_SUBPARTS (TREE_TYPE (arg1)), nelts)); + gcc_assert (known_eq (TYPE_VECTOR_SUBPARTS (type), sel.length ()) + && known_eq (TYPE_VECTOR_SUBPARTS (TREE_TYPE (arg0)), + TYPE_VECTOR_SUBPARTS (TREE_TYPE (arg1)))); + if (TREE_TYPE (TREE_TYPE (arg0)) != TREE_TYPE (type) || TREE_TYPE (TREE_TYPE (arg1)) != TREE_TYPE (type)) return NULL_TREE; + if (TREE_CODE (arg0) == VECTOR_CST + && TREE_CODE (arg1) == VECTOR_CST) + return fold_vec_perm_cst (type, arg0, arg1, sel); + + /* For fall back case, we want to ensure we have VLS vectors + with equal length. */ + if (!sel.length ().is_constant (&nelts)) + return NULL_TREE; + + gcc_assert (known_eq (sel.length (), + TYPE_VECTOR_SUBPARTS (TREE_TYPE (arg0)))); tree *in_elts = XALLOCAVEC (tree, nelts * 2); if (!vec_cst_ctor_to_array (arg0, nelts, in_elts) || !vec_cst_ctor_to_array (arg1, nelts, in_elts + nelts)) return NULL_TREE; - tree_vector_builder out_elts (type, nelts, 1); + vec *v; + vec_alloc (v, nelts); for (i = 0; i < nelts; i++) { HOST_WIDE_INT index; if (!sel[i].is_constant (&index)) return NULL_TREE; - if (!CONSTANT_CLASS_P (in_elts[index])) - need_ctor = true; - out_elts.quick_push (unshare_expr (in_elts[index])); + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, in_elts[index]); } - - if (need_ctor) - { - vec *v; - vec_alloc (v, nelts); - for (i = 0; i < nelts; i++) - CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, out_elts[i]); - return build_constructor (type, v); - } - else - return out_elts.build (); + return build_constructor (type, v); } /* Try to fold a pointer difference of type TYPE two address expressions of @@ -16892,6 +17066,618 @@ test_arithmetic_folding () x); } +namespace test_fold_vec_perm_cst { + +/* Build a VECTOR_CST corresponding to VMODE, and has + encoding given by NPATTERNS, NELTS_PER_PATTERN and STEP. + Fill it with randomized elements, using rand() % THRESHOLD. */ + +static tree +build_vec_cst_rand (machine_mode vmode, unsigned npatterns, + unsigned nelts_per_pattern, + int step = 0, int threshold = 100) +{ + tree inner_type = lang_hooks.types.type_for_mode (GET_MODE_INNER (vmode), 1); + tree vectype = build_vector_type_for_mode (inner_type, vmode); + tree_vector_builder builder (vectype, npatterns, nelts_per_pattern); + + // Fill a0 for each pattern + for (unsigned i = 0; i < npatterns; i++) + builder.quick_push (build_int_cst (inner_type, rand () % threshold)); + + if (nelts_per_pattern == 1) + return builder.build (); + + // Fill a1 for each pattern + for (unsigned i = 0; i < npatterns; i++) + builder.quick_push (build_int_cst (inner_type, rand () % threshold)); + + if (nelts_per_pattern == 2) + return builder.build (); + + for (unsigned i = npatterns * 2; i < npatterns * nelts_per_pattern; i++) + { + tree prev_elem = builder[i - npatterns]; + int prev_elem_val = TREE_INT_CST_LOW (prev_elem); + int val = prev_elem_val + step; + builder.quick_push (build_int_cst (inner_type, val)); + } + + return builder.build (); +} + +/* Validate result of VEC_PERM_EXPR folding for the unit-tests below, + when result is VLA. */ + +static void +validate_res (unsigned npatterns, unsigned nelts_per_pattern, + tree res, tree *expected_res) +{ + /* Actual npatterns and encoded_elts in res may be less than expected due + to canonicalization. */ + ASSERT_TRUE (res != NULL_TREE); + ASSERT_TRUE (VECTOR_CST_NPATTERNS (res) <= npatterns); + ASSERT_TRUE (vector_cst_encoded_nelts (res) <= npatterns * nelts_per_pattern); + + for (unsigned i = 0; i < npatterns * nelts_per_pattern; i++) + ASSERT_TRUE (operand_equal_p (VECTOR_CST_ELT (res, i), expected_res[i], 0)); +} + +/* Validate result of VEC_PERM_EXPR folding for the unit-tests below, + when the result is VLS. */ + +static void +validate_res_vls (tree res, tree *expected_res, unsigned expected_nelts) +{ + ASSERT_TRUE (known_eq (VECTOR_CST_NELTS (res), expected_nelts)); + for (unsigned i = 0; i < expected_nelts; i++) + ASSERT_TRUE (operand_equal_p (VECTOR_CST_ELT (res, i), expected_res[i], 0)); +} + +/* Helper routine to push multiple elements into BUILDER. */ +template +static void builder_push_elems (vec_perm_builder& builder, + poly_uint64 (&elems)[N]) +{ + for (unsigned i = 0; i < N; i++) + builder.quick_push (elems[i]); +} + +#define ARG0(index) vector_cst_elt (arg0, index) +#define ARG1(index) vector_cst_elt (arg1, index) + +/* Test cases where result is VNx4SI and input vectors are V4SI. */ + +static void +test_vnx4si_v4si (machine_mode vnx4si_mode, machine_mode v4si_mode) +{ + for (int i = 0; i < 10; i++) + { + /* Case 1: + sel = { 0, 4, 1, 5, ... } + res = { arg[0], arg1[0], arg0[1], arg1[1], ...} // (4, 1) */ + { + tree arg0 = build_vec_cst_rand (v4si_mode, 4, 1, 0); + tree arg1 = build_vec_cst_rand (v4si_mode, 4, 1, 0); + + tree inner_type + = lang_hooks.types.type_for_mode (GET_MODE_INNER (vnx4si_mode), 1); + tree res_type = build_vector_type_for_mode (inner_type, vnx4si_mode); + + poly_uint64 res_len = TYPE_VECTOR_SUBPARTS (res_type); + vec_perm_builder builder (res_len, 4, 1); + poly_uint64 mask_elems[] = { 0, 4, 1, 5 }; + builder_push_elems (builder, mask_elems); + + vec_perm_indices sel (builder, 2, res_len); + tree res = fold_vec_perm_cst (res_type, arg0, arg1, sel); + + tree expected_res[] = { ARG0(0), ARG1(0), ARG0(1), ARG1(1) }; + validate_res (4, 1, res, expected_res); + } + + /* Case 2: Same as case 1, but contains an out of bounds access which + should wrap around. + sel = {0, 8, 4, 12, ...} (4, 1) + res = { arg0[0], arg0[0], arg1[0], arg1[0], ... } (4, 1). */ + { + tree arg0 = build_vec_cst_rand (v4si_mode, 4, 1, 0); + tree arg1 = build_vec_cst_rand (v4si_mode, 4, 1, 0); + + tree inner_type + = lang_hooks.types.type_for_mode (GET_MODE_INNER (vnx4si_mode), 1); + tree res_type = build_vector_type_for_mode (inner_type, vnx4si_mode); + + poly_uint64 res_len = TYPE_VECTOR_SUBPARTS (res_type); + vec_perm_builder builder (res_len, 4, 1); + poly_uint64 mask_elems[] = { 0, 8, 4, 12 }; + builder_push_elems (builder, mask_elems); + + vec_perm_indices sel (builder, 2, res_len); + tree res = fold_vec_perm_cst (res_type, arg0, arg1, sel); + + tree expected_res[] = { ARG0(0), ARG0(0), ARG1(0), ARG1(0) }; + validate_res (4, 1, res, expected_res); + } + } +} + +/* Test cases where result is V4SI and input vectors are VNx4SI. */ + +static void +test_v4si_vnx4si (machine_mode v4si_mode, machine_mode vnx4si_mode) +{ + for (int i = 0; i < 10; i++) + { + /* Case 1: + sel = { 0, 1, 2, 3} + res = { arg0[0], arg0[1], arg0[2], arg0[3] }. */ + { + tree arg0 = build_vec_cst_rand (vnx4si_mode, 4, 1); + tree arg1 = build_vec_cst_rand (vnx4si_mode, 4, 1); + + tree inner_type + = lang_hooks.types.type_for_mode (GET_MODE_INNER (v4si_mode), 1); + tree res_type = build_vector_type_for_mode (inner_type, v4si_mode); + + poly_uint64 res_len = TYPE_VECTOR_SUBPARTS (res_type); + vec_perm_builder builder (res_len, 4, 1); + poly_uint64 mask_elems[] = {0, 1, 2, 3}; + builder_push_elems (builder, mask_elems); + + vec_perm_indices sel (builder, 2, res_len); + tree res = fold_vec_perm_cst (res_type, arg0, arg1, sel); + + tree expected_res[] = { ARG0(0), ARG0(1), ARG0(2), ARG0(3) }; + validate_res_vls (res, expected_res, 4); + } + + /* Case 2: Same as Case 1, but crossing input vector. + sel = {0, 2, 4, 6} + In this case,the index 4 is ambiguous since len = 4 + 4x. + Since we cannot determine, which vector to choose from during + compile time, should return NULL_TREE. */ + { + tree arg0 = build_vec_cst_rand (vnx4si_mode, 4, 1); + tree arg1 = build_vec_cst_rand (vnx4si_mode, 4, 1); + + tree inner_type + = lang_hooks.types.type_for_mode (GET_MODE_INNER (v4si_mode), 1); + tree res_type = build_vector_type_for_mode (inner_type, v4si_mode); + + poly_uint64 res_len = TYPE_VECTOR_SUBPARTS (res_type); + vec_perm_builder builder (res_len, 4, 1); + poly_uint64 mask_elems[] = {0, 2, 4, 6}; + builder_push_elems (builder, mask_elems); + + vec_perm_indices sel (builder, 2, res_len); + const char *reason; + tree res = fold_vec_perm_cst (res_type, arg0, arg1, sel, &reason); + + ASSERT_TRUE (res == NULL_TREE); + ASSERT_TRUE (!strcmp (reason, "cannot divide selector element by arg len")); + } + } +} + +/* Test all input vectors. */ + +static void +test_all_nunits (machine_mode vmode) +{ + /* Test with 10 different inputs. */ + for (int i = 0; i < 10; i++) + { + tree arg0 = build_vec_cst_rand (vmode, 1, 3, 1); + tree arg1 = build_vec_cst_rand (vmode, 1, 3, 1); + poly_uint64 len = TYPE_VECTOR_SUBPARTS (TREE_TYPE (arg0)); + + /* Case 1: mask = {0, ...} // (1, 1) + res = { arg0[0], ... } // (1, 1) */ + { + vec_perm_builder builder (len, 1, 1); + builder.quick_push (0); + vec_perm_indices sel (builder, 2, len); + tree res = fold_vec_perm_cst (TREE_TYPE (arg0), arg0, arg1, sel); + tree expected_res[] = { ARG0(0) }; + validate_res (1, 1, res, expected_res); + } + + /* Case 2: mask = {len, ...} // (1, 1) + res = { arg1[0], ... } // (1, 1) */ + { + vec_perm_builder builder (len, 1, 1); + builder.quick_push (len); + vec_perm_indices sel (builder, 2, len); + tree res = fold_vec_perm_cst (TREE_TYPE (arg0), arg0, arg1, sel); + + tree expected_res[] = { ARG1(0) }; + validate_res (1, 1, res, expected_res); + } + } +} + +/* Test all vectors which contain at-least 2 elements. */ + +static void +test_nunits_min_2 (machine_mode vmode) +{ + for (int i = 0; i < 10; i++) + { + /* Case 1: mask = { 0, len, ... } // (2, 1) + res = { arg0[0], arg1[0], ... } // (2, 1) */ + { + tree arg0 = build_vec_cst_rand (vmode, 1, 3, 1); + tree arg1 = build_vec_cst_rand (vmode, 1, 3, 1); + poly_uint64 len = TYPE_VECTOR_SUBPARTS (TREE_TYPE (arg0)); + + vec_perm_builder builder (len, 2, 1); + poly_uint64 mask_elems[] = { 0, len }; + builder_push_elems (builder, mask_elems); + + vec_perm_indices sel (builder, 2, len); + tree res = fold_vec_perm_cst (TREE_TYPE (arg0), arg0, arg1, sel); + + tree expected_res[] = { ARG0(0), ARG1(0) }; + validate_res (2, 1, res, expected_res); + } + + /* Case 2: mask = { 0, len, 1, len+1, ... } // (2, 2) + res = { arg0[0], arg1[0], arg0[1], arg1[1], ... } // (2, 2) */ + { + tree arg0 = build_vec_cst_rand (vmode, 1, 3, 1); + tree arg1 = build_vec_cst_rand (vmode, 1, 3, 1); + poly_uint64 len = TYPE_VECTOR_SUBPARTS (TREE_TYPE (arg0)); + + vec_perm_builder builder (len, 2, 2); + poly_uint64 mask_elems[] = { 0, len, 1, len + 1 }; + builder_push_elems (builder, mask_elems); + + vec_perm_indices sel (builder, 2, len); + tree res = fold_vec_perm_cst (TREE_TYPE (arg0), arg0, arg1, sel); + + tree expected_res[] = { ARG0(0), ARG1(0), ARG0(1), ARG1(1) }; + validate_res (2, 2, res, expected_res); + } + + /* Case 4: mask = {0, 0, 1, ...} // (1, 3) + Test that the stepped sequence of the pattern selects from + same input pattern. Since input vectors have npatterns = 2, + and step (a2 - a1) = 1, step is not a multiple of npatterns + in input vector. So return NULL_TREE. */ + { + tree arg0 = build_vec_cst_rand (vmode, 2, 3, 1); + tree arg1 = build_vec_cst_rand (vmode, 2, 3, 1); + poly_uint64 len = TYPE_VECTOR_SUBPARTS (TREE_TYPE (arg0)); + + vec_perm_builder builder (len, 1, 3); + poly_uint64 mask_elems[] = { 0, 0, 1 }; + builder_push_elems (builder, mask_elems); + + vec_perm_indices sel (builder, 2, len); + const char *reason; + tree res = fold_vec_perm_cst (TREE_TYPE (arg0), arg0, arg1, sel, + &reason); + ASSERT_TRUE (res == NULL_TREE); + ASSERT_TRUE (!strcmp (reason, "step is not multiple of npatterns")); + } + + /* Case 5: mask = {len, 0, 1, ...} // (1, 3) + Test that stepped sequence of the pattern selects from arg0. + res = { arg1[0], arg0[0], arg0[1], ... } // (1, 3) */ + { + tree arg0 = build_vec_cst_rand (vmode, 1, 3, 1); + tree arg1 = build_vec_cst_rand (vmode, 1, 3, 1); + poly_uint64 len = TYPE_VECTOR_SUBPARTS (TREE_TYPE (arg0)); + + vec_perm_builder builder (len, 1, 3); + poly_uint64 mask_elems[] = { len, 0, 1 }; + builder_push_elems (builder, mask_elems); + + vec_perm_indices sel (builder, 2, len); + tree res = fold_vec_perm_cst (TREE_TYPE (arg0), arg0, arg1, sel); + + tree expected_res[] = { ARG1(0), ARG0(0), ARG0(1) }; + validate_res (1, 3, res, expected_res); + } + } +} + +/* Test all vectors which contain at-least 4 elements. */ + +static void +test_nunits_min_4 (machine_mode vmode) +{ + for (int i = 0; i < 10; i++) + { + /* Case 1: mask = { 0, len, 1, len+1, ... } // (4, 1) + res: { arg0[0], arg1[0], arg0[1], arg1[1], ... } // (4, 1) */ + { + tree arg0 = build_vec_cst_rand (vmode, 1, 3, 1); + tree arg1 = build_vec_cst_rand (vmode, 1, 3, 1); + poly_uint64 len = TYPE_VECTOR_SUBPARTS (TREE_TYPE (arg0)); + + vec_perm_builder builder (len, 4, 1); + poly_uint64 mask_elems[] = { 0, len, 1, len + 1 }; + builder_push_elems (builder, mask_elems); + + vec_perm_indices sel (builder, 2, len); + tree res = fold_vec_perm_cst (TREE_TYPE (arg0), arg0, arg1, sel); + + tree expected_res[] = { ARG0(0), ARG1(0), ARG0(1), ARG1(1) }; + validate_res (4, 1, res, expected_res); + } + + /* Case 2: sel = {0, 1, 2, ...} // (1, 3) + res: { arg0[0], arg0[1], arg0[2], ... } // (1, 3) */ + { + tree arg0 = build_vec_cst_rand (vmode, 1, 3, 2); + tree arg1 = build_vec_cst_rand (vmode, 1, 3, 2); + poly_uint64 arg0_len = TYPE_VECTOR_SUBPARTS (TREE_TYPE (arg0)); + + vec_perm_builder builder (arg0_len, 1, 3); + poly_uint64 mask_elems[] = {0, 1, 2}; + builder_push_elems (builder, mask_elems); + + vec_perm_indices sel (builder, 2, arg0_len); + tree res = fold_vec_perm_cst (TREE_TYPE (arg0), arg0, arg1, sel); + tree expected_res[] = { ARG0(0), ARG0(1), ARG0(2) }; + validate_res (1, 3, res, expected_res); + } + + /* Case 3: sel = {len, len+1, len+2, ...} // (1, 3) + res: { arg1[0], arg1[1], arg1[2], ... } // (1, 3) */ + { + tree arg0 = build_vec_cst_rand (vmode, 1, 3, 2); + tree arg1 = build_vec_cst_rand (vmode, 1, 3, 2); + poly_uint64 len = TYPE_VECTOR_SUBPARTS (TREE_TYPE (arg0)); + + vec_perm_builder builder (len, 1, 3); + poly_uint64 mask_elems[] = {len, len + 1, len + 2}; + builder_push_elems (builder, mask_elems); + + vec_perm_indices sel (builder, 2, len); + tree res = fold_vec_perm_cst (TREE_TYPE (arg0), arg0, arg1, sel); + tree expected_res[] = { ARG1(0), ARG1(1), ARG1(2) }; + validate_res (1, 3, res, expected_res); + } + + /* Case 4: + sel = { len, 0, 2, ... } // (1, 3) + This should return NULL because we cross the input vectors. + Because, + Let's assume len = C + Cx + a1 = 0 + S = 2 + esel = arg0_len / sel_npatterns = C + Cx + ae = 0 + (esel - 2) * S + = 0 + (C + Cx - 2) * 2 + = 2(C-2) + 2Cx + + For C >= 4: + Let q1 = a1 / arg0_len = 0 / (C + Cx) = 0 + Let qe = ae / arg0_len = (2(C-2) + 2Cx) / (C + Cx) = 1 + Since q1 != qe, we cross input vectors. + So return NULL_TREE. */ + { + tree arg0 = build_vec_cst_rand (vmode, 1, 3, 2); + tree arg1 = build_vec_cst_rand (vmode, 1, 3, 2); + poly_uint64 arg0_len = TYPE_VECTOR_SUBPARTS (TREE_TYPE (arg0)); + + vec_perm_builder builder (arg0_len, 1, 3); + poly_uint64 mask_elems[] = { arg0_len, 0, 2 }; + builder_push_elems (builder, mask_elems); + + vec_perm_indices sel (builder, 2, arg0_len); + const char *reason; + tree res = fold_vec_perm_cst (TREE_TYPE (arg0), arg0, arg1, sel, &reason); + ASSERT_TRUE (res == NULL_TREE); + ASSERT_TRUE (!strcmp (reason, "crossed input vectors")); + } + + /* Case 5: npatterns(arg0) = 4 > npatterns(sel) = 2 + mask = { 0, len, 1, len + 1, ...} // (2, 2) + res = { arg0[0], arg1[0], arg0[1], arg1[1], ... } // (2, 2) + + Note that fold_vec_perm_cst will set + res_npatterns = max(4, max(4, 2)) = 4 + However after canonicalizing, we will end up with shape (2, 2). */ + { + tree arg0 = build_vec_cst_rand (vmode, 4, 1); + tree arg1 = build_vec_cst_rand (vmode, 4, 1); + poly_uint64 len = TYPE_VECTOR_SUBPARTS (TREE_TYPE (arg0)); + + vec_perm_builder builder (len, 2, 2); + poly_uint64 mask_elems[] = { 0, len, 1, len + 1 }; + builder_push_elems (builder, mask_elems); + + vec_perm_indices sel (builder, 2, len); + tree res = fold_vec_perm_cst (TREE_TYPE (arg0), arg0, arg1, sel); + tree expected_res[] = { ARG0(0), ARG1(0), ARG0(1), ARG1(1) }; + validate_res (2, 2, res, expected_res); + } + + /* Case 6: Test combination in sel, where one pattern is dup and other + is stepped sequence. + sel = { 0, 0, 0, 1, 0, 2, ... } // (2, 3) + res = { arg0[0], arg0[0], arg0[0], + arg0[1], arg0[0], arg0[2], ... } // (2, 3) */ + { + tree arg0 = build_vec_cst_rand (vmode, 1, 3, 1); + tree arg1 = build_vec_cst_rand (vmode, 1, 3, 1); + poly_uint64 len = TYPE_VECTOR_SUBPARTS (TREE_TYPE (arg0)); + + vec_perm_builder builder (len, 2, 3); + poly_uint64 mask_elems[] = { 0, 0, 0, 1, 0, 2 }; + builder_push_elems (builder, mask_elems); + + vec_perm_indices sel (builder, 2, len); + tree res = fold_vec_perm_cst (TREE_TYPE (arg0), arg0, arg1, sel); + + tree expected_res[] = { ARG0(0), ARG0(0), ARG0(0), + ARG0(1), ARG0(0), ARG0(2) }; + validate_res (2, 3, res, expected_res); + } + + /* Case 7: PR111048: Check that we set arg_npatterns correctly, + when arg0, arg1 and sel have different number of patterns. + arg0 is of shape (1, 1) + arg1 is of shape (4, 1) + sel is of shape (2, 3) = {1, len, 2, len+1, 3, len+2, ...} + + In this case the pattern: {len, len+1, len+2, ...} chooses arg1. + However, + step = (len+2) - (len+1) = 1 + arg_npatterns = VECTOR_CST_NPATTERNS (arg1) = 4 + Since step is not a multiple of arg_npatterns, + valid_mask_for_fold_vec_perm_cst should return false, + and thus fold_vec_perm_cst should return NULL_TREE. */ + { + tree arg0 = build_vec_cst_rand (vmode, 1, 1); + tree arg1 = build_vec_cst_rand (vmode, 4, 1); + poly_uint64 len = TYPE_VECTOR_SUBPARTS (TREE_TYPE (arg0)); + + vec_perm_builder builder (len, 2, 3); + poly_uint64 mask_elems[] = { 0, len, 1, len + 1, 2, len + 2 }; + builder_push_elems (builder, mask_elems); + + vec_perm_indices sel (builder, 2, len); + const char *reason; + tree res = fold_vec_perm_cst (TREE_TYPE (arg0), arg0, arg1, sel, &reason); + + ASSERT_TRUE (res == NULL_TREE); + ASSERT_TRUE (!strcmp (reason, "step is not multiple of npatterns")); + } + } +} + +/* Test all vectors which contain at-least 8 elements. */ + +static void +test_nunits_min_8 (machine_mode vmode) +{ + for (int i = 0; i < 10; i++) + { + /* Case 1: sel_npatterns (4) > input npatterns (2) + sel: { 0, 0, 1, len, 2, 0, 3, len, 4, 0, 5, len, ...} // (4, 3) + res: { arg0[0], arg0[0], arg0[0], arg1[0], + arg0[2], arg0[0], arg0[3], arg1[0], + arg0[4], arg0[0], arg0[5], arg1[0], ... } // (4, 3) */ + { + tree arg0 = build_vec_cst_rand (vmode, 2, 3, 2); + tree arg1 = build_vec_cst_rand (vmode, 2, 3, 2); + poly_uint64 len = TYPE_VECTOR_SUBPARTS (TREE_TYPE (arg0)); + + vec_perm_builder builder(len, 4, 3); + poly_uint64 mask_elems[] = { 0, 0, 1, len, 2, 0, 3, len, + 4, 0, 5, len }; + builder_push_elems (builder, mask_elems); + + vec_perm_indices sel (builder, 2, len); + tree res = fold_vec_perm_cst (TREE_TYPE (arg0), arg0, arg1, sel); + + tree expected_res[] = { ARG0(0), ARG0(0), ARG0(1), ARG1(0), + ARG0(2), ARG0(0), ARG0(3), ARG1(0), + ARG0(4), ARG0(0), ARG0(5), ARG1(0) }; + validate_res (4, 3, res, expected_res); + } + } +} + +/* Test vectors for which nunits[0] <= 4. */ + +static void +test_nunits_max_4 (machine_mode vmode) +{ + /* Case 1: mask = {0, 4, ...} // (1, 2) + This should return NULL_TREE because the index 4 may choose + from either arg0 or arg1 depending on vector length. */ + { + tree arg0 = build_vec_cst_rand (vmode, 1, 3, 1); + tree arg1 = build_vec_cst_rand (vmode, 1, 3, 1); + poly_uint64 len = TYPE_VECTOR_SUBPARTS (TREE_TYPE (arg0)); + + vec_perm_builder builder (len, 1, 2); + poly_uint64 mask_elems[] = {0, 4}; + builder_push_elems (builder, mask_elems); + + vec_perm_indices sel (builder, 2, len); + const char *reason; + tree res = fold_vec_perm_cst (TREE_TYPE (arg0), arg0, arg1, sel, &reason); + ASSERT_TRUE (res == NULL_TREE); + ASSERT_TRUE (reason != NULL); + ASSERT_TRUE (!strcmp (reason, "cannot divide selector element by arg len")); + } +} + +#undef ARG0 +#undef ARG1 + +/* Return true if SIZE is of the form C + Cx and C is power of 2. */ + +static bool +is_simple_vla_size (poly_uint64 size) +{ + if (size.is_constant () + || !pow2p_hwi (size.coeffs[0])) + return false; + for (unsigned i = 1; i < ARRAY_SIZE (size.coeffs); ++i) + if (size.coeffs[i] != (i <= 1 ? size.coeffs[0] : 0)) + return false; + return true; +} + +/* Execute fold_vec_perm_cst unit tests. */ + +static void +test () +{ + machine_mode vnx4si_mode = E_VOIDmode; + machine_mode v4si_mode = E_VOIDmode; + + machine_mode vmode; + FOR_EACH_MODE_IN_CLASS (vmode, MODE_VECTOR_INT) + { + /* Obtain modes corresponding to VNx4SI and V4SI, + to call mixed mode tests below. + FIXME: Is there a better way to do this ? */ + if (GET_MODE_INNER (vmode) == SImode) + { + poly_uint64 nunits = GET_MODE_NUNITS (vmode); + if (is_simple_vla_size (nunits) + && nunits.coeffs[0] == 4) + vnx4si_mode = vmode; + else if (known_eq (nunits, poly_uint64 (4))) + v4si_mode = vmode; + } + + if (!is_simple_vla_size (GET_MODE_NUNITS (vmode)) + || !targetm.vector_mode_supported_p (vmode)) + continue; + + poly_uint64 nunits = GET_MODE_NUNITS (vmode); + test_all_nunits (vmode); + if (nunits.coeffs[0] >= 2) + test_nunits_min_2 (vmode); + if (nunits.coeffs[0] >= 4) + test_nunits_min_4 (vmode); + if (nunits.coeffs[0] >= 8) + test_nunits_min_8 (vmode); + + if (nunits.coeffs[0] <= 4) + test_nunits_max_4 (vmode); + } + + if (vnx4si_mode != E_VOIDmode && v4si_mode != E_VOIDmode + && targetm.vector_mode_supported_p (vnx4si_mode) + && targetm.vector_mode_supported_p (v4si_mode)) + { + test_vnx4si_v4si (vnx4si_mode, v4si_mode); + test_v4si_vnx4si (v4si_mode, vnx4si_mode); + } +} +} // end of test_fold_vec_perm_cst namespace + /* Verify that various binary operations on vectors are folded correctly. */ @@ -16943,6 +17729,7 @@ fold_const_cc_tests () test_arithmetic_folding (); test_vector_folding (); test_vec_duplicate_folding (); + test_fold_vec_perm_cst::test (); } } // namespace selftest diff --git a/gcc/fortran/ChangeLog b/gcc/fortran/ChangeLog index 677008fb6cea..37ab7719fdd2 100644 --- a/gcc/fortran/ChangeLog +++ b/gcc/fortran/ChangeLog @@ -1,3 +1,161 @@ +2023-09-01 Harald Anlauf + + PR fortran/31059 + * trans-array.cc (gfc_conv_ss_startstride): For array bounds checking, + consider also array constructors in expressions, and use their shape. + +2023-08-31 Francois-Xavier Coudert + + * gfortran.texi: Likewise. + +2023-08-30 Mikael Morin + + PR fortran/48776 + * gfortran.h (gfc_drop_interface_elements_before): New prototype. + (gfc_current_interface_head): Return a reference to the pointer. + * interface.cc (gfc_current_interface_head): Ditto. + (free_interface_elements_until): New function, generalizing + gfc_free_interface. + (gfc_free_interface): Use free_interface_elements_until. + (gfc_drop_interface_elements_before): New function. + * parse.cc + (current_interface_ptr, previous_interface_head): New static variables. + (current_interface_valid_p, get_current_interface_ptr): New functions. + (decode_statement): Initialize previous_interface_head. + (reject_statement): Restore current interface pointer to point to + previous_interface_head. + +2023-08-26 Paul Thomas + + PR fortran/92586 + * trans-expr.cc (gfc_trans_arrayfunc_assign): Supply a missing + dereference for the call to gfc_deallocate_alloc_comp_no_caf. + +2023-08-25 Sandra Loosemore + + * gfortran.h (struct gfc_namespace): Add omp_structured_block bit. + * openmp.cc: Include omp-api.h. + (resolve_omp_clauses): Consolidate inscan reduction clause conflict + checking here. + (find_nested_loop_in_chain): New. + (find_nested_loop_in_block): New. + (gfc_resolve_omp_do_blocks): Set omp_current_do_collapse properly. + Handle imperfectly-nested loops when looking for nested omp scan. + Refactor to move inscan reduction clause conflict checking to + resolve_omp_clauses. + (gfc_resolve_do_iterator): Handle imperfectly-nested loops. + (struct icode_error_state): New. + (icode_code_error_callback): New. + (icode_expr_error_callback): New. + (diagnose_intervening_code_errors_1): New. + (diagnose_intervening_code_errors): New. + (make_structured_block): New. + (restructure_intervening_code): New. + (is_outer_iteration_variable): Do not assume loops are perfectly + nested. + (check_nested_loop_in_chain): New. + (check_nested_loop_in_block_state): New. + (check_nested_loop_in_block_symbol): New. + (check_nested_loop_in_block): New. + (expr_uses_intervening_var): New. + (is_intervening_var): New. + (expr_is_invariant): Do not assume loops are perfectly nested. + (resolve_omp_do): Handle imperfectly-nested loops. + * trans-stmt.cc (gfc_trans_block_construct): Generate + OMP_STRUCTURED_BLOCK if magic bit is set on block namespace. + +2023-08-25 Harald Anlauf + + PR fortran/35095 + * data.cc (get_array_index): Add bounds-checking code and return error + status. Overindexing will be allowed as an extension for -std=legacy + and generate an error in standard-conforming mode. + (gfc_assign_data_value): Use error status from get_array_index for + graceful error recovery. + +2023-08-25 Uros Bizjak + + * match.cc (gfc_match_equivalence): Rename TRUE/FALSE to true/false. + * module.cc (check_access): Ditto. + * primary.cc (match_real_constant): Ditto. + * trans-array.cc (gfc_trans_allocate_array_storage): Ditto. + (get_array_ctor_strlen): Ditto. + * trans-common.cc (find_equivalence): Ditto. + (add_equivalences): Ditto. + +2023-08-23 Harald Anlauf + + PR fortran/32986 + * resolve.cc (is_non_constant_shape_array): Add forward declaration. + (resolve_common_vars): Diagnose automatic array object in COMMON. + (resolve_symbol): Prevent confusing follow-on error. + +2023-08-22 Tobias Burnus + + * gfortran.h (enum gfc_omp_defaultmap_category): + Add OMP_DEFAULTMAP_CAT_ALL. + * openmp.cc (gfc_match_omp_clauses): Parse + 'all' as category. + * trans-openmp.cc (gfc_trans_omp_clauses): Handle it. + +2023-08-22 Harald Anlauf + + PR fortran/49588 + * data.cc (gfc_advance_section): Derive next index set and next offset + into DATA variable also for array references using vector sections. + Use auxiliary array to keep track of offsets into indexing vectors. + (gfc_get_section_index): Set up initial indices also for DATA variables + with array references using vector sections. + * data.h (gfc_get_section_index): Adjust prototype. + (gfc_advance_section): Likewise. + * resolve.cc (check_data_variable): Pass vector offsets. + +2023-08-16 Harald Anlauf + + PR fortran/110360 + * trans-expr.cc (conv_scalar_char_value): Use gfc_replace_expr to + avoid leaking replaced gfc_expr. + +2023-08-15 Martin Jambor + Harald Anlauf + + PR fortran/110677 + * resolve.cc (resolve_structure_cons): Check comp->ts is character + type before accessing stuff through comp->ts.u.cl. + +2023-08-15 Chung-Lin Tang + Thomas Schwinge + + * openmp.cc (OACC_DATA_CLAUSES): Add OMP_CLAUSE_DEFAULT. + +2023-08-14 Mikael Morin + + PR fortran/110360 + PR fortran/110419 + * trans-types.cc (gfc_sym_type): Use a bare character type for length + one value character dummy arguments. + * trans-expr.cc (gfc_conv_string_parameter): Handle single character + case. + (gfc_conv_procedure_call): Don't exclude interoperable kinds + from single character handling. For single character dummy arguments, + extend the existing handling of non-constant expressions to constant + expressions. + +2023-08-14 Mikael Morin + + * gfortran.h (gfc_length_one_character_type_p): New inline + function. + * check.cc (is_c_interoperable): Use + gfc_length_one_character_type_p. + * decl.cc (verify_bind_c_sym): Same. + * trans-expr.cc (gfc_conv_procedure_call): Same. + +2023-08-09 Steve Kargl + + PR fortran/109684 + * resolve.cc (resolve_types): Exclude contained procedures with + the artificial attribute from test for pureness. + 2023-07-31 Chung-Lin Tang * openmp.cc (resolve_omp_clauses): Add checking requiring diff --git a/gcc/fortran/check.cc b/gcc/fortran/check.cc index 4086dc71d340..6c45e6542f04 100644 --- a/gcc/fortran/check.cc +++ b/gcc/fortran/check.cc @@ -5250,10 +5250,9 @@ is_c_interoperable (gfc_expr *expr, const char **msg, bool c_loc, bool c_f_ptr) && !gfc_simplify_expr (expr->ts.u.cl->length, 0)) gfc_internal_error ("is_c_interoperable(): gfc_simplify_expr failed"); - if (!c_loc && expr->ts.u.cl - && (!expr->ts.u.cl->length - || expr->ts.u.cl->length->expr_type != EXPR_CONSTANT - || mpz_cmp_si (expr->ts.u.cl->length->value.integer, 1) != 0)) + if (!c_loc + && expr->ts.u.cl + && !gfc_length_one_character_type_p (&expr->ts)) { *msg = "Type shall have a character length of 1"; return false; diff --git a/gcc/fortran/data.cc b/gcc/fortran/data.cc index d29eb12c1b16..0589fc3906f8 100644 --- a/gcc/fortran/data.cc +++ b/gcc/fortran/data.cc @@ -43,13 +43,14 @@ static void formalize_init_expr (gfc_expr *); /* Calculate the array element offset. */ -static void +static bool get_array_index (gfc_array_ref *ar, mpz_t *offset) { gfc_expr *e; int i; mpz_t delta; mpz_t tmp; + bool ok = true; mpz_init (tmp); mpz_set_si (*offset, 0); @@ -59,13 +60,42 @@ get_array_index (gfc_array_ref *ar, mpz_t *offset) e = gfc_copy_expr (ar->start[i]); gfc_simplify_expr (e, 1); - if ((gfc_is_constant_expr (ar->as->lower[i]) == 0) - || (gfc_is_constant_expr (ar->as->upper[i]) == 0) - || (gfc_is_constant_expr (e) == 0)) - gfc_error ("non-constant array in DATA statement %L", &ar->where); + if (!gfc_is_constant_expr (ar->as->lower[i]) + || !gfc_is_constant_expr (ar->as->upper[i]) + || !gfc_is_constant_expr (e)) + { + gfc_error ("non-constant array in DATA statement %L", &ar->where); + ok = false; + break; + } mpz_set (tmp, e->value.integer); gfc_free_expr (e); + + /* Overindexing is only allowed as a legacy extension. */ + if (mpz_cmp (tmp, ar->as->lower[i]->value.integer) < 0 + && !gfc_notify_std (GFC_STD_LEGACY, + "Subscript at %L below array lower bound " + "(%ld < %ld) in dimension %d", &ar->c_where[i], + mpz_get_si (tmp), + mpz_get_si (ar->as->lower[i]->value.integer), + i+1)) + { + ok = false; + break; + } + if (mpz_cmp (tmp, ar->as->upper[i]->value.integer) > 0 + && !gfc_notify_std (GFC_STD_LEGACY, + "Subscript at %L above array upper bound " + "(%ld > %ld) in dimension %d", &ar->c_where[i], + mpz_get_si (tmp), + mpz_get_si (ar->as->upper[i]->value.integer), + i+1)) + { + ok = false; + break; + } + mpz_sub (tmp, tmp, ar->as->lower[i]->value.integer); mpz_mul (tmp, tmp, delta); mpz_add (*offset, tmp, *offset); @@ -77,6 +107,8 @@ get_array_index (gfc_array_ref *ar, mpz_t *offset) } mpz_clear (delta); mpz_clear (tmp); + + return ok; } /* Find if there is a constructor which component is equal to COM. @@ -298,7 +330,10 @@ gfc_assign_data_value (gfc_expr *lvalue, gfc_expr *rvalue, mpz_t index, } if (ref->u.ar.type == AR_ELEMENT) - get_array_index (&ref->u.ar, &offset); + { + if (!get_array_index (&ref->u.ar, &offset)) + goto abort; + } else mpz_set (offset, index); @@ -634,65 +669,102 @@ abort: void gfc_advance_section (mpz_t *section_index, gfc_array_ref *ar, - mpz_t *offset_ret) + mpz_t *offset_ret, int *vector_offset) { int i; mpz_t delta; mpz_t tmp; bool forwards; int cmp; - gfc_expr *start, *end, *stride; + gfc_expr *start, *end, *stride, *elem; + gfc_constructor_base base; for (i = 0; i < ar->dimen; i++) { - if (ar->dimen_type[i] != DIMEN_RANGE) - continue; + bool advance = false; - if (ar->stride[i]) + switch (ar->dimen_type[i]) { - stride = gfc_copy_expr(ar->stride[i]); - if(!gfc_simplify_expr(stride, 1)) - gfc_internal_error("Simplification error"); - mpz_add (section_index[i], section_index[i], - stride->value.integer); - if (mpz_cmp_si (stride->value.integer, 0) >= 0) - forwards = true; - else - forwards = false; - gfc_free_expr(stride); - } - else - { - mpz_add_ui (section_index[i], section_index[i], 1); - forwards = true; - } + case DIMEN_ELEMENT: + /* Loop to advance the next index. */ + advance = true; + break; - if (ar->end[i]) - { - end = gfc_copy_expr(ar->end[i]); - if(!gfc_simplify_expr(end, 1)) - gfc_internal_error("Simplification error"); - cmp = mpz_cmp (section_index[i], end->value.integer); - gfc_free_expr(end); - } - else - cmp = mpz_cmp (section_index[i], ar->as->upper[i]->value.integer); - - if ((cmp > 0 && forwards) || (cmp < 0 && !forwards)) - { - /* Reset index to start, then loop to advance the next index. */ - if (ar->start[i]) + case DIMEN_RANGE: + if (ar->stride[i]) { - start = gfc_copy_expr(ar->start[i]); - if(!gfc_simplify_expr(start, 1)) - gfc_internal_error("Simplification error"); - mpz_set (section_index[i], start->value.integer); - gfc_free_expr(start); + stride = gfc_copy_expr(ar->stride[i]); + if(!gfc_simplify_expr(stride, 1)) + gfc_internal_error("Simplification error"); + mpz_add (section_index[i], section_index[i], + stride->value.integer); + if (mpz_cmp_si (stride->value.integer, 0) >= 0) + forwards = true; + else + forwards = false; + gfc_free_expr(stride); } else - mpz_set (section_index[i], ar->as->lower[i]->value.integer); + { + mpz_add_ui (section_index[i], section_index[i], 1); + forwards = true; + } + + if (ar->end[i]) + { + end = gfc_copy_expr(ar->end[i]); + if(!gfc_simplify_expr(end, 1)) + gfc_internal_error("Simplification error"); + cmp = mpz_cmp (section_index[i], end->value.integer); + gfc_free_expr(end); + } + else + cmp = mpz_cmp (section_index[i], ar->as->upper[i]->value.integer); + + if ((cmp > 0 && forwards) || (cmp < 0 && !forwards)) + { + /* Reset index to start, then loop to advance the next index. */ + if (ar->start[i]) + { + start = gfc_copy_expr(ar->start[i]); + if(!gfc_simplify_expr(start, 1)) + gfc_internal_error("Simplification error"); + mpz_set (section_index[i], start->value.integer); + gfc_free_expr(start); + } + else + mpz_set (section_index[i], ar->as->lower[i]->value.integer); + advance = true; + } + break; + + case DIMEN_VECTOR: + vector_offset[i]++; + base = ar->start[i]->value.constructor; + elem = gfc_constructor_lookup_expr (base, vector_offset[i]); + + if (elem == NULL) + { + /* Reset to first vector element and advance the next index. */ + vector_offset[i] = 0; + elem = gfc_constructor_lookup_expr (base, 0); + advance = true; + } + if (elem) + { + start = gfc_copy_expr (elem); + if (!gfc_simplify_expr (start, 1)) + gfc_internal_error ("Simplification error"); + mpz_set (section_index[i], start->value.integer); + gfc_free_expr (start); + } + break; + + default: + gcc_unreachable (); } - else + + if (!advance) break; } @@ -793,12 +865,14 @@ gfc_formalize_init_value (gfc_symbol *sym) offset. */ void -gfc_get_section_index (gfc_array_ref *ar, mpz_t *section_index, mpz_t *offset) +gfc_get_section_index (gfc_array_ref *ar, mpz_t *section_index, mpz_t *offset, + int *vector_offset) { int i; mpz_t delta; mpz_t tmp; - gfc_expr *start; + gfc_expr *start, *elem; + gfc_constructor_base base; mpz_set_si (*offset, 0); mpz_init (tmp); @@ -810,29 +884,35 @@ gfc_get_section_index (gfc_array_ref *ar, mpz_t *section_index, mpz_t *offset) { case DIMEN_ELEMENT: case DIMEN_RANGE: - if (ar->start[i]) - { - start = gfc_copy_expr(ar->start[i]); - if(!gfc_simplify_expr(start, 1)) - gfc_internal_error("Simplification error"); - mpz_sub (tmp, start->value.integer, - ar->as->lower[i]->value.integer); - mpz_mul (tmp, tmp, delta); - mpz_add (*offset, tmp, *offset); - mpz_set (section_index[i], start->value.integer); - gfc_free_expr(start); - } - else - mpz_set (section_index[i], ar->as->lower[i]->value.integer); + elem = ar->start[i]; break; case DIMEN_VECTOR: - gfc_internal_error ("TODO: Vector sections in data statements"); + vector_offset[i] = 0; + base = ar->start[i]->value.constructor; + elem = gfc_constructor_lookup_expr (base, vector_offset[i]); + break; default: gcc_unreachable (); } + if (elem) + { + start = gfc_copy_expr (elem); + if (!gfc_simplify_expr (start, 1)) + gfc_internal_error ("Simplification error"); + mpz_sub (tmp, start->value.integer, + ar->as->lower[i]->value.integer); + mpz_mul (tmp, tmp, delta); + mpz_add (*offset, tmp, *offset); + mpz_set (section_index[i], start->value.integer); + gfc_free_expr (start); + } + else + /* Fallback for empty section or constructor. */ + mpz_set (section_index[i], ar->as->lower[i]->value.integer); + mpz_sub (tmp, ar->as->upper[i]->value.integer, ar->as->lower[i]->value.integer); mpz_add_ui (tmp, tmp, 1); diff --git a/gcc/fortran/data.h b/gcc/fortran/data.h index 40dbee1ef28b..8f2013ac8947 100644 --- a/gcc/fortran/data.h +++ b/gcc/fortran/data.h @@ -18,6 +18,6 @@ along with GCC; see the file COPYING3. If not see . */ void gfc_formalize_init_value (gfc_symbol *); -void gfc_get_section_index (gfc_array_ref *, mpz_t *, mpz_t *); +void gfc_get_section_index (gfc_array_ref *, mpz_t *, mpz_t *, int *); bool gfc_assign_data_value (gfc_expr *, gfc_expr *, mpz_t, mpz_t *); -void gfc_advance_section (mpz_t *, gfc_array_ref *, mpz_t *); +void gfc_advance_section (mpz_t *, gfc_array_ref *, mpz_t *, int *); diff --git a/gcc/fortran/decl.cc b/gcc/fortran/decl.cc index 844345df77e9..8182ef29f43f 100644 --- a/gcc/fortran/decl.cc +++ b/gcc/fortran/decl.cc @@ -6064,9 +6064,7 @@ verify_bind_c_sym (gfc_symbol *tmp_sym, gfc_typespec *ts, /* BIND(C) functions cannot return a character string. */ if (bind_c_function && tmp_sym->ts.type == BT_CHARACTER) - if (tmp_sym->ts.u.cl == NULL || tmp_sym->ts.u.cl->length == NULL - || tmp_sym->ts.u.cl->length->expr_type != EXPR_CONSTANT - || mpz_cmp_si (tmp_sym->ts.u.cl->length->value.integer, 1) != 0) + if (!gfc_length_one_character_type_p (&tmp_sym->ts)) gfc_error ("Return type of BIND(C) function %qs of character " "type at %L must have length 1", tmp_sym->name, &(tmp_sym->declared_at)); diff --git a/gcc/fortran/gfortran.h b/gcc/fortran/gfortran.h index 9a00e6dea6f1..b37c6bb9ad4c 100644 --- a/gcc/fortran/gfortran.h +++ b/gcc/fortran/gfortran.h @@ -1334,6 +1334,7 @@ enum gfc_omp_defaultmap enum gfc_omp_defaultmap_category { OMP_DEFAULTMAP_CAT_UNCATEGORIZED, + OMP_DEFAULTMAP_CAT_ALL, OMP_DEFAULTMAP_CAT_SCALAR, OMP_DEFAULTMAP_CAT_AGGREGATE, OMP_DEFAULTMAP_CAT_ALLOCATABLE, @@ -2236,6 +2237,9 @@ typedef struct gfc_namespace /* OpenMP requires. */ unsigned omp_requires:6; unsigned omp_target_seen:1; + + /* Set to 1 if this is an implicit OMP structured block. */ + unsigned omp_structured_block:1; } gfc_namespace; @@ -3182,6 +3186,21 @@ gfc_finalizer; /************************ Function prototypes *************************/ + +/* Returns true if the type specified in TS is a character type whose length + is the constant one. Otherwise returns false. */ + +inline bool +gfc_length_one_character_type_p (gfc_typespec *ts) +{ + return ts->type == BT_CHARACTER + && ts->u.cl + && ts->u.cl->length + && ts->u.cl->length->expr_type == EXPR_CONSTANT + && ts->u.cl->length->ts.type == BT_INTEGER + && mpz_cmp_ui (ts->u.cl->length->value.integer, 1) == 0; +} + /* decl.cc */ bool gfc_in_match_data (void); match gfc_match_char_spec (gfc_typespec *); @@ -3809,6 +3828,7 @@ bool gfc_ref_dimen_size (gfc_array_ref *, int dimen, mpz_t *, mpz_t *); /* interface.cc -- FIXME: some of these should be in symbol.cc */ void gfc_free_interface (gfc_interface *); +void gfc_drop_interface_elements_before (gfc_interface **, gfc_interface *); bool gfc_compare_derived_types (gfc_symbol *, gfc_symbol *); bool gfc_compare_types (gfc_typespec *, gfc_typespec *); bool gfc_check_dummy_characteristics (gfc_symbol *, gfc_symbol *, @@ -3828,7 +3848,7 @@ void gfc_free_formal_arglist (gfc_formal_arglist *); bool gfc_extend_assign (gfc_code *, gfc_namespace *); bool gfc_check_new_interface (gfc_interface *, gfc_symbol *, locus); bool gfc_add_interface (gfc_symbol *); -gfc_interface *gfc_current_interface_head (void); +gfc_interface *&gfc_current_interface_head (void); void gfc_set_current_interface_head (gfc_interface *); gfc_symtree* gfc_find_sym_in_symtree (gfc_symbol*); bool gfc_arglist_matches_symbol (gfc_actual_arglist**, gfc_symbol*); diff --git a/gcc/fortran/gfortran.texi b/gcc/fortran/gfortran.texi index f476a3719f55..e7ffc294dc81 100644 --- a/gcc/fortran/gfortran.texi +++ b/gcc/fortran/gfortran.texi @@ -978,7 +978,7 @@ low level file descriptor corresponding to an open Fortran unit. Then, using e.g. the @code{ISO_C_BINDING} feature, one can call the underlying system call to flush dirty data to stable storage, such as @code{fsync} on POSIX, @code{_commit} on MingW, or @code{fcntl(fd, -F_FULLSYNC, 0)} on Mac OS X. The following example shows how to call +F_FULLSYNC, 0)} on macOS. The following example shows how to call fsync: @smallexample diff --git a/gcc/fortran/interface.cc b/gcc/fortran/interface.cc index ea82056e9e3b..c01df0460d7e 100644 --- a/gcc/fortran/interface.cc +++ b/gcc/fortran/interface.cc @@ -78,18 +78,47 @@ along with GCC; see the file COPYING3. If not see gfc_interface_info current_interface; +/* Free the leading members of the gfc_interface linked list given in INTR + up to the END element (exclusive: the END element is not freed). + If END is not nullptr, it is assumed that END is in the linked list starting + with INTR. */ + +static void +free_interface_elements_until (gfc_interface *intr, gfc_interface *end) +{ + gfc_interface *next; + + for (; intr != end; intr = next) + { + next = intr->next; + free (intr); + } +} + + /* Free a singly linked list of gfc_interface structures. */ void gfc_free_interface (gfc_interface *intr) { - gfc_interface *next; + free_interface_elements_until (intr, nullptr); +} - for (; intr; intr = next) - { - next = intr->next; - free (intr); - } + +/* Update the interface pointer given by IFC_PTR to make it point to TAIL. + It is expected that TAIL (if non-null) is in the list pointed to by + IFC_PTR, hence the tail of it. The members of the list before TAIL are + freed before the pointer reassignment. */ + +void +gfc_drop_interface_elements_before (gfc_interface **ifc_ptr, + gfc_interface *tail) +{ + if (ifc_ptr == nullptr) + return; + + free_interface_elements_until (*ifc_ptr, tail); + *ifc_ptr = tail; } @@ -4953,7 +4982,7 @@ gfc_add_interface (gfc_symbol *new_sym) } -gfc_interface * +gfc_interface *& gfc_current_interface_head (void) { switch (current_interface.type) diff --git a/gcc/fortran/match.cc b/gcc/fortran/match.cc index ba23bcd96923..c926f38058f6 100644 --- a/gcc/fortran/match.cc +++ b/gcc/fortran/match.cc @@ -5788,7 +5788,7 @@ gfc_match_equivalence (void) goto syntax; set = eq; - common_flag = FALSE; + common_flag = false; cnt = 0; for (;;) @@ -5829,7 +5829,7 @@ gfc_match_equivalence (void) if (sym->attr.in_common) { - common_flag = TRUE; + common_flag = true; common_head = sym->common_head; } diff --git a/gcc/fortran/module.cc b/gcc/fortran/module.cc index 95fdda6b2aac..c07e9dc9ba21 100644 --- a/gcc/fortran/module.cc +++ b/gcc/fortran/module.cc @@ -5744,9 +5744,9 @@ check_access (gfc_access specific_access, gfc_access default_access) return true; if (specific_access == ACCESS_PUBLIC) - return TRUE; + return true; if (specific_access == ACCESS_PRIVATE) - return FALSE; + return false; if (flag_module_private) return default_access == ACCESS_PUBLIC; diff --git a/gcc/fortran/openmp.cc b/gcc/fortran/openmp.cc index 234d896b2ce2..dc0c8013c3d0 100644 --- a/gcc/fortran/openmp.cc +++ b/gcc/fortran/openmp.cc @@ -30,6 +30,7 @@ along with GCC; see the file COPYING3. If not see #include "gomp-constants.h" #include "target-memory.h" /* For gfc_encode_character. */ #include "bitmap.h" +#include "omp-api.h" /* For omp_runtime_api_procname. */ static gfc_statement omp_code_to_statement (gfc_code *); @@ -2250,17 +2251,22 @@ gfc_match_omp_clauses (gfc_omp_clauses **cp, const omp_mask mask, category = OMP_DEFAULTMAP_CAT_ALLOCATABLE; else if (gfc_match ("pointer ") == MATCH_YES) category = OMP_DEFAULTMAP_CAT_POINTER; + else if (gfc_match ("all ") == MATCH_YES) + category = OMP_DEFAULTMAP_CAT_ALL; else { - gfc_error ("Expected SCALAR, AGGREGATE, ALLOCATABLE or " - "POINTER at %C"); + gfc_error ("Expected SCALAR, AGGREGATE, ALLOCATABLE, " + "POINTER or ALL at %C"); break; } } for (int i = 0; i < OMP_DEFAULTMAP_CAT_NUM; ++i) { if (i != category - && category != OMP_DEFAULTMAP_CAT_UNCATEGORIZED) + && category != OMP_DEFAULTMAP_CAT_UNCATEGORIZED + && category != OMP_DEFAULTMAP_CAT_ALL + && i != OMP_DEFAULTMAP_CAT_UNCATEGORIZED + && i != OMP_DEFAULTMAP_CAT_ALL) continue; if (c->defaultmap[i] != OMP_DEFAULTMAP_UNSET) { @@ -2268,6 +2274,7 @@ gfc_match_omp_clauses (gfc_omp_clauses **cp, const omp_mask mask, switch (i) { case OMP_DEFAULTMAP_CAT_UNCATEGORIZED: break; + case OMP_DEFAULTMAP_CAT_ALL: pcategory = "ALL"; break; case OMP_DEFAULTMAP_CAT_SCALAR: pcategory = "SCALAR"; break; case OMP_DEFAULTMAP_CAT_AGGREGATE: pcategory = "AGGREGATE"; @@ -3802,7 +3809,8 @@ error: #define OACC_DATA_CLAUSES \ (omp_mask (OMP_CLAUSE_IF) | OMP_CLAUSE_DEVICEPTR | OMP_CLAUSE_COPY \ | OMP_CLAUSE_COPYIN | OMP_CLAUSE_COPYOUT | OMP_CLAUSE_CREATE \ - | OMP_CLAUSE_NO_CREATE | OMP_CLAUSE_PRESENT | OMP_CLAUSE_ATTACH) + | OMP_CLAUSE_NO_CREATE | OMP_CLAUSE_PRESENT | OMP_CLAUSE_ATTACH \ + | OMP_CLAUSE_DEFAULT) #define OACC_LOOP_CLAUSES \ (omp_mask (OMP_CLAUSE_COLLAPSE) | OMP_CLAUSE_GANG | OMP_CLAUSE_WORKER \ | OMP_CLAUSE_VECTOR | OMP_CLAUSE_SEQ | OMP_CLAUSE_INDEPENDENT \ @@ -7609,15 +7617,24 @@ resolve_omp_clauses (gfc_code *code, gfc_omp_clauses *omp_clauses, gfc_error ("Object %qs is not a variable at %L", n->sym->name, &n->where); } - if (omp_clauses->lists[OMP_LIST_REDUCTION_INSCAN] - && code->op != EXEC_OMP_DO - && code->op != EXEC_OMP_SIMD - && code->op != EXEC_OMP_DO_SIMD - && code->op != EXEC_OMP_PARALLEL_DO - && code->op != EXEC_OMP_PARALLEL_DO_SIMD) - gfc_error ("% REDUCTION clause on construct other than DO, SIMD, " - "DO SIMD, PARALLEL DO, PARALLEL DO SIMD at %L", - &omp_clauses->lists[OMP_LIST_REDUCTION_INSCAN]->where); + if (omp_clauses->lists[OMP_LIST_REDUCTION_INSCAN]) + { + locus *loc = &omp_clauses->lists[OMP_LIST_REDUCTION_INSCAN]->where; + if (code->op != EXEC_OMP_DO + && code->op != EXEC_OMP_SIMD + && code->op != EXEC_OMP_DO_SIMD + && code->op != EXEC_OMP_PARALLEL_DO + && code->op != EXEC_OMP_PARALLEL_DO_SIMD) + gfc_error ("% REDUCTION clause on construct other than DO, " + "SIMD, DO SIMD, PARALLEL DO, PARALLEL DO SIMD at %L", + loc); + if (omp_clauses->ordered) + gfc_error ("ORDERED clause specified together with % " + "REDUCTION clause at %L", loc); + if (omp_clauses->sched_kind != OMP_SCHED_NONE) + gfc_error ("SCHEDULE clause specified together with % " + "REDUCTION clause at %L", loc); + } for (list = 0; list < OMP_LIST_NUM; list++) if (list != OMP_LIST_FIRSTPRIVATE @@ -9566,68 +9583,114 @@ static struct fortran_omp_context static gfc_code *omp_current_do_code; static int omp_current_do_collapse; +/* Forward declaration for mutually recursive functions. */ +static gfc_code * +find_nested_loop_in_block (gfc_code *block); + +/* Return the first nested DO loop in CHAIN, or NULL if there + isn't one. Does no error checking on intervening code. */ + +static gfc_code * +find_nested_loop_in_chain (gfc_code *chain) +{ + gfc_code *code; + + if (!chain) + return NULL; + + for (code = chain; code; code = code->next) + { + if (code->op == EXEC_DO) + return code; + else if (code->op == EXEC_BLOCK) + { + gfc_code *c = find_nested_loop_in_block (code); + if (c) + return c; + } + } + return NULL; +} + +/* Return the first nested DO loop in BLOCK, or NULL if there + isn't one. Does no error checking on intervening code. */ +static gfc_code * +find_nested_loop_in_block (gfc_code *block) +{ + gfc_namespace *ns; + gcc_assert (block->op == EXEC_BLOCK); + ns = block->ext.block.ns; + gcc_assert (ns); + return find_nested_loop_in_chain (ns->code); +} + void gfc_resolve_omp_do_blocks (gfc_code *code, gfc_namespace *ns) { if (code->block->next && code->block->next->op == EXEC_DO) { int i; - gfc_code *c; omp_current_do_code = code->block->next; if (code->ext.omp_clauses->orderedc) omp_current_do_collapse = code->ext.omp_clauses->orderedc; - else + else if (code->ext.omp_clauses->collapse) omp_current_do_collapse = code->ext.omp_clauses->collapse; - for (i = 1, c = omp_current_do_code; i < omp_current_do_collapse; i++) - { - c = c->block; - if (c->op != EXEC_DO || c->next == NULL) - break; - c = c->next; - if (c->op != EXEC_DO) - break; - } - if (i < omp_current_do_collapse || omp_current_do_collapse <= 0) + else omp_current_do_collapse = 1; if (code->ext.omp_clauses->lists[OMP_LIST_REDUCTION_INSCAN]) { + /* Checking that there is a matching EXEC_OMP_SCAN in the + innermost body cannot be deferred to resolve_omp_do because + we process directives nested in the loop before we get + there. */ locus *loc = &code->ext.omp_clauses->lists[OMP_LIST_REDUCTION_INSCAN]->where; - if (code->ext.omp_clauses->ordered) - gfc_error ("ORDERED clause specified together with % " - "REDUCTION clause at %L", loc); - if (code->ext.omp_clauses->sched_kind != OMP_SCHED_NONE) - gfc_error ("SCHEDULE clause specified together with % " - "REDUCTION clause at %L", loc); - gfc_code *block = c->block ? c->block->next : NULL; - if (block && block->op != EXEC_OMP_SCAN) - while (block && block->next && block->next->op != EXEC_OMP_SCAN) - block = block->next; - if (!block - || (block->op != EXEC_OMP_SCAN - && (!block->next || block->next->op != EXEC_OMP_SCAN))) - gfc_error ("With INSCAN at %L, expected loop body with !$OMP SCAN " - "between two structured block sequences", loc); - else + gfc_code *c; + + for (i = 1, c = omp_current_do_code; + i < omp_current_do_collapse; i++) { - if (block->op == EXEC_OMP_SCAN) - gfc_warning (0, "!$OMP SCAN at %L with zero executable " - "statements in preceding structured block " - "sequence", &block->loc); - if ((block->op == EXEC_OMP_SCAN && !block->next) - || (block->next && block->next->op == EXEC_OMP_SCAN - && !block->next->next)) - gfc_warning (0, "!$OMP SCAN at %L with zero executable " - "statements in succeeding structured block " - "sequence", block->op == EXEC_OMP_SCAN - ? &block->loc : &block->next->loc); + c = find_nested_loop_in_chain (c->block->next); + if (!c || c->op != EXEC_DO || c->block == NULL) + break; + } + + /* Skip this if we don't have enough nested loops. That + problem will be diagnosed elsewhere. */ + if (c && c->op == EXEC_DO) + { + gfc_code *block = c->block ? c->block->next : NULL; + if (block && block->op != EXEC_OMP_SCAN) + while (block && block->next + && block->next->op != EXEC_OMP_SCAN) + block = block->next; + if (!block + || (block->op != EXEC_OMP_SCAN + && (!block->next || block->next->op != EXEC_OMP_SCAN))) + gfc_error ("With INSCAN at %L, expected loop body with " + "!$OMP SCAN between two " + "structured block sequences", loc); + else + { + if (block->op == EXEC_OMP_SCAN) + gfc_warning (0, "!$OMP SCAN at %L with zero executable " + "statements in preceding structured block " + "sequence", &block->loc); + if ((block->op == EXEC_OMP_SCAN && !block->next) + || (block->next && block->next->op == EXEC_OMP_SCAN + && !block->next->next)) + gfc_warning (0, "!$OMP SCAN at %L with zero executable " + "statements in succeeding structured block " + "sequence", block->op == EXEC_OMP_SCAN + ? &block->loc : &block->next->loc); + } + if (block && block->op != EXEC_OMP_SCAN) + block = block->next; + if (block && block->op == EXEC_OMP_SCAN) + /* Mark 'omp scan' as checked; flag will be unset later. */ + block->ext.omp_clauses->if_present = true; } - if (block && block->op != EXEC_OMP_SCAN) - block = block->next; - if (block && block->op == EXEC_OMP_SCAN) - /* Mark 'omp scan' as checked; flag will be unset later. */ - block->ext.omp_clauses->if_present = true; } } gfc_resolve_blocks (code->block, ns); @@ -9757,12 +9820,11 @@ gfc_resolve_do_iterator (gfc_code *code, gfc_symbol *sym, bool add_clause) private just in the !$omp do resp. !$omp parallel do construct, with no implications for the outer parallel constructs. */ - while (i-- >= 1) + while (i-- >= 1 && c) { if (code == c) return; - - c = c->block->next; + c = find_nested_loop_in_chain (c->block->next); } /* An openacc context may represent a data clause. Abort if so. */ @@ -9802,20 +9864,464 @@ gfc_resolve_omp_local_vars (gfc_namespace *ns) gfc_traverse_ns (ns, handle_local_var); } + +/* Error checking on intervening code uses a code walker. */ + +struct icode_error_state +{ + const char *name; + bool errorp; + gfc_code *nested; + gfc_code *next; +}; + +static int +icode_code_error_callback (gfc_code **codep, + int *walk_subtrees ATTRIBUTE_UNUSED, void *opaque) +{ + gfc_code *code = *codep; + icode_error_state *state = (icode_error_state *)opaque; + + /* gfc_code_walker walks down CODE's next chain as well as + walking things that are actually nested in CODE. We need to + special-case traversal of outer blocks, so stop immediately if we + are heading down such a next chain. */ + if (code == state->next) + return 1; + + switch (code->op) + { + case EXEC_DO: + case EXEC_DO_WHILE: + case EXEC_DO_CONCURRENT: + gfc_error ("%s cannot contain loop in intervening code at %L", + state->name, &code->loc); + state->errorp = true; + break; + case EXEC_CYCLE: + case EXEC_EXIT: + /* Errors have already been diagnosed in match_exit_cycle. */ + state->errorp = true; + break; + case EXEC_OMP_CRITICAL: + case EXEC_OMP_DO: + case EXEC_OMP_FLUSH: + case EXEC_OMP_MASTER: + case EXEC_OMP_ORDERED: + case EXEC_OMP_PARALLEL: + case EXEC_OMP_PARALLEL_DO: + case EXEC_OMP_PARALLEL_SECTIONS: + case EXEC_OMP_PARALLEL_WORKSHARE: + case EXEC_OMP_SECTIONS: + case EXEC_OMP_SINGLE: + case EXEC_OMP_WORKSHARE: + case EXEC_OMP_ATOMIC: + case EXEC_OMP_BARRIER: + case EXEC_OMP_END_NOWAIT: + case EXEC_OMP_END_SINGLE: + case EXEC_OMP_TASK: + case EXEC_OMP_TASKWAIT: + case EXEC_OMP_TASKYIELD: + case EXEC_OMP_CANCEL: + case EXEC_OMP_CANCELLATION_POINT: + case EXEC_OMP_TASKGROUP: + case EXEC_OMP_SIMD: + case EXEC_OMP_DO_SIMD: + case EXEC_OMP_PARALLEL_DO_SIMD: + case EXEC_OMP_TARGET: + case EXEC_OMP_TARGET_DATA: + case EXEC_OMP_TEAMS: + case EXEC_OMP_DISTRIBUTE: + case EXEC_OMP_DISTRIBUTE_SIMD: + case EXEC_OMP_DISTRIBUTE_PARALLEL_DO: + case EXEC_OMP_DISTRIBUTE_PARALLEL_DO_SIMD: + case EXEC_OMP_TARGET_TEAMS: + case EXEC_OMP_TEAMS_DISTRIBUTE: + case EXEC_OMP_TEAMS_DISTRIBUTE_SIMD: + case EXEC_OMP_TARGET_TEAMS_DISTRIBUTE: + case EXEC_OMP_TARGET_TEAMS_DISTRIBUTE_SIMD: + case EXEC_OMP_TEAMS_DISTRIBUTE_PARALLEL_DO: + case EXEC_OMP_TARGET_TEAMS_DISTRIBUTE_PARALLEL_DO: + case EXEC_OMP_TEAMS_DISTRIBUTE_PARALLEL_DO_SIMD: + case EXEC_OMP_TARGET_TEAMS_DISTRIBUTE_PARALLEL_DO_SIMD: + case EXEC_OMP_TARGET_UPDATE: + case EXEC_OMP_END_CRITICAL: + case EXEC_OMP_TARGET_ENTER_DATA: + case EXEC_OMP_TARGET_EXIT_DATA: + case EXEC_OMP_TARGET_PARALLEL: + case EXEC_OMP_TARGET_PARALLEL_DO: + case EXEC_OMP_TARGET_PARALLEL_DO_SIMD: + case EXEC_OMP_TARGET_SIMD: + case EXEC_OMP_TASKLOOP: + case EXEC_OMP_TASKLOOP_SIMD: + case EXEC_OMP_SCAN: + case EXEC_OMP_DEPOBJ: + case EXEC_OMP_PARALLEL_MASTER: + case EXEC_OMP_PARALLEL_MASTER_TASKLOOP: + case EXEC_OMP_PARALLEL_MASTER_TASKLOOP_SIMD: + case EXEC_OMP_MASTER_TASKLOOP: + case EXEC_OMP_MASTER_TASKLOOP_SIMD: + case EXEC_OMP_LOOP: + case EXEC_OMP_PARALLEL_LOOP: + case EXEC_OMP_TEAMS_LOOP: + case EXEC_OMP_TARGET_PARALLEL_LOOP: + case EXEC_OMP_TARGET_TEAMS_LOOP: + case EXEC_OMP_MASKED: + case EXEC_OMP_PARALLEL_MASKED: + case EXEC_OMP_PARALLEL_MASKED_TASKLOOP: + case EXEC_OMP_PARALLEL_MASKED_TASKLOOP_SIMD: + case EXEC_OMP_MASKED_TASKLOOP: + case EXEC_OMP_MASKED_TASKLOOP_SIMD: + case EXEC_OMP_SCOPE: + case EXEC_OMP_ERROR: + gfc_error ("%s cannot contain OpenMP directive in intervening code " + "at %L", + state->name, &code->loc); + state->errorp = true; + break; + case EXEC_CALL: + /* Per OpenMP 5.2, the "omp_" prefix is reserved, so we don't have to + consider the possibility that some locally-bound definition + overrides the runtime routine. */ + if (code->resolved_sym + && omp_runtime_api_procname (code->resolved_sym->name)) + { + gfc_error ("%s cannot contain OpenMP API call in intervening code " + "at %L", + state->name, &code->loc); + state->errorp = true; + } + break; + default: + break; + } + return 0; +} + +static int +icode_expr_error_callback (gfc_expr **expr, + int *walk_subtrees ATTRIBUTE_UNUSED, void *opaque) +{ + icode_error_state *state = (icode_error_state *)opaque; + + switch ((*expr)->expr_type) + { + /* As for EXPR_CALL with "omp_"-prefixed symbols. */ + case EXPR_FUNCTION: + { + gfc_symbol *sym = (*expr)->value.function.esym; + if (sym && omp_runtime_api_procname (sym->name)) + { + gfc_error ("%s cannot contain OpenMP API call in intervening code " + "at %L", + state->name, &((*expr)->where)); + state->errorp = true; + } + } + + break; + default: + break; + } + + /* FIXME: The description of canonical loop form in the OpenMP standard + also says "array expressions" are not permitted in intervening code. + That term is not defined in either the OpenMP spec or the Fortran + standard, although the latter uses it informally to refer to any + expression that is not scalar-valued. It is also apparently not the + thing GCC internally calls EXPR_ARRAY. It seems the intent of the + OpenMP restriction is to disallow elemental operations/intrinsics + (including things that are not expressions, like assignment + statements) that generate implicit loops over array operands + (even if the result is a scalar), but even if the spec said + that there is no list of all the cases that would be forbidden. + This is OpenMP issue 3326. */ + + return 0; +} + +static void +diagnose_intervening_code_errors_1 (gfc_code *chain, + struct icode_error_state *state) +{ + gfc_code *code; + for (code = chain; code; code = code->next) + { + if (code == state->nested) + /* Do not walk the nested loop or its body, we are only + interested in intervening code. */ + ; + else if (code->op == EXEC_BLOCK + && find_nested_loop_in_block (code) == state->nested) + /* This block contains the nested loop, recurse on its + statements. */ + { + gfc_namespace* ns = code->ext.block.ns; + diagnose_intervening_code_errors_1 (ns->code, state); + } + else + /* Treat the whole statement as a unit. */ + { + gfc_code *temp = state->next; + state->next = code->next; + gfc_code_walker (&code, icode_code_error_callback, + icode_expr_error_callback, state); + state->next = temp; + } + } +} + +/* Diagnose intervening code errors in BLOCK with nested loop NESTED. + NAME is the user-friendly name of the OMP directive, used for error + messages. Returns true if any error was found. */ +static bool +diagnose_intervening_code_errors (gfc_code *chain, const char *name, + gfc_code *nested) +{ + struct icode_error_state state; + state.name = name; + state.errorp = false; + state.nested = nested; + state.next = NULL; + diagnose_intervening_code_errors_1 (chain, &state); + return state.errorp; +} + +/* Helper function for restructure_intervening_code: wrap CHAIN in + a marker to indicate that it is a structured block sequence. That + information will be used later on (in omp-low.cc) for error checking. */ +static gfc_code * +make_structured_block (gfc_code *chain) +{ + gcc_assert (chain); + gfc_namespace *ns = gfc_build_block_ns (gfc_current_ns); + gfc_code *result = gfc_get_code (EXEC_BLOCK); + result->op = EXEC_BLOCK; + result->ext.block.ns = ns; + result->ext.block.assoc = NULL; + result->loc = chain->loc; + ns->omp_structured_block = 1; + ns->code = chain; + return result; +} + +/* Push intervening code surrounding a loop, including nested scopes, + into the body of the loop. CHAINP is the pointer to the head of + the next-chain to scan, OUTER_LOOP is the EXEC_DO for the next outer + loop level, and COLLAPSE is the number of nested loops we need to + process. + Note that CHAINP may point at outer_loop->block->next when we + are scanning the body of a loop, but if there is an intervening block + CHAINP points into the block's chain rather than its enclosing outer + loop. This is why OUTER_LOOP is passed separately. */ +static gfc_code * +restructure_intervening_code (gfc_code **chainp, gfc_code *outer_loop, + int count) +{ + gfc_code *code; + gfc_code *head = *chainp; + gfc_code *tail = NULL; + gfc_code *innermost_loop = NULL; + + for (code = *chainp; code; code = code->next, chainp = &((*chainp)->next)) + { + if (code->op == EXEC_DO) + { + /* Cut CODE free from its chain, leaving the ends dangling. */ + *chainp = NULL; + tail = code->next; + code->next = NULL; + + if (count == 1) + innermost_loop = code; + else + innermost_loop + = restructure_intervening_code (&(code->block->next), + code, count - 1); + break; + } + else if (code->op == EXEC_BLOCK + && find_nested_loop_in_block (code)) + { + gfc_namespace *ns = code->ext.block.ns; + + /* Cut CODE free from its chain, leaving the ends dangling. */ + *chainp = NULL; + tail = code->next; + code->next = NULL; + + innermost_loop + = restructure_intervening_code (&(ns->code), outer_loop, + count); + + /* At this point we have already pulled out the nested loop and + pointed outer_loop at it, and moved the intervening code that + was previously in the block into the body of innermost_loop. + Now we want to move the BLOCK itself so it wraps the entire + current body of innermost_loop. */ + ns->code = innermost_loop->block->next; + innermost_loop->block->next = code; + break; + } + } + + gcc_assert (innermost_loop); + + /* Now we have split the intervening code into two parts: + head is the start of the part before the loop/block, terminating + at *chainp, and tail is the part after it. Mark each part as + a structured block sequence, and splice the two parts around the + existing body of the innermost loop. */ + if (head != code) + { + gfc_code *block = make_structured_block (head); + if (innermost_loop->block->next) + gfc_append_code (block, innermost_loop->block->next); + innermost_loop->block->next = block; + } + if (tail) + { + gfc_code *block = make_structured_block (tail); + if (innermost_loop->block->next) + gfc_append_code (innermost_loop->block->next, block); + else + innermost_loop->block->next = block; + } + + /* For loops, finally splice CODE into OUTER_LOOP. We already handled + relinking EXEC_BLOCK above. */ + if (code->op == EXEC_DO && outer_loop) + outer_loop->block->next = code; + + return innermost_loop; +} + /* CODE is an OMP loop construct. Return true if VAR matches an iteration variable outer to level DEPTH. */ static bool is_outer_iteration_variable (gfc_code *code, int depth, gfc_symbol *var) { int i; - gfc_code *do_code = code->block->next; + gfc_code *do_code = code; for (i = 1; i < depth; i++) { + do_code = find_nested_loop_in_chain (do_code->block->next); + gcc_assert (do_code); gfc_symbol *ivar = do_code->ext.iterator->var->symtree->n.sym; if (var == ivar) return true; - do_code = do_code->block->next; + } + return false; +} + +/* Forward declaration for recursive functions. */ +static gfc_code * +check_nested_loop_in_block (gfc_code *block, gfc_expr *expr, gfc_symbol *sym, + bool *bad); + +/* Like find_nested_loop_in_chain, but additionally check that EXPR + does not reference any variables bound in intervening EXEC_BLOCKs + and that SYM is not bound in such intervening blocks. Either EXPR or SYM + may be null. Sets *BAD to true if either test fails. */ +static gfc_code * +check_nested_loop_in_chain (gfc_code *chain, gfc_expr *expr, gfc_symbol *sym, + bool *bad) +{ + for (gfc_code *code = chain; code; code = code->next) + { + if (code->op == EXEC_DO) + return code; + else if (code->op == EXEC_BLOCK) + { + gfc_code *c = check_nested_loop_in_block (code, expr, sym, bad); + if (c) + return c; + } + } + return NULL; +} + +/* Code walker for block symtrees. It doesn't take any kind of state + argument, so use a static variable. */ +static struct check_nested_loop_in_block_state_t { + gfc_expr *expr; + gfc_symbol *sym; + bool *bad; +} check_nested_loop_in_block_state; + +static void +check_nested_loop_in_block_symbol (gfc_symbol *sym) +{ + if (sym == check_nested_loop_in_block_state.sym + || (check_nested_loop_in_block_state.expr + && gfc_find_sym_in_expr (sym, + check_nested_loop_in_block_state.expr))) + *check_nested_loop_in_block_state.bad = true; +} + +/* Return the first nested DO loop in BLOCK, or NULL if there + isn't one. Set *BAD to true if EXPR references any variables in BLOCK, or + SYM is bound in BLOCK. Either EXPR or SYM may be null. */ +static gfc_code * +check_nested_loop_in_block (gfc_code *block, gfc_expr *expr, + gfc_symbol *sym, bool *bad) +{ + gfc_namespace *ns; + gcc_assert (block->op == EXEC_BLOCK); + ns = block->ext.block.ns; + gcc_assert (ns); + + /* Skip the check if this block doesn't contain the nested loop, or + if we already know it's bad. */ + gfc_code *result = check_nested_loop_in_chain (ns->code, expr, sym, bad); + if (result && !*bad) + { + check_nested_loop_in_block_state.expr = expr; + check_nested_loop_in_block_state.sym = sym; + check_nested_loop_in_block_state.bad = bad; + gfc_traverse_ns (ns, check_nested_loop_in_block_symbol); + check_nested_loop_in_block_state.expr = NULL; + check_nested_loop_in_block_state.sym = NULL; + check_nested_loop_in_block_state.bad = NULL; + } + return result; +} + +/* CODE is an OMP loop construct. Return true if EXPR references + any variables bound in intervening code, to level DEPTH. */ +static bool +expr_uses_intervening_var (gfc_code *code, int depth, gfc_expr *expr) +{ + int i; + gfc_code *do_code = code; + + for (i = 0; i < depth; i++) + { + bool bad = false; + do_code = check_nested_loop_in_chain (do_code->block->next, + expr, NULL, &bad); + if (bad) + return true; + } + return false; +} + +/* CODE is an OMP loop construct. Return true if SYM is bound in + intervening code, to level DEPTH. */ +static bool +is_intervening_var (gfc_code *code, int depth, gfc_symbol *sym) +{ + int i; + gfc_code *do_code = code; + + for (i = 0; i < depth; i++) + { + bool bad = false; + do_code = check_nested_loop_in_chain (do_code->block->next, + NULL, sym, &bad); + if (bad) + return true; } return false; } @@ -9826,14 +10332,15 @@ static bool expr_is_invariant (gfc_code *code, int depth, gfc_expr *expr) { int i; - gfc_code *do_code = code->block->next; + gfc_code *do_code = code; for (i = 1; i < depth; i++) { + do_code = find_nested_loop_in_chain (do_code->block->next); + gcc_assert (do_code); gfc_symbol *ivar = do_code->ext.iterator->var->symtree->n.sym; if (gfc_find_sym_in_expr (ivar, expr)) return false; - do_code = do_code->block->next; } return true; } @@ -9904,12 +10411,14 @@ bound_expr_is_canonical (gfc_code *code, int depth, gfc_expr *expr, static void resolve_omp_do (gfc_code *code) { - gfc_code *do_code, *c; - int list, i, collapse; + gfc_code *do_code, *next; + int list, i, count; gfc_omp_namelist *n; gfc_symbol *dovar; const char *name; bool is_simd = false; + bool errorp = false; + bool perfect_nesting_errorp = false; switch (code->op) { @@ -10012,12 +10521,12 @@ resolve_omp_do (gfc_code *code) do_code = code->block->next; if (code->ext.omp_clauses->orderedc) - collapse = code->ext.omp_clauses->orderedc; + count = code->ext.omp_clauses->orderedc; else { - collapse = code->ext.omp_clauses->collapse; - if (collapse <= 0) - collapse = 1; + count = code->ext.omp_clauses->collapse; + if (count <= 0) + count = 1; } /* While the spec defines the loop nest depth independently of the COLLAPSE @@ -10025,29 +10534,36 @@ resolve_omp_do (gfc_code *code) depth and treats any further inner loops as the final-loop-body. So here we also check canonical loop nest form only for the number of outer loops specified by the COLLAPSE clause too. */ - for (i = 1; i <= collapse; i++) + for (i = 1; i <= count; i++) { gfc_symbol *start_var = NULL, *end_var = NULL; + /* Parse errors are not recoverable. */ if (do_code->op == EXEC_DO_WHILE) { gfc_error ("%s cannot be a DO WHILE or DO without loop control " "at %L", name, &do_code->loc); - break; + return; } if (do_code->op == EXEC_DO_CONCURRENT) { gfc_error ("%s cannot be a DO CONCURRENT loop at %L", name, &do_code->loc); - break; + return; } gcc_assert (do_code->op == EXEC_DO); if (do_code->ext.iterator->var->ts.type != BT_INTEGER) - gfc_error ("%s iteration variable must be of type integer at %L", - name, &do_code->loc); + { + gfc_error ("%s iteration variable must be of type integer at %L", + name, &do_code->loc); + errorp = true; + } dovar = do_code->ext.iterator->var->symtree->n.sym; if (dovar->attr.threadprivate) - gfc_error ("%s iteration variable must not be THREADPRIVATE " - "at %L", name, &do_code->loc); + { + gfc_error ("%s iteration variable must not be THREADPRIVATE " + "at %L", name, &do_code->loc); + errorp = true; + } if (code->ext.omp_clauses) for (list = 0; list < OMP_LIST_NUM; list++) if (!is_simd || code->ext.omp_clauses->collapse > 1 @@ -10066,13 +10582,20 @@ resolve_omp_do (gfc_code *code) gfc_error ("%s iteration variable present on clause " "other than PRIVATE, LASTPRIVATE, ALLOCATE or " "LINEAR at %L", name, &do_code->loc); - break; + errorp = true; } if (is_outer_iteration_variable (code, i, dovar)) { gfc_error ("%s iteration variable used in more than one loop at %L", name, &do_code->loc); - break; + errorp = true; + } + else if (is_intervening_var (code, i, dovar)) + { + gfc_error ("%s iteration variable at %L is bound in " + "intervening code", + name, &do_code->loc); + errorp = true; } else if (!bound_expr_is_canonical (code, i, do_code->ext.iterator->start, @@ -10080,7 +10603,15 @@ resolve_omp_do (gfc_code *code) { gfc_error ("%s loop start expression not in canonical form at %L", name, &do_code->loc); - break; + errorp = true; + } + else if (expr_uses_intervening_var (code, i, + do_code->ext.iterator->start)) + { + gfc_error ("%s loop start expression at %L uses variable bound in " + "intervening code", + name, &do_code->loc); + errorp = true; } else if (!bound_expr_is_canonical (code, i, do_code->ext.iterator->end, @@ -10088,48 +10619,89 @@ resolve_omp_do (gfc_code *code) { gfc_error ("%s loop end expression not in canonical form at %L", name, &do_code->loc); - break; + errorp = true; + } + else if (expr_uses_intervening_var (code, i, + do_code->ext.iterator->end)) + { + gfc_error ("%s loop end expression at %L uses variable bound in " + "intervening code", + name, &do_code->loc); + errorp = true; } else if (start_var && end_var && start_var != end_var) { gfc_error ("%s loop bounds reference different " "iteration variables at %L", name, &do_code->loc); - break; + errorp = true; } else if (!expr_is_invariant (code, i, do_code->ext.iterator->step)) { gfc_error ("%s loop increment not in canonical form at %L", name, &do_code->loc); - break; + errorp = true; + } + else if (expr_uses_intervening_var (code, i, + do_code->ext.iterator->step)) + { + gfc_error ("%s loop increment expression at %L uses variable " + "bound in intervening code", + name, &do_code->loc); + errorp = true; } if (start_var || end_var) code->ext.omp_clauses->non_rectangular = 1; - for (c = do_code->next; c; c = c->next) - if (c->op != EXEC_NOP && c->op != EXEC_CONTINUE) - { - gfc_error ("collapsed %s loops not perfectly nested at %L", - name, &c->loc); - break; - } - if (i == collapse || c) + /* Only parse loop body into nested loop and intervening code if + there are supposed to be more loops in the nest to collapse. */ + if (i == count) break; - do_code = do_code->block; - if (do_code->op != EXEC_DO && do_code->op != EXEC_DO_WHILE) + + next = find_nested_loop_in_chain (do_code->block->next); + + if (!next) { - gfc_error ("not enough DO loops for collapsed %s at %L", - name, &code->loc); - break; + /* Parse error, can't recover from this. */ + gfc_error ("not enough DO loops for collapsed %s (level %d) at %L", + name, i, &code->loc); + return; } - do_code = do_code->next; - if (do_code == NULL - || (do_code->op != EXEC_DO && do_code->op != EXEC_DO_WHILE)) + else if (next != do_code->block->next || next->next) + /* Imperfectly nested loop found. */ { - gfc_error ("not enough DO loops for collapsed %s at %L", - name, &code->loc); - break; + /* Only diagnose violation of imperfect nesting constraints once. */ + if (!perfect_nesting_errorp) + { + if (code->ext.omp_clauses->orderedc) + { + gfc_error ("%s inner loops must be perfectly nested with " + "ORDERED clause at %L", + name, &code->loc); + perfect_nesting_errorp = true; + } + else if (code->ext.omp_clauses->lists[OMP_LIST_REDUCTION_INSCAN]) + { + gfc_error ("%s inner loops must be perfectly nested with " + "REDUCTION INSCAN clause at %L", + name, &code->loc); + perfect_nesting_errorp = true; + } + /* FIXME: Also diagnose for TILE directives. */ + if (perfect_nesting_errorp) + errorp = true; + } + if (diagnose_intervening_code_errors (do_code->block->next, + name, next)) + errorp = true; } + do_code = next; } + + /* Give up now if we found any constraint violations. */ + if (errorp) + return; + + restructure_intervening_code (&(code->block->next), code, count); } diff --git a/gcc/fortran/parse.cc b/gcc/fortran/parse.cc index e797402b59fc..8f09ddf753cc 100644 --- a/gcc/fortran/parse.cc +++ b/gcc/fortran/parse.cc @@ -37,6 +37,13 @@ gfc_st_label *gfc_statement_label; static locus label_locus; static jmp_buf eof_buf; +/* Respectively pointer and content of the current interface body being parsed + as they were at the beginning of decode_statement. Used to restore the + interface to its previous state in case a parsed statement is rejected after + some symbols have been added to the interface. */ +static gfc_interface **current_interface_ptr = nullptr; +static gfc_interface *previous_interface_head = nullptr; + gfc_state_data *gfc_state_stack; static bool last_was_use_stmt = false; bool in_exec_part; @@ -291,6 +298,46 @@ end_of_block: return ST_GET_FCN_CHARACTERISTICS; } + +/* Tells whether gfc_get_current_interface_head can be used safely. */ + +static bool +current_interface_valid_p () +{ + switch (current_interface.type) + { + case INTERFACE_INTRINSIC_OP: + return current_interface.ns != nullptr; + + case INTERFACE_GENERIC: + case INTERFACE_DTIO: + return current_interface.sym != nullptr; + + case INTERFACE_USER_OP: + return current_interface.uop != nullptr; + + default: + return false; + } +} + + +/* Return a pointer to the interface currently being parsed, or nullptr if + we are not currently parsing an interface body. */ + +static gfc_interface ** +get_current_interface_ptr () +{ + if (current_interface_valid_p ()) + { + gfc_interface *& ifc_ptr = gfc_current_interface_head (); + return &ifc_ptr; + } + else + return nullptr; +} + + static bool in_specification_block; /* This is the primary 'decode_statement'. */ @@ -307,6 +354,11 @@ decode_statement (void) gfc_clear_error (); /* Clear any pending errors. */ gfc_clear_warning (); /* Clear any pending warnings. */ + current_interface_ptr = get_current_interface_ptr (); + previous_interface_head = current_interface_ptr == nullptr + ? nullptr + : *current_interface_ptr; + gfc_matching_function = false; if (gfc_match_eos () == MATCH_YES) @@ -3042,6 +3094,8 @@ reject_statement (void) { gfc_free_equiv_until (gfc_current_ns->equiv, gfc_current_ns->old_equiv); gfc_current_ns->equiv = gfc_current_ns->old_equiv; + gfc_drop_interface_elements_before (current_interface_ptr, + previous_interface_head); gfc_reject_data (gfc_current_ns); diff --git a/gcc/fortran/primary.cc b/gcc/fortran/primary.cc index 0bb440b85a91..d3aeeb893628 100644 --- a/gcc/fortran/primary.cc +++ b/gcc/fortran/primary.cc @@ -530,13 +530,13 @@ match_real_constant (gfc_expr **result, int signflag) seen_dp = 0; seen_digits = 0; exp_char = ' '; - negate = FALSE; + negate = false; c = gfc_next_ascii_char (); if (signflag && (c == '+' || c == '-')) { if (c == '-') - negate = TRUE; + negate = true; gfc_gobble_whitespace (); c = gfc_next_ascii_char (); diff --git a/gcc/fortran/resolve.cc b/gcc/fortran/resolve.cc index 3cd470ddccaf..1042b8c18e8e 100644 --- a/gcc/fortran/resolve.cc +++ b/gcc/fortran/resolve.cc @@ -959,6 +959,10 @@ cleanup: } +/* Forward declaration. */ +static bool is_non_constant_shape_array (gfc_symbol *sym); + + /* Resolve common variables. */ static void resolve_common_vars (gfc_common_head *common_block, bool named_common) @@ -1007,6 +1011,15 @@ resolve_common_vars (gfc_common_head *common_block, bool named_common) gfc_error_now ("%qs at %L cannot appear in COMMON " "[F2008:C5100]", csym->name, &csym->declared_at); + if (csym->attr.dimension && is_non_constant_shape_array (csym)) + { + gfc_error_now ("Automatic object %qs at %L cannot appear in " + "COMMON at %L", csym->name, &csym->declared_at, + &common_block->where); + /* Avoid confusing follow-on error. */ + csym->error = 1; + } + if (csym->ts.type != BT_DERIVED) continue; @@ -1396,11 +1409,14 @@ resolve_structure_cons (gfc_expr *expr, int init) the one of the structure, ensure this if the lengths are known at compile time and when we are dealing with PARAMETER or structure constructors. */ - if (cons->expr->ts.type == BT_CHARACTER && comp->ts.u.cl - && comp->ts.u.cl->length + if (cons->expr->ts.type == BT_CHARACTER + && comp->ts.type == BT_CHARACTER + && comp->ts.u.cl && comp->ts.u.cl->length && comp->ts.u.cl->length->expr_type == EXPR_CONSTANT && cons->expr->ts.u.cl && cons->expr->ts.u.cl->length && cons->expr->ts.u.cl->length->expr_type == EXPR_CONSTANT + && cons->expr->ts.u.cl->length->ts.type == BT_INTEGER + && comp->ts.u.cl->length->ts.type == BT_INTEGER && mpz_cmp (cons->expr->ts.u.cl->length->value.integer, comp->ts.u.cl->length->value.integer) != 0) { @@ -16609,7 +16625,7 @@ resolve_symbol (gfc_symbol *sym) /* Resolve array specifier. Check as well some constraints on COMMON blocks. */ - check_constant = sym->attr.in_common && !sym->attr.pointer; + check_constant = sym->attr.in_common && !sym->attr.pointer && !sym->error; /* Set the formal_arg_flag so that check_conflict will not throw an error for host associated variables in the specification @@ -16762,6 +16778,7 @@ check_data_variable (gfc_data_variable *var, locus *where) ar_type mark = AR_UNKNOWN; int i; mpz_t section_index[GFC_MAX_DIMENSIONS]; + int vector_offset[GFC_MAX_DIMENSIONS]; gfc_ref *ref; gfc_array_ref *ar; gfc_symbol *sym; @@ -16885,7 +16902,7 @@ check_data_variable (gfc_data_variable *var, locus *where) case AR_SECTION: ar = &ref->u.ar; /* Get the start position of array section. */ - gfc_get_section_index (ar, section_index, &offset); + gfc_get_section_index (ar, section_index, &offset, vector_offset); mark = AR_SECTION; break; @@ -16968,7 +16985,7 @@ check_data_variable (gfc_data_variable *var, locus *where) /* Modify the array section indexes and recalculate the offset for next element. */ else if (mark == AR_SECTION) - gfc_advance_section (section_index, ar, &offset); + gfc_advance_section (section_index, ar, &offset, vector_offset); } } @@ -17966,7 +17983,10 @@ resolve_types (gfc_namespace *ns) for (n = ns->contained; n; n = n->sibling) { - if (gfc_pure (ns->proc_name) && !gfc_pure (n->proc_name)) + /* Exclude final wrappers with the test for the artificial attribute. */ + if (gfc_pure (ns->proc_name) + && !gfc_pure (n->proc_name) + && !n->proc_name->attr.artificial) gfc_error ("Contained procedure %qs at %L of a PURE procedure must " "also be PURE", n->proc_name->name, &n->proc_name->declared_at); diff --git a/gcc/fortran/trans-array.cc b/gcc/fortran/trans-array.cc index 951cecfa5d59..6ca58e98547a 100644 --- a/gcc/fortran/trans-array.cc +++ b/gcc/fortran/trans-array.cc @@ -1121,7 +1121,7 @@ gfc_trans_allocate_array_storage (stmtblock_t * pre, stmtblock_t * post, { /* A callee allocated array. */ gfc_conv_descriptor_data_set (pre, desc, null_pointer_node); - onstack = FALSE; + onstack = false; } else { @@ -2481,7 +2481,7 @@ get_array_ctor_strlen (stmtblock_t *block, gfc_constructor_base base, tree * len gfc_constructor *c; bool is_const; - is_const = TRUE; + is_const = true; if (gfc_constructor_first (base) == NULL) { @@ -4740,6 +4740,29 @@ done: for (n = 0; n < loop->dimen; n++) size[n] = NULL_TREE; + /* If there is a constructor involved, derive size[] from its shape. */ + for (ss = loop->ss; ss != gfc_ss_terminator; ss = ss->loop_chain) + { + gfc_ss_info *ss_info; + + ss_info = ss->info; + info = &ss_info->data.array; + + if (ss_info->type == GFC_SS_CONSTRUCTOR && info->shape) + { + for (n = 0; n < loop->dimen; n++) + { + if (size[n] == NULL) + { + gcc_assert (info->shape[n]); + size[n] = gfc_conv_mpz_to_tree (info->shape[n], + gfc_index_integer_kind); + } + } + break; + } + } + for (ss = loop->ss; ss != gfc_ss_terminator; ss = ss->loop_chain) { stmtblock_t inner; diff --git a/gcc/fortran/trans-common.cc b/gcc/fortran/trans-common.cc index c83b6f930ebc..91a98b30b8da 100644 --- a/gcc/fortran/trans-common.cc +++ b/gcc/fortran/trans-common.cc @@ -1048,7 +1048,7 @@ find_equivalence (segment_info *n) gfc_equiv *e1, *e2, *eq; bool found; - found = FALSE; + found = false; for (e1 = n->sym->ns->equiv; e1; e1 = e1->next) { @@ -1083,7 +1083,7 @@ find_equivalence (segment_info *n) { add_condition (n, eq, e2); e2->used = 1; - found = TRUE; + found = true; } } } @@ -1102,11 +1102,11 @@ static void add_equivalences (bool *saw_equiv) { segment_info *f; - bool more = TRUE; + bool more = true; while (more) { - more = FALSE; + more = false; for (f = current_segment; f; f = f->next) { if (!f->sym->equiv_built) diff --git a/gcc/fortran/trans-expr.cc b/gcc/fortran/trans-expr.cc index 764565476af2..244126cdd001 100644 --- a/gcc/fortran/trans-expr.cc +++ b/gcc/fortran/trans-expr.cc @@ -4044,8 +4044,9 @@ conv_scalar_char_value (gfc_symbol *sym, gfc_se *se, gfc_expr **expr) gfc_typespec ts; gfc_clear_ts (&ts); - *expr = gfc_get_int_expr (gfc_default_character_kind, NULL, - (*expr)->value.character.string[0]); + gfc_expr *tmp = gfc_get_int_expr (gfc_default_character_kind, NULL, + (*expr)->value.character.string[0]); + gfc_replace_expr (*expr, tmp); } else if (se != NULL && (*expr)->expr_type == EXPR_VARIABLE) { @@ -6451,30 +6452,24 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym, /* ABI: actual arguments to CHARACTER(len=1),VALUE dummy arguments are actually passed by value. - Strings are truncated to length 1. - The BIND(C) case is handled elsewhere. */ - if (fsym->ts.type == BT_CHARACTER - && !fsym->ts.is_c_interop - && fsym->ts.u.cl->length->expr_type == EXPR_CONSTANT - && fsym->ts.u.cl->length->ts.type == BT_INTEGER - && (mpz_cmp_ui - (fsym->ts.u.cl->length->value.integer, 1) == 0)) + Strings are truncated to length 1. */ + if (gfc_length_one_character_type_p (&fsym->ts)) { - if (e->expr_type != EXPR_CONSTANT) - { - tree slen1 = build_int_cst (gfc_charlen_type_node, 1); - gfc_conv_string_parameter (&parmse); - parmse.expr = gfc_string_to_single_character (slen1, - parmse.expr, - e->ts.kind); - /* Truncate resulting string to length 1. */ - parmse.string_length = slen1; - } - else if (e->value.character.length > 1) + if (e->expr_type == EXPR_CONSTANT + && e->value.character.length > 1) { e->value.character.length = 1; gfc_conv_expr (&parmse, e); } + + tree slen1 = build_int_cst (gfc_charlen_type_node, 1); + gfc_conv_string_parameter (&parmse); + parmse.expr + = gfc_string_to_single_character (slen1, + parmse.expr, + e->ts.kind); + /* Truncate resulting string to length 1. */ + parmse.string_length = slen1; } if (fsym->attr.optional @@ -10615,6 +10610,13 @@ gfc_conv_string_parameter (gfc_se * se) { tree type; + if (TREE_CODE (TREE_TYPE (se->expr)) == INTEGER_TYPE + && integer_onep (se->string_length)) + { + se->expr = gfc_build_addr_expr (NULL_TREE, se->expr); + return; + } + if (TREE_CODE (se->expr) == STRING_CST) { type = TREE_TYPE (TREE_TYPE (se->expr)); @@ -11169,7 +11171,8 @@ gfc_trans_arrayfunc_assign (gfc_expr * expr1, gfc_expr * expr2) if (expr1->ts.type == BT_DERIVED && expr1->ts.u.derived->attr.alloc_comp) { - tmp = gfc_deallocate_alloc_comp_no_caf (expr1->ts.u.derived, se.expr, + tmp = build_fold_indirect_ref_loc (input_location, se.expr); + tmp = gfc_deallocate_alloc_comp_no_caf (expr1->ts.u.derived, tmp, expr1->rank); gfc_add_expr_to_block (&se.pre, tmp); } diff --git a/gcc/fortran/trans-openmp.cc b/gcc/fortran/trans-openmp.cc index cf741cebf91b..2f116fd67380 100644 --- a/gcc/fortran/trans-openmp.cc +++ b/gcc/fortran/trans-openmp.cc @@ -4443,6 +4443,9 @@ gfc_trans_omp_clauses (stmtblock_t *block, gfc_omp_clauses *clauses, case OMP_DEFAULTMAP_CAT_UNCATEGORIZED: category = OMP_CLAUSE_DEFAULTMAP_CATEGORY_UNSPECIFIED; break; + case OMP_DEFAULTMAP_CAT_ALL: + category = OMP_CLAUSE_DEFAULTMAP_CATEGORY_ALL; + break; case OMP_DEFAULTMAP_CAT_SCALAR: category = OMP_CLAUSE_DEFAULTMAP_CATEGORY_SCALAR; break; diff --git a/gcc/fortran/trans-stmt.cc b/gcc/fortran/trans-stmt.cc index 93f36bfb955e..50b71e67234c 100644 --- a/gcc/fortran/trans-stmt.cc +++ b/gcc/fortran/trans-stmt.cc @@ -2334,6 +2334,7 @@ gfc_trans_block_construct (gfc_code* code) tree exit_label; stmtblock_t body; gfc_association_list *ass; + tree translated_body; ns = code->ext.block.ns; gcc_assert (ns); @@ -2352,7 +2353,11 @@ gfc_trans_block_construct (gfc_code* code) finish_oacc_declare (ns, sym, true); - gfc_add_expr_to_block (&body, gfc_trans_code (ns->code)); + translated_body = gfc_trans_code (ns->code); + if (ns->omp_structured_block) + translated_body = build1 (OMP_STRUCTURED_BLOCK, void_type_node, + translated_body); + gfc_add_expr_to_block (&body, translated_body); gfc_add_expr_to_block (&body, build1_v (LABEL_EXPR, exit_label)); /* Finish everything. */ diff --git a/gcc/fortran/trans-types.cc b/gcc/fortran/trans-types.cc index 987e3d26c463..084b8c3ae2cd 100644 --- a/gcc/fortran/trans-types.cc +++ b/gcc/fortran/trans-types.cc @@ -2313,7 +2313,10 @@ gfc_sym_type (gfc_symbol * sym, bool is_bind_c) && sym->ns->proc_name && sym->ns->proc_name->attr.is_bind_c) || (sym->ts.deferred && (!sym->ts.u.cl - || !sym->ts.u.cl->backend_decl)))) + || !sym->ts.u.cl->backend_decl)) + || (sym->attr.dummy + && sym->attr.value + && gfc_length_one_character_type_p (&sym->ts)))) type = gfc_get_char_type (sym->ts.kind); else type = gfc_typenode_for_spec (&sym->ts, sym->attr.codimension); diff --git a/gcc/gcc.cc b/gcc/gcc.cc index fdfac0b4fe4b..a9dd0eb655c5 100644 --- a/gcc/gcc.cc +++ b/gcc/gcc.cc @@ -5533,7 +5533,7 @@ set_collect_gcc_options (void) obstack_grow (&collect_obstack, "COLLECT_GCC_OPTIONS=", sizeof ("COLLECT_GCC_OPTIONS=") - 1); - first_time = TRUE; + first_time = true; for (i = 0; (int) i < n_switches; i++) { const char *const *args; @@ -5541,7 +5541,7 @@ set_collect_gcc_options (void) if (!first_time) obstack_grow (&collect_obstack, " ", 1); - first_time = FALSE; + first_time = false; /* Ignore elided switches. */ if ((switches[i].live_cond @@ -5579,7 +5579,7 @@ set_collect_gcc_options (void) { if (!first_time) obstack_grow (&collect_obstack, " ", 1); - first_time = FALSE; + first_time = false; obstack_grow (&collect_obstack, "'-dumpdir' '", 12); const char *p, *q; @@ -8332,7 +8332,7 @@ driver::build_multilib_strings () const obstack_1grow (&multilib_obstack, 0); multilib_reuse = XOBFINISH (&multilib_obstack, const char *); - need_space = FALSE; + need_space = false; for (size_t i = 0; i < ARRAY_SIZE (multilib_defaults_raw); i++) { if (need_space) @@ -8340,7 +8340,7 @@ driver::build_multilib_strings () const obstack_grow (&multilib_obstack, multilib_defaults_raw[i], strlen (multilib_defaults_raw[i])); - need_space = TRUE; + need_space = true; } obstack_1grow (&multilib_obstack, 0); @@ -10176,19 +10176,19 @@ print_multilib_info (void) /* If there are extra options, print them now. */ if (multilib_extra && *multilib_extra) { - int print_at = TRUE; + int print_at = true; const char *q; for (q = multilib_extra; *q != '\0'; q++) { if (*q == ' ') - print_at = TRUE; + print_at = true; else { if (print_at) putchar ('@'); putchar (*q); - print_at = FALSE; + print_at = false; } } } diff --git a/gcc/genautomata.cc b/gcc/genautomata.cc index bf2dcdf2967e..72f01686d6ba 100644 --- a/gcc/genautomata.cc +++ b/gcc/genautomata.cc @@ -1251,7 +1251,7 @@ gen_cpu_unit (md_rtx_info *info) int i; rtx def = info->def; - str_cpu_units = get_str_vect (XSTR (def, 0), &vect_length, ',', FALSE); + str_cpu_units = get_str_vect (XSTR (def, 0), &vect_length, ',', false); if (str_cpu_units == NULL) fatal_at (info->loc, "invalid string `%s' in %s", XSTR (def, 0), GET_RTX_NAME (GET_CODE (def))); @@ -1283,7 +1283,7 @@ gen_query_cpu_unit (md_rtx_info *info) rtx def = info->def; str_cpu_units = get_str_vect (XSTR (def, 0), &vect_length, ',', - FALSE); + false); if (str_cpu_units == NULL) fatal_at (info->loc, "invalid string `%s' in %s", XSTR (def, 0), GET_RTX_NAME (GET_CODE (def))); @@ -1315,11 +1315,11 @@ gen_bypass (md_rtx_info *info) int i, j; rtx def = info->def; - out_patterns = get_str_vect (XSTR (def, 1), &out_length, ',', FALSE); + out_patterns = get_str_vect (XSTR (def, 1), &out_length, ',', false); if (out_patterns == NULL) fatal_at (info->loc, "invalid string `%s' in %s", XSTR (def, 1), GET_RTX_NAME (GET_CODE (def))); - in_patterns = get_str_vect (XSTR (def, 2), &in_length, ',', FALSE); + in_patterns = get_str_vect (XSTR (def, 2), &in_length, ',', false); if (in_patterns == NULL) fatal_at (info->loc, "invalid string `%s' in %s", XSTR (def, 2), GET_RTX_NAME (GET_CODE (def))); @@ -1354,12 +1354,12 @@ gen_excl_set (md_rtx_info *info) rtx def = info->def; first_str_cpu_units - = get_str_vect (XSTR (def, 0), &first_vect_length, ',', FALSE); + = get_str_vect (XSTR (def, 0), &first_vect_length, ',', false); if (first_str_cpu_units == NULL) fatal_at (info->loc, "invalid string `%s' in %s", XSTR (def, 0), GET_RTX_NAME (GET_CODE (def))); second_str_cpu_units = get_str_vect (XSTR (def, 1), &length, ',', - FALSE); + false); if (second_str_cpu_units == NULL) fatal_at (info->loc, "invalid string `%s' in %s", XSTR (def, 1), GET_RTX_NAME (GET_CODE (def))); @@ -1399,12 +1399,12 @@ gen_presence_absence_set (md_rtx_info *info, int presence_p, int final_p) rtx def = info->def; str_cpu_units = get_str_vect (XSTR (def, 0), &cpu_units_length, ',', - FALSE); + false); if (str_cpu_units == NULL) fatal_at (info->loc, "invalid string `%s' in %s", XSTR (def, 0), GET_RTX_NAME (GET_CODE (def))); str_pattern_lists = get_str_vect (XSTR (def, 1), - &patterns_length, ',', FALSE); + &patterns_length, ',', false); if (str_pattern_lists == NULL) fatal_at (info->loc, "invalid string `%s' in %s", XSTR (def, 1), GET_RTX_NAME (GET_CODE (def))); @@ -1412,7 +1412,7 @@ gen_presence_absence_set (md_rtx_info *info, int presence_p, int final_p) for (i = 0; i < patterns_length; i++) { str_patterns [i] = get_str_vect (str_pattern_lists [i], - &length, ' ', FALSE); + &length, ' ', false); gcc_assert (str_patterns [i]); } decl = XCREATENODE (struct decl); @@ -1446,7 +1446,7 @@ gen_presence_absence_set (md_rtx_info *info, int presence_p, int final_p) static void gen_presence_set (md_rtx_info *info) { - gen_presence_absence_set (info, TRUE, FALSE); + gen_presence_absence_set (info, true, false); } /* Process a FINAL_PRESENCE_SET. @@ -1457,7 +1457,7 @@ gen_presence_set (md_rtx_info *info) static void gen_final_presence_set (md_rtx_info *info) { - gen_presence_absence_set (info, TRUE, TRUE); + gen_presence_absence_set (info, true, true); } /* Process an ABSENCE_SET. @@ -1468,7 +1468,7 @@ gen_final_presence_set (md_rtx_info *info) static void gen_absence_set (md_rtx_info *info) { - gen_presence_absence_set (info, FALSE, FALSE); + gen_presence_absence_set (info, false, false); } /* Process a FINAL_ABSENCE_SET. @@ -1479,7 +1479,7 @@ gen_absence_set (md_rtx_info *info) static void gen_final_absence_set (md_rtx_info *info) { - gen_presence_absence_set (info, FALSE, TRUE); + gen_presence_absence_set (info, false, true); } /* Process a DEFINE_AUTOMATON. @@ -1496,7 +1496,7 @@ gen_automaton (md_rtx_info *info) int i; rtx def = info->def; - str_automata = get_str_vect (XSTR (def, 0), &vect_length, ',', FALSE); + str_automata = get_str_vect (XSTR (def, 0), &vect_length, ',', false); if (str_automata == NULL) fatal_at (info->loc, "invalid string `%s' in %s", XSTR (def, 0), GET_RTX_NAME (GET_CODE (def))); @@ -1590,7 +1590,7 @@ gen_regexp_repeat (const char *str) int els_num; int i; - repeat_vect = get_str_vect (str, &els_num, '*', TRUE); + repeat_vect = get_str_vect (str, &els_num, '*', true); if (repeat_vect == NULL) fatal ("invalid `%s' in reservation `%s'", str, reserv_str); if (els_num > 1) @@ -1622,7 +1622,7 @@ gen_regexp_allof (const char *str) int els_num; int i; - allof_vect = get_str_vect (str, &els_num, '+', TRUE); + allof_vect = get_str_vect (str, &els_num, '+', true); if (allof_vect == NULL) fatal ("invalid `%s' in reservation `%s'", str, reserv_str); if (els_num > 1) @@ -1648,7 +1648,7 @@ gen_regexp_oneof (const char *str) int els_num; int i; - oneof_vect = get_str_vect (str, &els_num, '|', TRUE); + oneof_vect = get_str_vect (str, &els_num, '|', true); if (oneof_vect == NULL) fatal ("invalid `%s' in reservation `%s'", str, reserv_str); if (els_num > 1) @@ -1674,7 +1674,7 @@ gen_regexp_sequence (const char *str) int els_num; int i; - sequence_vect = get_str_vect (str, &els_num, ',', TRUE); + sequence_vect = get_str_vect (str, &els_num, ',', true); if (els_num == -1) fatal ("unbalanced parentheses in reservation `%s'", str); if (sequence_vect == NULL) @@ -2686,14 +2686,14 @@ process_decls (void) unit_set_el_list = process_presence_absence_names (DECL_PRESENCE (decl)->names, DECL_PRESENCE (decl)->names_num, - decl->pos, TRUE, DECL_PRESENCE (decl)->final_p); + decl->pos, true, DECL_PRESENCE (decl)->final_p); pattern_set_el_list = process_presence_absence_patterns (DECL_PRESENCE (decl)->patterns, DECL_PRESENCE (decl)->patterns_num, - decl->pos, TRUE, DECL_PRESENCE (decl)->final_p); + decl->pos, true, DECL_PRESENCE (decl)->final_p); add_presence_absence (unit_set_el_list, pattern_set_el_list, - decl->pos, TRUE, + decl->pos, true, DECL_PRESENCE (decl)->final_p); } } @@ -2710,14 +2710,14 @@ process_decls (void) unit_set_el_list = process_presence_absence_names (DECL_ABSENCE (decl)->names, DECL_ABSENCE (decl)->names_num, - decl->pos, FALSE, DECL_ABSENCE (decl)->final_p); + decl->pos, false, DECL_ABSENCE (decl)->final_p); pattern_set_el_list = process_presence_absence_patterns (DECL_ABSENCE (decl)->patterns, DECL_ABSENCE (decl)->patterns_num, - decl->pos, FALSE, DECL_ABSENCE (decl)->final_p); + decl->pos, false, DECL_ABSENCE (decl)->final_p); add_presence_absence (unit_set_el_list, pattern_set_el_list, - decl->pos, FALSE, + decl->pos, false, DECL_ABSENCE (decl)->final_p); } } @@ -3597,16 +3597,16 @@ reserv_sets_are_intersected (reserv_sets_t operand_1, el_ptr_1++, el_ptr_2++) if (*el_ptr_1 & *el_ptr_2) return 1; - if (!check_presence_pattern_sets (cycle_ptr_1, cycle_ptr_2, FALSE)) + if (!check_presence_pattern_sets (cycle_ptr_1, cycle_ptr_2, false)) return 1; if (!check_presence_pattern_sets (temp_reserv + (cycle_ptr_2 - operand_2), - cycle_ptr_2, TRUE)) + cycle_ptr_2, true)) return 1; - if (!check_absence_pattern_sets (cycle_ptr_1, cycle_ptr_2, FALSE)) + if (!check_absence_pattern_sets (cycle_ptr_1, cycle_ptr_2, false)) return 1; if (!check_absence_pattern_sets (temp_reserv + (cycle_ptr_2 - operand_2), - cycle_ptr_2, TRUE)) + cycle_ptr_2, true)) return 1; } return 0; @@ -4272,7 +4272,7 @@ initiate_excl_sets (void) el = el->next_unit_set_el) { bitmap_set_bit (unit_excl_set, el->unit_decl->unit_num); - el->unit_decl->in_set_p = TRUE; + el->unit_decl->in_set_p = true; } unit_excl_set_table [DECL_UNIT (decl)->unit_num] = unit_excl_set; } @@ -4337,7 +4337,7 @@ form_reserv_sets_list (pattern_set_el_t pattern_list) for (i = 0; i < el->units_num; i++) { bitmap_set_bit (curr->reserv, el->unit_decls [i]->unit_num); - el->unit_decls [i]->in_set_p = TRUE; + el->unit_decls [i]->in_set_p = true; } if (prev != NULL) prev->next_pattern_reserv = curr; @@ -4414,7 +4414,7 @@ check_presence_pattern_sets (reserv_sets_t checked_set, || (!final_p && unit_presence_set_table [start_unit_num] == NULL)) continue; - presence_p = FALSE; + presence_p = false; for (pat_reserv = (final_p ? unit_final_presence_set_table [start_unit_num] : unit_presence_set_table [start_unit_num]); @@ -4428,9 +4428,9 @@ check_presence_pattern_sets (reserv_sets_t checked_set, presence_p = presence_p || unit_num >= els_in_cycle_reserv; } if (!presence_p) - return FALSE; + return false; } - return TRUE; + return true; } /* The function checks that CHECKED_SET satisfies all absence pattern @@ -4467,10 +4467,10 @@ check_absence_pattern_sets (reserv_sets_t checked_set, && pat_reserv->reserv [unit_num]) break; if (unit_num >= els_in_cycle_reserv) - return FALSE; + return false; } } - return TRUE; + return true; } @@ -5284,7 +5284,7 @@ check_regexp_units_distribution (const char *insn_reserv_name, error ("The following units do not satisfy units-automata distribution rule"); error ("(Unit presence on one alt and its absence on other alt\n"); error (" result in different other automata reservations)"); - annotation_message_reported_p = TRUE; + annotation_message_reported_p = true; } if (! annotation_reservation_message_reported_p) { @@ -5319,7 +5319,7 @@ check_unit_distributions_to_automata (void) } if (automaton_decls.length () > 1) { - annotation_message_reported_p = FALSE; + annotation_message_reported_p = false; for (i = 0; i < description->decls_num; i++) { decl = description->decls [i]; @@ -6638,7 +6638,7 @@ create_ainsns (automaton_t automaton) { curr_ainsn = XCREATENODE (struct ainsn); curr_ainsn->insn_reserv_decl = DECL_INSN_RESERV (decl); - curr_ainsn->important_p = FALSE; + curr_ainsn->important_p = false; curr_ainsn->next_ainsn = NULL; if (prev_ainsn == NULL) first_ainsn = curr_ainsn; @@ -7897,7 +7897,7 @@ output_insn_code_cases (void (*output_automata_list_code) { decl = description->decls [i]; if (decl->mode == dm_insn_reserv) - DECL_INSN_RESERV (decl)->processed_p = FALSE; + DECL_INSN_RESERV (decl)->processed_p = false; } for (i = 0; i < description->decls_num; i++) { @@ -7912,7 +7912,7 @@ output_insn_code_cases (void (*output_automata_list_code) && (DECL_INSN_RESERV (decl2)->important_automata_list == DECL_INSN_RESERV (decl)->important_automata_list)) { - DECL_INSN_RESERV (decl2)->processed_p = TRUE; + DECL_INSN_RESERV (decl2)->processed_p = true; fprintf (output_file, " case %d: /* %s */\n", DECL_INSN_RESERV (decl2)->insn_num, DECL_INSN_RESERV (decl2)->name); @@ -8247,9 +8247,9 @@ output_internal_dead_lock_func (void) output_dead_lock_vect_name (output_file, automaton); fprintf (output_file, " [%s->", CHIP_PARAMETER_NAME); output_chip_member_name (output_file, automaton); - fprintf (output_file, "])\n return 1/* TRUE */;\n"); + fprintf (output_file, "])\n return 1 /* TRUE */;\n"); } - fprintf (output_file, " return 0/* FALSE */;\n}\n\n"); + fprintf (output_file, " return 0 /* FALSE */;\n}\n\n"); } /* The function outputs PHR interface function `state_dead_lock_p'. */ @@ -9382,7 +9382,7 @@ form_important_insn_automata_lists (void) for (ainsn = arc->insn; ainsn != NULL; ainsn = ainsn->next_same_reservs_insn) - ainsn->important_p = TRUE; + ainsn->important_p = true; } } } diff --git a/gcc/generic-match-head.cc b/gcc/generic-match-head.cc index ddaf22f21794..f40a35c48a6e 100644 --- a/gcc/generic-match-head.cc +++ b/gcc/generic-match-head.cc @@ -127,10 +127,11 @@ bitwise_equal_p (tree expr1, tree expr2) The types can differ through nop conversions. */ static inline bool -bitwise_inverted_equal_p (tree expr1, tree expr2) +bitwise_inverted_equal_p (tree expr1, tree expr2, bool &wascmp) { STRIP_NOPS (expr1); STRIP_NOPS (expr2); + wascmp = false; if (expr1 == expr2) return false; if (!tree_nop_conversion_p (TREE_TYPE (expr1), TREE_TYPE (expr2))) @@ -150,6 +151,7 @@ bitwise_inverted_equal_p (tree expr1, tree expr2) { tree op10 = TREE_OPERAND (expr1, 0); tree op20 = TREE_OPERAND (expr2, 0); + wascmp = true; if (!operand_equal_p (op10, op20)) return false; tree op11 = TREE_OPERAND (expr1, 1); diff --git a/gcc/gengtype-state.cc b/gcc/gengtype-state.cc index 4bba37f718f2..673c0613298b 100644 --- a/gcc/gengtype-state.cc +++ b/gcc/gengtype-state.cc @@ -2494,7 +2494,7 @@ read_state_files_list (void) build_headers = XCNEWVEC (const char *, num_build_headers); for (i = 0; i < (int) num_gt_files; i++) { - bool issrcfile = FALSE; + bool issrcfile = false; t0 = t1 = t2 = NULL; t0 = peek_state_token (0); t1 = peek_state_token (1); diff --git a/gcc/gengtype.cc b/gcc/gengtype.cc index 49ddba684af5..3db0a9b07691 100644 --- a/gcc/gengtype.cc +++ b/gcc/gengtype.cc @@ -5200,8 +5200,8 @@ main (int argc, char **argv) this_file = input_file_by_name (__FILE__); system_h_file = input_file_by_name ("system.h"); /* Set the scalar_is_char union number for predefined scalar types. */ - scalar_nonchar.u.scalar_is_char = FALSE; - scalar_char.u.scalar_is_char = TRUE; + scalar_nonchar.u.scalar_is_char = false; + scalar_char.u.scalar_is_char = true; parse_program_options (argc, argv); diff --git a/gcc/genmatch.cc b/gcc/genmatch.cc index 2302f2a7ff09..a1925a747a73 100644 --- a/gcc/genmatch.cc +++ b/gcc/genmatch.cc @@ -29,6 +29,7 @@ along with GCC; see the file COPYING3. If not see #include "hash-table.h" #include "hash-set.h" #include "is-a.h" +#include "ordered-hash-map.h" /* Stubs for GGC referenced through instantiations triggered by hash-map. */ @@ -216,10 +217,56 @@ fp_decl_done (FILE *f, const char *trailer) fprintf (header_file, "%s;", trailer); } +/* Line numbers for use by indirect line directives. */ +static vec dbg_line_numbers; + +static void +write_header_declarations (bool gimple, FILE *f) +{ + fprintf (f, "\nextern void\n%s_dump_logs (const char *file1, int line1_id, " + "const char *file2, int line2, bool simplify);\n", + gimple ? "gimple" : "generic"); +} + +static void +define_dump_logs (bool gimple, FILE *f) +{ + if (dbg_line_numbers.is_empty ()) + return; + + fprintf (f , "void\n%s_dump_logs (const char *file1, int line1_id, " + "const char *file2, int line2, bool simplify)\n{\n", + gimple ? "gimple" : "generic"); + + fprintf_indent (f, 2, "static int dbg_line_numbers[%d] = {", + dbg_line_numbers.length ()); + + for (unsigned i = 0; i < dbg_line_numbers.length () - 1; i++) + { + if (i % 20 == 0) + fprintf (f, "\n\t"); + + fprintf (f, "%d, ", dbg_line_numbers[i]); + } + fprintf (f, "%d\n };\n\n", dbg_line_numbers.last ()); + + + fprintf_indent (f, 2, "fprintf (dump_file, \"%%s " + "%%s:%%d, %%s:%%d\\n\",\n"); + fprintf_indent (f, 10, "simplify ? \"Applying pattern\" : " + "\"Matching expression\", file1, " + "dbg_line_numbers[line1_id], file2, line2);"); + + fprintf (f, "\n}\n\n"); +} + static void output_line_directive (FILE *f, location_t location, - bool dumpfile = false, bool fnargs = false) + bool dumpfile = false, bool fnargs = false, + bool indirect_line_numbers = false) { + typedef pair_hash> location_hash; + static hash_map loc_id_map; const line_map_ordinary *map; linemap_resolve_location (line_table, location, LRK_SPELLING_LOCATION, &map); expanded_location loc = linemap_expand_location (line_table, map, location); @@ -238,7 +285,23 @@ output_line_directive (FILE *f, location_t location, ++file; if (fnargs) - fprintf (f, "\"%s\", %d", file, loc.line); + { + if (indirect_line_numbers) + { + bool existed; + int &loc_id = loc_id_map.get_or_insert ( + std::make_pair (file, loc.line), &existed); + if (!existed) + { + loc_id = dbg_line_numbers.length (); + dbg_line_numbers.safe_push (loc.line); + } + + fprintf (f, "\"%s\", %d", file, loc_id); + } + else + fprintf (f, "\"%s\", %d", file, loc.line); + } else fprintf (f, "%s:%d", file, loc.line); } @@ -1684,7 +1747,7 @@ struct sinfo_hashmap_traits : simple_hashmap_traits, template static inline void remove (T &) {} }; -typedef hash_map +typedef ordered_hash_map sinfo_map_t; /* Current simplifier ID we are processing during insertion into the @@ -3374,20 +3437,19 @@ dt_operand::gen (FILE *f, int indent, bool gimple, int depth) } } -/* Emit a fprintf to the debug file to the file F, with the INDENT from +/* Emit a logging call to the debug file to the file F, with the INDENT from either the RESULT location or the S's match location if RESULT is null. */ static void -emit_debug_printf (FILE *f, int indent, class simplify *s, operand *result) +emit_logging_call (FILE *f, int indent, class simplify *s, operand *result, + bool gimple) { fprintf_indent (f, indent, "if (UNLIKELY (debug_dump)) " - "fprintf (dump_file, \"%s ", - s->kind == simplify::SIMPLIFY - ? "Applying pattern" : "Matching expression"); - fprintf (f, "%%s:%%d, %%s:%%d\\n\", "); + "%s_dump_logs (", gimple ? "gimple" : "generic"); output_line_directive (f, - result ? result->location : s->match->location, true, - true); - fprintf (f, ", __FILE__, __LINE__);\n"); + result ? result->location : s->match->location, + true, true, true); + fprintf (f, ", __FILE__, __LINE__, %s);\n", + s->kind == simplify::SIMPLIFY ? "true" : "false"); } /* Generate code for the '(if ...)', '(with ..)' and actual transform @@ -3523,7 +3585,7 @@ dt_simplify::gen_1 (FILE *f, int indent, bool gimple, operand *result) if (!result) { /* If there is no result then this is a predicate implementation. */ - emit_debug_printf (f, indent, s, result); + emit_logging_call (f, indent, s, result, gimple); fprintf_indent (f, indent, "return true;\n"); } else if (gimple) @@ -3614,7 +3676,7 @@ dt_simplify::gen_1 (FILE *f, int indent, bool gimple, operand *result) } else gcc_unreachable (); - emit_debug_printf (f, indent, s, result); + emit_logging_call (f, indent, s, result, gimple); fprintf_indent (f, indent, "return true;\n"); } else /* GENERIC */ @@ -3669,7 +3731,7 @@ dt_simplify::gen_1 (FILE *f, int indent, bool gimple, operand *result) } if (is_predicate) { - emit_debug_printf (f, indent, s, result); + emit_logging_call (f, indent, s, result, gimple); fprintf_indent (f, indent, "return true;\n"); } else @@ -3737,7 +3799,7 @@ dt_simplify::gen_1 (FILE *f, int indent, bool gimple, operand *result) i); } } - emit_debug_printf (f, indent, s, result); + emit_logging_call (f, indent, s, result, gimple); fprintf_indent (f, indent, "return _r;\n"); } } @@ -3990,7 +4052,7 @@ decision_tree::gen (vec &files, bool gimple) } fprintf (stderr, "removed %u duplicate tails\n", rcnt); - for (unsigned n = 1; n <= 5; ++n) + for (unsigned n = 1; n <= 7; ++n) { bool has_kids_p = false; @@ -5446,6 +5508,7 @@ main (int argc, char **argv) parts.quick_push (stdout); write_header (stdout, s_include_file); write_header_includes (gimple, stdout); + write_header_declarations (gimple, stdout); } else { @@ -5459,6 +5522,7 @@ main (int argc, char **argv) fprintf (header_file, "#ifndef GCC_GIMPLE_MATCH_AUTO_H\n" "#define GCC_GIMPLE_MATCH_AUTO_H\n"); write_header_includes (gimple, header_file); + write_header_declarations (gimple, header_file); } /* Go over all predicates defined with patterns and perform @@ -5501,6 +5565,8 @@ main (int argc, char **argv) dt.gen (parts, gimple); + define_dump_logs (gimple, choose_output (parts)); + for (FILE *f : parts) { fprintf (f, "#pragma GCC diagnostic pop\n"); diff --git a/gcc/genrecog.cc b/gcc/genrecog.cc index 04a5533ca4b2..6dd375da5e35 100644 --- a/gcc/genrecog.cc +++ b/gcc/genrecog.cc @@ -4619,7 +4619,6 @@ print_nonbool_test (output_state *os, const rtx_test &test) printf ("SUBREG_BYTE ("); print_test_rtx (os, test); printf (")"); - printf (".to_constant ()"); break; case rtx_test::WIDE_INT_FIELD: diff --git a/gcc/gensupport.cc b/gcc/gensupport.cc index b2feb03363ac..f7164b3214d2 100644 --- a/gcc/gensupport.cc +++ b/gcc/gensupport.cc @@ -640,7 +640,7 @@ public: name.assign (ns, len); if (numeric) - idx = std::stoi (name); + idx = strtol (name.c_str (), (char **)NULL, 10); } /* Adds a character to the end of the string. */ diff --git a/gcc/gimple-array-bounds.cc b/gcc/gimple-array-bounds.cc index e04c8e29d5af..381ccb64b001 100644 --- a/gcc/gimple-array-bounds.cc +++ b/gcc/gimple-array-bounds.cc @@ -799,7 +799,7 @@ array_bounds_checker::check_array_bounds (tree *tp, int *walk_subtree, else location = gimple_location (wi->stmt); - *walk_subtree = TRUE; + *walk_subtree = true; bool warned = false; array_bounds_checker *checker = (array_bounds_checker *) wi->info; diff --git a/gcc/gimple-harden-conditionals.cc b/gcc/gimple-harden-conditionals.cc index 2e5a42e9e71b..a299b984375c 100644 --- a/gcc/gimple-harden-conditionals.cc +++ b/gcc/gimple-harden-conditionals.cc @@ -235,6 +235,7 @@ insert_check_and_trap (location_t loc, gimple_stmt_iterator *gsip, gsi_insert_before (gsip, cond, GSI_SAME_STMT); basic_block trp = create_empty_bb (chk); + trp->count = profile_count::zero (); gimple_stmt_iterator gsit = gsi_after_labels (trp); gcall *trap = gimple_build_call (builtin_decl_explicit (BUILT_IN_TRAP), 0); diff --git a/gcc/gimple-low.cc b/gcc/gimple-low.cc index e6f04f234dfa..6abc286d2160 100644 --- a/gcc/gimple-low.cc +++ b/gcc/gimple-low.cc @@ -717,6 +717,10 @@ lower_stmt (gimple_stmt_iterator *gsi, struct lower_data *data) gsi_next (gsi); return; + case GIMPLE_OMP_STRUCTURED_BLOCK: + /* These are supposed to be removed already in OMP lowering. */ + gcc_unreachable (); + case GIMPLE_NOP: case GIMPLE_ASM: case GIMPLE_ASSIGN: diff --git a/gcc/gimple-match-exports.cc b/gcc/gimple-match-exports.cc index 7aeb4ddb1524..b36027b0bad7 100644 --- a/gcc/gimple-match-exports.cc +++ b/gcc/gimple-match-exports.cc @@ -60,6 +60,12 @@ extern bool gimple_simplify (gimple_match_op *, gimple_seq *, tree (*)(tree), code_helper, tree, tree, tree, tree, tree); extern bool gimple_simplify (gimple_match_op *, gimple_seq *, tree (*)(tree), code_helper, tree, tree, tree, tree, tree, tree); +extern bool gimple_simplify (gimple_match_op *, gimple_seq *, tree (*)(tree), + code_helper, tree, tree, tree, tree, tree, tree, + tree); +extern bool gimple_simplify (gimple_match_op *, gimple_seq *, tree (*)(tree), + code_helper, tree, tree, tree, tree, tree, tree, + tree, tree); /* Functions that are needed by gimple-match but that are exported and used in other places in the compiler. */ @@ -89,6 +95,8 @@ static bool gimple_resimplify2 (gimple_seq *, gimple_match_op *, tree (*)(tree)) static bool gimple_resimplify3 (gimple_seq *, gimple_match_op *, tree (*)(tree)); static bool gimple_resimplify4 (gimple_seq *, gimple_match_op *, tree (*)(tree)); static bool gimple_resimplify5 (gimple_seq *, gimple_match_op *, tree (*)(tree)); +static bool gimple_resimplify6 (gimple_seq *, gimple_match_op *, tree (*)(tree)); +static bool gimple_resimplify7 (gimple_seq *, gimple_match_op *, tree (*)(tree)); /* Match and simplify the toplevel valueized operation THIS. Replaces THIS with a simplified and/or canonicalized result and @@ -109,6 +117,10 @@ gimple_match_op::resimplify (gimple_seq *seq, tree (*valueize)(tree)) return gimple_resimplify4 (seq, this, valueize); case 5: return gimple_resimplify5 (seq, this, valueize); + case 6: + return gimple_resimplify6 (seq, this, valueize); + case 7: + return gimple_resimplify7 (seq, this, valueize); default: gcc_unreachable (); } @@ -146,7 +158,14 @@ convert_conditional_op (gimple_match_op *orig_op, if (ifn == IFN_LAST) return false; unsigned int num_ops = orig_op->num_ops; - new_op->set_op (as_combined_fn (ifn), orig_op->type, num_ops + 2); + unsigned int num_cond_ops = 2; + if (orig_op->cond.len) + { + /* Add the length and bias parameters. */ + ifn = get_len_internal_fn (ifn); + num_cond_ops = 4; + } + new_op->set_op (as_combined_fn (ifn), orig_op->type, num_ops + num_cond_ops); new_op->ops[0] = orig_op->cond.cond; for (unsigned int i = 0; i < num_ops; ++i) new_op->ops[i + 1] = orig_op->ops[i]; @@ -155,6 +174,11 @@ convert_conditional_op (gimple_match_op *orig_op, else_value = targetm.preferred_else_value (ifn, orig_op->type, num_ops, orig_op->ops); new_op->ops[num_ops + 1] = else_value; + if (orig_op->cond.len) + { + new_op->ops[num_ops + 2] = orig_op->cond.len; + new_op->ops[num_ops + 3] = orig_op->cond.bias; + } return true; } /* Helper for gimple_simplify valueizing OP using VALUEIZE and setting @@ -219,7 +243,9 @@ build_call_internal (internal_fn fn, gimple_match_op *res_op) res_op->op_or_null (1), res_op->op_or_null (2), res_op->op_or_null (3), - res_op->op_or_null (4)); + res_op->op_or_null (4), + res_op->op_or_null (5), + res_op->op_or_null (6)); } /* RES_OP is the result of a simplification. If it is conditional, @@ -319,6 +345,7 @@ try_conditional_simplification (internal_fn ifn, gimple_match_op *res_op, { code_helper op; tree_code code = conditional_internal_fn_code (ifn); + int len_index = internal_fn_len_index (ifn); if (code != ERROR_MARK) op = code; else @@ -330,12 +357,19 @@ try_conditional_simplification (internal_fn ifn, gimple_match_op *res_op, } unsigned int num_ops = res_op->num_ops; + /* num_cond_ops = 2 for COND_ADD (MASK and ELSE) + wheras num_cond_ops = 4 for COND_LEN_ADD (MASK, ELSE, LEN and BIAS). */ + unsigned int num_cond_ops = len_index < 0 ? 2 : 4; + tree else_value + = len_index < 0 ? res_op->ops[num_ops - 1] : res_op->ops[num_ops - 3]; + tree len = len_index < 0 ? NULL_TREE : res_op->ops[num_ops - 2]; + tree bias = len_index < 0 ? NULL_TREE : res_op->ops[num_ops - 1]; gimple_match_op cond_op (gimple_match_cond (res_op->ops[0], - res_op->ops[num_ops - 1]), - op, res_op->type, num_ops - 2); + else_value, len, bias), + op, res_op->type, num_ops - num_cond_ops); memcpy (cond_op.ops, res_op->ops + 1, (num_ops - 1) * sizeof *cond_op.ops); - switch (num_ops - 2) + switch (num_ops - num_cond_ops) { case 1: if (!gimple_resimplify1 (seq, &cond_op, valueize)) @@ -717,7 +751,7 @@ gimple_extract (gimple *stmt, gimple_match_op *res_op, /* ??? This way we can't simplify calls with side-effects. */ if (gimple_call_lhs (stmt) != NULL_TREE && gimple_call_num_args (stmt) >= 1 - && gimple_call_num_args (stmt) <= 5) + && gimple_call_num_args (stmt) <= 7) { combined_fn cfn; if (gimple_call_internal_p (stmt)) @@ -1145,6 +1179,83 @@ gimple_resimplify5 (gimple_seq *seq, gimple_match_op *res_op, return canonicalized; } +/* Helper that matches and simplifies the toplevel result from + a gimple_simplify run (where we don't want to build + a stmt in case it's used in in-place folding). Replaces + RES_OP with a simplified and/or canonicalized result and + returns whether any change was made. */ + +static bool +gimple_resimplify6 (gimple_seq *seq, gimple_match_op *res_op, + tree (*valueize)(tree)) +{ + /* No constant folding is defined for six-operand functions. */ + + /* Canonicalize operand order. */ + bool canonicalized = false; + int argno = first_commutative_argument (res_op->code, res_op->type); + if (argno >= 0 + && tree_swap_operands_p (res_op->ops[argno], res_op->ops[argno + 1])) + { + std::swap (res_op->ops[argno], res_op->ops[argno + 1]); + canonicalized = true; + } + + gimple_match_op res_op2 (*res_op); + if (gimple_simplify (&res_op2, seq, valueize, + res_op->code, res_op->type, + res_op->ops[0], res_op->ops[1], res_op->ops[2], + res_op->ops[3], res_op->ops[4], res_op->ops[5])) + { + *res_op = res_op2; + return true; + } + + if (maybe_resimplify_conditional_op (seq, res_op, valueize)) + return true; + + return canonicalized; +} + +/* Helper that matches and simplifies the toplevel result from + a gimple_simplify run (where we don't want to build + a stmt in case it's used in in-place folding). Replaces + RES_OP with a simplified and/or canonicalized result and + returns whether any change was made. */ + +static bool +gimple_resimplify7 (gimple_seq *seq, gimple_match_op *res_op, + tree (*valueize)(tree)) +{ + /* No constant folding is defined for seven-operand functions. */ + + /* Canonicalize operand order. */ + bool canonicalized = false; + int argno = first_commutative_argument (res_op->code, res_op->type); + if (argno >= 0 + && tree_swap_operands_p (res_op->ops[argno], res_op->ops[argno + 1])) + { + std::swap (res_op->ops[argno], res_op->ops[argno + 1]); + canonicalized = true; + } + + gimple_match_op res_op2 (*res_op); + if (gimple_simplify (&res_op2, seq, valueize, + res_op->code, res_op->type, + res_op->ops[0], res_op->ops[1], res_op->ops[2], + res_op->ops[3], res_op->ops[4], res_op->ops[5], + res_op->ops[6])) + { + *res_op = res_op2; + return true; + } + + if (maybe_resimplify_conditional_op (seq, res_op, valueize)) + return true; + + return canonicalized; +} + /* Return a canonical form for CODE when operating on TYPE. The idea is to remove redundant ways of representing the same operation so that code_helpers can be hashed and compared for equality. diff --git a/gcc/gimple-match-head.cc b/gcc/gimple-match-head.cc index a097a494c393..ea6387a1099d 100644 --- a/gcc/gimple-match-head.cc +++ b/gcc/gimple-match-head.cc @@ -267,8 +267,8 @@ gimple_bitwise_equal_p (tree expr1, tree expr2, tree (*valueize) (tree)) /* Return true if EXPR1 and EXPR2 have the bitwise opposite value, but not necessarily same type. The types can differ through nop conversions. */ -#define bitwise_inverted_equal_p(expr1, expr2) \ - gimple_bitwise_inverted_equal_p (expr1, expr2, valueize) +#define bitwise_inverted_equal_p(expr1, expr2, wascmp) \ + gimple_bitwise_inverted_equal_p (expr1, expr2, wascmp, valueize) bool gimple_bit_not_with_nop (tree, tree *, tree (*) (tree)); @@ -277,8 +277,9 @@ bool gimple_maybe_cmp (tree, tree *, tree (*) (tree)); /* Helper function for bitwise_equal_p macro. */ static inline bool -gimple_bitwise_inverted_equal_p (tree expr1, tree expr2, tree (*valueize) (tree)) +gimple_bitwise_inverted_equal_p (tree expr1, tree expr2, bool &wascmp, tree (*valueize) (tree)) { + wascmp = false; if (expr1 == expr2) return false; if (!tree_nop_conversion_p (TREE_TYPE (expr1), TREE_TYPE (expr2))) @@ -331,6 +332,7 @@ gimple_bitwise_inverted_equal_p (tree expr1, tree expr2, tree (*valueize) (tree) tree op21 = do_valueize (valueize, gimple_assign_rhs2 (a2)); if (!operand_equal_p (op11, op21)) return false; + wascmp = true; if (invert_tree_comparison (gimple_assign_rhs_code (a1), HONOR_NANS (op10)) == gimple_assign_rhs_code (a2)) diff --git a/gcc/gimple-match.h b/gcc/gimple-match.h index b20585dca4b0..bec3ff42e3ec 100644 --- a/gcc/gimple-match.h +++ b/gcc/gimple-match.h @@ -34,6 +34,7 @@ public: /* Build an unconditional op. */ gimple_match_cond (uncond) : cond (NULL_TREE), else_value (NULL_TREE) {} gimple_match_cond (tree, tree); + gimple_match_cond (tree, tree, tree, tree); gimple_match_cond any_else () const; @@ -44,6 +45,13 @@ public: /* The value to use when the condition is false. This is NULL_TREE if the operation is unconditional or if the value doesn't matter. */ tree else_value; + + /* The length and bias parameters to be applied to a vector operation, + so that the condition is forced to false when the element index is + >= LEN + BIAS. These are NULL_TREE if the operation isn't applied + to vectors, or if no such length limit is in use. */ + tree len; + tree bias; }; inline @@ -52,6 +60,12 @@ gimple_match_cond::gimple_match_cond (tree cond_in, tree else_value_in) { } +inline +gimple_match_cond::gimple_match_cond (tree cond_in, tree else_value_in, + tree len_in, tree bias_in) + : cond (cond_in), else_value (else_value_in), len (len_in), bias (bias_in) +{} + /* Return a gimple_match_cond with the same condition but with an arbitrary ELSE_VALUE. */ @@ -93,7 +107,7 @@ public: bool resimplify (gimple_seq *, tree (*)(tree)); /* The maximum value of NUM_OPS. */ - static const unsigned int MAX_NUM_OPS = 5; + static const unsigned int MAX_NUM_OPS = 7; /* The conditions under which the operation is performed, and the value to use as a fallback. */ diff --git a/gcc/gimple-pretty-print.cc b/gcc/gimple-pretty-print.cc index 8db221f65fe7..82017b92e89e 100644 --- a/gcc/gimple-pretty-print.cc +++ b/gcc/gimple-pretty-print.cc @@ -1896,7 +1896,7 @@ dump_gimple_omp_sections (pretty_printer *buffer, const gomp_sections *gs, } } -/* Dump a GIMPLE_OMP_{MASTER,ORDERED,SECTION} tuple on the +/* Dump a GIMPLE_OMP_{MASTER,ORDERED,SECTION,STRUCTURED_BLOCK} tuple on the pretty_printer BUFFER. */ static void @@ -1916,6 +1916,9 @@ dump_gimple_omp_block (pretty_printer *buffer, const gimple *gs, int spc, case GIMPLE_OMP_SECTION: pp_string (buffer, "#pragma omp section"); break; + case GIMPLE_OMP_STRUCTURED_BLOCK: + pp_string (buffer, "#pragma omp __structured_block"); + break; default: gcc_unreachable (); } @@ -2801,6 +2804,7 @@ pp_gimple_stmt_1 (pretty_printer *buffer, const gimple *gs, int spc, case GIMPLE_OMP_MASTER: case GIMPLE_OMP_SECTION: + case GIMPLE_OMP_STRUCTURED_BLOCK: dump_gimple_omp_block (buffer, gs, spc, flags); break; diff --git a/gcc/gimple-range-fold.cc b/gcc/gimple-range-fold.cc index 7fa5a27cb12b..8ebff7f59804 100644 --- a/gcc/gimple-range-fold.cc +++ b/gcc/gimple-range-fold.cc @@ -953,7 +953,7 @@ fold_using_range::range_of_phi (vrange &r, gphi *phi, fur_source &src) { if (dump_file && (dump_flags & TDF_DETAILS)) { - fprintf (dump_file, " Loops range found for "); + fprintf (dump_file, "Loops range found for "); print_generic_expr (dump_file, phi_def, TDF_SLIM); fprintf (dump_file, ": "); loop_range.dump (dump_file); @@ -975,9 +975,9 @@ fold_using_range::range_of_phi (vrange &r, gphi *phi, fur_source &src) { if (dump_file && (dump_flags & TDF_DETAILS)) { - fprintf (dump_file, " PHI group range found for "); + fprintf (dump_file, "PHI GROUP query for "); print_generic_expr (dump_file, phi_def, TDF_SLIM); - fprintf (dump_file, ": "); + fprintf (dump_file, " found : "); g->range ().dump (dump_file); fprintf (dump_file, " and adjusted original range from :"); r.dump (dump_file); diff --git a/gcc/gimple-range-phi.cc b/gcc/gimple-range-phi.cc index ffb4691d06bf..9884a0ebbb02 100644 --- a/gcc/gimple-range-phi.cc +++ b/gcc/gimple-range-phi.cc @@ -79,39 +79,33 @@ phi_analyzer &phi_analysis () phi_group::phi_group (const phi_group &g) { m_group = g.m_group; - m_initial_value = g.m_initial_value; - m_initial_edge = g.m_initial_edge; m_modifier = g.m_modifier; m_modifier_op = g.m_modifier_op; m_vr = g.m_vr; } -// Create a new phi_group with members BM, initialvalue INIT_VAL, modifier -// statement MOD, and resolve values using query Q. -// Calculate the range for the gropup if possible, otherwise set it to -// VARYING. +// Create a new phi_group with members BM, initial range INIT_RANGE, modifier +// statement MOD on edge MOD_EDGE, and resolve values using query Q. Calculate +// the range for the group if possible, otherwise set it to VARYING. -phi_group::phi_group (bitmap bm, tree init_val, edge e, gimple *mod, +phi_group::phi_group (bitmap bm, irange &init_range, gimple *mod, range_query *q) { // we dont expect a modifer and no inital value, so trap to have a look. // perhaps they are dead cycles and we can just used UNDEFINED. - gcc_checking_assert (init_val); + gcc_checking_assert (!init_range.undefined_p ()); + gcc_checking_assert (!init_range.varying_p ()); m_modifier_op = is_modifier_p (mod, bm); m_group = bm; - m_initial_value = init_val; - m_initial_edge = e; + m_vr = init_range; m_modifier = mod; - if (q->range_on_edge (m_vr, m_initial_edge, m_initial_value)) - { - // No modifier means the initial range is the full range. - // Otherwise try to calculate a range. - if (!m_modifier_op || calculate_using_modifier (q)) - return; - } + // No modifier means the initial range is the full range. + // Otherwise try to calculate a range. + if (!m_modifier_op || calculate_using_modifier (q)) + return; // Couldn't calculate a range, set to varying. - m_vr.set_varying (TREE_TYPE (init_val)); + m_vr.set_varying (init_range.type ()); } // Return 0 if S is not a modifier statment for group members BM. @@ -151,27 +145,29 @@ phi_group::calculate_using_modifier (range_query *q) else return false; + // Examine modifier and run 10 iterations to see if it convergences. + // The constructor initilaized m_vr to the initial value already. + const unsigned num_iter = 10; + int_range_max nv; + int_range_max iter_value = m_vr; + for (unsigned x = 0; x < num_iter; x++) + { + if (!fold_range (nv, m_modifier, iter_value, q)) + break; + // If union does nothing, then we have convergence. + if (!iter_value.union_ (nv)) + { + if (iter_value.varying_p ()) + break; + m_vr = iter_value; + return true; + } + } + // If we can resolve the range using relations, use that range. - if (refine_using_relation (k, q)) + if (refine_using_relation (k)) return true; - // If the initial value is undefined, do not calculate a range. - if (m_vr.undefined_p ()) - return false; - - // Examine modifier and run X iterations to see if it convergences. - // The constructor initilaized m_vr to the initial value already. - int_range_max nv; - for (unsigned x = 0; x< 10; x++) - { - if (!fold_range (nv, m_modifier, m_vr, q)) - return false; - // If they are equal, then we have convergence. - if (nv == m_vr) - return true; - // Update range and try again. - m_vr.union_ (nv); - } // Never converged, so bail for now. we could examine the pattern // from m_initial to m_vr as an extension Especially if we had a way // to project the actual number of iterations (SCEV?) @@ -185,34 +181,29 @@ phi_group::calculate_using_modifier (range_query *q) // IF the modifier statement has a relation K between the modifier and the // PHI member in it, we can project a range based on that. -// Use range_query Q to resolve values. // ie, a_2 = PHI <0, a_3> and a_3 = a_2 + 1 // if the relation a_3 > a_2 is present, the know the range is [0, +INF] +// m_vr contains the initial value for the PHI range. bool -phi_group::refine_using_relation (relation_kind k, range_query *q) +phi_group::refine_using_relation (relation_kind k) { if (k == VREL_VARYING) return false; - tree type = TREE_TYPE (m_initial_value); + tree type = m_vr.type (); // If the type wraps, then relations dont tell us much. if (TYPE_OVERFLOW_WRAPS (type)) return false; + int_range<2> type_range; + type_range.set_varying (type); switch (k) { case VREL_LT: case VREL_LE: { // Value always decreases. - int_range<2> lb; - int_range<2> ub; - if (!q->range_on_edge (ub, m_initial_edge, m_initial_value)) - break; - if (ub.undefined_p ()) - return false; - lb.set_varying (type); - m_vr.set (type, lb.lower_bound (), ub.upper_bound ()); + m_vr.set (type, type_range.lower_bound (), m_vr.upper_bound ()); return true; } @@ -220,14 +211,7 @@ phi_group::refine_using_relation (relation_kind k, range_query *q) case VREL_GE: { // Value always increases. - int_range<2> lb; - int_range<2> ub; - if (!q->range_on_edge (lb, m_initial_edge, m_initial_value)) - break; - if (lb.undefined_p ()) - return false; - ub.set_varying (type); - m_vr.set (type, lb.lower_bound (), ub.upper_bound ()); + m_vr.set (type, m_vr.lower_bound (), type_range.upper_bound ()); return true; } @@ -250,34 +234,20 @@ phi_group::dump (FILE *f) { unsigned i; bitmap_iterator bi; - fprintf (f, "PHI GROUP <"); + fprintf (f, "PHI GROUP < "); EXECUTE_IF_SET_IN_BITMAP (m_group, 0, i, bi) { print_generic_expr (f, ssa_name (i), TDF_SLIM); fputc (' ',f); } - - fprintf (f, ">\n - Initial value : "); - if (m_initial_value) - { - if (TREE_CODE (m_initial_value) == SSA_NAME) - print_gimple_stmt (f, SSA_NAME_DEF_STMT (m_initial_value), 0, TDF_SLIM); - else - print_generic_expr (f, m_initial_value, TDF_SLIM); - fprintf (f, " on edge %d->%d", m_initial_edge->src->index, - m_initial_edge->dest->index); - } - else - fprintf (f, "NONE"); - fprintf (f, "\n - Modifier : "); + fprintf (f, "> : range : "); + m_vr.dump (f); + fprintf (f, "\n Modifier : "); if (m_modifier) print_gimple_stmt (f, m_modifier, 0, TDF_SLIM); else fprintf (f, "NONE\n"); - fprintf (f, " - Range : "); - m_vr.dump (f); - fputc ('\n', f); } // ------------------------------------------------------------------------- @@ -344,9 +314,10 @@ phi_analyzer::operator[] (tree name) process_phi (as_a (SSA_NAME_DEF_STMT (name))); if (bitmap_bit_p (m_simple, v)) return NULL; - // If m_simple bit isn't set, then process_phi allocated the table - // and should have a group. - gcc_checking_assert (v < m_tab.length ()); + // If m_simple bit isn't set, and process_phi didn't allocated the table + // no group was created, so return NULL. + if (v >= m_tab.length ()) + return NULL; } return m_tab[v]; } @@ -363,6 +334,7 @@ phi_analyzer::process_phi (gphi *phi) unsigned x; m_work.truncate (0); m_work.safe_push (gimple_phi_result (phi)); + unsigned phi_count = 1; bitmap_clear (m_current); // We can only have 2 externals: an initial value and a modifier. @@ -370,17 +342,18 @@ phi_analyzer::process_phi (gphi *phi) unsigned m_num_extern = 0; tree m_external[2]; edge m_ext_edge[2]; + int_range_max init_range; + init_range.set_undefined (); while (m_work.length () > 0) { tree phi_def = m_work.pop (); gphi *phi_stmt = as_a (SSA_NAME_DEF_STMT (phi_def)); - // if the phi is already in a cycle, its a complex situation, so revert - // to simple. + // if the phi is already in a different cycle, we don't try to merge. if (group (phi_def)) { cycle_p = false; - continue; + break; } bitmap_set_bit (m_current, SSA_NAME_VERSION (phi_def)); // Process the args. @@ -403,36 +376,44 @@ phi_analyzer::process_phi (gphi *phi) break; } // Check if its a PHI to examine. - // *FIX* Will miss initial values that originate from a PHI. gimple *arg_stmt = SSA_NAME_DEF_STMT (arg); if (arg_stmt && is_a (arg_stmt)) { + phi_count++; m_work.safe_push (arg); continue; } + // More than 2 outside names is too complicated. + if (m_num_extern >= 2) + { + cycle_p = false; + break; + } + m_external[m_num_extern] = arg; + m_ext_edge[m_num_extern++] = gimple_phi_arg_edge (phi_stmt, x); } - // Other non-ssa names that arent constants are not understood - // and terminate analysis. - else if (code != INTEGER_CST && code != REAL_CST) + else if (code == INTEGER_CST) { - cycle_p = false; - continue; + // Constants are just added to the initialization value. + int_range<1> val (TREE_TYPE (arg), wi::to_wide (arg), + wi::to_wide (arg)); + init_range.union_ (val); } - // More than 2 outside names/CONST is too complicated. - if (m_num_extern >= 2) + else { + // Everything else terminates the cycle. cycle_p = false; break; } - - m_external[m_num_extern] = arg; - m_ext_edge[m_num_extern++] = gimple_phi_arg_edge (phi_stmt, x); } } - // If there are no names in the group, we're done. - if (bitmap_empty_p (m_current)) + // If there are less than 2 names, just return. This PHI may be included + // by another PHI, making it simple or a group of one will prevent a larger + // group from being formed. + if (phi_count < 2) return; + gcc_checking_assert (!bitmap_empty_p (m_current)); phi_group *g = NULL; if (cycle_p) @@ -459,14 +440,43 @@ phi_analyzer::process_phi (gphi *phi) valid = false; init_idx = x; } - if (valid) + int_range_max init_sym; + // If there is an symbolic initializer as well, include it here. + if (valid && init_idx != -1) + { + if (m_global.range_on_edge (init_sym, m_ext_edge[init_idx], + m_external[init_idx])) + init_range.union_ (init_sym); + else + valid = false; + } + if (valid && !init_range.varying_p () && !init_range.undefined_p ()) { // Try to create a group based on m_current. If a result comes back // with a range that isn't varying, create the group. - phi_group cyc (m_current, m_external[init_idx], - m_ext_edge[init_idx], mod, &m_global); + phi_group cyc (m_current, init_range, mod, &m_global); if (!cyc.range ().varying_p ()) - g = new phi_group (cyc); + { + g = new phi_group (cyc); + if (dump_file && (dump_flags & TDF_DETAILS)) + { + fprintf (dump_file, "PHI ANALYZER : New "); + g->dump (dump_file); + fprintf (dump_file," Initial range was "); + init_range.dump (dump_file); + if (init_idx != -1) + { + fprintf (dump_file, " including symbolic "); + print_generic_expr (dump_file, m_external[init_idx], + TDF_SLIM); + fprintf (dump_file, " on edge %d->%d with range ", + m_ext_edge[init_idx]->src->index, + m_ext_edge[init_idx]->dest->index); + init_sym.dump (dump_file); + } + fputc ('\n',dump_file); + } + } } } // If this dpoesn;t form a group, all members are instead simple phis. @@ -511,7 +521,7 @@ phi_analyzer::dump (FILE *f) if (!header) { header = true; - fprintf (dump_file, "\nPHI GROUPS:\n"); + fprintf (f, "\nPHI GROUPS:\n"); } g->dump (f); } diff --git a/gcc/gimple-range-phi.h b/gcc/gimple-range-phi.h index b5120e97bf3b..8e63303f7081 100644 --- a/gcc/gimple-range-phi.h +++ b/gcc/gimple-range-phi.h @@ -50,23 +50,20 @@ along with GCC; see the file COPYING3. If not see class phi_group { public: - phi_group (bitmap bm, tree init_val, edge e, gimple *mod, range_query *q); + phi_group (bitmap bm, irange &init_range, gimple *mod, range_query *q); phi_group (const phi_group &g); const_bitmap group () const { return m_group; } const vrange &range () const { return m_vr; } - tree initial_value () const { return m_initial_value; } gimple *modifier_stmt () const { return m_modifier; } void dump (FILE *); protected: bool calculate_using_modifier (range_query *q); - bool refine_using_relation (relation_kind k, range_query *q); + bool refine_using_relation (relation_kind k); static unsigned is_modifier_p (gimple *s, const bitmap bm); bitmap m_group; - tree m_initial_value; // Name or constant. - edge m_initial_edge; // Edge of initial value. gimple *m_modifier; // Single stmt which modifies phi group. unsigned m_modifier_op; // Operand of group member in modifier stmt. - int_range<3> m_vr; + int_range_max m_vr; friend class phi_analyzer; }; diff --git a/gcc/gimple-ssa-store-merging.cc b/gcc/gimple-ssa-store-merging.cc index 0d19b98ed73f..542958dd44f4 100644 --- a/gcc/gimple-ssa-store-merging.cc +++ b/gcc/gimple-ssa-store-merging.cc @@ -4687,12 +4687,13 @@ imm_store_chain_info::output_merged_store (merged_store_group *group) } else if ((BYTES_BIG_ENDIAN ? start_gap : end_gap) > 0) { - const unsigned HOST_WIDE_INT imask - = (HOST_WIDE_INT_1U << info->bitsize) - 1; + wide_int imask + = wi::mask (info->bitsize, false, + TYPE_PRECISION (TREE_TYPE (tem))); tem = gimple_build (&seq, loc, BIT_AND_EXPR, TREE_TYPE (tem), tem, - build_int_cst (TREE_TYPE (tem), - imask)); + wide_int_to_tree (TREE_TYPE (tem), + imask)); } const HOST_WIDE_INT shift = (BYTES_BIG_ENDIAN ? end_gap : start_gap); diff --git a/gcc/gimple-walk.cc b/gcc/gimple-walk.cc index a019515438c9..9516d61ffa99 100644 --- a/gcc/gimple-walk.cc +++ b/gcc/gimple-walk.cc @@ -693,6 +693,7 @@ walk_gimple_stmt (gimple_stmt_iterator *gsi, walk_stmt_fn callback_stmt, case GIMPLE_OMP_ORDERED: case GIMPLE_OMP_SCAN: case GIMPLE_OMP_SECTION: + case GIMPLE_OMP_STRUCTURED_BLOCK: case GIMPLE_OMP_PARALLEL: case GIMPLE_OMP_TASK: case GIMPLE_OMP_SCOPE: diff --git a/gcc/gimple.cc b/gcc/gimple.cc index e0ba42add39d..d5a4f634416c 100644 --- a/gcc/gimple.cc +++ b/gcc/gimple.cc @@ -415,7 +415,7 @@ gimple_build_call_from_tree (tree t, tree fnptrtype) tree fntype = TREE_TYPE (fnptrtype); if (lookup_attribute ("nocf_check", TYPE_ATTRIBUTES (fntype))) - gimple_call_set_nocf_check (call, TRUE); + gimple_call_set_nocf_check (call, true); } } @@ -1038,6 +1038,21 @@ gimple_build_omp_section (gimple_seq body) } +/* Build a GIMPLE_OMP_STRUCTURED_BLOCK statement. + + BODY is the structured block sequence. */ + +gimple * +gimple_build_omp_structured_block (gimple_seq body) +{ + gimple *p = gimple_alloc (GIMPLE_OMP_STRUCTURED_BLOCK, 0); + if (body) + gimple_omp_set_body (p, body); + + return p; +} + + /* Build a GIMPLE_OMP_MASTER statement. BODY is the sequence of statements to be executed by just the master. */ @@ -3187,7 +3202,7 @@ preprocess_case_label_vec_for_gimple (vec &labels, tree elt = labels[i]; tree low = CASE_LOW (elt); tree high = CASE_HIGH (elt); - bool remove_element = FALSE; + bool remove_element = false; if (low) { @@ -3211,7 +3226,7 @@ preprocess_case_label_vec_for_gimple (vec &labels, into a simple (one-value) case. */ int cmp = tree_int_cst_compare (high, low); if (cmp < 0) - remove_element = TRUE; + remove_element = true; else if (cmp == 0) high = NULL_TREE; } @@ -3223,7 +3238,7 @@ preprocess_case_label_vec_for_gimple (vec &labels, && tree_int_cst_compare (low, min_value) < 0) || (TREE_CODE (max_value) == INTEGER_CST && tree_int_cst_compare (low, max_value) > 0)) - remove_element = TRUE; + remove_element = true; else low = fold_convert (index_type, low); } @@ -3234,7 +3249,7 @@ preprocess_case_label_vec_for_gimple (vec &labels, && tree_int_cst_compare (high, min_value) < 0) || (TREE_CODE (max_value) == INTEGER_CST && tree_int_cst_compare (low, max_value) > 0)) - remove_element = TRUE; + remove_element = true; else { /* If the lower bound is less than the index type's @@ -3269,7 +3284,7 @@ preprocess_case_label_vec_for_gimple (vec &labels, is NULL, we do not remove the default case (it would be completely lost). */ if (default_casep) - remove_element = TRUE; + remove_element = true; } if (remove_element) diff --git a/gcc/gimple.def b/gcc/gimple.def index 274350d9534e..b164a8b847a2 100644 --- a/gcc/gimple.def +++ b/gcc/gimple.def @@ -275,6 +275,11 @@ DEFGSCODE(GIMPLE_OMP_CRITICAL, "gimple_omp_critical", GSS_OMP_CRITICAL) unspecified by the standards. */ DEFGSCODE(GIMPLE_OMP_FOR, "gimple_omp_for", GSS_OMP_FOR) +/* GIMPLE_STRUCTURED_BLOCK is an internal construct used to assert + that BODY is a structured block sequence, with no other semantics. It is + used to allow error-checking of intervening code in OMP_FOR constructs. */ +DEFGSCODE(GIMPLE_OMP_STRUCTURED_BLOCK, "gimple_omp_structured_block", GSS_OMP) + /* GIMPLE_OMP_MASTER represents #pragma omp master. BODY is the sequence of statements to execute in the master section. */ DEFGSCODE(GIMPLE_OMP_MASTER, "gimple_omp_master", GSS_OMP) diff --git a/gcc/gimple.h b/gcc/gimple.h index d3750f95d793..2d0ac103636d 100644 --- a/gcc/gimple.h +++ b/gcc/gimple.h @@ -1591,6 +1591,7 @@ gomp_parallel *gimple_build_omp_parallel (gimple_seq, tree, tree, tree); gomp_task *gimple_build_omp_task (gimple_seq, tree, tree, tree, tree, tree, tree); gimple *gimple_build_omp_section (gimple_seq); +gimple *gimple_build_omp_structured_block (gimple_seq); gimple *gimple_build_omp_scope (gimple_seq, tree); gimple *gimple_build_omp_master (gimple_seq); gimple *gimple_build_omp_masked (gimple_seq, tree); @@ -1879,6 +1880,7 @@ gimple_has_substatements (gimple *g) case GIMPLE_OMP_TASKGROUP: case GIMPLE_OMP_ORDERED: case GIMPLE_OMP_SECTION: + case GIMPLE_OMP_STRUCTURED_BLOCK: case GIMPLE_OMP_PARALLEL: case GIMPLE_OMP_TASK: case GIMPLE_OMP_SCOPE: @@ -6746,6 +6748,7 @@ gimple_return_set_retval (greturn *gs, tree retval) case GIMPLE_OMP_TEAMS: \ case GIMPLE_OMP_SCOPE: \ case GIMPLE_OMP_SECTION: \ + case GIMPLE_OMP_STRUCTURED_BLOCK: \ case GIMPLE_OMP_MASTER: \ case GIMPLE_OMP_MASKED: \ case GIMPLE_OMP_TASKGROUP: \ diff --git a/gcc/gimplify.cc b/gcc/gimplify.cc index 320920ed74c0..a49b50bc857a 100644 --- a/gcc/gimplify.cc +++ b/gcc/gimplify.cc @@ -3663,7 +3663,7 @@ gimplify_call_expr (tree *expr_p, gimple_seq *pre_p, bool want_value) case BUILT_IN_VA_START: { - builtin_va_start_p = TRUE; + builtin_va_start_p = true; if (call_expr_nargs (*expr_p) < 2) { error ("too few arguments to function %"); @@ -5980,6 +5980,7 @@ is_gimple_stmt (tree t) case OMP_SCOPE: case OMP_SECTIONS: case OMP_SECTION: + case OMP_STRUCTURED_BLOCK: case OMP_SINGLE: case OMP_MASTER: case OMP_MASKED: @@ -7699,6 +7700,25 @@ omp_default_clause (struct gimplify_omp_ctx *ctx, tree decl, return flags; } +/* Return string name for types of OpenACC constructs from ORT_* values. */ + +static const char * +oacc_region_type_name (enum omp_region_type region_type) +{ + switch (region_type) + { + case ORT_ACC_DATA: + return "data"; + case ORT_ACC_PARALLEL: + return "parallel"; + case ORT_ACC_KERNELS: + return "kernels"; + case ORT_ACC_SERIAL: + return "serial"; + default: + gcc_unreachable (); + } +} /* Determine outer default flags for DECL mentioned in an OACC region but not declared in an enclosing clause. */ @@ -7706,7 +7726,23 @@ omp_default_clause (struct gimplify_omp_ctx *ctx, tree decl, static unsigned oacc_default_clause (struct gimplify_omp_ctx *ctx, tree decl, unsigned flags) { - const char *rkind; + struct gimplify_omp_ctx *ctx_default = ctx; + /* If no 'default' clause appears on this compute construct... */ + if (ctx_default->default_kind == OMP_CLAUSE_DEFAULT_SHARED) + { + /* ..., see if one appears on a lexically containing 'data' + construct. */ + while ((ctx_default = ctx_default->outer_context)) + { + if (ctx_default->region_type == ORT_ACC_DATA + && ctx_default->default_kind != OMP_CLAUSE_DEFAULT_SHARED) + break; + } + /* If not, reset. */ + if (!ctx_default) + ctx_default = ctx; + } + bool on_device = false; bool is_private = false; bool declared = is_oacc_declared (decl); @@ -7738,14 +7774,12 @@ oacc_default_clause (struct gimplify_omp_ctx *ctx, tree decl, unsigned flags) switch (ctx->region_type) { case ORT_ACC_KERNELS: - rkind = "kernels"; - if (is_private) flags |= GOVD_FIRSTPRIVATE; else if (AGGREGATE_TYPE_P (type)) { /* Aggregates default to 'present_or_copy', or 'present'. */ - if (ctx->default_kind != OMP_CLAUSE_DEFAULT_PRESENT) + if (ctx_default->default_kind != OMP_CLAUSE_DEFAULT_PRESENT) flags |= GOVD_MAP; else flags |= GOVD_MAP | GOVD_MAP_FORCE_PRESENT; @@ -7758,8 +7792,6 @@ oacc_default_clause (struct gimplify_omp_ctx *ctx, tree decl, unsigned flags) case ORT_ACC_PARALLEL: case ORT_ACC_SERIAL: - rkind = ctx->region_type == ORT_ACC_PARALLEL ? "parallel" : "serial"; - if (is_private) flags |= GOVD_FIRSTPRIVATE; else if (on_device || declared) @@ -7767,7 +7799,7 @@ oacc_default_clause (struct gimplify_omp_ctx *ctx, tree decl, unsigned flags) else if (AGGREGATE_TYPE_P (type)) { /* Aggregates default to 'present_or_copy', or 'present'. */ - if (ctx->default_kind != OMP_CLAUSE_DEFAULT_PRESENT) + if (ctx_default->default_kind != OMP_CLAUSE_DEFAULT_PRESENT) flags |= GOVD_MAP; else flags |= GOVD_MAP | GOVD_MAP_FORCE_PRESENT; @@ -7785,16 +7817,23 @@ oacc_default_clause (struct gimplify_omp_ctx *ctx, tree decl, unsigned flags) if (DECL_ARTIFICIAL (decl)) ; /* We can get compiler-generated decls, and should not complain about them. */ - else if (ctx->default_kind == OMP_CLAUSE_DEFAULT_NONE) + else if (ctx_default->default_kind == OMP_CLAUSE_DEFAULT_NONE) { error ("%qE not specified in enclosing OpenACC %qs construct", - DECL_NAME (lang_hooks.decls.omp_report_decl (decl)), rkind); - inform (ctx->location, "enclosing OpenACC %qs construct", rkind); + DECL_NAME (lang_hooks.decls.omp_report_decl (decl)), + oacc_region_type_name (ctx->region_type)); + if (ctx_default != ctx) + inform (ctx->location, "enclosing OpenACC %qs construct and", + oacc_region_type_name (ctx->region_type)); + inform (ctx_default->location, + "enclosing OpenACC %qs construct with %qs clause", + oacc_region_type_name (ctx_default->region_type), + "default(none)"); } - else if (ctx->default_kind == OMP_CLAUSE_DEFAULT_PRESENT) + else if (ctx_default->default_kind == OMP_CLAUSE_DEFAULT_PRESENT) ; /* Handled above. */ else - gcc_checking_assert (ctx->default_kind == OMP_CLAUSE_DEFAULT_SHARED); + gcc_checking_assert (ctx_default->default_kind == OMP_CLAUSE_DEFAULT_SHARED); return flags; } @@ -11999,6 +12038,7 @@ gimplify_scan_omp_clauses (tree *list_p, gimple_seq *pre_p, switch (OMP_CLAUSE_DEFAULTMAP_CATEGORY (c)) { case OMP_CLAUSE_DEFAULTMAP_CATEGORY_UNSPECIFIED: + case OMP_CLAUSE_DEFAULTMAP_CATEGORY_ALL: gdmkmin = GDMK_SCALAR; gdmkmax = GDMK_POINTER; break; @@ -16998,6 +17038,7 @@ gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p, break; case OMP_SECTION: + case OMP_STRUCTURED_BLOCK: case OMP_MASTER: case OMP_MASKED: case OMP_ORDERED: @@ -17016,6 +17057,9 @@ gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p, case OMP_SECTION: g = gimple_build_omp_section (body); break; + case OMP_STRUCTURED_BLOCK: + g = gimple_build_omp_structured_block (body); + break; case OMP_MASTER: g = gimple_build_omp_master (body); break; @@ -17416,6 +17460,7 @@ gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p, && code != OMP_SCAN && code != OMP_SECTIONS && code != OMP_SECTION + && code != OMP_STRUCTURED_BLOCK && code != OMP_SINGLE && code != OMP_SCOPE); } diff --git a/gcc/ginclude/stdckdint.h b/gcc/ginclude/stdckdint.h new file mode 100644 index 000000000000..bcb1a25c900c --- /dev/null +++ b/gcc/ginclude/stdckdint.h @@ -0,0 +1,40 @@ +/* Copyright (C) 2023 Free Software Foundation, Inc. + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 3, or (at your option) +any later version. + +GCC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +Under Section 7 of GPL version 3, you are granted additional +permissions described in the GCC Runtime Library Exception, version +3.1, as published by the Free Software Foundation. + +You should have received a copy of the GNU General Public License and +a copy of the GCC Runtime Library Exception along with this program; +see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +. */ + +/* ISO C23: 7.20 Checked Integer Arithmetic . */ + +#ifndef _STDCKDINT_H +#define _STDCKDINT_H + +#define __STDC_VERSION_STDCKDINT_H__ 202311L + +#define ckd_add(r, a, b) ((_Bool) __builtin_add_overflow (a, b, r)) +#define ckd_sub(r, a, b) ((_Bool) __builtin_sub_overflow (a, b, r)) +#define ckd_mul(r, a, b) ((_Bool) __builtin_mul_overflow (a, b, r)) + +/* Allow for the C library to add its part to the header. */ +#if !defined (_LIBC_STDCKDINT_H) && __has_include_next () +# include_next +#endif + +#endif /* stdckdint.h */ diff --git a/gcc/graphite.cc b/gcc/graphite.cc index 19f8975ffa25..2b387d5b016b 100644 --- a/gcc/graphite.cc +++ b/gcc/graphite.cc @@ -512,6 +512,8 @@ graphite_transform_loops (void) if (changed) { + /* FIXME: Graphite does not update profile meaningfully currently. */ + cfun->cfg->full_profile = false; cleanup_tree_cfg (); profile_status_for_fn (cfun) = PROFILE_ABSENT; release_recorded_exits (cfun); diff --git a/gcc/internal-fn.cc b/gcc/internal-fn.cc index 8e294286388d..4138cc31d7ed 100644 --- a/gcc/internal-fn.cc +++ b/gcc/internal-fn.cc @@ -175,7 +175,7 @@ init_internal_fns () #define len_store_direct { 3, 3, false } #define mask_len_store_direct { 4, 5, false } #define vec_set_direct { 3, 3, false } -#define vec_extract_direct { 3, 3, false } +#define vec_extract_direct { 0, -1, false } #define unary_direct { 0, 0, true } #define unary_convert_direct { -1, 0, true } #define binary_direct { 0, 0, true } @@ -188,6 +188,7 @@ init_internal_fns () #define cond_len_ternary_direct { 1, 1, true } #define while_direct { 0, 2, false } #define fold_extract_direct { 2, 2, false } +#define fold_len_extract_direct { 2, 2, false } #define fold_left_direct { 1, 1, false } #define mask_fold_left_direct { 1, 1, false } #define mask_len_fold_left_direct { 1, 1, false } @@ -2931,7 +2932,8 @@ expand_partial_load_optab_fn (internal_fn ifn, gcall *stmt, convert_optab optab) type = TREE_TYPE (lhs); rhs = expand_call_mem_ref (type, stmt, 0); - if (optab == vec_mask_load_lanes_optab) + if (optab == vec_mask_load_lanes_optab + || optab == vec_mask_len_load_lanes_optab) icode = get_multi_vector_move (type, optab); else if (optab == len_load_optab) icode = direct_optab_handler (optab, TYPE_MODE (type)); @@ -2973,7 +2975,8 @@ expand_partial_store_optab_fn (internal_fn ifn, gcall *stmt, convert_optab optab type = TREE_TYPE (rhs); lhs = expand_call_mem_ref (type, stmt, 0); - if (optab == vec_mask_store_lanes_optab) + if (optab == vec_mask_store_lanes_optab + || optab == vec_mask_len_store_lanes_optab) icode = get_multi_vector_move (type, optab); else if (optab == len_store_optab) icode = direct_optab_handler (optab, TYPE_MODE (type)); @@ -3125,43 +3128,6 @@ expand_vec_set_optab_fn (internal_fn, gcall *stmt, convert_optab optab) gcc_unreachable (); } -/* Expand VEC_EXTRACT optab internal function. */ - -static void -expand_vec_extract_optab_fn (internal_fn, gcall *stmt, convert_optab optab) -{ - tree lhs = gimple_call_lhs (stmt); - tree op0 = gimple_call_arg (stmt, 0); - tree op1 = gimple_call_arg (stmt, 1); - - rtx target = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE); - - machine_mode outermode = TYPE_MODE (TREE_TYPE (op0)); - machine_mode extract_mode = TYPE_MODE (TREE_TYPE (lhs)); - - rtx src = expand_normal (op0); - rtx pos = expand_normal (op1); - - class expand_operand ops[3]; - enum insn_code icode = convert_optab_handler (optab, outermode, - extract_mode); - - if (icode != CODE_FOR_nothing) - { - create_output_operand (&ops[0], target, extract_mode); - create_input_operand (&ops[1], src, outermode); - create_convert_operand_from (&ops[2], pos, - TYPE_MODE (TREE_TYPE (op1)), true); - if (maybe_expand_insn (icode, 3, ops)) - { - if (!rtx_equal_p (target, ops[0].value)) - emit_move_insn (target, ops[0].value); - return; - } - } - gcc_unreachable (); -} - static void expand_ABNORMAL_DISPATCHER (internal_fn, gcall *) { @@ -3898,6 +3864,9 @@ expand_convert_optab_fn (internal_fn fn, gcall *stmt, convert_optab optab, #define expand_fold_extract_optab_fn(FN, STMT, OPTAB) \ expand_direct_optab_fn (FN, STMT, OPTAB, 3) +#define expand_fold_len_extract_optab_fn(FN, STMT, OPTAB) \ + expand_direct_optab_fn (FN, STMT, OPTAB, 5) + #define expand_fold_left_optab_fn(FN, STMT, OPTAB) \ expand_direct_optab_fn (FN, STMT, OPTAB, 2) @@ -3915,6 +3884,9 @@ expand_convert_optab_fn (internal_fn fn, gcall *stmt, convert_optab optab, #define expand_unary_convert_optab_fn(FN, STMT, OPTAB) \ expand_convert_optab_fn (FN, STMT, OPTAB, 1) +#define expand_vec_extract_optab_fn(FN, STMT, OPTAB) \ + expand_convert_optab_fn (FN, STMT, OPTAB, 2) + /* RETURN_TYPE and ARGS are a return type and argument list that are in principle compatible with FN (which satisfies direct_internal_fn_p). Return the types that should be used to determine whether the @@ -4012,12 +3984,13 @@ multi_vector_optab_supported_p (convert_optab optab, tree_pair types, #define direct_mask_len_store_optab_supported_p convert_optab_supported_p #define direct_while_optab_supported_p convert_optab_supported_p #define direct_fold_extract_optab_supported_p direct_optab_supported_p +#define direct_fold_len_extract_optab_supported_p direct_optab_supported_p #define direct_fold_left_optab_supported_p direct_optab_supported_p #define direct_mask_fold_left_optab_supported_p direct_optab_supported_p #define direct_mask_len_fold_left_optab_supported_p direct_optab_supported_p #define direct_check_ptrs_optab_supported_p direct_optab_supported_p #define direct_vec_set_optab_supported_p direct_optab_supported_p -#define direct_vec_extract_optab_supported_p direct_optab_supported_p +#define direct_vec_extract_optab_supported_p convert_optab_supported_p /* Return the optab used by internal function FN. */ @@ -4443,6 +4416,30 @@ get_conditional_internal_fn (internal_fn fn) } } +/* If there exists an internal function like IFN that operates on vectors, + but with additional length and bias parameters, return the internal_fn + for that function, otherwise return IFN_LAST. */ +internal_fn +get_len_internal_fn (internal_fn fn) +{ + switch (fn) + { +#undef DEF_INTERNAL_COND_FN +#undef DEF_INTERNAL_SIGNED_COND_FN +#define DEF_INTERNAL_COND_FN(NAME, ...) \ + case IFN_COND_##NAME: \ + return IFN_COND_LEN_##NAME; +#define DEF_INTERNAL_SIGNED_COND_FN(NAME, ...) \ + case IFN_COND_##NAME: \ + return IFN_COND_LEN_##NAME; +#include "internal-fn.def" +#undef DEF_INTERNAL_COND_FN +#undef DEF_INTERNAL_SIGNED_COND_FN + default: + return IFN_LAST; + } +} + /* If IFN implements the conditional form of an unconditional internal function, return that unconditional function, otherwise return IFN_LAST. */ @@ -4451,8 +4448,11 @@ get_unconditional_internal_fn (internal_fn ifn) { switch (ifn) { -#define CASE(NAME) case IFN_COND_##NAME: return IFN_##NAME; - FOR_EACH_COND_FN_PAIR(CASE) +#define CASE(NAME) \ + case IFN_COND_##NAME: \ + case IFN_COND_LEN_##NAME: \ + return IFN_##NAME; +FOR_EACH_COND_FN_PAIR (CASE) #undef CASE default: return IFN_LAST; @@ -4552,6 +4552,7 @@ internal_load_fn_p (internal_fn fn) case IFN_MASK_LOAD: case IFN_LOAD_LANES: case IFN_MASK_LOAD_LANES: + case IFN_MASK_LEN_LOAD_LANES: case IFN_GATHER_LOAD: case IFN_MASK_GATHER_LOAD: case IFN_MASK_LEN_GATHER_LOAD: @@ -4574,6 +4575,7 @@ internal_store_fn_p (internal_fn fn) case IFN_MASK_STORE: case IFN_STORE_LANES: case IFN_MASK_STORE_LANES: + case IFN_MASK_LEN_STORE_LANES: case IFN_SCATTER_STORE: case IFN_MASK_SCATTER_STORE: case IFN_MASK_LEN_SCATTER_STORE: @@ -4646,6 +4648,8 @@ internal_fn_len_index (internal_fn fn) case IFN_COND_LEN_NEG: case IFN_MASK_LEN_LOAD: case IFN_MASK_LEN_STORE: + case IFN_MASK_LEN_LOAD_LANES: + case IFN_MASK_LEN_STORE_LANES: return 3; default: @@ -4663,8 +4667,10 @@ internal_fn_mask_index (internal_fn fn) { case IFN_MASK_LOAD: case IFN_MASK_LOAD_LANES: + case IFN_MASK_LEN_LOAD_LANES: case IFN_MASK_STORE: case IFN_MASK_STORE_LANES: + case IFN_MASK_LEN_STORE_LANES: case IFN_MASK_LEN_LOAD: case IFN_MASK_LEN_STORE: return 2; @@ -4700,6 +4706,7 @@ internal_fn_stored_value_index (internal_fn fn) return 4; case IFN_MASK_LEN_STORE: + case IFN_MASK_LEN_STORE_LANES: return 5; default: diff --git a/gcc/internal-fn.def b/gcc/internal-fn.def index bf6825c5d008..d09403c0a912 100644 --- a/gcc/internal-fn.def +++ b/gcc/internal-fn.def @@ -50,6 +50,7 @@ along with GCC; see the file COPYING3. If not see - mask_load: currently just maskload - load_lanes: currently just vec_load_lanes - mask_load_lanes: currently just vec_mask_load_lanes + - mask_len_load_lanes: currently just vec_mask_len_load_lanes - gather_load: used for {mask_,mask_len_,}gather_load - len_load: currently just len_load - mask_len_load: currently just mask_len_load @@ -57,6 +58,7 @@ along with GCC; see the file COPYING3. If not see - mask_store: currently just maskstore - store_lanes: currently just vec_store_lanes - mask_store_lanes: currently just vec_mask_store_lanes + - mask_len_store_lanes: currently just vec_mask_len_store_lanes - scatter_store: used for {mask_,mask_len_,}scatter_store - len_store: currently just len_store - mask_len_store: currently just mask_len_store @@ -69,6 +71,7 @@ along with GCC; see the file COPYING3. If not see lround2. - cond_binary: a conditional binary optab, such as cond_add + - cond_unary: a conditional unary optab, such as cond_neg - cond_ternary: a conditional ternary optab, such as cond_fma_rev - fold_left: for scalar = FN (scalar, vector), keyed off the vector mode @@ -188,6 +191,8 @@ DEF_INTERNAL_OPTAB_FN (MASK_LOAD, ECF_PURE, maskload, mask_load) DEF_INTERNAL_OPTAB_FN (LOAD_LANES, ECF_CONST, vec_load_lanes, load_lanes) DEF_INTERNAL_OPTAB_FN (MASK_LOAD_LANES, ECF_PURE, vec_mask_load_lanes, mask_load_lanes) +DEF_INTERNAL_OPTAB_FN (MASK_LEN_LOAD_LANES, ECF_PURE, + vec_mask_len_load_lanes, mask_load_lanes) DEF_INTERNAL_OPTAB_FN (GATHER_LOAD, ECF_PURE, gather_load, gather_load) DEF_INTERNAL_OPTAB_FN (MASK_GATHER_LOAD, ECF_PURE, @@ -208,14 +213,18 @@ DEF_INTERNAL_OPTAB_FN (MASK_STORE, 0, maskstore, mask_store) DEF_INTERNAL_OPTAB_FN (STORE_LANES, ECF_CONST, vec_store_lanes, store_lanes) DEF_INTERNAL_OPTAB_FN (MASK_STORE_LANES, 0, vec_mask_store_lanes, mask_store_lanes) +DEF_INTERNAL_OPTAB_FN (MASK_LEN_STORE_LANES, 0, + vec_mask_len_store_lanes, mask_store_lanes) -DEF_INTERNAL_OPTAB_FN (VCOND, 0, vcond, vec_cond) -DEF_INTERNAL_OPTAB_FN (VCONDU, 0, vcondu, vec_cond) -DEF_INTERNAL_OPTAB_FN (VCONDEQ, 0, vcondeq, vec_cond) -DEF_INTERNAL_OPTAB_FN (VCOND_MASK, 0, vcond_mask, vec_cond_mask) +DEF_INTERNAL_OPTAB_FN (VCOND, ECF_CONST | ECF_NOTHROW, vcond, vec_cond) +DEF_INTERNAL_OPTAB_FN (VCONDU, ECF_CONST | ECF_NOTHROW, vcondu, vec_cond) +DEF_INTERNAL_OPTAB_FN (VCONDEQ, ECF_CONST | ECF_NOTHROW, vcondeq, vec_cond) +DEF_INTERNAL_OPTAB_FN (VCOND_MASK, ECF_CONST | ECF_NOTHROW, + vcond_mask, vec_cond_mask) -DEF_INTERNAL_OPTAB_FN (VEC_SET, 0, vec_set, vec_set) -DEF_INTERNAL_OPTAB_FN (VEC_EXTRACT, 0, vec_extract, vec_extract) +DEF_INTERNAL_OPTAB_FN (VEC_SET, ECF_CONST | ECF_NOTHROW, vec_set, vec_set) +DEF_INTERNAL_OPTAB_FN (VEC_EXTRACT, ECF_CONST | ECF_NOTHROW, + vec_extract, vec_extract) DEF_INTERNAL_OPTAB_FN (LEN_STORE, 0, len_store, len_store) DEF_INTERNAL_OPTAB_FN (MASK_LEN_STORE, 0, mask_len_store, mask_len_store) @@ -274,6 +283,7 @@ DEF_INTERNAL_COND_FN (FNMA, ECF_CONST, fnma, ternary) DEF_INTERNAL_COND_FN (FNMS, ECF_CONST, fnms, ternary) DEF_INTERNAL_COND_FN (NEG, ECF_CONST, neg, unary) +DEF_INTERNAL_COND_FN (NOT, ECF_CONST, one_cmpl, unary) DEF_INTERNAL_OPTAB_FN (RSQRT, ECF_CONST, rsqrt, unary) @@ -302,6 +312,9 @@ DEF_INTERNAL_OPTAB_FN (EXTRACT_LAST, ECF_CONST | ECF_NOTHROW, DEF_INTERNAL_OPTAB_FN (FOLD_EXTRACT_LAST, ECF_CONST | ECF_NOTHROW, fold_extract_last, fold_extract) +DEF_INTERNAL_OPTAB_FN (LEN_FOLD_EXTRACT_LAST, ECF_CONST | ECF_NOTHROW, + len_fold_extract_last, fold_len_extract) + DEF_INTERNAL_OPTAB_FN (FOLD_LEFT_PLUS, ECF_CONST | ECF_NOTHROW, fold_left_plus, fold_left) diff --git a/gcc/internal-fn.h b/gcc/internal-fn.h index a5c3f4765ff7..410c1b623d66 100644 --- a/gcc/internal-fn.h +++ b/gcc/internal-fn.h @@ -224,6 +224,7 @@ extern bool set_edom_supported_p (void); extern internal_fn get_conditional_internal_fn (tree_code); extern internal_fn get_conditional_internal_fn (internal_fn); +extern internal_fn get_len_internal_fn (internal_fn); extern internal_fn get_conditional_len_internal_fn (tree_code); extern tree_code conditional_internal_fn_code (internal_fn); extern internal_fn get_unconditional_internal_fn (internal_fn); diff --git a/gcc/ipa-prop.cc b/gcc/ipa-prop.cc index 4f6ed7b89bd7..9efaa5cb8489 100644 --- a/gcc/ipa-prop.cc +++ b/gcc/ipa-prop.cc @@ -5760,6 +5760,34 @@ ipcp_modif_dom_walker::before_dom_children (basic_block bb) return NULL; } +/* If IPA-CP discovered a constant in parameter PARM at OFFSET of a given SIZE + - whether passed by reference or not is given by BY_REF - return that + constant. Otherwise return NULL_TREE. */ + +tree +ipcp_get_aggregate_const (struct function *func, tree parm, bool by_ref, + HOST_WIDE_INT bit_offset, HOST_WIDE_INT bit_size) +{ + cgraph_node *node = cgraph_node::get (func->decl); + ipcp_transformation *ts = ipcp_get_transformation_summary (node); + + if (!ts || !ts->m_agg_values) + return NULL_TREE; + + int index = ts->get_param_index (func->decl, parm); + if (index < 0) + return NULL_TREE; + + ipa_argagg_value_list avl (ts); + unsigned unit_offset = bit_offset / BITS_PER_UNIT; + tree v = avl.get_value (index, unit_offset, by_ref); + if (!v + || maybe_ne (tree_to_poly_int64 (TYPE_SIZE (TREE_TYPE (v))), bit_size)) + return NULL_TREE; + + return v; +} + /* Return true if we have recorded VALUE and MASK about PARM. Set VALUE and MASk accordingly. */ @@ -6031,11 +6059,6 @@ ipcp_transform_function (struct cgraph_node *node) free_ipa_bb_info (bi); fbi.bb_infos.release (); - ipcp_transformation *s = ipcp_transformation_sum->get (node); - s->m_agg_values = NULL; - s->bits = NULL; - s->m_vr = NULL; - vec_free (descriptors); if (cfg_changed) delete_unreachable_blocks_update_callgraph (node, false); diff --git a/gcc/ipa-prop.h b/gcc/ipa-prop.h index 410c951a2564..7e033d2a7b83 100644 --- a/gcc/ipa-prop.h +++ b/gcc/ipa-prop.h @@ -1235,6 +1235,9 @@ void ipa_dump_param (FILE *, class ipa_node_params *info, int i); void ipa_release_body_info (struct ipa_func_body_info *); tree ipa_get_callee_param_type (struct cgraph_edge *e, int i); bool ipcp_get_parm_bits (tree, tree *, widest_int *); +tree ipcp_get_aggregate_const (struct function *func, tree parm, bool by_ref, + HOST_WIDE_INT bit_offset, + HOST_WIDE_INT bit_size); bool unadjusted_ptr_and_unit_offset (tree op, tree *ret, poly_int64 *offset_ret); diff --git a/gcc/ira-color.cc b/gcc/ira-color.cc index 1fb2958bddd0..5807d6d26f6d 100644 --- a/gcc/ira-color.cc +++ b/gcc/ira-color.cc @@ -3340,6 +3340,10 @@ improve_allocation (void) } /* Assign the best chosen hard register to A. */ ALLOCNO_HARD_REGNO (a) = best; + + for (j = nregs - 1; j >= 0; j--) + allocated_hardreg_p[best + j] = true; + if (internal_flag_ira_verbose > 2 && ira_dump_file != NULL) fprintf (ira_dump_file, "Assigning %d to a%dr%d\n", best, ALLOCNO_NUM (a), ALLOCNO_REGNO (a)); diff --git a/gcc/jit/ChangeLog b/gcc/jit/ChangeLog index 4c30cab1db82..1e60eaef5aeb 100644 --- a/gcc/jit/ChangeLog +++ b/gcc/jit/ChangeLog @@ -1,3 +1,23 @@ +2023-08-31 Francois-Xavier Coudert + + * jit-playback.cc: Change spelling to macOS. + +2023-08-29 Guillaume Gomez + + * docs/topics/compatibility.rst: Add documentation for LIBGCCJIT_ABI_25. + * docs/topics/types.rst: Add documentation for gcc_jit_type_get_restrict. + +2023-08-29 Guillaume Gomez + + * jit-playback.cc: Remove trailing whitespace characters. + * jit-playback.h: Add get_restrict method. + * jit-recording.cc: Add get_restrict methods. + * jit-recording.h: Add get_restrict methods. + * libgccjit++.h: Add get_restrict methods. + * libgccjit.cc: Add gcc_jit_type_get_restrict. + * libgccjit.h: Declare gcc_jit_type_get_restrict. + * libgccjit.map: Declare gcc_jit_type_get_restrict. + 2023-02-16 Patrick Palka * jit-dejagnu.h: Mechanically drop static from static inline diff --git a/gcc/jit/docs/topics/compatibility.rst b/gcc/jit/docs/topics/compatibility.rst index f4ffa07ec48b..ebede440ee4c 100644 --- a/gcc/jit/docs/topics/compatibility.rst +++ b/gcc/jit/docs/topics/compatibility.rst @@ -371,3 +371,10 @@ alignment of a variable: * :func:`gcc_jit_lvalue_set_alignment` * :func:`gcc_jit_lvalue_get_alignment` + +.. _LIBGCCJIT_ABI_25: + +``LIBGCCJIT_ABI_25`` +-------------------- +``LIBGCCJIT_ABI_25`` covers the addition of +:func:`gcc_jit_type_get_restrict` diff --git a/gcc/jit/docs/topics/types.rst b/gcc/jit/docs/topics/types.rst index f5f2aac1f0ce..d8c1d15d69d4 100644 --- a/gcc/jit/docs/topics/types.rst +++ b/gcc/jit/docs/topics/types.rst @@ -541,3 +541,15 @@ Reflection API .. code-block:: c #ifdef LIBGCCJIT_HAVE_SIZED_INTEGERS + +.. function:: gcc_jit_type *\ + gcc_jit_type_get_restrict (gcc_jit_type *type) + + Given type "T", get type "restrict T". + + This entrypoint was added in :ref:`LIBGCCJIT_ABI_25`; you can test for + its presence using + + .. code-block:: c + + #ifdef LIBGCCJIT_HAVE_gcc_jit_type_get_restrict diff --git a/gcc/jit/jit-playback.cc b/gcc/jit/jit-playback.cc index e06f161aad97..7249ce8cadbb 100644 --- a/gcc/jit/jit-playback.cc +++ b/gcc/jit/jit-playback.cc @@ -3024,7 +3024,7 @@ invoke_driver (const char *ctxt_progname, ADD_ARG ("-fno-use-linker-plugin"); #if defined (DARWIN_X86) || defined (DARWIN_PPC) - /* OS X's linker defaults to treating undefined symbols as errors. + /* macOS's linker defaults to treating undefined symbols as errors. If the context has any imported functions or globals they will be undefined until the .so is dynamically-linked into the process. Ensure that the driver passes in "-undefined dynamic_lookup" to the @@ -3393,7 +3393,7 @@ if (t) \ NAME_TYPE (complex_float_type_node, "complex float"); NAME_TYPE (complex_double_type_node, "complex double"); NAME_TYPE (complex_long_double_type_node, "complex long double"); - + m_const_char_ptr = build_pointer_type( build_qualified_type (char_type_node, TYPE_QUAL_CONST)); diff --git a/gcc/jit/jit-playback.h b/gcc/jit/jit-playback.h index 883159f03c38..438f395f6d91 100644 --- a/gcc/jit/jit-playback.h +++ b/gcc/jit/jit-playback.h @@ -446,6 +446,11 @@ public: return new type (build_qualified_type (m_inner, TYPE_QUAL_VOLATILE)); } + type *get_restrict () const + { + return new type (build_qualified_type (m_inner, TYPE_QUAL_RESTRICT)); + } + type *get_aligned (size_t alignment_in_bytes) const; type *get_vector (size_t num_units) const; diff --git a/gcc/jit/jit-recording.cc b/gcc/jit/jit-recording.cc index df0368ff8f70..326c8c2809fd 100644 --- a/gcc/jit/jit-recording.cc +++ b/gcc/jit/jit-recording.cc @@ -2267,6 +2267,19 @@ recording::type::get_const () return result; } +/* Given a type T, get the type restrict T. + + Implements the post-error-checking part of + gcc_jit_type_get_restrict. */ + +recording::type * +recording::type::get_restrict () +{ + recording::type *result = new memento_of_get_restrict (this); + m_ctxt->record (result); + return result; +} + /* Given a type T, get the type volatile T. Implements the post-error-checking part of @@ -2960,6 +2973,40 @@ recording::memento_of_get_volatile::write_reproducer (reproducer &r) r.get_identifier_as_type (m_other_type)); } +/* The implementation of class gcc::jit::recording::memento_of_get_restrict. */ + +/* Implementation of pure virtual hook recording::memento::replay_into + for recording::memento_of_get_restrict. */ + +void +recording::memento_of_get_restrict::replay_into (replayer *) +{ + set_playback_obj (m_other_type->playback_type ()->get_restrict ()); +} + +/* Implementation of recording::memento::make_debug_string for + results of get_restrict, prepending "restrict ". */ + +recording::string * +recording::memento_of_get_restrict::make_debug_string () +{ + return string::from_printf (m_ctxt, + "restrict %s", m_other_type->get_debug_string ()); +} + +/* Implementation of recording::memento::write_reproducer for restrict + types. */ + +void +recording::memento_of_get_restrict::write_reproducer (reproducer &r) +{ + const char *id = r.make_identifier (this, "type"); + r.write (" gcc_jit_type *%s =\n" + " gcc_jit_type_get_restrict (%s);\n", + id, + r.get_identifier_as_type (m_other_type)); +} + /* The implementation of class gcc::jit::recording::memento_of_get_aligned. */ /* Implementation of pure virtual hook recording::memento::replay_into diff --git a/gcc/jit/jit-recording.h b/gcc/jit/jit-recording.h index 400cf3456003..4a8082991fbf 100644 --- a/gcc/jit/jit-recording.h +++ b/gcc/jit/jit-recording.h @@ -524,6 +524,7 @@ public: type *get_pointer (); type *get_const (); type *get_volatile (); + type *get_restrict (); type *get_aligned (size_t alignment_in_bytes); type *get_vector (size_t num_units); @@ -568,6 +569,7 @@ public: virtual bool is_bool () const = 0; virtual type *is_pointer () = 0; virtual type *is_volatile () { return NULL; } + virtual type *is_restrict () { return NULL; } virtual type *is_const () { return NULL; } virtual type *is_array () = 0; virtual struct_ *is_struct () { return NULL; } @@ -686,7 +688,7 @@ private: }; /* A decorated version of a type, for get_const, get_volatile, - get_aligned, and get_vector. */ + get_aligned, get_restrict, and get_vector. */ class decorated_type : public type { @@ -769,6 +771,32 @@ private: void write_reproducer (reproducer &r) final override; }; +/* Result of "gcc_jit_type_get_restrict". */ +class memento_of_get_restrict : public decorated_type +{ +public: + memento_of_get_restrict (type *other_type) + : decorated_type (other_type) {} + + bool is_same_type_as (type *other) final override + { + if (!other->is_restrict ()) + return false; + return m_other_type->is_same_type_as (other->is_restrict ()); + } + + /* Strip off the "restrict", giving the underlying type. */ + type *unqualified () final override { return m_other_type; } + + type *is_restrict () final override { return m_other_type; } + + void replay_into (replayer *) final override; + +private: + string * make_debug_string () final override; + void write_reproducer (reproducer &r) final override; +}; + /* Result of "gcc_jit_type_get_aligned". */ class memento_of_get_aligned : public decorated_type { diff --git a/gcc/jit/libgccjit++.h b/gcc/jit/libgccjit++.h index df07889be896..4a04db386e67 100644 --- a/gcc/jit/libgccjit++.h +++ b/gcc/jit/libgccjit++.h @@ -1410,6 +1410,12 @@ type::get_const () return type (gcc_jit_type_get_const (get_inner_type ())); } +inline type +type::get_restrict () +{ + return type (gcc_jit_type_get_restrict (get_inner_type ())); +} + inline type type::get_volatile () { diff --git a/gcc/jit/libgccjit.cc b/gcc/jit/libgccjit.cc index 2def58f6aa73..0451b4df7f94 100644 --- a/gcc/jit/libgccjit.cc +++ b/gcc/jit/libgccjit.cc @@ -534,6 +534,21 @@ gcc_jit_type_get_volatile (gcc_jit_type *type) return (gcc_jit_type *)type->get_volatile (); } +/* Public entrypoint. See description in libgccjit.h. + + After error-checking, the real work is done by the + gcc::jit::recording::type::get_restrict method, in + jit-recording.cc. */ + +gcc_jit_type * +gcc_jit_type_get_restrict (gcc_jit_type *type) +{ + RETURN_NULL_IF_FAIL (type, NULL, NULL, "NULL type"); + RETURN_NULL_IF_FAIL (type->is_pointer (), NULL, NULL, "not a pointer type"); + + return (gcc_jit_type *)type->get_restrict (); +} + /* Public entrypoint. See description in libgccjit.h. After error-checking, the real work is done by the diff --git a/gcc/jit/libgccjit.h b/gcc/jit/libgccjit.h index 057d3e58e739..749f6c24177b 100644 --- a/gcc/jit/libgccjit.h +++ b/gcc/jit/libgccjit.h @@ -630,6 +630,15 @@ gcc_jit_type_get_const (gcc_jit_type *type); extern gcc_jit_type * gcc_jit_type_get_volatile (gcc_jit_type *type); +#define LIBGCCJIT_HAVE_gcc_jit_type_get_restrict + +/* Given type "T", get type "restrict T". + This API entrypoint was added in LIBGCCJIT_ABI_25; you can test for its + presence using + #ifdef LIBGCCJIT_HAVE_gcc_jit_type_get_restrict */ +extern gcc_jit_type * +gcc_jit_type_get_restrict (gcc_jit_type *type); + #define LIBGCCJIT_HAVE_SIZED_INTEGERS /* Given types LTYPE and RTYPE, return non-zero if they are compatible. diff --git a/gcc/jit/libgccjit.map b/gcc/jit/libgccjit.map index 25463b94fe8c..8b90a0e2ff3d 100644 --- a/gcc/jit/libgccjit.map +++ b/gcc/jit/libgccjit.map @@ -271,3 +271,8 @@ LIBGCCJIT_ABI_24 { gcc_jit_lvalue_set_alignment; gcc_jit_lvalue_get_alignment; } LIBGCCJIT_ABI_23; + +LIBGCCJIT_ABI_25 { + global: + gcc_jit_type_get_restrict; +} LIBGCCJIT_ABI_24; diff --git a/gcc/lcm.cc b/gcc/lcm.cc index 94a3ed43aeab..03421e490e46 100644 --- a/gcc/lcm.cc +++ b/gcc/lcm.cc @@ -56,9 +56,6 @@ along with GCC; see the file COPYING3. If not see #include "lcm.h" /* Edge based LCM routines. */ -static void compute_antinout_edge (sbitmap *, sbitmap *, sbitmap *, sbitmap *); -static void compute_earliest (struct edge_list *, int, sbitmap *, sbitmap *, - sbitmap *, sbitmap *, sbitmap *); static void compute_laterin (struct edge_list *, sbitmap *, sbitmap *, sbitmap *, sbitmap *); static void compute_insert_delete (struct edge_list *edge_list, sbitmap *, @@ -79,7 +76,7 @@ static void compute_rev_insert_delete (struct edge_list *edge_list, sbitmap *, This is done based on the flow graph, and not on the pred-succ lists. Other than that, its pretty much identical to compute_antinout. */ -static void +void compute_antinout_edge (sbitmap *antloc, sbitmap *transp, sbitmap *antin, sbitmap *antout) { @@ -170,7 +167,7 @@ compute_antinout_edge (sbitmap *antloc, sbitmap *transp, sbitmap *antin, /* Compute the earliest vector for edge based lcm. */ -static void +void compute_earliest (struct edge_list *edge_list, int n_exprs, sbitmap *antin, sbitmap *antout, sbitmap *avout, sbitmap *kill, sbitmap *earliest) diff --git a/gcc/lcm.h b/gcc/lcm.h index e08339352e03..7145d6fc46df 100644 --- a/gcc/lcm.h +++ b/gcc/lcm.h @@ -31,4 +31,7 @@ extern struct edge_list *pre_edge_rev_lcm (int, sbitmap *, sbitmap *, sbitmap *, sbitmap *, sbitmap **, sbitmap **); +extern void compute_antinout_edge (sbitmap *, sbitmap *, sbitmap *, sbitmap *); +extern void compute_earliest (struct edge_list *, int, sbitmap *, sbitmap *, + sbitmap *, sbitmap *, sbitmap *); #endif /* GCC_LCM_H */ diff --git a/gcc/lra-assigns.cc b/gcc/lra-assigns.cc index b8582dcafff8..d2ebcfd50566 100644 --- a/gcc/lra-assigns.cc +++ b/gcc/lra-assigns.cc @@ -522,14 +522,15 @@ find_hard_regno_for_1 (int regno, int *cost, int try_only_hard_regno, r2 != NULL; r2 = r2->start_next) { - if (r2->regno >= lra_constraint_new_regno_start + if (live_pseudos_reg_renumber[r2->regno] < 0 + && r2->regno >= lra_constraint_new_regno_start && lra_reg_info[r2->regno].preferred_hard_regno1 >= 0 - && live_pseudos_reg_renumber[r2->regno] < 0 && rclass_intersect_p[regno_allocno_class_array[r2->regno]]) sparseset_set_bit (conflict_reload_and_inheritance_pseudos, r2->regno); - if (live_pseudos_reg_renumber[r2->regno] >= 0 - && rclass_intersect_p[regno_allocno_class_array[r2->regno]]) + else if (live_pseudos_reg_renumber[r2->regno] >= 0 + && rclass_intersect_p + [regno_allocno_class_array[r2->regno]]) sparseset_set_bit (live_range_hard_reg_pseudos, r2->regno); } } diff --git a/gcc/lra-constraints.cc b/gcc/lra-constraints.cc index f3784cf5a5be..c718bedff32a 100644 --- a/gcc/lra-constraints.cc +++ b/gcc/lra-constraints.cc @@ -344,7 +344,8 @@ valid_address_p (machine_mode mode ATTRIBUTE_UNUSED, win: return true; #else - return targetm.addr_space.legitimate_address_p (mode, addr, 0, as); + return targetm.addr_space.legitimate_address_p (mode, addr, 0, as, + ERROR_MARK); #endif } @@ -1465,6 +1466,8 @@ static int goal_alt_dont_inherit_ops[MAX_RECOG_OPERANDS]; static bool goal_alt_swapped; /* The chosen insn alternative. */ static int goal_alt_number; +/* True if output reload of the stack pointer should be generated. */ +static bool goal_alt_out_sp_reload_p; /* True if the corresponding operand is the result of an equivalence substitution. */ @@ -2127,6 +2130,9 @@ process_alt_operands (int only_alternative) int curr_alt_dont_inherit_ops_num; /* Numbers of operands whose reload pseudos should not be inherited. */ int curr_alt_dont_inherit_ops[MAX_RECOG_OPERANDS]; + /* True if output stack pointer reload should be generated for the current + alternative. */ + bool curr_alt_out_sp_reload_p; rtx op; /* The register when the operand is a subreg of register, otherwise the operand itself. */ @@ -2210,7 +2216,8 @@ process_alt_operands (int only_alternative) } reject += static_reject; early_clobbered_regs_num = 0; - + curr_alt_out_sp_reload_p = false; + for (nop = 0; nop < n_operands; nop++) { const char *p; @@ -2681,12 +2688,10 @@ process_alt_operands (int only_alternative) bool no_regs_p; reject += op_reject; - /* Never do output reload of stack pointer. It makes - impossible to do elimination when SP is changed in - RTL. */ - if (op == stack_pointer_rtx && ! frame_pointer_needed + /* Mark output reload of the stack pointer. */ + if (op == stack_pointer_rtx && curr_static_id->operand[nop].type != OP_IN) - goto fail; + curr_alt_out_sp_reload_p = true; /* If this alternative asks for a specific reg class, see if there is at least one allocatable register in that class. */ @@ -3316,6 +3321,7 @@ process_alt_operands (int only_alternative) for (nop = 0; nop < curr_alt_dont_inherit_ops_num; nop++) goal_alt_dont_inherit_ops[nop] = curr_alt_dont_inherit_ops[nop]; goal_alt_swapped = curr_swapped; + goal_alt_out_sp_reload_p = curr_alt_out_sp_reload_p; best_overall = overall; best_losers = losers; best_reload_nregs = reload_nregs; @@ -4834,6 +4840,28 @@ curr_insn_transform (bool check_only_p) /* Most probably there are no enough registers to satisfy asm insn: */ lra_asm_insn_error (curr_insn); } + if (goal_alt_out_sp_reload_p) + { + /* We have an output stack pointer reload -- update sp offset: */ + rtx set; + bool done_p = false; + poly_int64 sp_offset = curr_id->sp_offset; + for (rtx_insn *insn = after; insn != NULL_RTX; insn = NEXT_INSN (insn)) + if ((set = single_set (insn)) != NULL_RTX + && SET_DEST (set) == stack_pointer_rtx) + { + lra_assert (!done_p); + done_p = true; + curr_id->sp_offset = 0; + lra_insn_recog_data_t id = lra_get_insn_recog_data (insn); + id->sp_offset = sp_offset; + if (lra_dump_file != NULL) + fprintf (lra_dump_file, + " Moving sp offset from insn %u to %u\n", + INSN_UID (curr_insn), INSN_UID (insn)); + } + lra_assert (done_p); + } lra_process_new_insns (curr_insn, before, after, "Inserting insn reload"); return change_p; } diff --git a/gcc/lra-eliminations.cc b/gcc/lra-eliminations.cc index 1f4e3fec9e0e..df613cdda76c 100644 --- a/gcc/lra-eliminations.cc +++ b/gcc/lra-eliminations.cc @@ -926,6 +926,18 @@ eliminate_regs_in_insn (rtx_insn *insn, bool replace_p, bool first_p, /* First see if the source is of the form (plus (...) CST). */ if (plus_src && poly_int_rtx_p (XEXP (plus_src, 1), &offset)) plus_cst_src = plus_src; + /* If we are doing initial offset computation, then utilize + eqivalences to discover a constant for the second term + of PLUS_SRC. */ + else if (plus_src && REG_P (XEXP (plus_src, 1))) + { + int regno = REGNO (XEXP (plus_src, 1)); + if (regno < ira_reg_equiv_len + && ira_reg_equiv[regno].constant != NULL_RTX + && !replace_p + && poly_int_rtx_p (ira_reg_equiv[regno].constant, &offset)) + plus_cst_src = plus_src; + } /* Check that the first operand of the PLUS is a hard reg or the lowpart subreg of one. */ if (plus_cst_src) @@ -1086,18 +1098,18 @@ eliminate_regs_in_insn (rtx_insn *insn, bool replace_p, bool first_p, lra_update_insn_recog_data (insn); } -/* Spill pseudos which are assigned to hard registers in SET. Add - affected insns for processing in the subsequent constraint - pass. */ -static void -spill_pseudos (HARD_REG_SET set) +/* Spill pseudos which are assigned to hard registers in SET, record them in + SPILLED_PSEUDOS unless it is null, and return the recorded pseudos number. + Add affected insns for processing in the subsequent constraint pass. */ +static int +spill_pseudos (HARD_REG_SET set, int *spilled_pseudos) { - int i; + int i, n; bitmap_head to_process; rtx_insn *insn; if (hard_reg_set_empty_p (set)) - return; + return 0; if (lra_dump_file != NULL) { fprintf (lra_dump_file, " Spilling non-eliminable hard regs:"); @@ -1107,6 +1119,7 @@ spill_pseudos (HARD_REG_SET set) fprintf (lra_dump_file, "\n"); } bitmap_initialize (&to_process, ®_obstack); + n = 0; for (i = FIRST_PSEUDO_REGISTER; i < max_reg_num (); i++) if (lra_reg_info[i].nrefs != 0 && reg_renumber[i] >= 0 && overlaps_hard_reg_set_p (set, @@ -1116,6 +1129,8 @@ spill_pseudos (HARD_REG_SET set) fprintf (lra_dump_file, " Spilling r%d(%d)\n", i, reg_renumber[i]); reg_renumber[i] = -1; + if (spilled_pseudos != NULL) + spilled_pseudos[n++] = i; bitmap_ior_into (&to_process, &lra_reg_info[i].insn_bitmap); } lra_no_alloc_regs |= set; @@ -1126,6 +1141,7 @@ spill_pseudos (HARD_REG_SET set) lra_set_used_insn_alternative (insn, LRA_UNKNOWN_ALT); } bitmap_clear (&to_process); + return n; } /* Update all offsets and possibility for elimination on eliminable @@ -1238,7 +1254,7 @@ update_reg_eliminate (bitmap insns_with_changed_offsets) } lra_no_alloc_regs |= temp_hard_reg_set; eliminable_regset &= ~temp_hard_reg_set; - spill_pseudos (temp_hard_reg_set); + spill_pseudos (temp_hard_reg_set, NULL); return result; } @@ -1382,15 +1398,17 @@ process_insn_for_elimination (rtx_insn *insn, bool final_p, bool first_p) /* Update frame pointer to stack pointer elimination if we started with permitted frame pointer elimination and now target reports that we can not - do this elimination anymore. */ -void -lra_update_fp2sp_elimination (void) + do this elimination anymore. Record spilled pseudos in SPILLED_PSEUDOS + unless it is null, and return the recorded pseudos number. */ +int +lra_update_fp2sp_elimination (int *spilled_pseudos) { + int n; HARD_REG_SET set; class lra_elim_table *ep; if (frame_pointer_needed || !targetm.frame_pointer_required ()) - return; + return 0; gcc_assert (!elimination_fp2sp_occured_p); if (lra_dump_file != NULL) fprintf (lra_dump_file, @@ -1398,10 +1416,11 @@ lra_update_fp2sp_elimination (void) frame_pointer_needed = true; CLEAR_HARD_REG_SET (set); add_to_hard_reg_set (&set, Pmode, HARD_FRAME_POINTER_REGNUM); - spill_pseudos (set); + n = spill_pseudos (set, spilled_pseudos); for (ep = reg_eliminate; ep < ®_eliminate[NUM_ELIMINABLE_REGS]; ep++) if (ep->from == FRAME_POINTER_REGNUM && ep->to == STACK_POINTER_REGNUM) setup_can_eliminate (ep, false); + return n; } /* Entry function to do final elimination if FINAL_P or to update diff --git a/gcc/lra-int.h b/gcc/lra-int.h index 633d9af80588..d0752c2ae505 100644 --- a/gcc/lra-int.h +++ b/gcc/lra-int.h @@ -414,7 +414,7 @@ extern int lra_get_elimination_hard_regno (int); extern rtx lra_eliminate_regs_1 (rtx_insn *, rtx, machine_mode, bool, bool, poly_int64, bool); extern void eliminate_regs_in_insn (rtx_insn *insn, bool, bool, poly_int64); -extern void lra_update_fp2sp_elimination (void); +extern int lra_update_fp2sp_elimination (int *spilled_pseudos); extern void lra_eliminate (bool, bool); extern poly_int64 lra_update_sp_offset (rtx, poly_int64); diff --git a/gcc/lra-spills.cc b/gcc/lra-spills.cc index fe58f162d050..a663a1931e30 100644 --- a/gcc/lra-spills.cc +++ b/gcc/lra-spills.cc @@ -363,7 +363,6 @@ assign_stack_slot_num_and_sort_pseudos (int *pseudo_regnos, int n) { int i, j, regno; - slots_num = 0; /* Assign stack slot numbers to spilled pseudos, use smaller numbers for most frequently used pseudos. */ for (i = 0; i < n; i++) @@ -606,7 +605,7 @@ lra_need_for_spills_p (void) void lra_spill (void) { - int i, n, curr_regno; + int i, n, n2, curr_regno; int *pseudo_regnos; regs_num = max_reg_num (); @@ -628,12 +627,20 @@ lra_spill (void) /* Sort regnos according their usage frequencies. */ qsort (pseudo_regnos, n, sizeof (int), regno_freq_compare); n = assign_spill_hard_regs (pseudo_regnos, n); + slots_num = 0; assign_stack_slot_num_and_sort_pseudos (pseudo_regnos, n); for (i = 0; i < n; i++) if (pseudo_slots[pseudo_regnos[i]].mem == NULL_RTX) assign_mem_slot (pseudo_regnos[i]); - lra_update_fp2sp_elimination (); - if (n > 0 && crtl->stack_alignment_needed) + if ((n2 = lra_update_fp2sp_elimination (pseudo_regnos)) > 0) + { + /* Assign stack slots to spilled pseudos assigned to fp. */ + assign_stack_slot_num_and_sort_pseudos (pseudo_regnos, n2); + for (i = 0; i < n2; i++) + if (pseudo_slots[pseudo_regnos[i]].mem == NULL_RTX) + assign_mem_slot (pseudo_regnos[i]); + } + if (n + n2 > 0 && crtl->stack_alignment_needed) /* If we have a stack frame, we must align it now. The stack size may be a part of the offset computation for register elimination. */ diff --git a/gcc/lto-streamer-in.cc b/gcc/lto-streamer-in.cc index 1876e1967ec0..d3128fcebe4b 100644 --- a/gcc/lto-streamer-in.cc +++ b/gcc/lto-streamer-in.cc @@ -1030,6 +1030,7 @@ input_cfg (class lto_input_block *ib, class data_in *data_in, basic_block p_bb; unsigned int i; int index; + bool full_profile = false; init_empty_tree_cfg_for_function (fn); @@ -1071,6 +1072,8 @@ input_cfg (class lto_input_block *ib, class data_in *data_in, data_in->location_cache.input_location_and_block (&e->goto_locus, &bp, ib, data_in); e->probability = profile_probability::stream_in (ib); + if (!e->probability.initialized_p ()) + full_profile = false; } @@ -1145,6 +1148,7 @@ input_cfg (class lto_input_block *ib, class data_in *data_in, /* Rebuild the loop tree. */ flow_loops_find (loops); + cfun->cfg->full_profile = full_profile; } @@ -1888,7 +1892,7 @@ lto_input_tree_1 (class lto_input_block *ib, class data_in *data_in, for (i = 0; i < len; i++) a[i] = streamer_read_hwi (ib); - gcc_assert (TYPE_PRECISION (type) <= MAX_BITSIZE_MODE_ANY_INT); + gcc_assert (TYPE_PRECISION (type) <= WIDE_INT_MAX_PRECISION); result = wide_int_to_tree (type, wide_int::from_array (a, len, TYPE_PRECISION (type))); streamer_tree_cache_append (data_in->reader_cache, result, hash); diff --git a/gcc/m2/ChangeLog b/gcc/m2/ChangeLog index 463faafc785b..847412ad7cc7 100644 --- a/gcc/m2/ChangeLog +++ b/gcc/m2/ChangeLog @@ -1,3 +1,60 @@ +2023-08-20 Gaius Mulley + + PR modula2/111085 + * gm2-libs/Builtins.def (nexttoward): Alter the second + parameter to LONGREAL. + (nexttowardf): Alter the second parameter to LONGREAL. + * gm2-libs/Builtins.mod (nexttoward): Alter the second + parameter to LONGREAL. + (nexttowardf): Alter the second parameter to LONGREAL. + * gm2-libs/cbuiltin.def (nexttoward): Alter the second + parameter to LONGREAL. + (nexttowardf): Alter the second parameter to LONGREAL. + +2023-08-13 Iain Sandoe + + * Make-lang.in: Update suffix spellings to use 'soext'. + Add libc to the plugin link. + +2023-08-12 Gaius Mulley + + PR modula2/110779 + * gm2-libs-iso/SysClock.mod (EpochTime): New procedure. + (GetClock): Call EpochTime if the C time functions are + unavailable. + * gm2-libs-iso/wrapclock.def (istimezone): New function + definition. + +2023-08-12 Gaius Mulley + + PR modula2/108119 + * Make-lang.in (M2RTE_PLUGIN_SO): Assigned to + plugin/m2rte$(exeext).so if enable_plugin is yes. + (m2.all.cross): Replace plugin/m2rte$(soext) with + $(M2RTE_PLUGIN_SO). + (m2.all.encap): Replace plugin/m2rte$(soext) with + $(M2RTE_PLUGIN_SO). + (m2.install-plugin): Add dummy rule when enable_plugin + is not yes. + (plugin/m2rte$(exeext).so): Add dummy rule when enable_plugin + is not yes. + (m2/stage2/cc1gm2$(exeext)): Replace plugin/m2rte$(soext) with + $(M2RTE_PLUGIN_SO). + (m2/stage1/cc1gm2$(exeext)): Replace plugin/m2rte$(soext) with + $(M2RTE_PLUGIN_SO). + * gm2spec.cc (lang_specific_driver): Set need_plugin to false + by default. + +2023-08-09 Gaius Mulley + + PR modula2/110779 + * gm2-libs-iso/SysClock.mod (GetClock): Test GetTimespec + return value. + (SetClock): Test SetTimespec return value. + * gm2-libs-iso/wrapclock.def (GetTimespec): Add integer + return type. + (SetTimespec): Add integer return type. + 2023-08-05 Gaius Mulley PR modula2/110779 diff --git a/gcc/m2/Make-lang.in b/gcc/m2/Make-lang.in index 23632c29125b..ca1581fe643e 100644 --- a/gcc/m2/Make-lang.in +++ b/gcc/m2/Make-lang.in @@ -39,6 +39,7 @@ else PLUGINLDFLAGS = -Wl,-undefined,dynamic_lookup PLUGINLDFLAGS += -Wl,-install_name,m2rte$(soext) PLUGINLDFLAGS += -nodefaultlibs + PLUGINLDFLAGS += -lc endif TEXISRC = $(srcdir)/doc/gm2.texi \ @@ -90,6 +91,10 @@ PGE=m2/pge$(exeext) SRC_PREFIX=G +ifeq ($(enable_plugin),yes) +M2RTE_PLUGIN_SO=plugin/m2rte$(soext) +endif + m2/gm2spec.o: $(srcdir)/m2/gm2spec.cc $(SYSTEM_H) $(GCC_H) $(CONFIG_H) \ m2/gm2config.h $(TARGET_H) $(PLUGIN_HEADERS) \ $(generated_files) $(C_TREE_H) insn-attr-common.h @@ -122,9 +127,9 @@ po-generated: # Build hooks: -m2.all.cross: gm2-cross$(exeext) plugin/m2rte$(soext) +m2.all.cross: gm2-cross$(exeext) $(M2RTE_PLUGIN_SO) -m2.start.encap: gm2$(exeext) plugin/m2rte$(soext) +m2.start.encap: gm2$(exeext) $(M2RTE_PLUGIN_SO) m2.rest.encap: @@ -400,9 +405,10 @@ m2.uninstall: -rm -rf $(bindir)/$(GM2_INSTALL_NAME) -rm -rf $(bindir)/$(GM2_CROSS_NAME) +ifeq ($(enable_plugin),yes) m2.install-plugin: installdirs $(mkinstalldirs) $(DESTDIR)$(plugin_resourcesdir) - $(INSTALL_PROGRAM) plugin/m2rte$(soext) $(DESTDIR)$(plugin_resourcesdir)/m2rte$(soext) + $(INSTALL_PROGRAM) $(M2RTE_PLUGIN_SO) $(DESTDIR)$(plugin_resourcesdir)/m2rte$(soext) chmod a+x $(DESTDIR)$(plugin_resourcesdir)/m2rte$(soext) override PLUGINCFLAGS := $(filter-out -mdynamic-no-pic,$(PLUGINCFLAGS)) @@ -412,6 +418,12 @@ plugin/m2rte$(soext): $(srcdir)/m2/plugin/m2rte.cc $(GCC_HEADER_DEPENDENCIES_FOR -test -d $(@D) || $(mkinstalldirs) $(@D) $(PLUGINCC) $(PLUGINCFLAGS) -fno-rtti -I. -I$(srcdir) $(INCINTL) -I$(srcdir)/m2 -I$(srcdir)/m2/gm2-gcc -I$(srcdir)/../include -I$(srcdir)/../libcpp/include -Wall $(GMPINC) -Wno-literal-suffix -fPIC -c -o plugin/m2rte.o $(srcdir)/m2/plugin/m2rte.cc $(PLUGINCC) $(PLUGINCFLAGS) $(PLUGINLDFLAGS) $(PLUGINLIBS) $(LIBINTL) -fno-rtti plugin/m2rte.o -shared -o $@ +else +m2.install-plugin: + +plugin/m2rte$(soext): + +endif # Clean hooks: @@ -524,7 +536,7 @@ cc1gm2$(exeext): m2/stage1/cc1gm2$(exeext) $(m2.prev) m2/stage2/cc1gm2$(exeext): m2/stage1/cc1gm2$(exeext) m2/gm2-compiler/m2flex.o \ $(GM2_C_OBJS) $(BACKEND) $(LIBDEPS) $(GM2_LIBS) \ - m2/gm2-gcc/rtegraph.o plugin/m2rte$(soext) + m2/gm2-gcc/rtegraph.o $(M2RTE_PLUGIN_SO) -test -d $(@D) || $(mkinstalldirs) $(@D) @$(call LINK_PROGRESS,$(INDEX.m2),start) +$(LLINKER) $(ALL_CFLAGS) $(LDFLAGS) -o $@ $(GM2_C_OBJS) m2/gm2-compiler/m2flex.o \ @@ -537,7 +549,7 @@ m2/stage2/cc1gm2$(exeext): m2/stage1/cc1gm2$(exeext) m2/gm2-compiler/m2flex.o \ m2/stage1/cc1gm2$(exeext): gm2$(exeext) m2/gm2-compiler-boot/m2flex.o \ $(GM2_C_OBJS) $(BACKEND) $(LIBDEPS) \ $(GM2_LIBS_BOOT) $(MC_LIBS) \ - m2/gm2-gcc/rtegraph.o plugin/m2rte$(soext) \ + m2/gm2-gcc/rtegraph.o $(M2RTE_PLUGIN_SO) \ $(m2.prev) -test -d $(@D) || $(mkinstalldirs) $(@D) @$(call LINK_PROGRESS,$(INDEX.m2),start) diff --git a/gcc/m2/gm2-libs-iso/SysClock.mod b/gcc/m2/gm2-libs-iso/SysClock.mod index 60261f2fd744..56d5503a87c5 100644 --- a/gcc/m2/gm2-libs-iso/SysClock.mod +++ b/gcc/m2/gm2-libs-iso/SysClock.mod @@ -173,6 +173,26 @@ BEGIN END ExtractDate ; +(* + EpochTime - assigns all fields of userData to 0 or FALSE. +*) + +PROCEDURE EpochTime (VAR userData: DateTime) ; +BEGIN + WITH userData DO + second := 0 ; + minute := 0 ; + hour := 0 ; + year := 0 ; + month := 0 ; + day := 0 ; + fractions := 0 ; + zone := 0 ; + summerTimeFlag := FALSE + END +END EpochTime ; + + PROCEDURE GetClock (VAR userData: DateTime) ; (* Assigns local date and time of the day to userData *) VAR @@ -185,28 +205,32 @@ BEGIN ts := InitTimespec () ; IF GetTimeRealtime (ts) = 0 THEN - GetTimespec (ts, sec, nano) ; - offset := timezone () ; - IF Debugging + IF GetTimespec (ts, sec, nano) = 1 THEN - printf ("getclock = %ld\n", sec) - END ; - sec := VAL (LONGINT, sec) + offset ; - IF Debugging - THEN - printf ("getclock = %ld\n", sec) - END ; - WITH userData DO - second := VAL (Sec, DivMod (sec, MAX (Sec) + 1)) ; - minute := VAL (Min, DivMod (sec, MAX (Min) + 1)) ; - hour := VAL (Hour, DivMod (sec, MAX (Hour) + 1)) ; - ExtractDate (sec, year, month, day) ; - fractions := nano DIV ((1000 * 1000 * 1000) DIV maxSecondParts) ; - zone := - (offset DIV 60) ; - summerTimeFlag := (isdst () = 1) + offset := timezone () ; + IF Debugging + THEN + printf ("getclock = %ld\n", sec) + END ; + sec := VAL (LONGINT, sec) + offset ; + IF Debugging + THEN + printf ("getclock = %ld\n", sec) + END ; + WITH userData DO + second := VAL (Sec, DivMod (sec, MAX (Sec) + 1)) ; + minute := VAL (Min, DivMod (sec, MAX (Min) + 1)) ; + hour := VAL (Hour, DivMod (sec, MAX (Hour) + 1)) ; + ExtractDate (sec, year, month, day) ; + fractions := nano DIV ((1000 * 1000 * 1000) DIV maxSecondParts) ; + zone := - (offset DIV 60) ; + summerTimeFlag := (isdst () = 1) + END + ELSE + EpochTime (userData) END ELSE - HALT + EpochTime (userData) END ; ts := KillTimespec (ts) END @@ -306,10 +330,11 @@ BEGIN userData.month, userData.year) ; offset := timezone () ; sec := VAL (LONGINT, sec) - offset ; - SetTimespec (ts, sec, nano) ; - IF SetTimeRealtime (ts) # 0 + IF SetTimespec (ts, sec, nano) = 1 THEN - HALT + IF SetTimeRealtime (ts) = 0 + THEN + END END ; ts := KillTimespec (ts) END diff --git a/gcc/m2/gm2-libs-iso/wrapclock.def b/gcc/m2/gm2-libs-iso/wrapclock.def index 9e1644b39922..9f5f28624448 100644 --- a/gcc/m2/gm2-libs-iso/wrapclock.def +++ b/gcc/m2/gm2-libs-iso/wrapclock.def @@ -36,11 +36,23 @@ TYPE timezone - return the glibc timezone value. This contains the difference between UTC and the latest local standard time, in seconds west of UTC. + If the underlying timezone is unavailable and + clock_gettime, localtime_r, tm_gmtoff + is unavailable then 0 is returned. *) PROCEDURE timezone () : LONGINT ; +(* + istimezone returns 1 if timezone in wrapclock.cc can resolve the + timezone value using the timezone C library call or by using + clock_gettime, localtime_r and tm_gmtoff. +*) + +PROCEDURE istimezone () : INTEGER ; + + (* daylight - return the glibc daylight value. This variable has a nonzero value if Daylight Saving @@ -88,18 +100,20 @@ PROCEDURE KillTimespec (tv: timespec) : timespec ; (* GetTimespec - retrieves the number of seconds and nanoseconds - from the timespec. + from the timespec. A return value of 0 means timespec + is unavailable and a return value of 1 indicates success. *) -PROCEDURE GetTimespec (ts: timespec; VAR sec, nano: LONGCARD) ; +PROCEDURE GetTimespec (ts: timespec; VAR sec, nano: LONGCARD) : INTEGER ; (* SetTimespec - sets the number of seconds and nanoseconds - into timespec. + into timespec. A return value of 0 means timespec + is unavailable and a return value of 1 indicates success. *) -PROCEDURE SetTimespec (ts: timespec; sec, nano: LONGCARD) ; +PROCEDURE SetTimespec (ts: timespec; sec, nano: LONGCARD) : INTEGER ; (* diff --git a/gcc/m2/gm2-libs/Builtins.def b/gcc/m2/gm2-libs/Builtins.def index eda36c3cfce7..651ade580cb0 100644 --- a/gcc/m2/gm2-libs/Builtins.def +++ b/gcc/m2/gm2-libs/Builtins.def @@ -91,8 +91,8 @@ PROCEDURE __BUILTIN__ nextafter (x, y: REAL) : REAL ; PROCEDURE __BUILTIN__ nextafterf (x, y: SHORTREAL) : SHORTREAL ; PROCEDURE __BUILTIN__ nextafterl (x, y: LONGREAL) : LONGREAL ; -PROCEDURE __BUILTIN__ nexttoward (x, y: REAL) : LONGREAL ; -PROCEDURE __BUILTIN__ nexttowardf (x, y: SHORTREAL) : LONGREAL ; +PROCEDURE __BUILTIN__ nexttoward (x: REAL; y: LONGREAL) : REAL ; +PROCEDURE __BUILTIN__ nexttowardf (x: SHORTREAL; y: LONGREAL) : SHORTREAL ; PROCEDURE __BUILTIN__ nexttowardl (x, y: LONGREAL) : LONGREAL ; PROCEDURE __BUILTIN__ scalbln (x: REAL; n: LONGINT) : REAL ; diff --git a/gcc/m2/gm2-libs/Builtins.mod b/gcc/m2/gm2-libs/Builtins.mod index 963e88ec461f..70c1f8a3e1fa 100644 --- a/gcc/m2/gm2-libs/Builtins.mod +++ b/gcc/m2/gm2-libs/Builtins.mod @@ -267,12 +267,12 @@ BEGIN RETURN cbuiltin.nextafterl (x, y) END nextafterl ; -PROCEDURE __ATTRIBUTE__ __BUILTIN__ ((__builtin_nexttoward)) nexttoward (x, y: REAL) : LONGREAL ; +PROCEDURE __ATTRIBUTE__ __BUILTIN__ ((__builtin_nexttoward)) nexttoward (x: REAL; y: LONGREAL) : REAL ; BEGIN RETURN cbuiltin.nexttoward (x, y) END nexttoward ; -PROCEDURE __ATTRIBUTE__ __BUILTIN__ ((__builtin_nexttowardf)) nexttowardf (x, y: SHORTREAL) : LONGREAL ; +PROCEDURE __ATTRIBUTE__ __BUILTIN__ ((__builtin_nexttowardf)) nexttowardf (x: SHORTREAL; y: LONGREAL) : SHORTREAL ; BEGIN RETURN cbuiltin.nexttowardf (x, y) END nexttowardf ; diff --git a/gcc/m2/gm2-libs/cbuiltin.def b/gcc/m2/gm2-libs/cbuiltin.def index 99927058bc6c..64d0a79fb509 100644 --- a/gcc/m2/gm2-libs/cbuiltin.def +++ b/gcc/m2/gm2-libs/cbuiltin.def @@ -118,8 +118,8 @@ PROCEDURE nextafter (x, y: REAL) : REAL ; PROCEDURE nextafterf (x, y: SHORTREAL) : SHORTREAL ; PROCEDURE nextafterl (x, y: LONGREAL) : LONGREAL ; -PROCEDURE nexttoward (x, y: REAL) : REAL ; -PROCEDURE nexttowardf (x, y: SHORTREAL) : SHORTREAL ; +PROCEDURE nexttoward (x: REAL; y: LONGREAL) : REAL ; +PROCEDURE nexttowardf (x: SHORTREAL; y: LONGREAL) : SHORTREAL ; PROCEDURE nexttowardl (x, y: LONGREAL) : LONGREAL ; PROCEDURE scalb (x, n: REAL) : REAL ; diff --git a/gcc/m2/gm2spec.cc b/gcc/m2/gm2spec.cc index cd7ae808d987..75a6ed36c82a 100644 --- a/gcc/m2/gm2spec.cc +++ b/gcc/m2/gm2spec.cc @@ -469,12 +469,8 @@ lang_specific_driver (struct cl_decoded_option **in_decoded_options, /* The number of libraries added in. */ int added_libraries; -#ifdef ENABLE_PLUGIN /* True if we should add -fplugin=m2rte to the command-line. */ - bool need_plugin = true; -#else bool need_plugin = false; -#endif /* True if we should set up include paths and library paths. */ bool allow_libraries = true; diff --git a/gcc/match.pd b/gcc/match.pd index 9b4819e5be7a..c6df4230b5f7 100644 --- a/gcc/match.pd +++ b/gcc/match.pd @@ -84,9 +84,9 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) /* Unary operations and their associated IFN_COND_* function. */ (define_operator_list UNCOND_UNARY - negate) + negate bit_not) (define_operator_list COND_UNARY - IFN_COND_NEG) + IFN_COND_NEG IFN_COND_NOT) /* Binary operations and their associated IFN_COND_* function. */ (define_operator_list UNCOND_BINARY @@ -959,6 +959,86 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) #endif )))) +#if GIMPLE +(for div (trunc_div exact_div) + /* Simplify (X + M*N) / N -> X / N + M. */ + (simplify + (div (plus:c@4 @0 (mult:c@3 @1 @2)) @2) + (with {value_range vr0, vr1, vr2, vr3, vr4;} + (if (INTEGRAL_TYPE_P (type) + && get_range_query (cfun)->range_of_expr (vr1, @1) + && get_range_query (cfun)->range_of_expr (vr2, @2) + /* "N*M" doesn't overflow. */ + && range_op_handler (MULT_EXPR).overflow_free_p (vr1, vr2) + && get_range_query (cfun)->range_of_expr (vr0, @0) + && get_range_query (cfun)->range_of_expr (vr3, @3) + /* "X+(N*M)" doesn't overflow. */ + && range_op_handler (PLUS_EXPR).overflow_free_p (vr0, vr3) + && get_range_query (cfun)->range_of_expr (vr4, @4) + /* "X+N*M" is not with opposite sign as "X". */ + && (TYPE_UNSIGNED (type) + || (vr0.nonnegative_p () && vr4.nonnegative_p ()) + || (vr0.nonpositive_p () && vr4.nonpositive_p ()))) + (plus (div @0 @2) @1)))) + + /* Simplify (X - M*N) / N -> X / N - M. */ + (simplify + (div (minus@4 @0 (mult:c@3 @1 @2)) @2) + (with {value_range vr0, vr1, vr2, vr3, vr4;} + (if (INTEGRAL_TYPE_P (type) + && get_range_query (cfun)->range_of_expr (vr1, @1) + && get_range_query (cfun)->range_of_expr (vr2, @2) + /* "N * M" doesn't overflow. */ + && range_op_handler (MULT_EXPR).overflow_free_p (vr1, vr2) + && get_range_query (cfun)->range_of_expr (vr0, @0) + && get_range_query (cfun)->range_of_expr (vr3, @3) + /* "X - (N*M)" doesn't overflow. */ + && range_op_handler (MINUS_EXPR).overflow_free_p (vr0, vr3) + && get_range_query (cfun)->range_of_expr (vr4, @4) + /* "X-N*M" is not with opposite sign as "X". */ + && (TYPE_UNSIGNED (type) + || (vr0.nonnegative_p () && vr4.nonnegative_p ()) + || (vr0.nonpositive_p () && vr4.nonpositive_p ()))) + (minus (div @0 @2) @1))))) + +/* Simplify + (X + C) / N -> X / N + C / N where C is multiple of N. + (X + C) >> N -> X >> N + C>>N if low N bits of C is 0. */ +(for op (trunc_div exact_div rshift) + (simplify + (op (plus@3 @0 INTEGER_CST@1) INTEGER_CST@2) + (with + { + wide_int c = wi::to_wide (@1); + wide_int n = wi::to_wide (@2); + bool shift = op == RSHIFT_EXPR; +#define plus_op1(v) (shift ? wi::rshift (v, n, TYPE_SIGN (type)) \ + : wi::div_trunc (v, n, TYPE_SIGN (type))) +#define exact_mod(v) (shift ? wi::ctz (v) >= n.to_shwi () \ + : wi::multiple_of_p (v, n, TYPE_SIGN (type))) + value_range vr0, vr1, vr3; + } + (if (INTEGRAL_TYPE_P (type) + && get_range_query (cfun)->range_of_expr (vr0, @0)) + (if (exact_mod (c) + && get_range_query (cfun)->range_of_expr (vr1, @1) + /* "X+C" doesn't overflow. */ + && range_op_handler (PLUS_EXPR).overflow_free_p (vr0, vr1) + && get_range_query (cfun)->range_of_expr (vr3, @3) + /* "X+C" and "X" are not of opposite sign. */ + && (TYPE_UNSIGNED (type) + || (vr0.nonnegative_p () && vr3.nonnegative_p ()) + || (vr0.nonpositive_p () && vr3.nonpositive_p ()))) + (plus (op @0 @2) { wide_int_to_tree (type, plus_op1 (c)); }) + (if (TYPE_UNSIGNED (type) && c.sign_mask () < 0 + && exact_mod (-c) + /* unsigned "X-(-C)" doesn't underflow. */ + && wi::geu_p (vr0.lower_bound (), -c)) + (plus (op @0 @2) { wide_int_to_tree (type, -plus_op1 (-c)); }))))))) +#undef plus_op1 +#undef exact_mod +#endif + (for op (negate abs) /* Simplify cos(-x) and cos(|x|) -> cos(x). Similarly for cosh. */ (for coss (COS COSH) @@ -1179,9 +1259,10 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) /* Simplify ~X & X as zero. */ (simplify (bit_and (convert? @0) (convert? @1)) - (if (types_match (TREE_TYPE (@0), TREE_TYPE (@1)) - && bitwise_inverted_equal_p (@0, @1)) - { build_zero_cst (type); })) + (with { bool wascmp; } + (if (types_match (TREE_TYPE (@0), TREE_TYPE (@1)) + && bitwise_inverted_equal_p (@0, @1, wascmp)) + { wascmp ? constant_boolean_node (false, type) : build_zero_cst (type); }))) /* PR71636: Transform x & ((1U << b) - 1) -> x & ~(~0U << b); */ (simplify @@ -1227,12 +1308,13 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) /* Simplify (X & ~Y) |^+ (~X & Y) -> X ^ Y. */ (for op (bit_ior bit_xor plus) (simplify - (op (bit_and:c @0 (bit_not @1)) (bit_and:c (bit_not @0) @1)) - (bit_xor @0 @1)) - (simplify - (op:c (bit_and @0 INTEGER_CST@2) (bit_and (bit_not @0) INTEGER_CST@1)) - (if (~wi::to_wide (@2) == wi::to_wide (@1)) - (bit_xor @0 @1)))) + (op (bit_and:c @0 @2) (bit_and:c @3 @1)) + (with { bool wascmp0, wascmp1; } + (if (bitwise_inverted_equal_p (@2, @1, wascmp0) + && bitwise_inverted_equal_p (@0, @3, wascmp1) + && ((!wascmp0 && !wascmp1) + || element_precision (type) == 1)) + (bit_xor @0 @1))))) /* PR53979: Transform ((a ^ b) | a) -> (a | b) */ (simplify @@ -1419,9 +1501,13 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) (for op (bit_ior bit_xor) (simplify (op (convert? @0) (convert? @1)) - (if (types_match (TREE_TYPE (@0), TREE_TYPE (@1)) - && bitwise_inverted_equal_p (@0, @1)) - (convert { build_all_ones_cst (TREE_TYPE (@0)); })))) + (with { bool wascmp; } + (if (types_match (TREE_TYPE (@0), TREE_TYPE (@1)) + && bitwise_inverted_equal_p (@0, @1, wascmp)) + (convert + { wascmp + ? constant_boolean_node (true, type) + : build_all_ones_cst (TREE_TYPE (@0)); }))))) /* x ^ x -> 0 */ (simplify @@ -1451,6 +1537,12 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) (if (INTEGRAL_TYPE_P (TREE_TYPE (@0)) && wi::bit_and_not (get_nonzero_bits (@0), wi::to_wide (@1)) == 0) @0)) +/* x | C -> C if we know that x & ~C == 0. */ +(simplify + (bit_ior SSA_NAME@0 INTEGER_CST@1) + (if (INTEGRAL_TYPE_P (TREE_TYPE (@0)) + && wi::bit_and_not (get_nonzero_bits (@0), wi::to_wide (@1)) == 0) + @1)) #endif /* ~(~X - Y) -> X + Y and ~(~X + Y) -> X - Y. */ @@ -1545,14 +1637,6 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) (bit_ior:c (bit_xor:s @0 @1) (bit_not:s (bit_ior:s @0 @1))) (bit_not (bit_and @0 @1))) -/* (x | y) & ~x -> y & ~x */ -/* (x & y) | ~x -> y | ~x */ -(for bitop (bit_and bit_ior) - rbitop (bit_ior bit_and) - (simplify - (bitop:c (rbitop:c @0 @1) (bit_not@2 @0)) - (bitop @1 @2))) - /* (x & y) ^ (x | y) -> x ^ y */ (simplify (bit_xor:c (bit_and @0 @1) (bit_ior @0 @1)) @@ -1612,8 +1696,11 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) /* (x | y) & (~x ^ y) -> x & y */ (simplify - (bit_and:c (bit_ior:c @0 @1) (bit_xor:c @1 (bit_not @0))) - (bit_and @0 @1)) + (bit_and:c (bit_ior:c @0 @1) (bit_xor:c @1 @2)) + (with { bool wascmp; } + (if (bitwise_inverted_equal_p (@0, @2, wascmp) + && (!wascmp || element_precision (type) == 1)) + (bit_and @0 @1)))) /* (~x | y) & (x | ~y) -> ~(x ^ y) */ (simplify @@ -1969,13 +2056,19 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) /* (~x & y) | x -> x | y */ (simplify (bitop:c (rbitop:c @2 @1) @0) - (if (bitwise_inverted_equal_p (@0, @2)) - (bitop @0 @1)))) + (with { bool wascmp; } + (if (bitwise_inverted_equal_p (@0, @2, wascmp) + && (!wascmp || element_precision (type) == 1)) + (bitop @0 @1))))) -/* ((x | y) & z) | x -> (z & y) | x */ -(simplify - (bit_ior:c (bit_and:cs (bit_ior:cs @0 @1) @2) @0) - (bit_ior (bit_and @2 @1) @0)) +/* ((x | y) & z) | x -> (z & y) | x + ((x ^ y) & z) | x -> (z & y) | x */ +(for op (bit_ior bit_xor) + (simplify + (bit_ior:c (nop_convert1?:s + (bit_and:cs (nop_convert2?:s (op:cs @0 @1)) @2)) @3) + (if (bitwise_equal_p (@0, @3)) + (convert (bit_ior (bit_and @1 (convert @2)) (convert @0)))))) /* (x | CST1) & CST2 -> (x & CST2) | (CST1 & CST2) */ (simplify @@ -2076,6 +2169,7 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) (bit_and:c (convert? (cmp@0 @01 @02)) @3) (bit_and:c (convert? (icmp@4 @01 @02)) @5)) (if (INTEGRAL_TYPE_P (type) + && invert_tree_comparison (cmp, HONOR_NANS (@01)) == icmp /* The scalar version has to be canonicalized after vectorization because it makes unconditional loads conditional ones, which means we lose vectorization because the loads may trap. */ @@ -2090,6 +2184,7 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) (cond (cmp@0 @01 @02) @3 zerop) (cond (icmp@4 @01 @02) @5 zerop)) (if (INTEGRAL_TYPE_P (type) + && invert_tree_comparison (cmp, HONOR_NANS (@01)) == icmp /* The scalar version has to be canonicalized after vectorization because it makes unconditional loads conditional ones, which means we lose vectorization because the loads may trap. */ @@ -2102,13 +2197,15 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) (bit_ior (bit_and:c (vec_cond:s (cmp@0 @6 @7) @4 @5) @2) (bit_and:c (vec_cond:s (icmp@1 @6 @7) @4 @5) @3)) - (if (integer_zerop (@5)) + (if (integer_zerop (@5) + && invert_tree_comparison (cmp, HONOR_NANS (@6)) == icmp) (switch (if (integer_onep (@4)) (bit_and (vec_cond @0 @2 @3) @4)) (if (integer_minus_onep (@4)) (vec_cond @0 @2 @3))) - (if (integer_zerop (@4)) + (if (integer_zerop (@4) + && invert_tree_comparison (cmp, HONOR_NANS (@6)) == icmp) (switch (if (integer_onep (@5)) (bit_and (vec_cond @0 @3 @2) @5)) @@ -2121,7 +2218,8 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) (bit_ior (vec_cond:s (cmp@0 @4 @5) @2 integer_zerop) (vec_cond:s (icmp@1 @4 @5) @3 integer_zerop)) - (vec_cond @0 @2 @3))) + (if (invert_tree_comparison (cmp, HONOR_NANS (@4)) == icmp) + (vec_cond @0 @2 @3)))) /* Transform X & -Y into X * Y when Y is { 0 or 1 }. */ (simplify @@ -2732,16 +2830,24 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) & (bitpos / BITS_PER_UNIT))); })))) (match min_value - INTEGER_CST - (if ((INTEGRAL_TYPE_P (type) - || POINTER_TYPE_P(type)) - && wi::eq_p (wi::to_wide (t), wi::min_value (type))))) + uniform_integer_cst_p + (with { + tree int_cst = uniform_integer_cst_p (t); + tree inner_type = TREE_TYPE (int_cst); + } + (if ((INTEGRAL_TYPE_P (inner_type) + || POINTER_TYPE_P (inner_type)) + && wi::eq_p (wi::to_wide (int_cst), wi::min_value (inner_type)))))) (match max_value - INTEGER_CST - (if ((INTEGRAL_TYPE_P (type) - || POINTER_TYPE_P(type)) - && wi::eq_p (wi::to_wide (t), wi::max_value (type))))) + uniform_integer_cst_p + (with { + tree int_cst = uniform_integer_cst_p (t); + tree itype = TREE_TYPE (int_cst); + } + (if ((INTEGRAL_TYPE_P (itype) + || POINTER_TYPE_P (itype)) + && wi::eq_p (wi::to_wide (int_cst), wi::max_value (itype)))))) /* x > y && x != XXX_MIN --> x > y x > y && x == XXX_MIN --> false . */ @@ -4693,6 +4799,23 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) (op (vec_cond:s @0 @1 @2)) (vec_cond @0 (op! @1) (op! @2)))) +/* Sink unary conversions to branches, but only if we do fold both + and the target's truth type is the same as we already have. */ +(simplify + (convert (vec_cond:s @0 @1 @2)) + (if (VECTOR_TYPE_P (type) + && types_match (TREE_TYPE (@0), truth_type_for (type))) + (vec_cond @0 (convert! @1) (convert! @2)))) + +/* Likewise for view_convert of nop_conversions. */ +(simplify + (view_convert (vec_cond:s @0 @1 @2)) + (if (VECTOR_TYPE_P (type) && VECTOR_TYPE_P (TREE_TYPE (@1)) + && known_eq (TYPE_VECTOR_SUBPARTS (type), + TYPE_VECTOR_SUBPARTS (TREE_TYPE (@1))) + && tree_nop_conversion_p (TREE_TYPE (type), TREE_TYPE (TREE_TYPE (@1)))) + (vec_cond @0 (view_convert! @1) (view_convert! @2)))) + /* Sink binary operation to branches, but only if we can fold it. */ (for op (tcc_comparison plus minus mult bit_and bit_ior bit_xor lshift rshift rdiv trunc_div ceil_div floor_div round_div @@ -4922,24 +5045,6 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) ) ) -(simplify - (cond @0 zero_one_valued_p@1 zero_one_valued_p@2) - (switch - /* bool0 ? bool1 : 0 -> bool0 & bool1 */ - (if (integer_zerop (@2)) - (bit_and (convert @0) @1)) - /* bool0 ? 0 : bool2 -> (bool0^1) & bool2 */ - (if (integer_zerop (@1)) - (bit_and (bit_xor (convert @0) { build_one_cst (type); } ) @2)) - /* bool0 ? 1 : bool2 -> bool0 | bool2 */ - (if (integer_onep (@1)) - (bit_ior (convert @0) @2)) - /* bool0 ? bool1 : 1 -> (bool0^1) | bool1 */ - (if (integer_onep (@2)) - (bit_ior (bit_xor (convert @0) @2) @1)) - ) -) - /* Optimize # x_5 in range [cst1, cst2] where cst2 = cst1 + 1 x_5 ? cstN ? cst4 : cst3 @@ -5236,6 +5341,37 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) (convert @c0)))))))) #endif +(for cnd (cond vec_cond) + /* (a != b) ? (a - b) : 0 -> (a - b) */ + (simplify + (cnd (ne:c @0 @1) (minus@2 @0 @1) integer_zerop) + @2) + /* (a != b) ? (a ^ b) : 0 -> (a ^ b) */ + (simplify + (cnd (ne:c @0 @1) (bit_xor:c@2 @0 @1) integer_zerop) + @2) + /* (a != b) ? (a & b) : a -> (a & b) */ + /* (a != b) ? (a | b) : a -> (a | b) */ + /* (a != b) ? min(a,b) : a -> min(a,b) */ + /* (a != b) ? max(a,b) : a -> max(a,b) */ + (for op (bit_and bit_ior min max) + (simplify + (cnd (ne:c @0 @1) (op:c@2 @0 @1) @0) + @2)) + /* (a != b) ? (a * b) : (a * a) -> (a * b) */ + /* (a != b) ? (a + b) : (a + a) -> (a + b) */ + (for op (mult plus) + (simplify + (cnd (ne:c @0 @1) (op@2 @0 @1) (op @0 @0)) + (if (ANY_INTEGRAL_TYPE_P (type)) + @2))) + /* (a != b) ? (a + b) : (2 * a) -> (a + b) */ + (simplify + (cnd (ne:c @0 @1) (plus@2 @0 @1) (mult @0 uniform_integer_cst_p@3)) + (if (wi::to_wide (uniform_integer_cst_p (@3)) == 2) + @2)) +) + /* These was part of minmax phiopt. */ /* Optimize (a CMP b) ? minmax : minmax to minmax, c> */ @@ -5270,6 +5406,30 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) && integer_nonzerop (fold_build2 (GE_EXPR, boolean_type_node, @3, @1))) (max @2 @4)))))) +#if GIMPLE +/* These patterns should be after min/max detection as simplifications + of `(type)(zero_one ==/!= 0)` to `(type)(zero_one)` + and `(type)(zero_one^1)` are not done yet. See PR 110637. + Even without those, reaching min/max/and/ior faster is better. */ +(simplify + (cond @0 zero_one_valued_p@1 zero_one_valued_p@2) + (switch + /* bool0 ? bool1 : 0 -> bool0 & bool1 */ + (if (integer_zerop (@2)) + (bit_and (convert @0) @1)) + /* bool0 ? 0 : bool2 -> (bool0^1) & bool2 */ + (if (integer_zerop (@1)) + (bit_and (bit_xor (convert @0) { build_one_cst (type); } ) @2)) + /* bool0 ? 1 : bool2 -> bool0 | bool2 */ + (if (integer_onep (@1)) + (bit_ior (convert @0) @2)) + /* bool0 ? bool1 : 1 -> (bool0^1) | bool1 */ + (if (integer_onep (@2)) + (bit_ior (bit_xor (convert @0) @2) @1)) + ) +) +#endif + /* X != C1 ? -X : C2 simplifies to -X when -C1 == C2. */ (simplify (cond (ne @0 INTEGER_CST@1) (negate@3 @0) INTEGER_CST@2) @@ -6460,6 +6620,22 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) (if (cmp == NE_EXPR) { constant_boolean_node (true, type); }))))))) +#if GIMPLE +/* a?~t:t -> (-(a))^t */ +(simplify + (cond @0 @1 @2) + (with { bool wascmp; } + (if (INTEGRAL_TYPE_P (type) + && bitwise_inverted_equal_p (@1, @2, wascmp) + && (!wascmp || element_precision (type) == 1)) + (with { + auto prec = TYPE_PRECISION (type); + auto unsign = TYPE_UNSIGNED (type); + tree inttype = build_nonstandard_integer_type (prec, unsign); + } + (convert (bit_xor (negate (convert:inttype @0)) (convert:inttype @2))))))) +#endif + /* Simplify pointer equality compares using PTA. */ (for neeq (ne eq) (simplify @@ -7962,6 +8138,31 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) wi::to_wide (@ipos) + isize)) (BIT_FIELD_REF @0 @rsize @rpos))))) +/* Simplify vector inserts of other vector extracts to a permute. */ +(simplify + (bit_insert @0 (BIT_FIELD_REF@2 @1 @rsize @rpos) @ipos) + (if (VECTOR_TYPE_P (type) + && types_match (@0, @1) + && types_match (TREE_TYPE (TREE_TYPE (@0)), TREE_TYPE (@2)) + && TYPE_VECTOR_SUBPARTS (type).is_constant ()) + (with + { + unsigned HOST_WIDE_INT elsz + = tree_to_uhwi (TYPE_SIZE (TREE_TYPE (TREE_TYPE (@1)))); + poly_uint64 relt = exact_div (tree_to_poly_uint64 (@rpos), elsz); + poly_uint64 ielt = exact_div (tree_to_poly_uint64 (@ipos), elsz); + unsigned nunits = TYPE_VECTOR_SUBPARTS (type).to_constant (); + vec_perm_builder builder; + builder.new_vector (nunits, nunits, 1); + for (unsigned i = 0; i < nunits; ++i) + builder.quick_push (known_eq (ielt, i) ? nunits + relt : i); + vec_perm_indices sel (builder, 2, nunits); + } + (if (!VECTOR_MODE_P (TYPE_MODE (type)) + || can_vec_perm_const_p (TYPE_MODE (type), TYPE_MODE (type), sel, false)) + (vec_perm @0 @1 { vec_perm_indices_to_tree + (build_vector_type (ssizetype, nunits), sel); }))))) + (if (canonicalize_math_after_vectorization_p ()) (for fmas (FMA) (simplify @@ -8459,6 +8660,17 @@ and, && is_truth_type_for (op_type, TREE_TYPE (@0))) (cond_op (bit_not @0) @2 @1))))) +/* `(a ? -1 : 0) ^ b` can be converted into a conditional not. */ +(simplify + (bit_xor:c (vec_cond @0 uniform_integer_cst_p@1 uniform_integer_cst_p@2) @3) + (if (canonicalize_math_after_vectorization_p () + && vectorized_internal_fn_supported_p (IFN_COND_NOT, type) + && is_truth_type_for (type, TREE_TYPE (@0))) + (if (integer_all_onesp (@1) && integer_zerop (@2)) + (IFN_COND_NOT @0 @3 @3)) + (if (integer_all_onesp (@2) && integer_zerop (@1)) + (IFN_COND_NOT (bit_not @0) @3 @3)))) + /* Simplify: a = a1 op a2 @@ -8900,10 +9112,10 @@ and, /* Merge - c = VEC_PERM_EXPR ; - d = VEC_PERM_EXPR ; + c = VEC_PERM_EXPR ; + d = VEC_PERM_EXPR ; to - d = VEC_PERM_EXPR ; */ + d = VEC_PERM_EXPR ; */ (simplify (vec_perm (vec_perm@0 @1 @2 VECTOR_CST@3) @0 VECTOR_CST@4) @@ -8945,6 +9157,141 @@ and, (if (op0) (vec_perm @1 @2 { op0; }))))))) +/* Merge + c = VEC_PERM_EXPR ; + d = VEC_PERM_EXPR ; + to + d = VEC_PERM_EXPR ; + when all elements from a or b are replaced by the later + permutation. */ + +(simplify + (vec_perm @5 (vec_perm@0 @1 @2 VECTOR_CST@3) VECTOR_CST@4) + (if (TYPE_VECTOR_SUBPARTS (type).is_constant ()) + (with + { + machine_mode result_mode = TYPE_MODE (type); + machine_mode op_mode = TYPE_MODE (TREE_TYPE (@1)); + int nelts = TYPE_VECTOR_SUBPARTS (type).to_constant (); + vec_perm_builder builder0; + vec_perm_builder builder1; + vec_perm_builder builder2 (nelts, nelts, 2); + } + (if (tree_to_vec_perm_builder (&builder0, @3) + && tree_to_vec_perm_builder (&builder1, @4)) + (with + { + vec_perm_indices sel0 (builder0, 2, nelts); + vec_perm_indices sel1 (builder1, 2, nelts); + bool use_1 = false, use_2 = false; + + for (int i = 0; i < nelts; i++) + { + if (known_lt ((poly_uint64)sel1[i], sel1.nelts_per_input ())) + builder2.quick_push (sel1[i]); + else + { + poly_uint64 j = sel0[(sel1[i] - sel1.nelts_per_input ()) + .to_constant ()]; + if (known_lt (j, sel0.nelts_per_input ())) + use_1 = true; + else + { + use_2 = true; + j -= sel0.nelts_per_input (); + } + builder2.quick_push (j + sel1.nelts_per_input ()); + } + } + } + (if (use_1 ^ use_2) + (with + { + vec_perm_indices sel2 (builder2, 2, nelts); + tree op0 = NULL_TREE; + /* If the new VEC_PERM_EXPR can't be handled but both + original VEC_PERM_EXPRs can, punt. + If one or both of the original VEC_PERM_EXPRs can't be + handled and the new one can't be either, don't increase + number of VEC_PERM_EXPRs that can't be handled. */ + if (can_vec_perm_const_p (result_mode, op_mode, sel2, false) + || (single_use (@0) + ? (!can_vec_perm_const_p (result_mode, op_mode, sel0, false) + || !can_vec_perm_const_p (result_mode, op_mode, sel1, false)) + : !can_vec_perm_const_p (result_mode, op_mode, sel1, false))) + op0 = vec_perm_indices_to_tree (TREE_TYPE (@4), sel2); + } + (if (op0) + (switch + (if (use_1) + (vec_perm @5 @1 { op0; })) + (if (use_2) + (vec_perm @5 @2 { op0; }))))))))))) + +/* And the case with swapped outer permute sources. */ + +(simplify + (vec_perm (vec_perm@0 @1 @2 VECTOR_CST@3) @5 VECTOR_CST@4) + (if (TYPE_VECTOR_SUBPARTS (type).is_constant ()) + (with + { + machine_mode result_mode = TYPE_MODE (type); + machine_mode op_mode = TYPE_MODE (TREE_TYPE (@1)); + int nelts = TYPE_VECTOR_SUBPARTS (type).to_constant (); + vec_perm_builder builder0; + vec_perm_builder builder1; + vec_perm_builder builder2 (nelts, nelts, 2); + } + (if (tree_to_vec_perm_builder (&builder0, @3) + && tree_to_vec_perm_builder (&builder1, @4)) + (with + { + vec_perm_indices sel0 (builder0, 2, nelts); + vec_perm_indices sel1 (builder1, 2, nelts); + bool use_1 = false, use_2 = false; + + for (int i = 0; i < nelts; i++) + { + if (known_ge ((poly_uint64)sel1[i], sel1.nelts_per_input ())) + builder2.quick_push (sel1[i]); + else + { + poly_uint64 j = sel0[sel1[i].to_constant ()]; + if (known_lt (j, sel0.nelts_per_input ())) + use_1 = true; + else + { + use_2 = true; + j -= sel0.nelts_per_input (); + } + builder2.quick_push (j); + } + } + } + (if (use_1 ^ use_2) + (with + { + vec_perm_indices sel2 (builder2, 2, nelts); + tree op0 = NULL_TREE; + /* If the new VEC_PERM_EXPR can't be handled but both + original VEC_PERM_EXPRs can, punt. + If one or both of the original VEC_PERM_EXPRs can't be + handled and the new one can't be either, don't increase + number of VEC_PERM_EXPRs that can't be handled. */ + if (can_vec_perm_const_p (result_mode, op_mode, sel2, false) + || (single_use (@0) + ? (!can_vec_perm_const_p (result_mode, op_mode, sel0, false) + || !can_vec_perm_const_p (result_mode, op_mode, sel1, false)) + : !can_vec_perm_const_p (result_mode, op_mode, sel1, false))) + op0 = vec_perm_indices_to_tree (TREE_TYPE (@4), sel2); + } + (if (op0) + (switch + (if (use_1) + (vec_perm @1 @5 { op0; })) + (if (use_2) + (vec_perm @2 @5 { op0; }))))))))))) + /* Match count trailing zeroes for simplify_count_trailing_zeroes in fwprop. The canonical form is array[((x & -x) * C) >> SHIFT] where C is a magic @@ -9002,6 +9349,18 @@ and, (if (!TYPE_OVERFLOW_SANITIZED (type)) (bit_and @0 @1))) +/* `-a` is just `a` if the type is 1bit wide or when converting + to a 1bit type; similar to the above transformation of `(-x)&1`. + This is used mostly with the transformation of + `a ? ~b : b` into `(-a)^b`. + It also can show up with bitfields. */ +(simplify + (convert? (negate @0)) + (if (INTEGRAL_TYPE_P (type) + && TYPE_PRECISION (type) == 1 + && !TYPE_OVERFLOW_SANITIZED (TREE_TYPE (@0))) + (convert @0))) + /* Optimize c1 = VEC_PERM_EXPR (a, a, mask) c2 = VEC_PERM_EXPR (b, b, mask) diff --git a/gcc/mode-switching.cc b/gcc/mode-switching.cc index 64ae2bc29c30..f483c831c35f 100644 --- a/gcc/mode-switching.cc +++ b/gcc/mode-switching.cc @@ -411,6 +411,7 @@ create_pre_exit (int n_entities, int *entity_map, const int *num_modes) conflict with address reloads. */ if (copy_start >= ret_start && copy_start + copy_num <= ret_end + && GET_CODE (return_copy_pat) == SET && OBJECT_P (SET_SRC (return_copy_pat))) forced_late_switch = true; break; diff --git a/gcc/objc/ChangeLog b/gcc/objc/ChangeLog index 0d96523b880f..155efd18df2d 100644 --- a/gcc/objc/ChangeLog +++ b/gcc/objc/ChangeLog @@ -1,3 +1,7 @@ +2023-08-31 Francois-Xavier Coudert + + * objc-act.cc: Change spelling to macOS. + 2023-05-18 Bernhard Reutner-Fischer * objc-act.cc (objc_volatilize_decl): Use _P() defines from tree.h. diff --git a/gcc/objc/objc-act.cc b/gcc/objc/objc-act.cc index e4c49e664e17..186a29cd2705 100644 --- a/gcc/objc/objc-act.cc +++ b/gcc/objc/objc-act.cc @@ -3314,7 +3314,7 @@ objc_build_string_object (tree string) length = TREE_STRING_LENGTH (string) - 1; /* The target may have different ideas on how to construct an ObjC string - literal. On Darwin (Mac OS X), for example, we may wish to obtain a + literal. On Darwin / macOS, for example, we may wish to obtain a constant CFString reference instead. At present, this is only supported for the NeXT runtime. */ if (flag_next_runtime diff --git a/gcc/omp-api.h b/gcc/omp-api.h new file mode 100644 index 000000000000..2a7ec7b72a61 --- /dev/null +++ b/gcc/omp-api.h @@ -0,0 +1,32 @@ +/* Functions for querying whether a function name is reserved by the + OpenMP API. This is used for error checking. + + Copyright (C) 2023 Free Software Foundation, Inc. + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 3, or (at your option) any later +version. + +GCC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +. */ + +#ifndef GCC_OMP_API_H +#define GCC_OMP_API_H + +#include "coretypes.h" + +/* In omp-general.cc, but declared in a separate header file for + convenience of the Fortran front end. */ +extern bool omp_runtime_api_procname (const char *name); +extern bool omp_runtime_api_call (const_tree fndecl); + +#endif diff --git a/gcc/omp-expand.cc b/gcc/omp-expand.cc index db58b3cb49b6..6172839c7193 100644 --- a/gcc/omp-expand.cc +++ b/gcc/omp-expand.cc @@ -2562,7 +2562,8 @@ expand_omp_for_init_vars (struct omp_for_data *fd, gimple_stmt_iterator *gsi, tree factor = fd->factor; gcond *cond_stmt = expand_omp_build_cond (gsi, NE_EXPR, factor, - build_zero_cst (TREE_TYPE (factor))); + build_zero_cst (TREE_TYPE (factor)), + true); edge e = split_block (gsi_bb (*gsi), cond_stmt); basic_block bb0 = e->src; e->flags = EDGE_TRUE_VALUE; @@ -10592,6 +10593,10 @@ expand_omp (struct omp_region *region) parent GIMPLE_OMP_SECTIONS region. */ break; + case GIMPLE_OMP_STRUCTURED_BLOCK: + /* We should have gotten rid of these in gimple lowering. */ + gcc_unreachable (); + case GIMPLE_OMP_SINGLE: case GIMPLE_OMP_SCOPE: expand_omp_single (region); diff --git a/gcc/omp-general.cc b/gcc/omp-general.cc index eefdcb54590f..1e31014c4544 100644 --- a/gcc/omp-general.cc +++ b/gcc/omp-general.cc @@ -3013,4 +3013,138 @@ omp_build_component_ref (tree obj, tree field) return ret; } +/* Return true if NAME is the name of an omp_* runtime API call. */ +bool +omp_runtime_api_procname (const char *name) +{ + if (!startswith (name, "omp_")) + return false; + + static const char *omp_runtime_apis[] = + { + /* This array has 3 sections. First omp_* calls that don't + have any suffixes. */ + "aligned_alloc", + "aligned_calloc", + "alloc", + "calloc", + "free", + "get_mapped_ptr", + "realloc", + "target_alloc", + "target_associate_ptr", + "target_disassociate_ptr", + "target_free", + "target_is_accessible", + "target_is_present", + "target_memcpy", + "target_memcpy_async", + "target_memcpy_rect", + "target_memcpy_rect_async", + NULL, + /* Now omp_* calls that are available as omp_* and omp_*_; however, the + DECL_NAME is always omp_* without tailing underscore. */ + "capture_affinity", + "destroy_allocator", + "destroy_lock", + "destroy_nest_lock", + "display_affinity", + "fulfill_event", + "get_active_level", + "get_affinity_format", + "get_cancellation", + "get_default_allocator", + "get_default_device", + "get_device_num", + "get_dynamic", + "get_initial_device", + "get_level", + "get_max_active_levels", + "get_max_task_priority", + "get_max_teams", + "get_max_threads", + "get_nested", + "get_num_devices", + "get_num_places", + "get_num_procs", + "get_num_teams", + "get_num_threads", + "get_partition_num_places", + "get_place_num", + "get_proc_bind", + "get_supported_active_levels", + "get_team_num", + "get_teams_thread_limit", + "get_thread_limit", + "get_thread_num", + "get_wtick", + "get_wtime", + "in_explicit_task", + "in_final", + "in_parallel", + "init_lock", + "init_nest_lock", + "is_initial_device", + "pause_resource", + "pause_resource_all", + "set_affinity_format", + "set_default_allocator", + "set_lock", + "set_nest_lock", + "test_lock", + "test_nest_lock", + "unset_lock", + "unset_nest_lock", + NULL, + /* And finally calls available as omp_*, omp_*_ and omp_*_8_; however, + as DECL_NAME only omp_* and omp_*_8 appear. */ + "display_env", + "get_ancestor_thread_num", + "init_allocator", + "get_partition_place_nums", + "get_place_num_procs", + "get_place_proc_ids", + "get_schedule", + "get_team_size", + "set_default_device", + "set_dynamic", + "set_max_active_levels", + "set_nested", + "set_num_teams", + "set_num_threads", + "set_schedule", + "set_teams_thread_limit" + }; + + int mode = 0; + for (unsigned i = 0; i < ARRAY_SIZE (omp_runtime_apis); i++) + { + if (omp_runtime_apis[i] == NULL) + { + mode++; + continue; + } + size_t len = strlen (omp_runtime_apis[i]); + if (strncmp (name + 4, omp_runtime_apis[i], len) == 0 + && (name[4 + len] == '\0' + || (mode > 1 && strcmp (name + 4 + len, "_8") == 0))) + return true; + } + return false; +} + +/* Return true if FNDECL is an omp_* runtime API call. */ + +bool +omp_runtime_api_call (const_tree fndecl) +{ + tree declname = DECL_NAME (fndecl); + if (!declname + || (DECL_CONTEXT (fndecl) != NULL_TREE + && TREE_CODE (DECL_CONTEXT (fndecl)) != TRANSLATION_UNIT_DECL) + || !TREE_PUBLIC (fndecl)) + return false; + return omp_runtime_api_procname (IDENTIFIER_POINTER (declname)); +} + #include "gt-omp-general.h" diff --git a/gcc/omp-general.h b/gcc/omp-general.h index 92717db16280..1a52bfdb56b7 100644 --- a/gcc/omp-general.h +++ b/gcc/omp-general.h @@ -23,6 +23,7 @@ along with GCC; see the file COPYING3. If not see #define GCC_OMP_GENERAL_H #include "gomp-constants.h" +#include "omp-api.h" /* Flags for an OpenACC loop. */ diff --git a/gcc/omp-low.cc b/gcc/omp-low.cc index b882df048ef2..5d7c32dac39f 100644 --- a/gcc/omp-low.cc +++ b/gcc/omp-low.cc @@ -4009,135 +4009,6 @@ setjmp_or_longjmp_p (const_tree fndecl) return !strcmp (name, "setjmp") || !strcmp (name, "longjmp"); } -/* Return true if FNDECL is an omp_* runtime API call. */ - -static bool -omp_runtime_api_call (const_tree fndecl) -{ - tree declname = DECL_NAME (fndecl); - if (!declname - || (DECL_CONTEXT (fndecl) != NULL_TREE - && TREE_CODE (DECL_CONTEXT (fndecl)) != TRANSLATION_UNIT_DECL) - || !TREE_PUBLIC (fndecl)) - return false; - - const char *name = IDENTIFIER_POINTER (declname); - if (!startswith (name, "omp_")) - return false; - - static const char *omp_runtime_apis[] = - { - /* This array has 3 sections. First omp_* calls that don't - have any suffixes. */ - "aligned_alloc", - "aligned_calloc", - "alloc", - "calloc", - "free", - "get_mapped_ptr", - "realloc", - "target_alloc", - "target_associate_ptr", - "target_disassociate_ptr", - "target_free", - "target_is_accessible", - "target_is_present", - "target_memcpy", - "target_memcpy_async", - "target_memcpy_rect", - "target_memcpy_rect_async", - NULL, - /* Now omp_* calls that are available as omp_* and omp_*_; however, the - DECL_NAME is always omp_* without tailing underscore. */ - "capture_affinity", - "destroy_allocator", - "destroy_lock", - "destroy_nest_lock", - "display_affinity", - "fulfill_event", - "get_active_level", - "get_affinity_format", - "get_cancellation", - "get_default_allocator", - "get_default_device", - "get_device_num", - "get_dynamic", - "get_initial_device", - "get_level", - "get_max_active_levels", - "get_max_task_priority", - "get_max_teams", - "get_max_threads", - "get_nested", - "get_num_devices", - "get_num_places", - "get_num_procs", - "get_num_teams", - "get_num_threads", - "get_partition_num_places", - "get_place_num", - "get_proc_bind", - "get_supported_active_levels", - "get_team_num", - "get_teams_thread_limit", - "get_thread_limit", - "get_thread_num", - "get_wtick", - "get_wtime", - "in_explicit_task", - "in_final", - "in_parallel", - "init_lock", - "init_nest_lock", - "is_initial_device", - "pause_resource", - "pause_resource_all", - "set_affinity_format", - "set_default_allocator", - "set_lock", - "set_nest_lock", - "test_lock", - "test_nest_lock", - "unset_lock", - "unset_nest_lock", - NULL, - /* And finally calls available as omp_*, omp_*_ and omp_*_8_; however, - as DECL_NAME only omp_* and omp_*_8 appear. */ - "display_env", - "get_ancestor_thread_num", - "init_allocator", - "get_partition_place_nums", - "get_place_num_procs", - "get_place_proc_ids", - "get_schedule", - "get_team_size", - "set_default_device", - "set_dynamic", - "set_max_active_levels", - "set_nested", - "set_num_teams", - "set_num_threads", - "set_schedule", - "set_teams_thread_limit" - }; - - int mode = 0; - for (unsigned i = 0; i < ARRAY_SIZE (omp_runtime_apis); i++) - { - if (omp_runtime_apis[i] == NULL) - { - mode++; - continue; - } - size_t len = strlen (omp_runtime_apis[i]); - if (strncmp (name + 4, omp_runtime_apis[i], len) == 0 - && (name[4 + len] == '\0' - || (mode > 1 && strcmp (name + 4 + len, "_8") == 0))) - return true; - } - return false; -} - /* Helper function for scan_omp. Callback for walk_gimple_stmt used to scan for OMP directives in @@ -4300,6 +4171,7 @@ scan_omp_1_stmt (gimple_stmt_iterator *gsi, bool *handled_ops_p, } /* FALLTHRU */ case GIMPLE_OMP_SECTION: + case GIMPLE_OMP_STRUCTURED_BLOCK: case GIMPLE_OMP_MASTER: case GIMPLE_OMP_ORDERED: case GIMPLE_OMP_CRITICAL: @@ -14499,6 +14371,14 @@ lower_omp_1 (gimple_stmt_iterator *gsi_p, omp_context *ctx) gcc_assert (ctx); lower_omp_single (gsi_p, ctx); break; + case GIMPLE_OMP_STRUCTURED_BLOCK: + /* We have already done error checking at this point, so these nodes + can be completely removed and replaced with their body. */ + ctx = maybe_lookup_ctx (stmt); + gcc_assert (ctx); + lower_omp (gimple_omp_body_ptr (stmt), ctx); + gsi_replace_with_seq (gsi_p, gimple_omp_body (stmt), true); + break; case GIMPLE_OMP_MASTER: case GIMPLE_OMP_MASKED: ctx = maybe_lookup_ctx (stmt); @@ -14886,6 +14766,7 @@ diagnose_sb_1 (gimple_stmt_iterator *gsi_p, bool *handled_ops_p, case GIMPLE_OMP_SECTIONS: case GIMPLE_OMP_SINGLE: case GIMPLE_OMP_SECTION: + case GIMPLE_OMP_STRUCTURED_BLOCK: case GIMPLE_OMP_MASTER: case GIMPLE_OMP_MASKED: case GIMPLE_OMP_ORDERED: @@ -14949,6 +14830,7 @@ diagnose_sb_2 (gimple_stmt_iterator *gsi_p, bool *handled_ops_p, case GIMPLE_OMP_SECTIONS: case GIMPLE_OMP_SINGLE: case GIMPLE_OMP_SECTION: + case GIMPLE_OMP_STRUCTURED_BLOCK: case GIMPLE_OMP_MASTER: case GIMPLE_OMP_MASKED: case GIMPLE_OMP_ORDERED: diff --git a/gcc/optabs.def b/gcc/optabs.def index 1ea1947b3b57..2ccbe4197b7b 100644 --- a/gcc/optabs.def +++ b/gcc/optabs.def @@ -82,6 +82,8 @@ OPTAB_CD(vec_load_lanes_optab, "vec_load_lanes$a$b") OPTAB_CD(vec_store_lanes_optab, "vec_store_lanes$a$b") OPTAB_CD(vec_mask_load_lanes_optab, "vec_mask_load_lanes$a$b") OPTAB_CD(vec_mask_store_lanes_optab, "vec_mask_store_lanes$a$b") +OPTAB_CD(vec_mask_len_load_lanes_optab, "vec_mask_len_load_lanes$a$b") +OPTAB_CD(vec_mask_len_store_lanes_optab, "vec_mask_len_store_lanes$a$b") OPTAB_CD(vcond_optab, "vcond$a$b") OPTAB_CD(vcondu_optab, "vcondu$a$b") OPTAB_CD(vcondeq_optab, "vcondeq$a$b") @@ -254,6 +256,7 @@ OPTAB_D (cond_fms_optab, "cond_fms$a") OPTAB_D (cond_fnma_optab, "cond_fnma$a") OPTAB_D (cond_fnms_optab, "cond_fnms$a") OPTAB_D (cond_neg_optab, "cond_neg$a") +OPTAB_D (cond_one_cmpl_optab, "cond_one_cmpl$a") OPTAB_D (cond_len_add_optab, "cond_len_add$a") OPTAB_D (cond_len_sub_optab, "cond_len_sub$a") OPTAB_D (cond_len_smul_optab, "cond_len_mul$a") @@ -278,6 +281,7 @@ OPTAB_D (cond_len_fms_optab, "cond_len_fms$a") OPTAB_D (cond_len_fnma_optab, "cond_len_fnma$a") OPTAB_D (cond_len_fnms_optab, "cond_len_fnms$a") OPTAB_D (cond_len_neg_optab, "cond_len_neg$a") +OPTAB_D (cond_len_one_cmpl_optab, "cond_len_one_cmpl$a") OPTAB_D (cmov_optab, "cmov$a6") OPTAB_D (cstore_optab, "cstore$a4") OPTAB_D (ctrap_optab, "ctrap$a4") @@ -389,6 +393,7 @@ OPTAB_D (mask_len_fold_left_plus_optab, "mask_len_fold_left_plus_$a") OPTAB_D (extract_last_optab, "extract_last_$a") OPTAB_D (fold_extract_last_optab, "fold_extract_last_$a") +OPTAB_D (len_fold_extract_last_optab, "len_fold_extract_last_$a") OPTAB_D (uabd_optab, "uabd$a3") OPTAB_D (sabd_optab, "sabd$a3") diff --git a/gcc/ordered-hash-map-tests.cc b/gcc/ordered-hash-map-tests.cc index 1c26bbfa9793..c2516b8cf3b0 100644 --- a/gcc/ordered-hash-map-tests.cc +++ b/gcc/ordered-hash-map-tests.cc @@ -58,6 +58,7 @@ static void test_map_of_strings_to_int () { ordered_hash_map m; + bool existed; const char *ostrich = "ostrich"; const char *elephant = "elephant"; @@ -74,17 +75,23 @@ test_map_of_strings_to_int () ASSERT_EQ (false, m.put (ostrich, 2)); ASSERT_EQ (false, m.put (elephant, 4)); ASSERT_EQ (false, m.put (ant, 6)); - ASSERT_EQ (false, m.put (spider, 8)); + existed = true; + int &value = m.get_or_insert (spider, &existed); + value = 8; + ASSERT_EQ (false, existed); ASSERT_EQ (false, m.put (millipede, 750)); ASSERT_EQ (false, m.put (eric, 3)); + /* Verify that we can recover the stored values. */ ASSERT_EQ (6, m.elements ()); ASSERT_EQ (2, *m.get (ostrich)); ASSERT_EQ (4, *m.get (elephant)); ASSERT_EQ (6, *m.get (ant)); ASSERT_EQ (8, *m.get (spider)); - ASSERT_EQ (750, *m.get (millipede)); + existed = false; + ASSERT_EQ (750, m.get_or_insert (millipede, &existed)); + ASSERT_EQ (true, existed); ASSERT_EQ (3, *m.get (eric)); /* Verify that the order of insertion is preserved. */ @@ -113,6 +120,7 @@ test_map_of_int_to_strings () { const int EMPTY = -1; const int DELETED = -2; + bool existed; typedef int_hash int_hash_t; ordered_hash_map m; @@ -131,7 +139,9 @@ test_map_of_int_to_strings () ASSERT_EQ (false, m.put (2, ostrich)); ASSERT_EQ (false, m.put (4, elephant)); ASSERT_EQ (false, m.put (6, ant)); - ASSERT_EQ (false, m.put (8, spider)); + const char* &value = m.get_or_insert (8, &existed); + value = spider; + ASSERT_EQ (false, existed); ASSERT_EQ (false, m.put (750, millipede)); ASSERT_EQ (false, m.put (3, eric)); @@ -141,7 +151,8 @@ test_map_of_int_to_strings () ASSERT_EQ (*m.get (4), elephant); ASSERT_EQ (*m.get (6), ant); ASSERT_EQ (*m.get (8), spider); - ASSERT_EQ (*m.get (750), millipede); + ASSERT_EQ (m.get_or_insert (750, &existed), millipede); + ASSERT_EQ (existed, true); ASSERT_EQ (*m.get (3), eric); /* Verify that the order of insertion is preserved. */ diff --git a/gcc/ordered-hash-map.h b/gcc/ordered-hash-map.h index 6b68cc96305d..9fc875182e1c 100644 --- a/gcc/ordered-hash-map.h +++ b/gcc/ordered-hash-map.h @@ -76,6 +76,32 @@ public: return m_map.get (k); } + /* Return a reference to the value for the passed in key, creating the entry + if it doesn't already exist. If existed is not NULL then it is set to + false if the key was not previously in the map, and true otherwise. */ + + Value &get_or_insert (const Key &k, bool *existed = NULL) + { + bool _existed; + Value &ret = m_map.get_or_insert (k, &_existed); + + if (!_existed) + { + bool key_present; + int &slot = m_key_index.get_or_insert (k, &key_present); + if (!key_present) + { + slot = m_keys.length (); + m_keys.safe_push (k); + } + } + + if (existed) + *existed = _existed; + + return ret; + } + /* Removing a key removes it from the map, but retains the insertion order. */ diff --git a/gcc/plugin.cc b/gcc/plugin.cc index 142f3fa4131f..c3e40b2cf757 100644 --- a/gcc/plugin.cc +++ b/gcc/plugin.cc @@ -190,10 +190,10 @@ add_new_plugin (const char* plugin_name) #if defined(__MINGW32__) static const char plugin_ext[] = ".dll"; #elif defined(__APPLE__) - /* Mac OS has two types of libraries: dynamic libraries (.dylib) and + /* macOS has two types of libraries: dynamic libraries (.dylib) and plugins (.bundle). Both can be used with dlopen()/dlsym() but the former cannot be linked at build time (i.e., with the -lfoo linker - option). A GCC plugin is therefore probably a Mac OS plugin but their + option). A GCC plugin is therefore probably a macOS plugin but their use seems to be quite rare and the .bundle extension is more of a recommendation rather than the rule. This raises the questions of how well they are supported by tools (e.g., libtool). So to avoid diff --git a/gcc/predict.cc b/gcc/predict.cc index 5a1a561cc246..396746cbfd1a 100644 --- a/gcc/predict.cc +++ b/gcc/predict.cc @@ -4131,6 +4131,7 @@ pass_profile::execute (function *fun) scev_initialize (); tree_estimate_probability (false); + cfun->cfg->full_profile = true; if (nb_loops > 1) scev_finalize (); diff --git a/gcc/profile-count.cc b/gcc/profile-count.cc index e63c9432388b..a14f379db8fa 100644 --- a/gcc/profile-count.cc +++ b/gcc/profile-count.cc @@ -128,13 +128,14 @@ profile_count::differs_from_p (profile_count other) const { gcc_checking_assert (compatible_p (other)); if (!initialized_p () || !other.initialized_p ()) - return false; + return initialized_p () != other.initialized_p (); if ((uint64_t)m_val - (uint64_t)other.m_val < 100 || (uint64_t)other.m_val - (uint64_t)m_val < 100) return false; if (!other.m_val) return true; - int64_t ratio = (int64_t)m_val * 100 / other.m_val; + uint64_t ratio; + safe_scale_64bit (m_val, 100, other.m_val, &ratio); return ratio < 99 || ratio > 101; } diff --git a/gcc/range-op-float.cc b/gcc/range-op-float.cc index e30b489c410e..eebc73f9918c 100644 --- a/gcc/range-op-float.cc +++ b/gcc/range-op-float.cc @@ -268,22 +268,75 @@ maybe_isnan (const frange &op1, const frange &op2) return op1.maybe_isnan () || op2.maybe_isnan (); } -// Floating version of relop_early_resolve that takes into account NAN -// and -ffinite-math-only. +// Floating point version of relop_early_resolve that takes NANs into +// account. +// +// For relation opcodes, first try to see if the supplied relation +// forces a true or false result, and return that. +// Then check for undefined operands. If none of this applies, +// return false. +// +// TRIO are the relations between operands as they appear in the IL. +// MY_REL is the relation that corresponds to the operator being +// folded. For example, when attempting to fold x_3 == y_5, MY_REL is +// VREL_EQ, and if the statement is dominated by x_3 > y_5, then +// TRIO.op1_op2() is VREL_GT. +// +// Relations in a floating point world are a bit tricky, as TRIO +// behaves as the corresponding unordered variant if either operand +// could be a NAN. For example, when resolving "if (x_5 == x_5)", the +// relation is VREL_EQ, but it behaves like VREL_UNEQ if NANs are a +// possibility. Similarly, the false edge of "if (x >= y)" has a +// relation of VREL_LT, but behaves as VREL_UNLT unless we can prove +// neither operand can be NAN. +// +// ?? It is unclear whether providing unordered VREL relations would +// simplify things, as we'd have to add more entries to various +// tables, tweak all the op1_op2_relation() entries, etc. static inline bool frelop_early_resolve (irange &r, tree type, const frange &op1, const frange &op2, - relation_trio rel, relation_kind my_rel) + relation_trio trio, relation_kind my_rel) { + relation_kind rel = trio.op1_op2 (); + + if (maybe_isnan (op1, op2)) + { + // There's not much we can do for VREL_EQ if NAN is a + // possibility. It is up to the caller to deal with these + // special cases. + if (rel == VREL_EQ) + return empty_range_varying (r, type, op1, op2); + } + // If known relation is a complete subset of this relation, always + // return true. However, avoid doing this when NAN is a possibility + // as we'll incorrectly fold conditions: + // + // if (x_3 >= y_5) + // ; + // else + // ;; With NANs the relation here is basically VREL_UNLT, so we + // ;; can't fold the following: + // if (x_3 < y_5) + else if (relation_union (rel, my_rel) == my_rel) + { + r = range_true (type); + return true; + } + + // If known relation has no subset of this relation, always false. + if (relation_intersect (rel, my_rel) == VREL_UNDEFINED) + { + r = range_false (type); + return true; + } + // If either operand is undefined, return VARYING. if (empty_range_varying (r, type, op1, op2)) return true; - // We can fold relations from the oracle when we know both operands - // are free of NANs, or when -ffinite-math-only. - return (!maybe_isnan (op1, op2) - && relop_early_resolve (r, type, op1, op2, rel, my_rel)); + return false; } // Set VALUE to its next real value, or INF if the operation overflows. @@ -738,9 +791,17 @@ operator_equal::op1_op2_relation (const irange &lhs, const frange &, bool operator_not_equal::fold_range (irange &r, tree type, const frange &op1, const frange &op2, - relation_trio rel) const + relation_trio trio) const { - if (frelop_early_resolve (r, type, op1, op2, rel, VREL_NE)) + relation_kind rel = trio.op1_op2 (); + + // VREL_NE & NE_EXPR is always true, even with NANs. + if (rel == VREL_NE) + { + r = range_true (type); + return true; + } + if (frelop_early_resolve (r, type, op1, op2, trio, VREL_NE)) return true; // x != NAN is always TRUE. @@ -862,9 +923,17 @@ operator_not_equal::op1_op2_relation (const irange &lhs, const frange &, bool operator_lt::fold_range (irange &r, tree type, const frange &op1, const frange &op2, - relation_trio rel) const + relation_trio trio) const { - if (frelop_early_resolve (r, type, op1, op2, rel, VREL_LT)) + relation_kind rel = trio.op1_op2 (); + + // VREL_EQ & LT_EXPR is impossible, even with NANs. + if (rel == VREL_EQ) + { + r = range_false (type); + return true; + } + if (frelop_early_resolve (r, type, op1, op2, trio, VREL_LT)) return true; if (op1.known_isnan () @@ -1083,9 +1152,17 @@ operator_le::op1_op2_relation (const irange &lhs, const frange &, bool operator_gt::fold_range (irange &r, tree type, const frange &op1, const frange &op2, - relation_trio rel) const + relation_trio trio) const { - if (frelop_early_resolve (r, type, op1, op2, rel, VREL_GT)) + relation_kind rel = trio.op1_op2 (); + + // VREL_EQ & GT_EXPR is impossible, even with NANs. + if (rel == VREL_EQ) + { + r = range_false (type); + return true; + } + if (frelop_early_resolve (r, type, op1, op2, trio, VREL_GT)) return true; if (op1.known_isnan () @@ -1587,9 +1664,12 @@ class foperator_unordered_lt : public range_operator public: bool fold_range (irange &r, tree type, const frange &op1, const frange &op2, - relation_trio rel = TRIO_VARYING) const final override + relation_trio trio = TRIO_VARYING) const final override { - if (op1.known_isnan () || op2.known_isnan ()) + relation_kind rel = trio.op1_op2 (); + + if (op1.known_isnan () || op2.known_isnan () + || rel == VREL_LT) { r = range_true (type); return true; @@ -1601,7 +1681,7 @@ public: if (op2.maybe_isnan ()) op2_no_nan.clear_nan (); if (!range_op_handler (LT_EXPR).fold_range (r, type, op1_no_nan, - op2_no_nan, rel)) + op2_no_nan, trio)) return false; // The result is the same as the ordered version when the // comparison is true or when the operands cannot be NANs. @@ -1699,9 +1779,12 @@ class foperator_unordered_le : public range_operator public: bool fold_range (irange &r, tree type, const frange &op1, const frange &op2, - relation_trio rel = TRIO_VARYING) const final override + relation_trio trio = TRIO_VARYING) const final override { - if (op1.known_isnan () || op2.known_isnan ()) + relation_kind rel = trio.op1_op2 (); + + if (op1.known_isnan () || op2.known_isnan () + || rel == VREL_LE) { r = range_true (type); return true; @@ -1713,7 +1796,7 @@ public: if (op2.maybe_isnan ()) op2_no_nan.clear_nan (); if (!range_op_handler (LE_EXPR).fold_range (r, type, op1_no_nan, - op2_no_nan, rel)) + op2_no_nan, trio)) return false; // The result is the same as the ordered version when the // comparison is true or when the operands cannot be NANs. @@ -1807,9 +1890,12 @@ class foperator_unordered_gt : public range_operator public: bool fold_range (irange &r, tree type, const frange &op1, const frange &op2, - relation_trio rel = TRIO_VARYING) const final override + relation_trio trio = TRIO_VARYING) const final override { - if (op1.known_isnan () || op2.known_isnan ()) + relation_kind rel = trio.op1_op2 (); + + if (op1.known_isnan () || op2.known_isnan () + || rel == VREL_GT) { r = range_true (type); return true; @@ -1821,7 +1907,7 @@ public: if (op2.maybe_isnan ()) op2_no_nan.clear_nan (); if (!range_op_handler (GT_EXPR).fold_range (r, type, op1_no_nan, - op2_no_nan, rel)) + op2_no_nan, trio)) return false; // The result is the same as the ordered version when the // comparison is true or when the operands cannot be NANs. @@ -1919,9 +2005,12 @@ class foperator_unordered_ge : public range_operator public: bool fold_range (irange &r, tree type, const frange &op1, const frange &op2, - relation_trio rel = TRIO_VARYING) const final override + relation_trio trio = TRIO_VARYING) const final override { - if (op1.known_isnan () || op2.known_isnan ()) + relation_kind rel = trio.op1_op2 (); + + if (op1.known_isnan () || op2.known_isnan () + || rel == VREL_GE) { r = range_true (type); return true; @@ -1933,7 +2022,7 @@ public: if (op2.maybe_isnan ()) op2_no_nan.clear_nan (); if (!range_op_handler (GE_EXPR).fold_range (r, type, op1_no_nan, - op2_no_nan, rel)) + op2_no_nan, trio)) return false; // The result is the same as the ordered version when the // comparison is true or when the operands cannot be NANs. @@ -2030,9 +2119,12 @@ class foperator_unordered_equal : public range_operator public: bool fold_range (irange &r, tree type, const frange &op1, const frange &op2, - relation_trio rel = TRIO_VARYING) const final override + relation_trio trio = TRIO_VARYING) const final override { - if (op1.known_isnan () || op2.known_isnan ()) + relation_kind rel = trio.op1_op2 (); + + if (op1.known_isnan () || op2.known_isnan () + || rel == VREL_EQ) { r = range_true (type); return true; @@ -2044,7 +2136,7 @@ public: if (op2.maybe_isnan ()) op2_no_nan.clear_nan (); if (!range_op_handler (EQ_EXPR).fold_range (r, type, op1_no_nan, - op2_no_nan, rel)) + op2_no_nan, trio)) return false; // The result is the same as the ordered version when the // comparison is true or when the operands cannot be NANs. @@ -2112,8 +2204,23 @@ class foperator_ltgt : public range_operator public: bool fold_range (irange &r, tree type, const frange &op1, const frange &op2, - relation_trio rel = TRIO_VARYING) const final override + relation_trio trio = TRIO_VARYING) const final override { + relation_kind rel = trio.op1_op2 (); + + // VREL_EQ is really VREL_(UN)EQ because we could have a NAN in + // the operands, but since LTGT_EXPR is really a NE_EXPR without + // the NAN, VREL_EQ & LTGT_EXPR is an impossibility. + if (rel == VREL_EQ) + { + r = range_false (type); + return true; + } + // ...otherwise pretend we're trying to resolve a NE_EXPR and + // everything will "just work". + if (frelop_early_resolve (r, type, op1, op2, trio, VREL_NE)) + return true; + if (op1.known_isnan () || op2.known_isnan ()) { r = range_false (type); @@ -2126,7 +2233,7 @@ public: if (op2.maybe_isnan ()) op2_no_nan.clear_nan (); if (!range_op_handler (NE_EXPR).fold_range (r, type, op1_no_nan, - op2_no_nan, rel)) + op2_no_nan, trio)) return false; // The result is the same as the ordered version when the // comparison is true or when the operands cannot be NANs. diff --git a/gcc/range-op-mixed.h b/gcc/range-op-mixed.h index 825f934cf603..ef562326c1f7 100644 --- a/gcc/range-op-mixed.h +++ b/gcc/range-op-mixed.h @@ -403,6 +403,10 @@ public: relation_kind rel) const final override; void update_bitmask (irange &r, const irange &lh, const irange &rh) const final override; + + virtual bool overflow_free_p (const irange &lh, const irange &rh, + relation_trio = TRIO_VARYING) const; + private: void wi_fold (irange &r, tree type, const wide_int &lh_lb, const wide_int &lh_ub, const wide_int &rh_lb, @@ -468,6 +472,10 @@ public: relation_kind rel) const final override; void update_bitmask (irange &r, const irange &lh, const irange &rh) const final override; + + virtual bool overflow_free_p (const irange &lh, const irange &rh, + relation_trio = TRIO_VARYING) const; + private: void wi_fold (irange &r, tree type, const wide_int &lh_lb, const wide_int &lh_ub, const wide_int &rh_lb, @@ -547,6 +555,9 @@ public: const REAL_VALUE_TYPE &lh_lb, const REAL_VALUE_TYPE &lh_ub, const REAL_VALUE_TYPE &rh_lb, const REAL_VALUE_TYPE &rh_ub, relation_kind kind) const final override; + virtual bool overflow_free_p (const irange &lh, const irange &rh, + relation_trio = TRIO_VARYING) const; + }; class operator_addr_expr : public range_operator diff --git a/gcc/range-op.cc b/gcc/range-op.cc index 086c6c197358..619979f2f61d 100644 --- a/gcc/range-op.cc +++ b/gcc/range-op.cc @@ -377,6 +377,22 @@ range_op_handler::op1_op2_relation (const vrange &lhs, } } +bool +range_op_handler::overflow_free_p (const vrange &lh, + const vrange &rh, + relation_trio rel) const +{ + gcc_checking_assert (m_operator); + switch (dispatch_kind (lh, lh, rh)) + { + case RO_III: + return m_operator->overflow_free_p(as_a (lh), + as_a (rh), + rel); + default: + return false; + } +} // Update the known bitmasks in R when applying the operation CODE to // LH and RH. @@ -706,6 +722,13 @@ range_operator::op1_op2_relation_effect (irange &lhs_range ATTRIBUTE_UNUSED, return false; } +bool +range_operator::overflow_free_p (const irange &, const irange &, + relation_trio) const +{ + return false; +} + // Apply any known bitmask updates based on this operator. void @@ -4325,7 +4348,17 @@ operator_addr_expr::op1_range (irange &r, tree type, const irange &op2, relation_trio) const { - return operator_addr_expr::fold_range (r, type, lhs, op2); + if (empty_range_varying (r, type, lhs, op2)) + return true; + + // Return a non-null pointer of the LHS type (passed in op2), but only + // if we cant overflow, eitherwise a no-zero offset could wrap to zero. + // See PR 111009. + if (!contains_zero_p (lhs) && TYPE_OVERFLOW_UNDEFINED (type)) + r = range_nonzero (type); + else + r.set_varying (type); + return true; } // Initialize any integral operators to the primary table @@ -4354,6 +4387,107 @@ range_op_table::initialize_integral_ops () } +bool +operator_plus::overflow_free_p (const irange &lh, const irange &rh, + relation_trio) const +{ + if (lh.undefined_p () || rh.undefined_p ()) + return false; + + tree type = lh.type (); + if (TYPE_OVERFLOW_UNDEFINED (type)) + return true; + + wi::overflow_type ovf; + signop sgn = TYPE_SIGN (type); + wide_int wmax0 = lh.upper_bound (); + wide_int wmax1 = rh.upper_bound (); + wi::add (wmax0, wmax1, sgn, &ovf); + if (ovf != wi::OVF_NONE) + return false; + + if (TYPE_UNSIGNED (type)) + return true; + + wide_int wmin0 = lh.lower_bound (); + wide_int wmin1 = rh.lower_bound (); + wi::add (wmin0, wmin1, sgn, &ovf); + if (ovf != wi::OVF_NONE) + return false; + + return true; +} + +bool +operator_minus::overflow_free_p (const irange &lh, const irange &rh, + relation_trio) const +{ + if (lh.undefined_p () || rh.undefined_p ()) + return false; + + tree type = lh.type (); + if (TYPE_OVERFLOW_UNDEFINED (type)) + return true; + + wi::overflow_type ovf; + signop sgn = TYPE_SIGN (type); + wide_int wmin0 = lh.lower_bound (); + wide_int wmax1 = rh.upper_bound (); + wi::sub (wmin0, wmax1, sgn, &ovf); + if (ovf != wi::OVF_NONE) + return false; + + if (TYPE_UNSIGNED (type)) + return true; + + wide_int wmax0 = lh.upper_bound (); + wide_int wmin1 = rh.lower_bound (); + wi::sub (wmax0, wmin1, sgn, &ovf); + if (ovf != wi::OVF_NONE) + return false; + + return true; +} + +bool +operator_mult::overflow_free_p (const irange &lh, const irange &rh, + relation_trio) const +{ + if (lh.undefined_p () || rh.undefined_p ()) + return false; + + tree type = lh.type (); + if (TYPE_OVERFLOW_UNDEFINED (type)) + return true; + + wi::overflow_type ovf; + signop sgn = TYPE_SIGN (type); + wide_int wmax0 = lh.upper_bound (); + wide_int wmax1 = rh.upper_bound (); + wi::mul (wmax0, wmax1, sgn, &ovf); + if (ovf != wi::OVF_NONE) + return false; + + if (TYPE_UNSIGNED (type)) + return true; + + wide_int wmin0 = lh.lower_bound (); + wide_int wmin1 = rh.lower_bound (); + wi::mul (wmin0, wmin1, sgn, &ovf); + if (ovf != wi::OVF_NONE) + return false; + + wi::mul (wmin0, wmax1, sgn, &ovf); + if (ovf != wi::OVF_NONE) + return false; + + wi::mul (wmax0, wmin1, sgn, &ovf); + if (ovf != wi::OVF_NONE) + return false; + + return true; +} + #if CHECKING_P #include "selftest.h" diff --git a/gcc/range-op.h b/gcc/range-op.h index 51121410233f..21d401cc83d9 100644 --- a/gcc/range-op.h +++ b/gcc/range-op.h @@ -154,6 +154,9 @@ public: virtual relation_kind op1_op2_relation (const frange &lhs, const frange &op1, const frange &op2) const; + + virtual bool overflow_free_p (const irange &lh, const irange &rh, + relation_trio = TRIO_VARYING) const; protected: // Perform an integral operation between 2 sub-ranges and return it. virtual void wi_fold (irange &r, tree type, @@ -223,6 +226,8 @@ public: relation_kind op1_op2_relation (const vrange &lhs, const vrange &op1, const vrange &op2) const; + bool overflow_free_p (const vrange &lh, const vrange &rh, + relation_trio = TRIO_VARYING) const; protected: unsigned dispatch_kind (const vrange &lhs, const vrange &op1, const vrange& op2) const; diff --git a/gcc/recog.cc b/gcc/recog.cc index 374320878127..92f151248a64 100644 --- a/gcc/recog.cc +++ b/gcc/recog.cc @@ -1802,8 +1802,8 @@ pop_operand (rtx op, machine_mode mode) for mode MODE in address space AS. */ bool -memory_address_addr_space_p (machine_mode mode ATTRIBUTE_UNUSED, - rtx addr, addr_space_t as) +memory_address_addr_space_p (machine_mode mode ATTRIBUTE_UNUSED, rtx addr, + addr_space_t as, code_helper ch ATTRIBUTE_UNUSED) { #ifdef GO_IF_LEGITIMATE_ADDRESS gcc_assert (ADDR_SPACE_GENERIC_P (as)); @@ -1813,7 +1813,7 @@ memory_address_addr_space_p (machine_mode mode ATTRIBUTE_UNUSED, win: return true; #else - return targetm.addr_space.legitimate_address_p (mode, addr, 0, as); + return targetm.addr_space.legitimate_address_p (mode, addr, 0, as, ch); #endif } @@ -2429,7 +2429,7 @@ offsettable_address_addr_space_p (int strictp, machine_mode mode, rtx y, rtx z; rtx y1 = y; rtx *y2; - bool (*addressp) (machine_mode, rtx, addr_space_t) = + bool (*addressp) (machine_mode, rtx, addr_space_t, code_helper) = (strictp ? strict_memory_address_addr_space_p : memory_address_addr_space_p); poly_int64 mode_sz = GET_MODE_SIZE (mode); @@ -2468,7 +2468,7 @@ offsettable_address_addr_space_p (int strictp, machine_mode mode, rtx y, *y2 = plus_constant (address_mode, *y2, mode_sz - 1); /* Use QImode because an odd displacement may be automatically invalid for any wider mode. But it should be valid for a single byte. */ - good = (*addressp) (QImode, y, as); + good = (*addressp) (QImode, y, as, ERROR_MARK); /* In any case, restore old contents of memory. */ *y2 = y1; @@ -2503,7 +2503,7 @@ offsettable_address_addr_space_p (int strictp, machine_mode mode, rtx y, /* Use QImode because an odd displacement may be automatically invalid for any wider mode. But it should be valid for a single byte. */ - return (*addressp) (QImode, z, as); + return (*addressp) (QImode, z, as, ERROR_MARK); } /* Return true if ADDR is an address-expression whose effect depends diff --git a/gcc/recog.h b/gcc/recog.h index badf8e3dc1c0..c6ef619c5dd7 100644 --- a/gcc/recog.h +++ b/gcc/recog.h @@ -20,6 +20,9 @@ along with GCC; see the file COPYING3. If not see #ifndef GCC_RECOG_H #define GCC_RECOG_H +/* For enum tree_code ERROR_MARK. */ +#include "tree.h" + /* Random number that should be large enough for all purposes. Also define a type that has at least MAX_RECOG_ALTERNATIVES + 1 bits, with the extra bit giving an invalid value that can be used to mean "uninitialized". */ @@ -200,11 +203,12 @@ extern void temporarily_undo_changes (int); extern void redo_changes (int); extern bool constrain_operands (int, alternative_mask); extern bool constrain_operands_cached (rtx_insn *, int); -extern bool memory_address_addr_space_p (machine_mode, rtx, addr_space_t); +extern bool memory_address_addr_space_p (machine_mode, rtx, addr_space_t, + code_helper = ERROR_MARK); #define memory_address_p(mode,addr) \ memory_address_addr_space_p ((mode), (addr), ADDR_SPACE_GENERIC) -extern bool strict_memory_address_addr_space_p (machine_mode, rtx, - addr_space_t); +extern bool strict_memory_address_addr_space_p (machine_mode, rtx, addr_space_t, + code_helper = ERROR_MARK); #define strict_memory_address_p(mode,addr) \ strict_memory_address_addr_space_p ((mode), (addr), ADDR_SPACE_GENERIC) extern bool validate_replace_rtx_subexp (rtx, rtx, rtx_insn *, rtx *); diff --git a/gcc/reload.cc b/gcc/reload.cc index d079bc120d52..2126bdd117c8 100644 --- a/gcc/reload.cc +++ b/gcc/reload.cc @@ -2162,7 +2162,7 @@ hard_reg_set_here_p (unsigned int beg_regno, unsigned int end_regno, rtx x) bool strict_memory_address_addr_space_p (machine_mode mode ATTRIBUTE_UNUSED, - rtx addr, addr_space_t as) + rtx addr, addr_space_t as, code_helper) { #ifdef GO_IF_LEGITIMATE_ADDRESS gcc_assert (ADDR_SPACE_GENERIC_P (as)); @@ -2172,7 +2172,8 @@ strict_memory_address_addr_space_p (machine_mode mode ATTRIBUTE_UNUSED, win: return true; #else - return targetm.addr_space.legitimate_address_p (mode, addr, 1, as); + return targetm.addr_space.legitimate_address_p (mode, addr, 1, as, + ERROR_MARK); #endif } diff --git a/gcc/rtl.h b/gcc/rtl.h index e1c51156f909..0e9491b89b4d 100644 --- a/gcc/rtl.h +++ b/gcc/rtl.h @@ -45,7 +45,7 @@ class predefined_function_abi; /* Register Transfer Language EXPRESSIONS CODES */ #define RTX_CODE enum rtx_code -enum rtx_code { +enum rtx_code : unsigned { #define DEF_RTL_EXPR(ENUM, NAME, FORMAT, CLASS) ENUM , #include "rtl.def" /* rtl expressions are documented here */ diff --git a/gcc/simplify-rtx.cc b/gcc/simplify-rtx.cc index d7315d82aa3f..eb1ac1208320 100644 --- a/gcc/simplify-rtx.cc +++ b/gcc/simplify-rtx.cc @@ -3071,7 +3071,7 @@ simplify_context::simplify_binary_operation_1 (rtx_code code, /* (-1 - a) is ~a, unless the expression contains symbolic constants, in which case not retaining additions and subtractions could cause invalid assembly to be produced. */ - if (trueop0 == constm1_rtx + if (trueop0 == CONSTM1_RTX (mode) && !contains_symbolic_reference_p (op1)) return simplify_gen_unary (NOT, mode, op1, mode); diff --git a/gcc/symtab-thunks.cc b/gcc/symtab-thunks.cc index 4c04235c41b0..23ead0d2138d 100644 --- a/gcc/symtab-thunks.cc +++ b/gcc/symtab-thunks.cc @@ -648,6 +648,7 @@ expand_thunk (cgraph_node *node, bool output_asm_thunks, ? PROFILE_READ : PROFILE_GUESSED; /* FIXME: C++ FE should stop setting TREE_ASM_WRITTEN on thunks. */ TREE_ASM_WRITTEN (thunk_fndecl) = false; + cfun->cfg->full_profile = true; delete_unreachable_blocks (); update_ssa (TODO_update_ssa); checking_verify_flow_info (); diff --git a/gcc/target.def b/gcc/target.def index 7d684296c178..05f267183a39 100644 --- a/gcc/target.def +++ b/gcc/target.def @@ -2735,7 +2735,7 @@ DEFHOOK insns are saved in @var{gen_seq}. They will be emitted when all the\n\ compares in the conditional comparision are generated without error.\n\ @var{code} is the @code{rtx_code} of the compare for @var{op0} and @var{op1}.", - rtx, (rtx_insn **prep_seq, rtx_insn **gen_seq, int code, tree op0, tree op1), + rtx, (rtx_insn **prep_seq, rtx_insn **gen_seq, rtx_code code, tree op0, tree op1), NULL) DEFHOOK @@ -2752,7 +2752,7 @@ DEFHOOK be appropriate for passing to @code{gen_ccmp_next} or @code{cbranch_optab}.\n\ @var{code} is the @code{rtx_code} of the compare for @var{op0} and @var{op1}.\n\ @var{bit_code} is @code{AND} or @code{IOR}, which is the op on the compares.", - rtx, (rtx_insn **prep_seq, rtx_insn **gen_seq, rtx prev, int cmp_code, tree op0, tree op1, int bit_code), + rtx, (rtx_insn **prep_seq, rtx_insn **gen_seq, rtx prev, rtx_code cmp_code, tree op0, tree op1, rtx_code bit_code), NULL) /* Return a new value for loop unroll size. */ @@ -2897,6 +2897,13 @@ DEFHOOK (legitimate_address_p, "A function that returns whether @var{x} (an RTX) is a legitimate memory\n\ address on the target machine for a memory operand of mode @var{mode}.\n\ +If @var{ch} is not @code{ERROR_MARK}, it can be called from middle-end to\n\ +determine if it is valid to use @var{x} as a memory operand for RTX insn\n\ +which is generated for the given code_helper @var{ch}. For example,\n\ +assuming the given @var{ch} is IFN_LEN_LOAD, on some target its underlying\n\ +hardware instructions support fewer addressing modes than what are for the\n\ +normal vector load and store, then with this @var{ch} target can know the\n\ +actual use context and return more exact result.\n\ \n\ Legitimate addresses are defined in two variants: a strict variant and a\n\ non-strict one. The @var{strict} parameter chooses which variant is\n\ @@ -2957,7 +2964,7 @@ that case and the non-strict variant otherwise.\n\ \n\ Using the hook is usually simpler because it limits the number of\n\ files that are recompiled when changes are made.", - bool, (machine_mode mode, rtx x, bool strict), + bool, (machine_mode mode, rtx x, bool strict, code_helper ch), default_legitimate_address_p) /* True if the given constant can be put into an object_block. */ @@ -3348,12 +3355,13 @@ target hooks for the given address space.", DEFHOOK (legitimate_address_p, "Define this to return true if @var{exp} is a valid address for mode\n\ -@var{mode} in the named address space @var{as}. The @var{strict}\n\ -parameter says whether strict addressing is in effect after reload has\n\ -finished. This target hook is the same as the\n\ +@var{mode} in the named address space @var{as} with the use context\n\ +@var{ch}. The @var{strict} parameter says whether strict addressing\n\ +is in effect after reload has finished. The @var{ch} indicates what\n\ +context @var{exp} will be used for. This target hook is the same as the\n\ @code{TARGET_LEGITIMATE_ADDRESS_P} target hook, except that it includes\n\ explicit named address space support.", - bool, (machine_mode mode, rtx exp, bool strict, addr_space_t as), + bool, (machine_mode mode, rtx exp, bool strict, addr_space_t as, code_helper ch), default_addr_space_legitimate_address_p) /* Return an updated address to convert an invalid pointer to a named diff --git a/gcc/targhooks.cc b/gcc/targhooks.cc index e190369f87a9..4ef53267e500 100644 --- a/gcc/targhooks.cc +++ b/gcc/targhooks.cc @@ -99,7 +99,8 @@ along with GCC; see the file COPYING3. If not see bool default_legitimate_address_p (machine_mode mode ATTRIBUTE_UNUSED, rtx addr ATTRIBUTE_UNUSED, - bool strict ATTRIBUTE_UNUSED) + bool strict ATTRIBUTE_UNUSED, + code_helper ATTRIBUTE_UNUSED) { #ifdef GO_IF_LEGITIMATE_ADDRESS /* Defer to the old implementation using a goto. */ @@ -1680,9 +1681,10 @@ target_default_pointer_address_modes_p (void) bool default_addr_space_legitimate_address_p (machine_mode mode, rtx mem, bool strict, - addr_space_t as ATTRIBUTE_UNUSED) + addr_space_t as ATTRIBUTE_UNUSED, + code_helper code) { - return targetm.legitimate_address_p (mode, mem, strict); + return targetm.legitimate_address_p (mode, mem, strict, code); } /* Named address space version of LEGITIMIZE_ADDRESS. diff --git a/gcc/targhooks.h b/gcc/targhooks.h index 1a0db8dddd59..761225512b76 100644 --- a/gcc/targhooks.h +++ b/gcc/targhooks.h @@ -20,7 +20,7 @@ along with GCC; see the file COPYING3. If not see #ifndef GCC_TARGHOOKS_H #define GCC_TARGHOOKS_H -extern bool default_legitimate_address_p (machine_mode, rtx, bool); +extern bool default_legitimate_address_p (machine_mode, rtx, bool, code_helper); extern void default_external_libcall (rtx); extern rtx default_legitimize_address (rtx, rtx, machine_mode); @@ -202,8 +202,8 @@ extern scalar_int_mode default_addr_space_pointer_mode (addr_space_t); extern scalar_int_mode default_addr_space_address_mode (addr_space_t); extern bool default_addr_space_valid_pointer_mode (scalar_int_mode, addr_space_t); -extern bool default_addr_space_legitimate_address_p (machine_mode, rtx, - bool, addr_space_t); +extern bool default_addr_space_legitimate_address_p (machine_mode, rtx, bool, + addr_space_t, code_helper); extern rtx default_addr_space_legitimize_address (rtx, rtx, machine_mode, addr_space_t); extern bool default_addr_space_subset_p (addr_space_t, addr_space_t); diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 4cd1a2e6ec46..11db817bef0a 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,2620 @@ +2023-09-03 Francois-Xavier Coudert + + PR testsuite/111066 + * g++.dg/special/initpri3.C: Fix wording. + +2023-09-03 Pan Li + + * gcc.target/riscv/rvv/autovec/vls/def.h: New macros. + * gcc.target/riscv/rvv/autovec/vls/floating-point-max-1.c: New test. + * gcc.target/riscv/rvv/autovec/vls/floating-point-max-2.c: New test. + * gcc.target/riscv/rvv/autovec/vls/floating-point-max-3.c: New test. + * gcc.target/riscv/rvv/autovec/vls/floating-point-max-4.c: New test. + * gcc.target/riscv/rvv/autovec/vls/floating-point-max-5.c: New test. + * gcc.target/riscv/rvv/autovec/vls/floating-point-min-1.c: New test. + * gcc.target/riscv/rvv/autovec/vls/floating-point-min-2.c: New test. + * gcc.target/riscv/rvv/autovec/vls/floating-point-min-3.c: New test. + * gcc.target/riscv/rvv/autovec/vls/floating-point-min-4.c: New test. + * gcc.target/riscv/rvv/autovec/vls/floating-point-min-5.c: New test. + +2023-09-02 chenxiaolong + + * gcc.target/loongarch/math-float-128.c: New test. + +2023-09-01 Harald Anlauf + + PR fortran/31059 + * gfortran.dg/bounds_check_fail_5.f90: New test. + +2023-09-01 benjamin priour + + PR analyzer/105948 + PR analyzer/94355 + * g++.dg/analyzer/out-of-bounds-placement-new.C: Added a directive. + * g++.dg/analyzer/placement-new.C: Added tests. + * g++.dg/analyzer/new-2.C: New test. + * g++.dg/analyzer/noexcept-new.C: New test. + * g++.dg/analyzer/placement-new-size.C: New test. + +2023-09-01 Hans-Peter Nilsson + + PR testsuite/111264 + * gcc.dg/plugin/analyzer_cpython_plugin.c: Make declarations + C++11-compatible. + +2023-09-01 Jonathan Wakely + + * g++.dg/pr110879.C: Moved to... + * g++.dg/opt/pr110879.C: ...here. + +2023-09-01 Vladimir Palevich + + PR libstdc++/110879 + * g++.dg/pr110879.C: New test. + +2023-09-01 Jakub Jelinek + + PR c++/111069 + * g++.dg/cpp2a/decomp8.C: New test. + * g++.dg/cpp2a/decomp9.C: New test. + * g++.dg/abi/macro0.C: Expect __GXX_ABI_VERSION 1019 rather than + 1018. + +2023-09-01 Jakub Jelinek + + PR tree-optimization/19832 + * g++.dg/opt/vectcond-1.C: Add -Wno-psabi to dg-options. + +2023-09-01 Jakub Jelinek + + PR tree-optimization/110915 + * gcc.dg/pr110915-1.c: Add -Wno-psabi to dg-options. Move vector + macro definition after limits.h inclusion. + * gcc.dg/pr110915-2.c: Likewise. + * gcc.dg/pr110915-3.c: Likewise. + * gcc.dg/pr110915-4.c: Likewise. + * gcc.dg/pr110915-5.c: Likewise. + * gcc.dg/pr110915-6.c: Likewise. + * gcc.dg/pr110915-7.c: Likewise. + * gcc.dg/pr110915-8.c: Likewise. + * gcc.dg/pr110915-9.c: Likewise. + * gcc.dg/pr110915-10.c: Likewise. + * gcc.dg/pr110915-11.c: Likewise. + * gcc.dg/pr110915-12.c: Likewise. + +2023-09-01 Lehua Ding + + * gcc.target/riscv/rvv/autovec/cond/cond_convert_float2int-1.h: New test. + * gcc.target/riscv/rvv/autovec/cond/cond_convert_float2int-2.h: New test. + * gcc.target/riscv/rvv/autovec/cond/cond_convert_float2int-rv32-1.c: New test. + * gcc.target/riscv/rvv/autovec/cond/cond_convert_float2int-rv32-2.c: New test. + * gcc.target/riscv/rvv/autovec/cond/cond_convert_float2int-rv64-1.c: New test. + * gcc.target/riscv/rvv/autovec/cond/cond_convert_float2int-rv64-2.c: New test. + * gcc.target/riscv/rvv/autovec/cond/cond_convert_float2int_run-1.c: New test. + * gcc.target/riscv/rvv/autovec/cond/cond_convert_float2int_run-2.c: New test. + * gcc.target/riscv/rvv/autovec/cond/cond_convert_int2float-1.h: New test. + * gcc.target/riscv/rvv/autovec/cond/cond_convert_int2float-2.h: New test. + * gcc.target/riscv/rvv/autovec/cond/cond_convert_int2float-rv32-1.c: New test. + * gcc.target/riscv/rvv/autovec/cond/cond_convert_int2float-rv32-2.c: New test. + * gcc.target/riscv/rvv/autovec/cond/cond_convert_int2float-rv64-1.c: New test. + * gcc.target/riscv/rvv/autovec/cond/cond_convert_int2float-rv64-2.c: New test. + * gcc.target/riscv/rvv/autovec/cond/cond_convert_int2float_run-1.c: New test. + * gcc.target/riscv/rvv/autovec/cond/cond_convert_int2float_run-2.c: New test. + +2023-09-01 Lehua Ding + + * gcc.target/riscv/rvv/autovec/cond/cond_convert_float2float-1.h: New test. + * gcc.target/riscv/rvv/autovec/cond/cond_convert_float2float-2.h: New test. + * gcc.target/riscv/rvv/autovec/cond/cond_convert_float2float-rv32-1.c: New test. + * gcc.target/riscv/rvv/autovec/cond/cond_convert_float2float-rv32-2.c: New test. + * gcc.target/riscv/rvv/autovec/cond/cond_convert_float2float-rv64-1.c: New test. + * gcc.target/riscv/rvv/autovec/cond/cond_convert_float2float-rv64-2.c: New test. + * gcc.target/riscv/rvv/autovec/cond/cond_convert_float2float_run-1.c: New test. + * gcc.target/riscv/rvv/autovec/cond/cond_convert_float2float_run-2.c: New test. + +2023-09-01 Lehua Ding + + * gcc.target/riscv/rvv/autovec/binop/narrow-3.c: Adjust. + * gcc.target/riscv/rvv/autovec/cond/cond_convert_int2int-1.h: New test. + * gcc.target/riscv/rvv/autovec/cond/cond_convert_int2int-2.h: New test. + * gcc.target/riscv/rvv/autovec/cond/cond_convert_int2int-rv32-1.c: New test. + * gcc.target/riscv/rvv/autovec/cond/cond_convert_int2int-rv32-2.c: New test. + * gcc.target/riscv/rvv/autovec/cond/cond_convert_int2int-rv64-1.c: New test. + * gcc.target/riscv/rvv/autovec/cond/cond_convert_int2int-rv64-2.c: New test. + * gcc.target/riscv/rvv/autovec/cond/cond_convert_int2int_run-1.c: New test. + * gcc.target/riscv/rvv/autovec/cond/cond_convert_int2int_run-2.c: New test. + +2023-09-01 Robin Dapp + + * gcc.target/riscv/rvv/autovec/partial/live-2.c: New test. + * gcc.target/riscv/rvv/autovec/partial/live_run-2.c: New test. + +2023-09-01 Robin Dapp + + * gcc.dg/vect/vect-outer-4c-big-array.c: Adjust regex pattern. + * gcc.dg/vect/vect-reduc-dot-s16a.c: Ditto. + * gcc.dg/vect/vect-reduc-dot-s8a.c: Ditto. + * gcc.dg/vect/vect-reduc-dot-s8b.c: Ditto. + * gcc.dg/vect/vect-reduc-dot-u16a.c: Ditto. + * gcc.dg/vect/vect-reduc-dot-u16b.c: Ditto. + * gcc.dg/vect/vect-reduc-dot-u8a.c: Ditto. + * gcc.dg/vect/vect-reduc-dot-u8b.c: Ditto. + * gcc.dg/vect/vect-reduc-pattern-1a.c: Ditto. + * gcc.dg/vect/vect-reduc-pattern-1b-big-array.c: Ditto. + * gcc.dg/vect/vect-reduc-pattern-1c-big-array.c: Ditto. + * gcc.dg/vect/vect-reduc-pattern-2a.c: Ditto. + * gcc.dg/vect/vect-reduc-pattern-2b-big-array.c: Ditto. + * gcc.dg/vect/wrapv-vect-reduc-dot-s8b.c: Ditto. + +2023-09-01 Pan Li + + * gcc.target/riscv/rvv/autovec/vls/def.h: + * gcc.target/riscv/rvv/autovec/vls/floating-point-add-1.c: New test. + * gcc.target/riscv/rvv/autovec/vls/floating-point-add-2.c: New test. + * gcc.target/riscv/rvv/autovec/vls/floating-point-add-3.c: New test. + * gcc.target/riscv/rvv/autovec/vls/floating-point-div-1.c: New test. + * gcc.target/riscv/rvv/autovec/vls/floating-point-div-2.c: New test. + * gcc.target/riscv/rvv/autovec/vls/floating-point-div-3.c: New test. + * gcc.target/riscv/rvv/autovec/vls/floating-point-mul-1.c: New test. + * gcc.target/riscv/rvv/autovec/vls/floating-point-mul-2.c: New test. + * gcc.target/riscv/rvv/autovec/vls/floating-point-mul-3.c: New test. + * gcc.target/riscv/rvv/autovec/vls/floating-point-sub-1.c: New test. + * gcc.target/riscv/rvv/autovec/vls/floating-point-sub-2.c: New test. + * gcc.target/riscv/rvv/autovec/vls/floating-point-sub-3.c: New test. + +2023-09-01 Andrew Pinski + + PR tree-optimization/19832 + * g++.dg/opt/vectcond-1.C: New test. + * gcc.dg/tree-ssa/phi-opt-same-1.c: New test. + +2023-08-31 Andrew Pinski + + PR tree-optimization/110915 + * gcc.dg/pr110915-1.c: New test. + * gcc.dg/pr110915-10.c: New test. + * gcc.dg/pr110915-11.c: New test. + * gcc.dg/pr110915-12.c: New test. + * gcc.dg/pr110915-2.c: New test. + * gcc.dg/pr110915-3.c: New test. + * gcc.dg/pr110915-4.c: New test. + * gcc.dg/pr110915-5.c: New test. + * gcc.dg/pr110915-6.c: New test. + * gcc.dg/pr110915-7.c: New test. + * gcc.dg/pr110915-8.c: New test. + * gcc.dg/pr110915-9.c: New test. + +2023-08-31 Pan Li + + * gcc.target/riscv/rvv/base/float-point-frm-autovec-4.c: New test. + +2023-08-31 Pan Li + + * gcc.target/riscv/rvv/base/float-point-frm-autovec-3.c: New test. + +2023-08-31 Peter Bergner + + PR testsuite/111228 + * gcc.target/powerpc/fold-vec-logical-ors-char.c: Update instruction + counts to match the number of associated vec_* built-in calls. + * gcc.target/powerpc/fold-vec-logical-ors-int.c: Likewise. + * gcc.target/powerpc/fold-vec-logical-ors-longlong.c: Likewise. + * gcc.target/powerpc/fold-vec-logical-ors-short.c: Likewise. + * gcc.target/powerpc/fold-vec-logical-other-char.c: Likewise. + * gcc.target/powerpc/fold-vec-logical-other-int.c: Likewise. + * gcc.target/powerpc/fold-vec-logical-other-longlong.c: Likewise. + * gcc.target/powerpc/fold-vec-logical-other-short.c: Likewise. + +2023-08-31 Pan Li + + * gcc.target/riscv/rvv/base/float-point-frm-autovec-2.c: New test. + +2023-08-31 Pan Li + Ju-Zhe Zhong + + * gcc.target/riscv/rvv/base/float-point-frm-autovec-1.c: New test. + +2023-08-31 Richard Biener + + PR middle-end/111253 + * gcc.dg/Wfree-nonheap-object-7.c: New testcase. + +2023-08-31 Jeevitha Palanisamy + + PR target/110411 + * gcc.target/powerpc/pr110411-1.c: New testcase. + * gcc.target/powerpc/pr110411-2.c: New testcase. + +2023-08-31 Lehua Ding + + * gcc.target/riscv/rvv/base/binop_vx_constraint-171.c: Adjust. + * gcc.target/riscv/rvv/base/binop_vx_constraint-173.c: Adjust. + * gcc.target/riscv/rvv/vsetvl/vsetvl-24.c: New test. + +2023-08-31 Richard Biener + + * gcc.dg/tree-ssa/forwprop-42.c: Move ... + * gcc.target/i386/pr111228.c: ... here. Enable SSE2. + +2023-08-31 Richard Biener + + * gcc.target/i386/pr52252-atom.c: Add -mprefer-vector-width=128. + * gcc.target/i386/pr52252-core.c: Likewise. + +2023-08-31 Haochen Gui + + PR target/96762 + * gcc.target/powerpc/pr96762.c: New. + +2023-08-31 Lehua Ding + + PR target/111234 + * gcc.target/riscv/rvv/vsetvl/pr111234.c: New test. + +2023-08-30 Eric Feng + + PR analyzer/107646 + * gcc.dg/plugin/analyzer_cpython_plugin.c: Implements reference + count checking for PyObjects. + * gcc.dg/plugin/cpython-plugin-test-2.c: Moved to... + * gcc.dg/plugin/cpython-plugin-test-PyList_Append.c: ...here + (and added more tests). + * gcc.dg/plugin/cpython-plugin-test-1.c: Moved to... + * gcc.dg/plugin/cpython-plugin-test-no-Python-h.c: ...here (and + added more tests). + * gcc.dg/plugin/plugin.exp: New tests. + * gcc.dg/plugin/cpython-plugin-test-PyList_New.c: New test. + * gcc.dg/plugin/cpython-plugin-test-PyLong_FromLong.c: New test. + +2023-08-30 Dimitar Dimitrov + + PR target/106562 + * gcc.target/pru/pr106562-10.c: New test. + * gcc.target/pru/pr106562-11.c: New test. + * gcc.target/pru/pr106562-5.c: New test. + * gcc.target/pru/pr106562-6.c: New test. + * gcc.target/pru/pr106562-7.c: New test. + * gcc.target/pru/pr106562-8.c: New test. + * gcc.target/pru/pr106562-9.c: New test. + +2023-08-30 Marek Polacek + + PR c++/91319 + * g++.dg/cpp2a/desig30.C: New test. + +2023-08-30 Marek Polacek + + PR c++/111173 + * g++.dg/cpp2a/constinit19.C: New test. + +2023-08-30 Richard Biener + + * gcc.dg/tree-ssa/forwprop-42.c: Use __UINT64_TYPE__ instead + of unsigned long. + +2023-08-30 Juzhe-Zhong + + * gcc.dg/vect/slp-reduc-7.c: Add RVV. + +2023-08-30 Juzhe-Zhong + + * gcc.dg/vect/slp-26.c: Adapt for RVV. + +2023-08-30 Mikael Morin + + PR fortran/48776 + * gfortran.dg/interface_procedure_1.f90: New test. + +2023-08-30 Richard Biener + + PR tree-optimization/111228 + * gcc.dg/tree-ssa/forwprop-42.c: New testcase. + +2023-08-30 Juzhe-Zhong + + * gcc.dg/vect/vect-double-reduc-5.c: Add riscv. + * gcc.dg/vect/vect-outer-4e.c: Ditto. + * gcc.dg/vect/vect-outer-4f.c: Ditto. + * gcc.dg/vect/vect-outer-4g.c: Ditto. + * gcc.dg/vect/vect-outer-4k.c: Ditto. + * gcc.dg/vect/vect-outer-4l.c: Ditto. + +2023-08-30 Juzhe-Zhong + + * gcc.dg/vect/pr88598-1.c: Add riscv_vector. + * gcc.dg/vect/pr88598-2.c: Ditto. + * gcc.dg/vect/pr88598-3.c: Ditto. + +2023-08-30 Die Li + Fei Gao + + * gcc.target/riscv/cm_mv_rv32.c: New test. + +2023-08-30 Fei Gao + + * gcc.target/riscv/rv32e_zcmp.c: add testcase for cm.popretz in rv32e + * gcc.target/riscv/rv32i_zcmp.c: add testcase for cm.popretz in rv32i + +2023-08-30 Fei Gao + + * gcc.target/riscv/rv32e_zcmp.c: New test. + * gcc.target/riscv/rv32i_zcmp.c: New test. + * gcc.target/riscv/zcmp_push_fpr.c: New test. + * gcc.target/riscv/zcmp_stack_alignment.c: New test. + +2023-08-30 Jakub Jelinek + + PR tree-optimization/110914 + * gcc.c-torture/execute/pr110914.c: New test. + +2023-08-30 Jakub Jelinek + + PR tree-optimization/111015 + * gcc.dg/pr111015.c: New test. + +2023-08-30 Tsukasa OI + + * gcc.target/riscv/arch-24.c: Test RV32I+Zcf instead. + +2023-08-30 Juzhe-Zhong + + * gcc.target/riscv/rvv/autovec/vls/misalign-1.c: New test. + +2023-08-29 Philipp Tomsich + + * gcc.target/riscv/zicond-xor-01.c: New test. + Co-authored-by: Jeff Law + +2023-08-29 David Malcolm + + PR analyzer/99860 + * c-c++-common/analyzer/overlapping-buffers.c: New test. + +2023-08-29 Marek Polacek + + * g++.dg/diagnostic/explicit.C: New test. + +2023-08-29 Jin Ma + + * gcc.target/riscv/zfa-fli-7.c: Change fa0 to fa\[0-9\] to avoid + assigning register numbers that are non-zero. + * gcc.target/riscv/zfa-fli-8.c: Ditto. + * gcc.target/riscv/zfa-fli-5.c: New test. + +2023-08-29 Edwin Lu + Vineet Gupta + + * gcc.target/riscv/attribute-1.c: Check for + __riscv_unaligned_slow or __riscv_unaligned_fast + * gcc.target/riscv/attribute-4.c: Check for + __riscv_unaligned_avoid + * gcc.target/riscv/attribute-5.c: Check for + __riscv_unaligned_slow or __riscv_unaligned_fast + * gcc.target/riscv/predef-align-1.c: New test. + * gcc.target/riscv/predef-align-2.c: New test. + * gcc.target/riscv/predef-align-3.c: New test. + * gcc.target/riscv/predef-align-4.c: New test. + * gcc.target/riscv/predef-align-5.c: New test. + * gcc.target/riscv/predef-align-6.c: New test. + +2023-08-29 Guillaume Gomez + + * jit.dg/test-restrict.c: Add test for __restrict__ attribute. + * jit.dg/all-non-failing-tests.h: Add test-restrict.c to the list. + +2023-08-29 Carl Love + + PR target/93448 + * gcc.target/powerpc/pr93448.c: New test case. + +2023-08-29 David Malcolm + + PR analyzer/105899 + * c-c++-common/analyzer/pr99193-2.c: Add + -Wno-analyzer-too-complex. + * gcc.dg/analyzer/strdup-1.c: Include "analyzer-decls.h". + (test_concrete_strlen): New. + (test_symbolic_strlen): New. + +2023-08-29 Tsukasa OI + + * gcc.target/riscv/predef-31.c: New test for a stub unprivileged + extension 'Zcb' with some implications. + +2023-08-29 Tsukasa OI + + * gcc.target/riscv/predef-30.c: New test for a stub + vendor extension 'XVentanaCondOps'. + +2023-08-29 Tsukasa OI + + * gcc.target/riscv/predef-29.c: New test for a stub privileged + extension 'Smstateen' with some implications. + +2023-08-29 Tsukasa OI + + * gcc.target/riscv/pr102957-2.c: New test case using the 'Zk' + extension to continue testing whether we can use valid two-letter + extensions. + +2023-08-29 Jakub Jelinek + + PR middle-end/79173 + PR middle-end/111209 + * gcc.target/i386/pr79173-12.c: New test. + +2023-08-29 Andrew Pinski + + PR tree-optimization/111147 + * gcc.dg/tree-ssa/cmpbit-4.c: New test. + +2023-08-29 Juzhe-Zhong + + * gcc.dg/vect/no-scevccp-outer-12.c: Add riscv xfail. + +2023-08-29 Juzhe-Zhong + + * gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-16.c: Fix ASM check. + +2023-08-29 Lehua Ding + + PR target/110943 + * gcc.target/riscv/rvv/base/zvfhmin-intrinsic.c: Adjust. + * gcc.target/riscv/rvv/base/pr110943.c: New test. + +2023-08-29 Lulu Cheng + + * gcc.target/loongarch/sign-extend.c: New test. + +2023-08-28 Tsukasa OI + + * gcc.target/riscv/builtin_pause.c: Removed. + * gcc.target/riscv/zihintpause-1.c: New test when the 'Zihintpause' + extension is enabled. + * gcc.target/riscv/zihintpause-2.c: Likewise. + * gcc.target/riscv/zihintpause-noarch.c: New test when the 'Zihintpause' + extension is disabled. + +2023-08-28 Andrew Pinski + + PR testsuite/111215 + * gcc.dg/tree-ssa/cond-bool-2.c: Add + `--param logical-op-non-short-circuit=1` to the options. + +2023-08-28 Andrew Pinski + + * gcc.dg/tree-ssa/cmpbit-3.c: New test. + * gcc.dg/pr87009.c: Update test. + +2023-08-28 Lulu Cheng + + * gcc.target/loongarch/slt-sign-extend.c: New test. + +2023-08-28 Juzhe-Zhong + + * gcc.target/riscv/rvv/base/vxrm-8.c: Adapt tests. + * gcc.target/riscv/rvv/base/vxrm-9.c: Ditto. + * gcc.target/riscv/rvv/vsetvl/vlmax_bb_prop-10.c: Ditto. + * gcc.target/riscv/rvv/vsetvl/vlmax_bb_prop-11.c: Ditto. + * gcc.target/riscv/rvv/vsetvl/vlmax_bb_prop-12.c: Ditto. + * gcc.target/riscv/rvv/vsetvl/vlmax_bb_prop-3.c: Ditto. + * gcc.target/riscv/rvv/vsetvl/vlmax_bb_prop-9.c: Ditto. + +2023-08-28 Juzhe-Zhong + + * gcc.target/riscv/rvv/vsetvl/avl_multiple-7.c: Adapt test. + * gcc.target/riscv/rvv/vsetvl/avl_multiple-8.c: Ditto. + * gcc.target/riscv/rvv/vsetvl/avl_single-102.c: Ditto. + * gcc.target/riscv/rvv/vsetvl/avl_single-14.c: Ditto. + * gcc.target/riscv/rvv/vsetvl/avl_single-15.c: Ditto. + * gcc.target/riscv/rvv/vsetvl/avl_single-27.c: Ditto. + * gcc.target/riscv/rvv/vsetvl/avl_single-28.c: Ditto. + * gcc.target/riscv/rvv/vsetvl/avl_single-29.c: Ditto. + * gcc.target/riscv/rvv/vsetvl/avl_single-30.c: Ditto. + * gcc.target/riscv/rvv/vsetvl/avl_single-35.c: Ditto. + * gcc.target/riscv/rvv/vsetvl/avl_single-36.c: Ditto. + * gcc.target/riscv/rvv/vsetvl/avl_single-46.c: Ditto. + * gcc.target/riscv/rvv/vsetvl/avl_single-48.c: Ditto. + * gcc.target/riscv/rvv/vsetvl/avl_single-50.c: Ditto. + * gcc.target/riscv/rvv/vsetvl/avl_single-51.c: Ditto. + * gcc.target/riscv/rvv/vsetvl/avl_single-6.c: Ditto. + * gcc.target/riscv/rvv/vsetvl/avl_single-66.c: + * gcc.target/riscv/rvv/vsetvl/avl_single-67.c: Ditto. + * gcc.target/riscv/rvv/vsetvl/avl_single-68.c: Ditto. + * gcc.target/riscv/rvv/vsetvl/avl_single-69.c: Ditto. + * gcc.target/riscv/rvv/vsetvl/avl_single-70.c: Ditto. + * gcc.target/riscv/rvv/vsetvl/avl_single-71.c: Ditto. + * gcc.target/riscv/rvv/vsetvl/avl_single-72.c: Ditto. + * gcc.target/riscv/rvv/vsetvl/avl_single-76.c: Ditto. + * gcc.target/riscv/rvv/vsetvl/avl_single-77.c: Ditto. + * gcc.target/riscv/rvv/vsetvl/avl_single-82.c: Ditto. + * gcc.target/riscv/rvv/vsetvl/avl_single-83.c: Ditto. + * gcc.target/riscv/rvv/vsetvl/avl_single-84.c: Ditto. + * gcc.target/riscv/rvv/vsetvl/avl_single-89.c: Ditto. + * gcc.target/riscv/rvv/vsetvl/avl_single-93.c: Ditto. + * gcc.target/riscv/rvv/vsetvl/avl_single-94.c: Ditto. + * gcc.target/riscv/rvv/vsetvl/avl_single-95.c: Ditto. + * gcc.target/riscv/rvv/vsetvl/avl_single-96.c: Ditto. + * gcc.target/riscv/rvv/vsetvl/ffload-5.c: Ditto. + * gcc.target/riscv/rvv/vsetvl/imm_bb_prop-3.c: Ditto. + * gcc.target/riscv/rvv/vsetvl/imm_bb_prop-4.c: Ditto. + * gcc.target/riscv/rvv/vsetvl/imm_bb_prop-9.c: Ditto. + * gcc.target/riscv/rvv/vsetvl/imm_switch-7.c: Ditto. + * gcc.target/riscv/rvv/vsetvl/imm_switch-9.c: Ditto. + * gcc.target/riscv/rvv/vsetvl/vlmax_back_prop-45.c: Ditto. + * gcc.target/riscv/rvv/vsetvl/vlmax_bb_prop-1.c: Ditto. + * gcc.target/riscv/rvv/vsetvl/vlmax_bb_prop-9.c: Ditto. + * gcc.target/riscv/rvv/vsetvl/vlmax_bb_prop-10.c: Ditto. + * gcc.target/riscv/rvv/vsetvl/vlmax_bb_prop-11.c: Ditto. + * gcc.target/riscv/rvv/vsetvl/vlmax_bb_prop-12.c: Ditto. + * gcc.target/riscv/rvv/vsetvl/vlmax_bb_prop-3.c: Ditto. + * gcc.target/riscv/rvv/vsetvl/vlmax_bb_prop-4.c: Ditto. + * gcc.target/riscv/rvv/vsetvl/vlmax_conflict-7.c: Ditto. + * gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-1.c: Ditto. + * gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-16.c: Ditto. + * gcc.target/riscv/rvv/vsetvl/vsetvl-11.c: Ditto. + * gcc.target/riscv/rvv/vsetvl/vsetvl-23.c: Ditto. + * gcc.target/riscv/rvv/vsetvl/vsetvlmax-2.c: Ditto. + * gcc.target/riscv/rvv/vsetvl/vsetvlmax-4.c: Ditto. + * gcc.target/riscv/rvv/vsetvl/avl_single-103.c: New test. + * gcc.target/riscv/rvv/vsetvl/vlmax_conflict-13.c: New test. + +2023-08-27 Jeff Law + + * gcc.target/riscv/rvv/base/spill-11.c: Adjust expected output. + +2023-08-27 Jeff Law + + * gcc.target/riscv/rvv/base/spill-12.c: Update expected output. + +2023-08-27 Jeff Law + + * gcc.target/riscv/xtheadcondmov-indirect.c: Turn off pressure + sensitive scheduling. + +2023-08-27 benjamin priour + + PR analyzer/96395 + * gcc.dg/analyzer/aliasing-3.c: Moved to... + * c-c++-common/analyzer/aliasing-3.c: ...here. + * gcc.dg/analyzer/aliasing-pr106473.c: Moved to... + * c-c++-common/analyzer/aliasing-pr106473.c: ...here. + * gcc.dg/analyzer/asm-x86-dyndbg-2.c: Moved to... + * c-c++-common/analyzer/asm-x86-dyndbg-2.c: ...here. + * gcc.dg/analyzer/asm-x86-lp64-2.c: Moved to... + * c-c++-common/analyzer/asm-x86-lp64-2.c: ...here. + * gcc.dg/analyzer/atomic-builtins-haproxy-proxy.c: Moved to... + * c-c++-common/analyzer/atomic-builtins-haproxy-proxy.c: ...here. + * gcc.dg/analyzer/atomic-builtins-qemu-sockets.c: Moved to... + * c-c++-common/analyzer/atomic-builtins-qemu-sockets.c: ...here. + * gcc.dg/analyzer/attr-malloc-6.c: Moved to... + * c-c++-common/analyzer/attr-malloc-6.c: ...here. + * gcc.dg/analyzer/attr-malloc-CVE-2019-19078-usb-leak.c: Moved to... + * c-c++-common/analyzer/attr-malloc-CVE-2019-19078-usb-leak.c: ...here. + * gcc.dg/analyzer/attr-tainted_args-1.c: Moved to... + * c-c++-common/analyzer/attr-tainted_args-1.c: ...here. + * gcc.dg/analyzer/call-summaries-pr107158.c: Moved to... + * c-c++-common/analyzer/call-summaries-pr107158.c: ...here. + * gcc.dg/analyzer/calloc-1.c: Moved to... + * c-c++-common/analyzer/calloc-1.c: ...here. + * gcc.dg/analyzer/compound-assignment-5.c: Moved to... + * c-c++-common/analyzer/compound-assignment-5.c: ...here. + * gcc.dg/analyzer/coreutils-cksum-pr108664.c: Moved to... + * c-c++-common/analyzer/coreutils-cksum-pr108664.c: ...here. + * gcc.dg/analyzer/coreutils-sum-pr108666.c: Moved to... + * c-c++-common/analyzer/coreutils-sum-pr108666.c: ...here. + * gcc.dg/analyzer/deref-before-check-pr108455-1.c: Moved to... + * c-c++-common/analyzer/deref-before-check-pr108455-1.c: ...here. + * gcc.dg/analyzer/deref-before-check-pr108455-git-pack-revindex.c: Moved to... + * c-c++-common/analyzer/deref-before-check-pr108455-git-pack-revindex.c: ...here. + * gcc.dg/analyzer/deref-before-check-pr108475-1.c: Moved to... + * c-c++-common/analyzer/deref-before-check-pr108475-1.c: ...here. + * gcc.dg/analyzer/deref-before-check-pr108475-haproxy-tcpcheck.c: Moved to... + * c-c++-common/analyzer/deref-before-check-pr108475-haproxy-tcpcheck.c: ...here. + * gcc.dg/analyzer/deref-before-check-pr109060-haproxy-cfgparse.c: Moved to... + * c-c++-common/analyzer/deref-before-check-pr109060-haproxy-cfgparse.c: ...here. + * gcc.dg/analyzer/deref-before-check-pr109239-linux-bus.c: Moved to... + * c-c++-common/analyzer/deref-before-check-pr109239-linux-bus.c: ...here. + * gcc.dg/analyzer/deref-before-check-pr77425.c: Moved to... + * c-c++-common/analyzer/deref-before-check-pr77425.c: ...here. + * gcc.dg/analyzer/exec-1.c: Moved to... + * c-c++-common/analyzer/exec-1.c: ...here. + * gcc.dg/analyzer/feasibility-3.c: Moved to... + * c-c++-common/analyzer/feasibility-3.c: ...here. + * gcc.dg/analyzer/fields.c: Moved to... + * c-c++-common/analyzer/fields.c: ...here. + * gcc.dg/analyzer/function-ptr-5.c: Moved to... + * c-c++-common/analyzer/function-ptr-5.c: ...here. + * gcc.dg/analyzer/infinite-recursion-pr108524-1.c: Moved to... + * c-c++-common/analyzer/infinite-recursion-pr108524-1.c: ...here. + * gcc.dg/analyzer/infinite-recursion-pr108524-2.c: Moved to... + * c-c++-common/analyzer/infinite-recursion-pr108524-2.c: ...here. + * gcc.dg/analyzer/infinite-recursion-pr108524-qobject-json-parser.c: Moved to... + * c-c++-common/analyzer/infinite-recursion-pr108524-qobject-json-parser.c: ...here. + * gcc.dg/analyzer/init.c: Moved to... + * c-c++-common/analyzer/init.c: ...here. + * gcc.dg/analyzer/inlining-3-multiline.c: Moved to... + * c-c++-common/analyzer/inlining-3-multiline.c: ...here. + * gcc.dg/analyzer/inlining-3.c: Moved to... + * c-c++-common/analyzer/inlining-3.c: ...here. + * gcc.dg/analyzer/inlining-4-multiline.c: Moved to... + * c-c++-common/analyzer/inlining-4-multiline.c: ...here. + * gcc.dg/analyzer/inlining-4.c: Moved to... + * c-c++-common/analyzer/inlining-4.c: ...here. + * gcc.dg/analyzer/leak-pr105906.c: Moved to... + * c-c++-common/analyzer/leak-pr105906.c: ...here. + * gcc.dg/analyzer/leak-pr108045-with-call-summaries.c: Moved to... + * c-c++-common/analyzer/leak-pr108045-with-call-summaries.c: ...here. + * gcc.dg/analyzer/leak-pr108045-without-call-summaries.c: Moved to... + * c-c++-common/analyzer/leak-pr108045-without-call-summaries.c: ...here. + * gcc.dg/analyzer/leak-pr109059-1.c: Moved to... + * c-c++-common/analyzer/leak-pr109059-1.c: ...here. + * gcc.dg/analyzer/leak-pr109059-2.c: Moved to... + * c-c++-common/analyzer/leak-pr109059-2.c: ...here. + * gcc.dg/analyzer/malloc-2.c: Moved to... + * c-c++-common/analyzer/malloc-2.c: ...here. + * gcc.dg/analyzer/memcpy-2.c: Moved to... + * c-c++-common/analyzer/memcpy-2.c: ...here. + * gcc.dg/analyzer/null-deref-pr108251-smp_fetch_ssl_fc_has_early-O2.c: Moved to... + * c-c++-common/analyzer/null-deref-pr108251-smp_fetch_ssl_fc_has_early-O2.c: ...here. + * gcc.dg/analyzer/null-deref-pr108251-smp_fetch_ssl_fc_has_early.c: Moved to... + * c-c++-common/analyzer/null-deref-pr108251-smp_fetch_ssl_fc_has_early.c: ...here. + * gcc.dg/analyzer/null-deref-pr108806-qemu.c: Moved to... + * c-c++-common/analyzer/null-deref-pr108806-qemu.c: ...here. + * gcc.dg/analyzer/null-deref-pr108830.c: Moved to... + * c-c++-common/analyzer/null-deref-pr108830.c: ...here. + * gcc.dg/analyzer/pr101962.c: Moved to... + * c-c++-common/analyzer/pr101962.c: ...here. + * gcc.dg/analyzer/pr103217-2.c: Moved to... + * c-c++-common/analyzer/pr103217-2.c: ...here. + * gcc.dg/analyzer/pr103217.c: Moved to... + * c-c++-common/analyzer/pr103217.c: ...here. + * gcc.dg/analyzer/pr104029.c: Moved to... + * c-c++-common/analyzer/pr104029.c: ...here. + * gcc.dg/analyzer/pr104062.c: Moved to... + * c-c++-common/analyzer/pr104062.c: ...here. + * gcc.dg/analyzer/pr105783.c: Moved to... + * c-c++-common/analyzer/pr105783.c: ...here. + * gcc.dg/analyzer/pr107345.c: Moved to... + * c-c++-common/analyzer/pr107345.c: ...here. + * gcc.dg/analyzer/pr93695-1.c: Moved to... + * c-c++-common/analyzer/pr93695-1.c: ...here. + * gcc.dg/analyzer/pr94596.c: Moved to... + * c-c++-common/analyzer/pr94596.c: ...here. + * gcc.dg/analyzer/pr94839.c: Moved to... + * c-c++-common/analyzer/pr94839.c: ...here. + * gcc.dg/analyzer/pr95152-4.c: C only. + * gcc.dg/analyzer/pr95152-5.c: C only. + * gcc.dg/analyzer/pr95240.c: Moved to... + * c-c++-common/analyzer/pr95240.c: ...here. + * gcc.dg/analyzer/pr96639.c: Moved to... + * c-c++-common/analyzer/pr96639.c: ...here. + * gcc.dg/analyzer/pr96653.c: Moved to... + * c-c++-common/analyzer/pr96653.c: ...here. + * gcc.dg/analyzer/pr96792.c: Moved to... + * c-c++-common/analyzer/pr96792.c: ...here. + * gcc.dg/analyzer/pr96841.c: Moved to... + * c-c++-common/analyzer/pr96841.c: ...here. + * gcc.dg/analyzer/pr98564.c: Moved to... + * c-c++-common/analyzer/pr98564.c: ...here. + * gcc.dg/analyzer/pr98628.c: Moved to... + * c-c++-common/analyzer/pr98628.c: ...here. + * gcc.dg/analyzer/pr98969.c: Moved to... + * c-c++-common/analyzer/pr98969.c: ...here. + * gcc.dg/analyzer/pr99193-2.c: Moved to... + * c-c++-common/analyzer/pr99193-2.c: ...here. + * gcc.dg/analyzer/pr99193-3.c: Moved to... + * c-c++-common/analyzer/pr99193-3.c: ...here. + * gcc.dg/analyzer/pr99716-1.c: Moved to... + * c-c++-common/analyzer/pr99716-1.c: ...here. + * gcc.dg/analyzer/pr99774-1.c: Moved to... + * c-c++-common/analyzer/pr99774-1.c: ...here. + * gcc.dg/analyzer/realloc-1.c: Moved to... + * c-c++-common/analyzer/realloc-1.c: ...here. + * gcc.dg/analyzer/realloc-2.c: Moved to... + * c-c++-common/analyzer/realloc-2.c: ...here. + * gcc.dg/analyzer/realloc-3.c: Moved to... + * c-c++-common/analyzer/realloc-3.c: ...here. + * gcc.dg/analyzer/realloc-4.c: Moved to... + * c-c++-common/analyzer/realloc-4.c: ...here. + * gcc.dg/analyzer/realloc-5.c: Moved to... + * c-c++-common/analyzer/realloc-5.c: ...here. + * gcc.dg/analyzer/realloc-pr110014.c: Moved to... + * c-c++-common/analyzer/realloc-pr110014.c: ...here. + * gcc.dg/analyzer/snprintf-concat.c: Moved to... + * c-c++-common/analyzer/snprintf-concat.c: ...here. + * gcc.dg/analyzer/sock-1.c: Moved to... + * c-c++-common/analyzer/sock-1.c: ...here. + * gcc.dg/analyzer/sprintf-concat.c: Moved to... + * c-c++-common/analyzer/sprintf-concat.c: ...here. + * gcc.dg/analyzer/string-ops-concat-pair.c: Moved to... + * c-c++-common/analyzer/string-ops-concat-pair.c: ...here. + * gcc.dg/analyzer/string-ops-dup.c: Moved to... + * c-c++-common/analyzer/string-ops-dup.c: ...here. + * gcc.dg/analyzer/switch-enum-pr105273-git-vreportf-2.c: Moved to... + * c-c++-common/analyzer/switch-enum-pr105273-git-vreportf-2.c: ...here. + * gcc.dg/analyzer/symbolic-12.c: Moved to... + * c-c++-common/analyzer/symbolic-12.c: ...here. + * gcc.dg/analyzer/uninit-alloca.c: Moved to... + * c-c++-common/analyzer/uninit-alloca.c: ...here. + * gcc.dg/analyzer/untracked-2.c: Moved to... + * c-c++-common/analyzer/untracked-2.c: ...here. + * gcc.dg/analyzer/vasprintf-1.c: Moved to... + * c-c++-common/analyzer/vasprintf-1.c: ...here. + * gcc.dg/analyzer/write-to-const-1.c: Moved to... + * c-c++-common/analyzer/write-to-const-1.c: ...here. + * gcc.dg/analyzer/write-to-function-1.c: C only. + * gcc.dg/analyzer/write-to-string-literal-1.c: Moved to... + * c-c++-common/analyzer/write-to-string-literal-1.c: ...here. + * gcc.dg/analyzer/write-to-string-literal-4-disabled.c: Moved to... + * c-c++-common/analyzer/write-to-string-literal-4-disabled.c: ...here. + * gcc.dg/analyzer/write-to-string-literal-5.c: Moved to... + * c-c++-common/analyzer/write-to-string-literal-5.c: ...here. + * g++.dg/analyzer/analyzer.exp: Now also run tests under + c-c++-common/analyzer. + * gcc.dg/analyzer/analyzer-decls.h: Add NULL definition. + * gcc.dg/analyzer/analyzer.exp: Now also run tests under + c-c++-common/analyzer. + * gcc.dg/analyzer/pr104369-1.c: C only. + * gcc.dg/analyzer/pr104369-2.c: Likewise. + * gcc.dg/analyzer/pr93355-localealias-feasibility-2.c: Likewise. + * gcc.dg/analyzer/sprintf-1.c: Split into C-only and + C++-friendly bits. + * gcc.dg/analyzer/allocation-size-multiline-1.c: Removed. + * gcc.dg/analyzer/allocation-size-multiline-2.c: Removed. + * gcc.dg/analyzer/allocation-size-multiline-3.c: Removed. + * gcc.dg/analyzer/data-model-11.c: Removed. + * gcc.dg/analyzer/pr61861.c: C only. + * gcc.dg/analyzer/pr93457.c: Removed. + * gcc.dg/analyzer/pr97568.c: Removed. + * gcc.dg/analyzer/write-to-string-literal-4.c: Removed. + * c-c++-common/analyzer/allocation-size-multiline-1.c: New test. + * c-c++-common/analyzer/allocation-size-multiline-2.c: New test. + * c-c++-common/analyzer/allocation-size-multiline-3.c: New test. + * c-c++-common/analyzer/data-model-11.c: New test. + * c-c++-common/analyzer/pr93457.c: New test. + * c-c++-common/analyzer/pr97568.c: New test. + * c-c++-common/analyzer/sprintf-2.c: C++-friendly bit of + previous gcc.dg/analyzer/sprintf-1.c. + * c-c++-common/analyzer/write-to-string-literal-4.c: New test. + +2023-08-26 Paul Thomas + + PR fortran/92586 + * gfortran.dg/pr92586.f90 : New test + +2023-08-26 Juzhe-Zhong + + * gcc.target/riscv/rvv/autovec/reduc/extract_last-1.c: New test. + * gcc.target/riscv/rvv/autovec/reduc/extract_last-10.c: New test. + * gcc.target/riscv/rvv/autovec/reduc/extract_last-11.c: New test. + * gcc.target/riscv/rvv/autovec/reduc/extract_last-12.c: New test. + * gcc.target/riscv/rvv/autovec/reduc/extract_last-13.c: New test. + * gcc.target/riscv/rvv/autovec/reduc/extract_last-14.c: New test. + * gcc.target/riscv/rvv/autovec/reduc/extract_last-2.c: New test. + * gcc.target/riscv/rvv/autovec/reduc/extract_last-3.c: New test. + * gcc.target/riscv/rvv/autovec/reduc/extract_last-4.c: New test. + * gcc.target/riscv/rvv/autovec/reduc/extract_last-5.c: New test. + * gcc.target/riscv/rvv/autovec/reduc/extract_last-6.c: New test. + * gcc.target/riscv/rvv/autovec/reduc/extract_last-7.c: New test. + * gcc.target/riscv/rvv/autovec/reduc/extract_last-8.c: New test. + * gcc.target/riscv/rvv/autovec/reduc/extract_last-9.c: New test. + * gcc.target/riscv/rvv/autovec/reduc/extract_last_run-1.c: New test. + * gcc.target/riscv/rvv/autovec/reduc/extract_last_run-10.c: New test. + * gcc.target/riscv/rvv/autovec/reduc/extract_last_run-11.c: New test. + * gcc.target/riscv/rvv/autovec/reduc/extract_last_run-12.c: New test. + * gcc.target/riscv/rvv/autovec/reduc/extract_last_run-13.c: New test. + * gcc.target/riscv/rvv/autovec/reduc/extract_last_run-14.c: New test. + * gcc.target/riscv/rvv/autovec/reduc/extract_last_run-2.c: New test. + * gcc.target/riscv/rvv/autovec/reduc/extract_last_run-3.c: New test. + * gcc.target/riscv/rvv/autovec/reduc/extract_last_run-4.c: New test. + * gcc.target/riscv/rvv/autovec/reduc/extract_last_run-5.c: New test. + * gcc.target/riscv/rvv/autovec/reduc/extract_last_run-6.c: New test. + * gcc.target/riscv/rvv/autovec/reduc/extract_last_run-7.c: New test. + * gcc.target/riscv/rvv/autovec/reduc/extract_last_run-8.c: New test. + * gcc.target/riscv/rvv/autovec/reduc/extract_last_run-9.c: New test. + +2023-08-26 Andrew Pinski + + * gcc.dg/tree-ssa/phi-opt-34.c: Fix dg-options directive. + +2023-08-25 Jeff Law + + * gcc.target/riscv/stack_save_restore_1.c: Robustify. + * gcc.target/riscv/stack_save_restore_2.c: Robustify. + +2023-08-25 Jeff Law + + * gcc.target/riscv/zicond-primitiveSemantics.c: Disable for -Og. + +2023-08-25 Jin Ma + + * gcc.target/riscv/zfa-fleq-fltq.c: New test. + * gcc.target/riscv/zfa-fli-zfh.c: New test. + * gcc.target/riscv/zfa-fli.c: New test. + * gcc.target/riscv/zfa-fmovh-fmovp.c: New test. + * gcc.target/riscv/zfa-fli-1.c: New test. + * gcc.target/riscv/zfa-fli-2.c: New test. + * gcc.target/riscv/zfa-fli-3.c: New test. + * gcc.target/riscv/zfa-fli-4.c: New test. + * gcc.target/riscv/zfa-fli-6.c: New test. + * gcc.target/riscv/zfa-fli-7.c: New test. + * gcc.target/riscv/zfa-fli-8.c: New test. + Co-authored-by: Tsukasa OI + * gcc.target/riscv/zfa-fround.c: New file. + +2023-08-25 Sandra Loosemore + + * gfortran.dg/gomp/collapse1.f90: Adjust expected errors. + * gfortran.dg/gomp/collapse2.f90: Likewise. + * gfortran.dg/gomp/imperfect-gotos.f90: New. + * gfortran.dg/gomp/imperfect-invalid-scope.f90: New. + * gfortran.dg/gomp/imperfect1.f90: New. + * gfortran.dg/gomp/imperfect2.f90: New. + * gfortran.dg/gomp/imperfect3.f90: New. + * gfortran.dg/gomp/imperfect4.f90: New. + * gfortran.dg/gomp/imperfect5.f90: New. + +2023-08-25 Sandra Loosemore + + * c-c++-common/gomp/imperfect-attributes.c: New. + * c-c++-common/gomp/imperfect-badloops.c: New. + * c-c++-common/gomp/imperfect-blocks.c: New. + * c-c++-common/gomp/imperfect-extension.c: New. + * c-c++-common/gomp/imperfect-gotos.c: New. + * c-c++-common/gomp/imperfect-invalid-scope.c: New. + * c-c++-common/gomp/imperfect-labels.c: New. + * c-c++-common/gomp/imperfect-legacy-syntax.c: New. + * c-c++-common/gomp/imperfect-pragmas.c: New. + * c-c++-common/gomp/imperfect1.c: New. + * c-c++-common/gomp/imperfect2.c: New. + * c-c++-common/gomp/imperfect3.c: New. + * c-c++-common/gomp/imperfect4.c: New. + * c-c++-common/gomp/imperfect5.c: New. + +2023-08-25 Sandra Loosemore + + * c-c++-common/goacc/tile-2.c: Adjust expected error patterns. + * g++.dg/gomp/attrs-imperfect1.C: New test. + * g++.dg/gomp/attrs-imperfect2.C: New test. + * g++.dg/gomp/attrs-imperfect3.C: New test. + * g++.dg/gomp/attrs-imperfect4.C: New test. + * g++.dg/gomp/attrs-imperfect5.C: New test. + * g++.dg/gomp/pr41967.C: Adjust expected error patterns. + * g++.dg/gomp/tpl-imperfect-gotos.C: New test. + * g++.dg/gomp/tpl-imperfect-invalid-scope.C: New test. + +2023-08-25 Sandra Loosemore + + * c-c++-common/goacc/collapse-1.c: Update for new C error behavior. + * c-c++-common/goacc/tile-2.c: Likewise. + * gcc.dg/gomp/collapse-1.c: Likewise. + +2023-08-25 Vineet Gupta + + * gcc.target/riscv/gcse-const.c: New Test + * gcc.target/riscv/rvv/vsetvl/vlmax_conflict-7.c: Remove test + for Jump. + * gcc.target/riscv/rvv/vsetvl/vlmax_conflict-8.c: Ditto. + +2023-08-25 Andrew Pinski + + * gcc.dg/tree-ssa/phi-opt-34.c: New test. + +2023-08-25 Harald Anlauf + + PR fortran/35095 + * gfortran.dg/data_bounds_1.f90: Adjust options to disable warnings. + * gfortran.dg/data_bounds_2.f90: New test. + +2023-08-25 David Malcolm + + * gcc.dg/analyzer/out-of-bounds-diagram-17.c: New test. + * gcc.dg/analyzer/out-of-bounds-diagram-18.c: New test. + * gcc.dg/analyzer/out-of-bounds-diagram-19.c: New test. + +2023-08-25 Richard Biener + + PR tree-optimization/111137 + * gcc.dg/torture/pr111137.c: New testcase. + +2023-08-25 Aldy Hernandez + + * gcc.dg/tree-ssa/vrp-float-12.c: New test. + +2023-08-25 Patrick O'Neill + + * gcc.target/riscv/vector-abi-1.c: Moved to... + * gcc.target/riscv/rvv/base/vector-abi-1.c: ...here. + * gcc.target/riscv/vector-abi-2.c: Moved to... + * gcc.target/riscv/rvv/base/vector-abi-2.c: ...here. + * gcc.target/riscv/vector-abi-3.c: Moved to... + * gcc.target/riscv/rvv/base/vector-abi-3.c: ...here. + * gcc.target/riscv/vector-abi-4.c: Moved to... + * gcc.target/riscv/rvv/base/vector-abi-4.c: ...here. + * gcc.target/riscv/vector-abi-5.c: Moved to... + * gcc.target/riscv/rvv/base/vector-abi-5.c: ...here. + * gcc.target/riscv/vector-abi-6.c: Moved to... + * gcc.target/riscv/rvv/base/vector-abi-6.c: ...here. + * gcc.target/riscv/vector-abi-7.c: Moved to... + * gcc.target/riscv/rvv/base/vector-abi-7.c: ...here. + * gcc.target/riscv/vector-abi-8.c: Moved to... + * gcc.target/riscv/rvv/base/vector-abi-8.c: ...here. + * gcc.target/riscv/vector-abi-9.c: Moved to... + * gcc.target/riscv/rvv/base/vector-abi-9.c: ...here. + +2023-08-25 Hongyu Wang + + PR target/111127 + * gcc.target/i386/pr111127.c: New test. + +2023-08-24 Uros Bizjak + + PR target/94866 + * g++.target/i386/pr94866.C: New test. + +2023-08-24 Jose E. Marchesi + + PR c/106537 + * gcc.c-torture/compile/pr106537-1.c: Comparing void pointers to + non-function pointers is legit. + * gcc.c-torture/compile/pr106537-2.c: Likewise. + +2023-08-24 David Malcolm + + PR analyzer/105899 + * gcc.dg/analyzer/strcat-1.c: New test. + +2023-08-24 David Malcolm + + PR analyzer/105899 + * gcc.dg/analyzer/strcpy-3.c (test_2): New. + +2023-08-24 David Malcolm + + PR analyzer/105899 + * gcc.dg/analyzer/out-of-bounds-diagram-16.c: New test. + * gcc.dg/analyzer/strcpy-1.c: Add test coverage. + * gcc.dg/analyzer/strcpy-3.c: Likewise. + * gcc.dg/analyzer/strcpy-4.c: New test. + +2023-08-24 David Malcolm + + PR analyzer/105899 + * gcc.dg/analyzer/sprintf-1.c: Include "analyzer-decls.h". + (test_strlen_1): New. + +2023-08-24 Richard Biener + + PR tree-optimization/111123 + * g++.dg/warn/Wuninitialized-pr111123-1.C: New testcase. + +2023-08-24 Juzhe-Zhong + + * gcc.target/riscv/rvv/autovec/binop/vadd-rv32gcv-nofm.c: Adapt test. + * gcc.target/riscv/rvv/autovec/binop/vadd-rv64gcv-nofm.c: Ditto. + * gcc.target/riscv/rvv/autovec/cond/cond_fadd-1.c: Ditto. + * gcc.target/riscv/rvv/autovec/cond/cond_fadd-2.c: Ditto. + * gcc.target/riscv/rvv/autovec/cond/cond_fadd-3.c: Ditto. + * gcc.target/riscv/rvv/autovec/cond/cond_fadd-4.c: Ditto. + * gcc.target/riscv/rvv/autovec/ternop/ternop_nofm-1.c: Ditto. + * gcc.target/riscv/rvv/autovec/ternop/ternop_nofm-3.c: Ditto. + * gcc.target/riscv/rvv/autovec/ternop/ternop_nofm-10.c: New test. + * gcc.target/riscv/rvv/autovec/ternop/ternop_nofm-11.c: New test. + * gcc.target/riscv/rvv/autovec/ternop/ternop_nofm-12.c: New test. + * gcc.target/riscv/rvv/autovec/ternop/ternop_nofm-4.c: New test. + * gcc.target/riscv/rvv/autovec/ternop/ternop_nofm-5.c: New test. + * gcc.target/riscv/rvv/autovec/ternop/ternop_nofm-6.c: New test. + * gcc.target/riscv/rvv/autovec/ternop/ternop_nofm-7.c: New test. + * gcc.target/riscv/rvv/autovec/ternop/ternop_nofm-8.c: New test. + * gcc.target/riscv/rvv/autovec/ternop/ternop_nofm-9.c: New test. + * gcc.target/riscv/rvv/autovec/ternop/ternop_nofm_run-10.c: New test. + * gcc.target/riscv/rvv/autovec/ternop/ternop_nofm_run-11.c: New test. + * gcc.target/riscv/rvv/autovec/ternop/ternop_nofm_run-12.c: New test. + * gcc.target/riscv/rvv/autovec/ternop/ternop_nofm_run-4.c: New test. + * gcc.target/riscv/rvv/autovec/ternop/ternop_nofm_run-5.c: New test. + * gcc.target/riscv/rvv/autovec/ternop/ternop_nofm_run-6.c: New test. + * gcc.target/riscv/rvv/autovec/ternop/ternop_nofm_run-7.c: New test. + * gcc.target/riscv/rvv/autovec/ternop/ternop_nofm_run-8.c: New test. + * gcc.target/riscv/rvv/autovec/ternop/ternop_nofm_run-9.c: New test. + +2023-08-24 Robin Dapp + + * gcc.target/riscv/rvv/base/narrow_constraint-1.c: Add + -fno-sched-pressure. + * gcc.target/riscv/rvv/base/narrow_constraint-17.c: Ditto. + * gcc.target/riscv/rvv/base/narrow_constraint-18.c: Ditto. + * gcc.target/riscv/rvv/base/narrow_constraint-19.c: Ditto. + * gcc.target/riscv/rvv/base/narrow_constraint-20.c: Ditto. + * gcc.target/riscv/rvv/base/narrow_constraint-21.c: Ditto. + * gcc.target/riscv/rvv/base/narrow_constraint-22.c: Ditto. + * gcc.target/riscv/rvv/base/narrow_constraint-23.c: Ditto. + * gcc.target/riscv/rvv/base/narrow_constraint-24.c: Ditto. + * gcc.target/riscv/rvv/base/narrow_constraint-25.c: Ditto. + * gcc.target/riscv/rvv/base/narrow_constraint-26.c: Ditto. + * gcc.target/riscv/rvv/base/narrow_constraint-27.c: Ditto. + * gcc.target/riscv/rvv/base/narrow_constraint-28.c: Ditto. + * gcc.target/riscv/rvv/base/narrow_constraint-29.c: Ditto. + * gcc.target/riscv/rvv/base/narrow_constraint-30.c: Ditto. + * gcc.target/riscv/rvv/base/narrow_constraint-31.c: Ditto. + * gcc.target/riscv/rvv/base/narrow_constraint-4.c: Ditto. + * gcc.target/riscv/rvv/base/narrow_constraint-5.c: Ditto. + * gcc.target/riscv/rvv/base/narrow_constraint-8.c: Ditto. + * gcc.target/riscv/rvv/base/narrow_constraint-9.c: Ditto. + * gcc.target/riscv/rvv/vsetvl/vlmax_bb_prop-10.c: Ditto. + * gcc.target/riscv/rvv/vsetvl/vlmax_bb_prop-11.c: Ditto. + * gcc.target/riscv/rvv/vsetvl/vlmax_bb_prop-12.c: Ditto. + * gcc.target/riscv/rvv/vsetvl/vlmax_bb_prop-3.c: Ditto. + * gcc.target/riscv/rvv/vsetvl/vlmax_bb_prop-9.c: Ditto. + +2023-08-24 Robin Dapp + + * gcc.target/riscv/rvv/autovec/binop/shift-immediate.c: New test. + +2023-08-24 Robin Dapp + + * gcc.target/riscv/rvv/autovec/conversions/vfncvt-ftoi-run.c: + Add tests. + * gcc.target/riscv/rvv/autovec/conversions/vfncvt-ftoi-rv32gcv.c: + Ditto. + * gcc.target/riscv/rvv/autovec/conversions/vfncvt-ftoi-rv64gcv.c: + Ditto. + * gcc.target/riscv/rvv/autovec/conversions/vfncvt-ftoi-template.h: + Ditto. + * gcc.target/riscv/rvv/autovec/conversions/vfncvt-itof-rv32gcv.c: + Ditto. + * gcc.target/riscv/rvv/autovec/conversions/vfncvt-itof-rv64gcv.c: + Ditto. + * gcc.target/riscv/rvv/autovec/conversions/vfncvt-itof-template.h: + Ditto. + * gcc.target/riscv/rvv/autovec/conversions/vfncvt-itof-zvfh-run.c: + Ditto. + * gcc.target/riscv/rvv/autovec/conversions/vfwcvt-ftoi-rv32gcv.c: + Ditto. + * gcc.target/riscv/rvv/autovec/conversions/vfwcvt-ftoi-rv64gcv.c: + Ditto. + * gcc.target/riscv/rvv/autovec/conversions/vfwcvt-ftoi-template.h: + Ditto. + * gcc.target/riscv/rvv/autovec/conversions/vfwcvt-ftoi-zvfh-run.c: + Ditto. + * gcc.target/riscv/rvv/autovec/conversions/vfwcvt-itof-run.c: + Ditto. + * gcc.target/riscv/rvv/autovec/conversions/vfwcvt-itof-rv32gcv.c: + Ditto. + * gcc.target/riscv/rvv/autovec/conversions/vfwcvt-itof-rv64gcv.c: + Ditto. + * gcc.target/riscv/rvv/autovec/conversions/vfwcvt-itof-template.h: + Ditto. + * gcc.target/riscv/rvv/autovec/conversions/vfwcvt-itof-zvfh-run.c: + Ditto. + +2023-08-24 Robin Dapp + + * gcc.target/riscv/rvv/autovec/reduc/reduc_strict_run-1.c: + Add variable to hold reference result. + +2023-08-24 Richard Sandiford + + * gcc.dg/c2x-attr-syntax-6.c: New test. + * gcc.dg/c2x-attr-syntax-7.c: Likewise. + +2023-08-24 Richard Biener + + PR tree-optimization/111115 + * lib/target-supports.exp (check_effective_target_vect_masked_store): + Supported with check_avx_available. + * gcc.dg/vect/slp-mask-store-1.c: New testcase. + +2023-08-24 Richard Sandiford + + * gcc.target/aarch64/neoverse_v1_2.c: New test. + * gcc.target/aarch64/neoverse_v1_3.c: Likewise. + +2023-08-24 Richard Biener + + PR tree-optimization/111128 + * gcc.dg/torture/pr111128.c: New testcase. + +2023-08-24 Richard Biener + + PR testsuite/111125 + * gcc.dg/vect/pr53773.c: Disable BB vectorization. + +2023-08-24 Andrew Pinski + + PR tree-optimization/111109 + * gcc.c-torture/execute/ieee/fp-cmp-cond-1.c: New test. + +2023-08-24 Andrew Pinski + + PR tree-optimization/95929 + * gcc.dg/tree-ssa/bit1neg-1.c: New test. + * gcc.dg/tree-ssa/cond-bool-1.c: New test. + * gcc.dg/tree-ssa/cond-bool-2.c: New test. + +2023-08-24 Haochen Jiang + + Revert: + 2023-08-24 Haochen Jiang + + * g++.target/i386/mv33.C: New test. + * gcc.target/i386/avx10_1-1.c: Ditto. + * gcc.target/i386/avx10_1-2.c: Ditto. + * gcc.target/i386/avx10_1-3.c: Ditto. + * gcc.target/i386/avx10_1-4.c: Ditto. + * gcc.target/i386/avx10_1-5.c: Ditto. + * gcc.target/i386/avx10_1-6.c: Ditto. + * gcc.target/i386/avx10_1-7.c: Ditto. + * gcc.target/i386/avx10_1-8.c: Ditto. + * gcc.target/i386/avx10_1-9.c: Ditto. + * gcc.target/i386/avx10_1-10.c: Ditto. + +2023-08-24 Haochen Jiang + + Revert: + 2023-08-24 Haochen Jiang + + * gcc.target/i386/avx10_1-11.c: New test. + * gcc.target/i386/avx10_1-12.c: Ditto. + * gcc.target/i386/avx10_1-13.c: Ditto. + * gcc.target/i386/avx10_1-14.c: Ditto. + +2023-08-24 Haochen Jiang + + Revert: + 2023-08-24 Haochen Jiang + + * gcc.target/i386/avx10_1-15.c: New test. + * gcc.target/i386/avx10_1-16.c: Ditto. + * gcc.target/i386/avx10_1-17.c: Ditto. + * gcc.target/i386/avx10_1-18.c: Ditto. + +2023-08-24 Haochen Jiang + + Revert: + 2023-08-24 Haochen Jiang + + * gcc.target/i386/avx-1.c: Add -mavx10.1. + * gcc.target/i386/avx-2.c: Ditto. + * gcc.target/i386/sse-26.c: Skip AVX512VLDQ intrin file. + +2023-08-24 Haochen Jiang + + Revert: + 2023-08-17 Haochen Jiang + + * gcc.target/i386/avx10_1-vandnpd-1.c: New test. + * gcc.target/i386/avx10_1-vandnps-1.c: Ditto. + * gcc.target/i386/avx10_1-vbroadcastf32x2-1.c: Ditto. + * gcc.target/i386/avx10_1-vbroadcastf64x2-1.c: Ditto. + * gcc.target/i386/avx10_1-vbroadcasti32x2-1.c: Ditto. + * gcc.target/i386/avx10_1-vbroadcasti64x2-1.c: Ditto. + * gcc.target/i386/avx10_1-vcvtpd2qq-1.c: Ditto. + * gcc.target/i386/avx10_1-vcvtpd2uqq-1.c: Ditto. + * gcc.target/i386/avx10_1-vcvttpd2qq-1.c: Ditto. + * gcc.target/i386/avx10_1-vcvttpd2uqq-1.c: Ditto. + * gcc.target/i386/avx10_1-vcvttps2qq-1.c: Ditto. + * gcc.target/i386/avx10_1-vcvttps2uqq-1.c: Ditto. + * gcc.target/i386/avx10_1-vpmullq-1.c: Ditto. + +2023-08-24 Haochen Jiang + + Revert: + 2023-08-17 Haochen Jiang + + * gcc.target/i386/avx10_1-abs-copysign-1.c: New test. + * gcc.target/i386/avx10_1-vandpd-1.c: Ditto. + * gcc.target/i386/avx10_1-vandps-1.c: Ditto. + * gcc.target/i386/avx10_1-vcvtps2qq-1.c: Ditto. + * gcc.target/i386/avx10_1-vcvtps2uqq-1.c: Ditto. + * gcc.target/i386/avx10_1-vcvtqq2pd-1.c: Ditto. + * gcc.target/i386/avx10_1-vcvtqq2ps-1.c: Ditto. + * gcc.target/i386/avx10_1-vcvtuqq2pd-1.c: Ditto. + * gcc.target/i386/avx10_1-vcvtuqq2ps-1.c: Ditto. + * gcc.target/i386/avx10_1-vorpd-1.c: Ditto. + * gcc.target/i386/avx10_1-vorps-1.c: Ditto. + * gcc.target/i386/avx10_1-vpmovd2m-1.c: Ditto. + * gcc.target/i386/avx10_1-vpmovm2d-1.c: Ditto. + * gcc.target/i386/avx10_1-vpmovm2q-1.c: Ditto. + * gcc.target/i386/avx10_1-vpmovq2m-1.c: Ditto. + * gcc.target/i386/avx10_1-vxorpd-1.c: Ditto. + * gcc.target/i386/avx10_1-vxorps-1.c: Ditto. + +2023-08-24 Haochen Jiang + + Revert: + 2023-08-17 Haochen Jiang + + * gcc.target/i386/avx10_1-vextractf64x2-1.c: New test. + * gcc.target/i386/avx10_1-vextracti64x2-1.c: Ditto. + * gcc.target/i386/avx10_1-vfpclasspd-1.c: Ditto. + * gcc.target/i386/avx10_1-vfpclassps-1.c: Ditto. + * gcc.target/i386/avx10_1-vinsertf64x2-1.c: Ditto. + * gcc.target/i386/avx10_1-vinserti64x2-1.c: Ditto. + * gcc.target/i386/avx10_1-vrangepd-1.c: Ditto. + * gcc.target/i386/avx10_1-vrangeps-1.c: Ditto. + * gcc.target/i386/avx10_1-vreducepd-1.c: Ditto. + * gcc.target/i386/avx10_1-vreduceps-1.c: Ditto. + +2023-08-24 Haochen Jiang + + Revert: + 2023-08-24 Haochen Jiang + + PR target/111051 + PR target/111051 + * gcc.target/i386/pr111051-1.c: New test. + +2023-08-24 Richard Biener + + PR debug/111080 + * gcc.dg/debug/dwarf2/pr111080.c: New testcase. + +2023-08-24 Hans-Peter Nilsson + + * gcc.dg/tree-ssa/update-threading.c: Xfail for cris-*-*. + +2023-08-23 Harald Anlauf + + PR fortran/32986 + * gfortran.dg/common_28.f90: New test. + +2023-08-23 Andrew MacLeod + + * gcc.dg/pr102983.c: Adjust output expectations. + * gcc.dg/pr110918.c: New. + +2023-08-23 Lehua Ding + + * gcc.target/riscv/rvv/autovec/cond/cond_unary-1.c: New test. + * gcc.target/riscv/rvv/autovec/cond/cond_unary-2.c: New test. + * gcc.target/riscv/rvv/autovec/cond/cond_unary-3.c: New test. + * gcc.target/riscv/rvv/autovec/cond/cond_unary-4.c: New test. + * gcc.target/riscv/rvv/autovec/cond/cond_unary-5.c: New test. + * gcc.target/riscv/rvv/autovec/cond/cond_unary-6.c: New test. + * gcc.target/riscv/rvv/autovec/cond/cond_unary-7.c: New test. + * gcc.target/riscv/rvv/autovec/cond/cond_unary-8.c: New test. + * gcc.target/riscv/rvv/autovec/cond/cond_unary_run-1.c: New test. + * gcc.target/riscv/rvv/autovec/cond/cond_unary_run-2.c: New test. + * gcc.target/riscv/rvv/autovec/cond/cond_unary_run-3.c: New test. + * gcc.target/riscv/rvv/autovec/cond/cond_unary_run-4.c: New test. + * gcc.target/riscv/rvv/autovec/cond/cond_unary_run-5.c: New test. + * gcc.target/riscv/rvv/autovec/cond/cond_unary_run-6.c: New test. + * gcc.target/riscv/rvv/autovec/cond/cond_unary_run-7.c: New test. + * gcc.target/riscv/rvv/autovec/cond/cond_unary_run-8.c: New test. + +2023-08-23 Jan Hubicka + + * gcc.dg/tree-ssa/copy-headers-9.c: Update template. + +2023-08-23 Jan Hubicka + + PR middle-end/110940 + * gcc.c-torture/compile/pr110940.c: New test. + +2023-08-23 Juzhe-Zhong + + * gcc.target/riscv/rvv/autovec/gather-scatter/gather_load_run-12.c: + Add vsetvli asm. + +2023-08-23 Juzhe-Zhong + + * gcc.target/riscv/rvv/autovec/partial/live-1.c: Adapt test. + +2023-08-22 David Malcolm + + PR analyzer/105899 + * gcc.dg/analyzer/null-terminated-strings-1.c: Update expected + results on symbolic values. + * gcc.dg/analyzer/strlen-1.c: New test. + +2023-08-22 Jason Merrill + + PR c++/109751 + * g++.dg/cpp2a/concepts-friend11.C: Now works. Add template. + * g++.dg/cpp2a/concepts-friend15.C: New test. + * g++.dg/cpp2a/concepts-friend11a.C: New file. + +2023-08-22 Tobias Burnus + + * gfortran.dg/gomp/defaultmap-1.f90: Update dg-error. + * c-c++-common/gomp/defaultmap-5.c: New test. + * c-c++-common/gomp/defaultmap-6.c: New test. + * gfortran.dg/gomp/defaultmap-10.f90: New test. + * gfortran.dg/gomp/defaultmap-9.f90: New test. + +2023-08-22 Richard Biener + + PR tree-optimization/94864 + PR tree-optimization/94865 + PR tree-optimization/93080 + * gcc.target/i386/pr94864.c: New testcase. + * gcc.target/i386/pr94865.c: Likewise. + * gcc.target/i386/avx512fp16-vmovsh-1a.c: XFAIL. + * gcc.dg/tree-ssa/forwprop-40.c: Likewise. + * gcc.dg/tree-ssa/forwprop-41.c: Likewise. + +2023-08-22 Harald Anlauf + + PR fortran/49588 + * gfortran.dg/data_vector_section.f90: New test. + +2023-08-22 Juzhe-Zhong + Kewen.Lin + + * gcc.target/riscv/rvv/autovec/partial/live-1.c: New test. + * gcc.target/riscv/rvv/autovec/partial/live_run-1.c: New test. + +2023-08-22 liuhongt + + * gcc.target/i386/invariant-ternlog-1.c: Only scan %rdx under + TARGET_64BIT. + +2023-08-22 Lehua Ding + + * gcc.target/riscv/rvv/autovec/cond/cond_fms_fnms-1.c: Adjust. + * gcc.target/riscv/rvv/autovec/cond/cond_fms_fnms-2.c: Ditto. + * gcc.target/riscv/rvv/autovec/cond/cond_fms_fnms-3.c: Ditto. + * gcc.target/riscv/rvv/autovec/cond/cond_fms_fnms-4.c: Ditto. + * gcc.target/riscv/rvv/autovec/cond/cond_fms_fnms-5.c: Ditto. + * gcc.target/riscv/rvv/autovec/cond/cond_fms_fnms-6.c: Ditto. + +2023-08-22 David Malcolm + + PR analyzer/105899 + * gcc.dg/analyzer/attr-format-1.c: New test. + * gcc.dg/analyzer/sprintf-1.c: Update expected results for + now-passing tests. + +2023-08-22 David Malcolm + + * gcc.dg/analyzer/fopen-1.c: New test. + +2023-08-22 David Malcolm + + PR analyzer/105899 + * gcc.dg/analyzer/error-1.c: Update expected results to reflect + reimplementation of unterminated string detection. Add test + coverage for uninitialized buffers. + * gcc.dg/analyzer/null-terminated-strings-1.c: Likewise. + * gcc.dg/analyzer/putenv-1.c: Likewise. + * gcc.dg/analyzer/strchr-1.c: Likewise. + * gcc.dg/analyzer/strcpy-1.c: Likewise. + * gcc.dg/analyzer/strdup-1.c: Likewise. + +2023-08-22 Pan Li + + * gcc.target/riscv/rvv/base/float-point-wredusum.c: New test. + +2023-08-21 Thiago Jung Bauermann + + * gcc.dg/unroll-7.c: Remove xfail. + +2023-08-21 Tsukasa OI + + * gcc.target/riscv/xtheadba.c: Quote unquoted #error message. + * gcc.target/riscv/xtheadbb.c: Ditto. + * gcc.target/riscv/xtheadbs.c: Ditto. + * gcc.target/riscv/xtheadcmo.c: Ditto. + * gcc.target/riscv/xtheadcondmov.c: Ditto. + * gcc.target/riscv/xtheadfmemidx.c: Ditto. + * gcc.target/riscv/xtheadfmv.c: Ditto. + * gcc.target/riscv/xtheadint.c: Ditto. + * gcc.target/riscv/xtheadmac.c: Ditto. + * gcc.target/riscv/xtheadmemidx.c: Ditto. + * gcc.target/riscv/xtheadmempair.c: Ditto. + * gcc.target/riscv/xtheadsync.c: Ditto. + * gcc.target/riscv/zawrs.c: Ditto. + * gcc.target/riscv/zvbb.c: Ditto. + * gcc.target/riscv/zvbc.c: Ditto. + * gcc.target/riscv/zvkg.c: Ditto. + * gcc.target/riscv/zvkned.c: Ditto. + * gcc.target/riscv/zvknha.c: Ditto. + * gcc.target/riscv/zvknhb.c: Ditto. + * gcc.target/riscv/zvksed.c: Ditto. + * gcc.target/riscv/zvksh.c: Ditto. + * gcc.target/riscv/zvkt.c: Ditto. + +2023-08-21 Tsukasa OI + + * gcc.target/riscv/zvkn.c: Quote #error messages. + * gcc.target/riscv/zvkn-1.c: Ditto. + * gcc.target/riscv/zvknc.c: Ditto. + * gcc.target/riscv/zvknc-1.c: Ditto. + * gcc.target/riscv/zvknc-2.c: Ditto. + * gcc.target/riscv/zvkng.c: Ditto. + * gcc.target/riscv/zvkng-1.c: Ditto. + * gcc.target/riscv/zvkng-2.c: Ditto. + * gcc.target/riscv/zvks.c: Ditto. + * gcc.target/riscv/zvks-1.c: Ditto. + * gcc.target/riscv/zvksc.c: Ditto. + * gcc.target/riscv/zvksc-1.c: Ditto. + * gcc.target/riscv/zvksc-2.c: Ditto. + * gcc.target/riscv/zvksg.c: Ditto. + * gcc.target/riscv/zvksg-1.c: Ditto. + * gcc.target/riscv/zvksg-2.c: Ditto. + +2023-08-21 Richard Biener + + * gcc.target/i386/pr87007-5.c: Update comment, adjust subtest. + +2023-08-21 Richard Biener + + * lib/target-supports.exp: Add vect128, vect256 and vect512 + effective targets. + * gcc.dg/vect/bb-slp-subgroups-2.c: Properly handle the + vect256 case. + +2023-08-21 Prathamesh Kulkarni + + * gcc.dg/vect/pr65947-7.c: Add target check aarch64*-*-* and scan vect + dump for pattern "optimizing condition reduction with FOLD_EXTRACT_LAST" + for targets that support vect_fold_extract_last. + +2023-08-21 Richard Biener + + * gcc.dg/vect/bb-slp-46.c: Use division instead of addition + to avoid reduction vectorization. + +2023-08-21 liuhongt + + * gcc.target/i386/avx512f-pr88464-2.c: Add -mgather to + options. + * gcc.target/i386/avx512f-pr88464-3.c: Ditto. + * gcc.target/i386/avx512f-pr88464-4.c: Ditto. + * gcc.target/i386/avx512f-pr88464-6.c: Ditto. + * gcc.target/i386/avx512f-pr88464-7.c: Ditto. + * gcc.target/i386/avx512f-pr88464-8.c: Ditto. + * gcc.target/i386/avx512vl-pr88464-10.c: Ditto. + * gcc.target/i386/avx512vl-pr88464-12.c: Ditto. + * gcc.target/i386/avx512vl-pr88464-13.c: Ditto. + * gcc.target/i386/avx512vl-pr88464-14.c: Ditto. + * gcc.target/i386/avx512vl-pr88464-15.c: Ditto. + * gcc.target/i386/avx512vl-pr88464-16.c: Ditto. + * gcc.target/i386/avx512vl-pr88464-2.c: Ditto. + * gcc.target/i386/avx512vl-pr88464-4.c: Ditto. + * gcc.target/i386/avx512vl-pr88464-5.c: Ditto. + * gcc.target/i386/avx512vl-pr88464-6.c: Ditto. + * gcc.target/i386/avx512vl-pr88464-7.c: Ditto. + * gcc.target/i386/avx512vl-pr88464-8.c: Ditto. + +2023-08-21 Richard Biener + + PR tree-optimization/111082 + * gcc.dg/pr111082.c: New testcase. + +2023-08-21 Richard Biener + + PR tree-optimization/111070 + * gcc.dg/pr111070.c: New testcase. + +2023-08-21 Andrew Pinski + + PR tree-optimization/111002 + * gcc.target/aarch64/sve/cond_convert_8.c: New test. + +2023-08-21 Francois-Xavier Coudert + + * gcc.dg/lto/20091013-1_2.c: Add -Wno-stringop-overread. + +2023-08-20 Francois-Xavier Coudert + + * gcc.dg/darwin-minversion-link.c: Account for macOS 13 and 14. + +2023-08-20 Thiago Jung Bauermann + + PR testsuite/110756 + * g++.dg/gomp/pr58567.C: Adjust to new compiler error message. + +2023-08-20 Francois-Xavier Coudert + + * gcc.dg/plugin/taint-CVE-2011-0521-5-fixed.c: Use + _FORTIFY_SOURCE=0 on darwin. + * gcc.dg/plugin/taint-CVE-2011-0521-5.c: Likewise. + * gcc.dg/plugin/taint-CVE-2011-0521-6.c: Likewise. + +2023-08-20 Francois-Xavier Coudert + + * gcc.dg/ipa/ipa-icf-38.c: Require alias support. + +2023-08-20 Francois-Xavier Coudert + + * gcc.dg/plugin/crash-test-write-though-null-sarif.c: Update + expected pattern. + +2023-08-20 Francois-Xavier Coudert + + PR analyzer/104042 + * gcc.dg/analyzer/analyzer.exp: Pass -D_FORTIFY_SOURCE=0 on Darwin. + * gcc.dg/analyzer/fd-bind.c: Add missing header. + * gcc.dg/analyzer/fd-datagram-socket.c: Likewise. + * gcc.dg/analyzer/fd-listen.c: Likewise. + * gcc.dg/analyzer/fd-socket-misuse.c: Likewise. + * gcc.dg/analyzer/fd-stream-socket-active-open.c: Likewise. + * gcc.dg/analyzer/fd-stream-socket-passive-open.c: Likewise. + * gcc.dg/analyzer/fd-stream-socket.c: Likewise. + * gcc.dg/analyzer/fd-symbolic-socket.c: Likewise. + +2023-08-20 Andrew Pinski + + PR tree-optimization/111006 + * gcc.target/aarch64/sve/cond_convert_7.c: New test. + +2023-08-18 Thiago Jung Bauermann + + * lib/target-supports.exp (dg-require-python-h): Test + whether Python.h can really be used. + +2023-08-18 Uros Bizjak + + PR target/111023 + * gcc.target/i386/pr111023-2.c: New test. + * gcc.target/i386/pr111023-4b.c: New test. + * gcc.target/i386/pr111023-8b.c: New test. + * gcc.target/i386/pr111023.c: New test. + +2023-08-18 Aldy Hernandez + + PR ipa/110753 + * gcc.dg/tree-ssa/pr110753.c: New test. + +2023-08-18 Richard Biener + + PR tree-optimization/111019 + * g++.dg/torture/pr111019.C: New testcase. + +2023-08-18 Jose E. Marchesi + + * gcc.target/bpf/frame-limit-1.c: New test. + * gcc.target/bpf/frame-limit-2.c: Likewise. + +2023-08-18 Richard Biener + + PR tree-optimization/111048 + * gcc.dg/torture/pr111048.c: New testcase. + +2023-08-18 Haochen Jiang + + PR target/111051 + PR target/111051 + * gcc.target/i386/pr111051-1.c: New test. + +2023-08-18 Lehua Ding + + * gcc.target/riscv/_Float16-zhinxmin-3.c: Adjust. + * gcc.target/riscv/_Float16-zhinxmin-4.c: Ditto. + +2023-08-18 Lehua Ding + + * gcc.target/riscv/_Float16-zfhmin-4.c: New test. + * gcc.target/riscv/_Float16-zhinxmin-4.c: New test. + +2023-08-18 Lehua Ding + Ju-Zhe Zhong + + * gcc.target/riscv/rvv/base/scalar_move-5.c: Update. + * gcc.target/riscv/rvv/base/scalar_move-6.c: Ditto. + +2023-08-18 Lehua Ding + + * gcc.target/riscv/rvv/autovec/gather-scatter/strided_load_run-1.c: + Address failure due to uninitialized vtype register. + +2023-08-17 Andrew MacLeod + + PR tree-optimization/111009 + * gcc.dg/pr111009.c: New. + +2023-08-17 Patrick O'Neill + Charlie Jenkins + + * gcc.target/riscv/zbb-rol-ror-08.c: New test. + * gcc.target/riscv/zbb-rol-ror-09.c: New test. + +2023-08-17 Jose E. Marchesi + + PR c/106537 + * gcc.c-torture/compile/pr106537-1.c: New test. + * gcc.c-torture/compile/pr106537-2.c: Likewise. + * gcc.c-torture/compile/pr106537-3.c: Likewise. + +2023-08-17 Tsukasa OI + + * gcc.target/riscv/zvkn.c: Deduplicate #error messages. + * gcc.target/riscv/zvkn-1.c: Ditto. + * gcc.target/riscv/zvknc.c: Ditto. + * gcc.target/riscv/zvknc-1.c: Ditto. + * gcc.target/riscv/zvknc-2.c: Ditto. + * gcc.target/riscv/zvkng.c: Ditto. + * gcc.target/riscv/zvkng-1.c: Ditto. + * gcc.target/riscv/zvkng-2.c: Ditto. + * gcc.target/riscv/zvks.c: Ditto. + * gcc.target/riscv/zvks-1.c: Ditto. + * gcc.target/riscv/zvksc.c: Ditto. + * gcc.target/riscv/zvksc-1.c: Ditto. + * gcc.target/riscv/zvksc-2.c: Ditto. + * gcc.target/riscv/zvksg.c: Ditto. + * gcc.target/riscv/zvksg-1.c: Ditto. + * gcc.target/riscv/zvksg-2.c: Ditto. + +2023-08-17 Richard Biener + + PR tree-optimization/111039 + * gcc.dg/pr111039.c: New testcase. + +2023-08-17 Lehua Ding + + * gcc.target/riscv/rvv/autovec/partial/slp-1.c: Fix. + * gcc.target/riscv/rvv/autovec/partial/slp-16.c: Ditto. + * gcc.target/riscv/rvv/autovec/partial/slp-17.c: Ditto. + * gcc.target/riscv/rvv/autovec/partial/slp-18.c: Ditto. + * gcc.target/riscv/rvv/autovec/partial/slp-19.c: Ditto. + * gcc.target/riscv/rvv/autovec/partial/slp-2.c: Ditto. + * gcc.target/riscv/rvv/autovec/partial/slp-3.c: Ditto. + * gcc.target/riscv/rvv/autovec/partial/slp-4.c: Ditto. + * gcc.target/riscv/rvv/autovec/partial/slp-5.c: Ditto. + * gcc.target/riscv/rvv/autovec/partial/slp-6.c: Ditto. + +2023-08-17 Jose E. Marchesi + + * gcc.target/bpf/naked-1.c: New test. + +2023-08-17 Richard Biener + + * gcc.target/i386/vect-reduc-2.c: New testcase. + +2023-08-17 benjamin priour + + * g++.dg/analyzer/fanalyzer-show-events-in-system-headers.C: + Remove dg-line var declare_a. + +2023-08-17 Pan Li + + * gcc.target/riscv/rvv/base/float-point-wredosum.c: New test. + +2023-08-17 Pan Li + + * gcc.target/riscv/rvv/base/float-point-redosum.c: New test. + +2023-08-17 Pan Li + + * gcc.target/riscv/rvv/base/float-point-redusum.c: New test. + +2023-08-17 Pan Li + + * gcc.target/riscv/rvv/base/float-point-ncvt-f.c: New test. + +2023-08-17 Pan Li + + * gcc.target/riscv/rvv/base/float-point-ncvt-xu.c: New test. + +2023-08-17 Pan Li + + * gcc.target/riscv/rvv/base/float-point-ncvt-x.c: New test. + +2023-08-17 Haochen Jiang + + * gcc.target/i386/avx10_1-vextractf64x2-1.c: New test. + * gcc.target/i386/avx10_1-vextracti64x2-1.c: Ditto. + * gcc.target/i386/avx10_1-vfpclasspd-1.c: Ditto. + * gcc.target/i386/avx10_1-vfpclassps-1.c: Ditto. + * gcc.target/i386/avx10_1-vinsertf64x2-1.c: Ditto. + * gcc.target/i386/avx10_1-vinserti64x2-1.c: Ditto. + * gcc.target/i386/avx10_1-vrangepd-1.c: Ditto. + * gcc.target/i386/avx10_1-vrangeps-1.c: Ditto. + * gcc.target/i386/avx10_1-vreducepd-1.c: Ditto. + * gcc.target/i386/avx10_1-vreduceps-1.c: Ditto. + +2023-08-17 Haochen Jiang + + * gcc.target/i386/avx10_1-abs-copysign-1.c: New test. + * gcc.target/i386/avx10_1-vandpd-1.c: Ditto. + * gcc.target/i386/avx10_1-vandps-1.c: Ditto. + * gcc.target/i386/avx10_1-vcvtps2qq-1.c: Ditto. + * gcc.target/i386/avx10_1-vcvtps2uqq-1.c: Ditto. + * gcc.target/i386/avx10_1-vcvtqq2pd-1.c: Ditto. + * gcc.target/i386/avx10_1-vcvtqq2ps-1.c: Ditto. + * gcc.target/i386/avx10_1-vcvtuqq2pd-1.c: Ditto. + * gcc.target/i386/avx10_1-vcvtuqq2ps-1.c: Ditto. + * gcc.target/i386/avx10_1-vorpd-1.c: Ditto. + * gcc.target/i386/avx10_1-vorps-1.c: Ditto. + * gcc.target/i386/avx10_1-vpmovd2m-1.c: Ditto. + * gcc.target/i386/avx10_1-vpmovm2d-1.c: Ditto. + * gcc.target/i386/avx10_1-vpmovm2q-1.c: Ditto. + * gcc.target/i386/avx10_1-vpmovq2m-1.c: Ditto. + * gcc.target/i386/avx10_1-vxorpd-1.c: Ditto. + * gcc.target/i386/avx10_1-vxorps-1.c: Ditto. + +2023-08-17 Juzhe-Zhong + + PR target/111037 + * gcc.target/riscv/rvv/base/pr111037-1.c: New test. + * gcc.target/riscv/rvv/base/pr111037-2.c: New test. + +2023-08-17 Haochen Jiang + + * gcc.target/i386/avx10_1-vandnpd-1.c: New test. + * gcc.target/i386/avx10_1-vandnps-1.c: Ditto. + * gcc.target/i386/avx10_1-vbroadcastf32x2-1.c: Ditto. + * gcc.target/i386/avx10_1-vbroadcastf64x2-1.c: Ditto. + * gcc.target/i386/avx10_1-vbroadcasti32x2-1.c: Ditto. + * gcc.target/i386/avx10_1-vbroadcasti64x2-1.c: Ditto. + * gcc.target/i386/avx10_1-vcvtpd2qq-1.c: Ditto. + * gcc.target/i386/avx10_1-vcvtpd2uqq-1.c: Ditto. + * gcc.target/i386/avx10_1-vcvttpd2qq-1.c: Ditto. + * gcc.target/i386/avx10_1-vcvttpd2uqq-1.c: Ditto. + * gcc.target/i386/avx10_1-vcvttps2qq-1.c: Ditto. + * gcc.target/i386/avx10_1-vcvttps2uqq-1.c: Ditto. + * gcc.target/i386/avx10_1-vpmullq-1.c: Ditto. + +2023-08-17 Haochen Jiang + + * gcc.target/i386/avx-1.c: Add -mavx10.1. + * gcc.target/i386/avx-2.c: Ditto. + * gcc.target/i386/sse-26.c: Skip AVX512VLDQ intrin file. + +2023-08-17 Haochen Jiang + + * gcc.target/i386/avx10_1-15.c: New test. + * gcc.target/i386/avx10_1-16.c: Ditto. + * gcc.target/i386/avx10_1-17.c: Ditto. + * gcc.target/i386/avx10_1-18.c: Ditto. + +2023-08-17 Haochen Jiang + + * gcc.target/i386/avx10_1-11.c: New test. + * gcc.target/i386/avx10_1-12.c: Ditto. + * gcc.target/i386/avx10_1-13.c: Ditto. + * gcc.target/i386/avx10_1-14.c: Ditto. + +2023-08-17 Haochen Jiang + + * g++.target/i386/mv33.C: New test. + * gcc.target/i386/avx10_1-1.c: Ditto. + * gcc.target/i386/avx10_1-2.c: Ditto. + * gcc.target/i386/avx10_1-3.c: Ditto. + * gcc.target/i386/avx10_1-4.c: Ditto. + * gcc.target/i386/avx10_1-5.c: Ditto. + * gcc.target/i386/avx10_1-6.c: Ditto. + * gcc.target/i386/avx10_1-7.c: Ditto. + * gcc.target/i386/avx10_1-8.c: Ditto. + * gcc.target/i386/avx10_1-9.c: Ditto. + * gcc.target/i386/avx10_1-10.c: Ditto. + +2023-08-17 Yanzhang Wang + + * gcc.target/riscv/rvv/base/simplify-vrsub.c: New test. + +2023-08-17 Andrew Pinski + + PR target/110986 + * gcc.target/aarch64/sve/cond_unary_9.c: New test. + +2023-08-16 Robin Dapp + + * gcc.target/riscv/rvv/autovec/widen/vec-avg-run.c: New test. + * gcc.target/riscv/rvv/autovec/widen/vec-avg-rv32gcv.c: New test. + * gcc.target/riscv/rvv/autovec/widen/vec-avg-rv64gcv.c: New test. + * gcc.target/riscv/rvv/autovec/widen/vec-avg-template.h: New test. + +2023-08-16 Robin Dapp + + * gcc.target/riscv/rvv/autovec/vls-vlmax/vec_extract-1u.c: New test. + * gcc.target/riscv/rvv/autovec/vls-vlmax/vec_extract-2u.c: New test. + * gcc.target/riscv/rvv/autovec/vls-vlmax/vec_extract-3u.c: New test. + * gcc.target/riscv/rvv/autovec/vls-vlmax/vec_extract-4u.c: New test. + * gcc.target/riscv/rvv/autovec/vls-vlmax/vec_extract-runu.c: New test. + +2023-08-16 Pan Li + + * gcc.target/riscv/rvv/base/float-point-wcvt-xu.c: New test. + +2023-08-16 Pan Li + + * gcc.target/riscv/rvv/base/float-point-wcvt-x.c: New test. + +2023-08-16 Pan Li + + * gcc.target/riscv/rvv/base/float-point-cvt-f.c: New test. + +2023-08-16 Pan Li + + * gcc.target/riscv/rvv/base/float-point-cvt-xu.c: New test. + +2023-08-16 Haochen Gui + + PR target/110429 + * gcc.target/powerpc/pr110429.c: New. + +2023-08-16 Haochen Gui + + PR target/106769 + * gcc.target/powerpc/pr106769.h: New. + * gcc.target/powerpc/pr106769-p8.c: New. + * gcc.target/powerpc/pr106769-p9.c: New. + +2023-08-16 Juzhe-Zhong + + * gcc.target/riscv/rvv/autovec/gather-scatter/strided_load-2.c: + Adapt test. + * gcc.target/riscv/rvv/autovec/partial/slp-1.c: Ditto. + * gcc.target/riscv/rvv/autovec/partial/slp-16.c: Ditto. + * gcc.target/riscv/rvv/autovec/partial/slp-17.c: Ditto. + * gcc.target/riscv/rvv/autovec/partial/slp-18.c: Ditto. + * gcc.target/riscv/rvv/autovec/partial/slp-19.c: Ditto. + * gcc.target/riscv/rvv/autovec/partial/slp-2.c: Ditto. + * gcc.target/riscv/rvv/autovec/partial/slp-3.c: Ditto. + * gcc.target/riscv/rvv/autovec/partial/slp-4.c: Ditto. + * gcc.target/riscv/rvv/autovec/partial/slp-5.c: Ditto. + * gcc.target/riscv/rvv/autovec/partial/slp-6.c: Ditto. + * gcc.target/riscv/rvv/rvv.exp: Add lanes tests. + * gcc.target/riscv/rvv/autovec/struct/mask_struct_load-1.c: New test. + * gcc.target/riscv/rvv/autovec/struct/mask_struct_load-2.c: New test. + * gcc.target/riscv/rvv/autovec/struct/mask_struct_load-3.c: New test. + * gcc.target/riscv/rvv/autovec/struct/mask_struct_load-4.c: New test. + * gcc.target/riscv/rvv/autovec/struct/mask_struct_load-5.c: New test. + * gcc.target/riscv/rvv/autovec/struct/mask_struct_load-6.c: New test. + * gcc.target/riscv/rvv/autovec/struct/mask_struct_load-7.c: New test. + * gcc.target/riscv/rvv/autovec/struct/mask_struct_load_run-1.c: + New test. + * gcc.target/riscv/rvv/autovec/struct/mask_struct_load_run-2.c: + New test. + * gcc.target/riscv/rvv/autovec/struct/mask_struct_load_run-3.c: + New test. + * gcc.target/riscv/rvv/autovec/struct/mask_struct_load_run-4.c: + New test. + * gcc.target/riscv/rvv/autovec/struct/mask_struct_load_run-5.c: + New test. + * gcc.target/riscv/rvv/autovec/struct/mask_struct_load_run-6.c: + New test. + * gcc.target/riscv/rvv/autovec/struct/mask_struct_load_run-7.c: + New test. + * gcc.target/riscv/rvv/autovec/struct/mask_struct_store-1.c: New test. + * gcc.target/riscv/rvv/autovec/struct/mask_struct_store-2.c: New test. + * gcc.target/riscv/rvv/autovec/struct/mask_struct_store-3.c: New test. + * gcc.target/riscv/rvv/autovec/struct/mask_struct_store-4.c: New test. + * gcc.target/riscv/rvv/autovec/struct/mask_struct_store-5.c: New test. + * gcc.target/riscv/rvv/autovec/struct/mask_struct_store-6.c: New test. + * gcc.target/riscv/rvv/autovec/struct/mask_struct_store-7.c: New test. + * gcc.target/riscv/rvv/autovec/struct/mask_struct_store_run-1.c: + New test. + * gcc.target/riscv/rvv/autovec/struct/mask_struct_store_run-2.c: + New test. + * gcc.target/riscv/rvv/autovec/struct/mask_struct_store_run-3.c: + New test. + * gcc.target/riscv/rvv/autovec/struct/mask_struct_store_run-4.c: + New test. + * gcc.target/riscv/rvv/autovec/struct/mask_struct_store_run-5.c: + New test. + * gcc.target/riscv/rvv/autovec/struct/mask_struct_store_run-6.c: + New test. + * gcc.target/riscv/rvv/autovec/struct/mask_struct_store_run-7.c: + New test. + * gcc.target/riscv/rvv/autovec/struct/struct_vect-1.c: New test. + * gcc.target/riscv/rvv/autovec/struct/struct_vect-10.c: New test. + * gcc.target/riscv/rvv/autovec/struct/struct_vect-11.c: New test. + * gcc.target/riscv/rvv/autovec/struct/struct_vect-12.c: New test. + * gcc.target/riscv/rvv/autovec/struct/struct_vect-13.c: New test. + * gcc.target/riscv/rvv/autovec/struct/struct_vect-14.c: New test. + * gcc.target/riscv/rvv/autovec/struct/struct_vect-15.c: New test. + * gcc.target/riscv/rvv/autovec/struct/struct_vect-16.c: New test. + * gcc.target/riscv/rvv/autovec/struct/struct_vect-17.c: New test. + * gcc.target/riscv/rvv/autovec/struct/struct_vect-18.c: New test. + * gcc.target/riscv/rvv/autovec/struct/struct_vect-2.c: New test. + * gcc.target/riscv/rvv/autovec/struct/struct_vect-3.c: New test. + * gcc.target/riscv/rvv/autovec/struct/struct_vect-4.c: New test. + * gcc.target/riscv/rvv/autovec/struct/struct_vect-5.c: New test. + * gcc.target/riscv/rvv/autovec/struct/struct_vect-6.c: New test. + * gcc.target/riscv/rvv/autovec/struct/struct_vect-7.c: New test. + * gcc.target/riscv/rvv/autovec/struct/struct_vect-8.c: New test. + * gcc.target/riscv/rvv/autovec/struct/struct_vect-9.c: New test. + * gcc.target/riscv/rvv/autovec/struct/struct_vect_run-1.c: New test. + * gcc.target/riscv/rvv/autovec/struct/struct_vect_run-10.c: New test. + * gcc.target/riscv/rvv/autovec/struct/struct_vect_run-11.c: New test. + * gcc.target/riscv/rvv/autovec/struct/struct_vect_run-12.c: New test. + * gcc.target/riscv/rvv/autovec/struct/struct_vect_run-13.c: New test. + * gcc.target/riscv/rvv/autovec/struct/struct_vect_run-14.c: New test. + * gcc.target/riscv/rvv/autovec/struct/struct_vect_run-15.c: New test. + * gcc.target/riscv/rvv/autovec/struct/struct_vect_run-16.c: New test. + * gcc.target/riscv/rvv/autovec/struct/struct_vect_run-17.c: New test. + * gcc.target/riscv/rvv/autovec/struct/struct_vect_run-18.c: New test. + * gcc.target/riscv/rvv/autovec/struct/struct_vect_run-2.c: New test. + * gcc.target/riscv/rvv/autovec/struct/struct_vect_run-3.c: New test. + * gcc.target/riscv/rvv/autovec/struct/struct_vect_run-4.c: New test. + * gcc.target/riscv/rvv/autovec/struct/struct_vect_run-5.c: New test. + * gcc.target/riscv/rvv/autovec/struct/struct_vect_run-6.c: New test. + * gcc.target/riscv/rvv/autovec/struct/struct_vect_run-7.c: New test. + * gcc.target/riscv/rvv/autovec/struct/struct_vect_run-8.c: New test. + * gcc.target/riscv/rvv/autovec/struct/struct_vect_run-9.c: New test. + +2023-08-16 Pan Li + + * gcc.target/riscv/rvv/base/float-point-cvt-x.c: New test. + +2023-08-16 liuhongt + + * gcc.target/i386/avx2-gather-2.c: Adjust options to keep + gather vectorization. + * gcc.target/i386/avx2-gather-6.c: Ditto. + * gcc.target/i386/avx512f-pr88464-1.c: Ditto. + * gcc.target/i386/avx512f-pr88464-5.c: Ditto. + * gcc.target/i386/avx512vl-pr88464-1.c: Ditto. + * gcc.target/i386/avx512vl-pr88464-11.c: Ditto. + * gcc.target/i386/avx512vl-pr88464-3.c: Ditto. + * gcc.target/i386/avx512vl-pr88464-9.c: Ditto. + * gcc.target/i386/pr88531-1b.c: Ditto. + * gcc.target/i386/pr88531-1c.c: Ditto. + +2023-08-16 liuhongt + + * gcc.target/i386/pr89229-4a.c: Adjust testcase. + +2023-08-15 David Faust + + PR target/111029 + * gcc.target/bpf/smov-2.c: New test. + * gcc.target/bpf/smov-pseudoc-2.c: New test. + +2023-08-15 Martin Jambor + + PR ipa/68930 + PR ipa/92497 + * gcc.dg/ipa/pr92497-1.c: New test. + * gcc.dg/ipa/pr92497-2.c: Likewise. + +2023-08-15 Iain Buclaw + + PR d/110959 + * gdc.dg/pr110959.d: New test. + +2023-08-15 Chung-Lin Tang + Thomas Schwinge + + * c-c++-common/goacc/default-3.c: Adjust testcase. + * c-c++-common/goacc/default-4.c: Adjust testcase. + * c-c++-common/goacc/default-5.c: Adjust testcase. + * gfortran.dg/goacc/default-3.f95: Adjust testcase. + * gfortran.dg/goacc/default-4.f: Adjust testcase. + * gfortran.dg/goacc/default-5.f: Adjust testcase. + +2023-08-15 Juzhe-Zhong + + PR target/110989 + * gcc.target/riscv/rvv/autovec/pr110989.c: Add vsetvli assembly check. + +2023-08-15 Richard Biener + + * gcc.dg/vect/bb-slp-75.c: New testcase. + +2023-08-15 Richard Biener + + PR tree-optimization/110963 + * gcc.dg/tree-ssa/ssa-pre-34.c: New testcase. + +2023-08-15 Richard Biener + + PR tree-optimization/110991 + * gcc.dg/tree-ssa/cunroll-16.c: New testcase. + +2023-08-15 Pan Li + + * gcc.target/riscv/mode-switch-ice-1.c: New test. + +2023-08-15 Pan Li + + * gcc.target/riscv/rvv/base/float-point-rec7.c: New test. + +2023-08-14 Mikael Morin + + * gfortran.dg/value_9.f90 (val, val4, sub, sub4): Take the error + codes from the arguments. + (p): Update calls: pass explicit distinct error codes. + +2023-08-14 Mikael Morin + + PR fortran/110360 + PR fortran/110419 + * gfortran.dg/bind_c_usage_13.f03: Update tree dump patterns. + +2023-08-14 benjamin priour + + PR analyzer/110543 + * g++.dg/analyzer/fanalyzer-show-events-in-system-headers-default.C: + New test. + * g++.dg/analyzer/fanalyzer-show-events-in-system-headers-no.C: + New test. + * g++.dg/analyzer/fanalyzer-show-events-in-system-headers.C: + New test. + +2023-08-14 gnaggnoyil + + DR 2386 + PR c++/110216 + * g++.dg/cpp1z/decomp10.C: Update expected error for DR 2386. + * g++.dg/cpp1z/pr110216.C: New test. + +2023-08-14 Jiawei + + * gcc.target/riscv/arch-24.c: New test. + * gcc.target/riscv/arch-25.c: New test. + +2023-08-14 Pan Li + + * gcc.target/riscv/rvv/base/float-point-sqrt.c: New test. + +2023-08-14 Pan Li + + * gcc.target/riscv/rvv/base/float-point-wnmsac.c: New test. + +2023-08-14 Pan Li + + * gcc.target/riscv/rvv/base/float-point-wmsac.c: New test. + +2023-08-14 Pan Li + + * gcc.target/riscv/rvv/base/float-point-wnmacc.c: New test. + +2023-08-14 Pan Li + + * gcc.target/riscv/rvv/base/float-point-fwmacc.c: New test. + +2023-08-14 Pan Li + + * gcc.target/riscv/rvv/base/float-point-nmsub.c: New test. + +2023-08-12 Gaius Mulley + + PR modula2/108119 + * gm2/iso/check/fail/iso-check-fail.exp (gm2_init_iso): Add -fm2-plugin. + * gm2/switches/auto-init/fail/switches-auto-init-fail.exp + (gm2_init_iso): Add -fm2-plugin. + * gm2/switches/check-all/pim2/fail/switches-check-all-pim2-fail.exp + (gm2_init_pim2): Add -fm2-plugin. + * gm2/switches/check-all/plugin/iso/fail/switches-check-all-plugin-iso-fail.exp + (gm2_init_iso): Add -fm2-plugin. + * gm2/switches/check-all/plugin/pim2/fail/switches-check-all-plugin-pim2-fail.exp + (gm2_init_pim2): Add -fm2-plugin. + +2023-08-12 Jakub Jelinek + + * gcc.dg/stdckdint-1.c: New test. + * gcc.dg/stdckdint-2.c: New test. + +2023-08-12 Juzhe-Zhong + + PR target/110994 + * gcc.target/riscv/rvv/autovec/vls/pr110994.c: New test. + +2023-08-12 Patrick Palka + Jason Merrill + + PR c++/106604 + * g++.dg/cpp1z/class-deduction74.C: Expect "defined" instead + of "declared" in the repeated deduction guide diagnostics. + * g++.dg/cpp1z/class-deduction116.C: New test. + +2023-08-12 Juzhe-Zhong + + PR target/110985 + * gcc.target/riscv/rvv/autovec/vls-vlmax/pr110985.c: New test. + +2023-08-12 Juzhe-Zhong + + * gcc.target/riscv/rvv/autovec/vls/def.h: Add VLS CONST_VECTOR tests. + * gcc.target/riscv/rvv/autovec/vls/const-1.c: New test. + * gcc.target/riscv/rvv/autovec/vls/const-2.c: New test. + * gcc.target/riscv/rvv/autovec/vls/const-3.c: New test. + * gcc.target/riscv/rvv/autovec/vls/const-4.c: New test. + * gcc.target/riscv/rvv/autovec/vls/const-5.c: New test. + * gcc.target/riscv/rvv/autovec/vls/series-1.c: New test. + * gcc.target/riscv/rvv/autovec/vls/series-2.c: New test. + * gcc.target/riscv/rvv/autovec/vls/series-3.c: New test. + * gcc.target/riscv/rvv/autovec/vls/series-4.c: New test. + +2023-08-11 David Malcolm + + PR analyzer/105899 + * gcc.dg/analyzer/analyzer-decls.h (__analyzer_get_strlen): New. + * gcc.dg/analyzer/error-1.c (test_error_unterminated): New. + (test_error_at_line_unterminated): New. + * gcc.dg/analyzer/null-terminated-strings-1.c: New test. + * gcc.dg/analyzer/putenv-1.c (test_unterminated): New. + * gcc.dg/analyzer/strchr-1.c (test_unterminated): New. + * gcc.dg/analyzer/strcpy-1.c (test_unterminated): New. + * gcc.dg/analyzer/strdup-1.c (test_unterminated): New. + +2023-08-11 Juzhe-Zhong + + PR middle-end/110989 + * gcc.target/riscv/rvv/autovec/pr110989.c: New test. + +2023-08-11 Patrick O'Neill + + * gcc.target/riscv/amo-table-ztso-amo-add-1.c: Add -mabi=lp64d + to dg-options. + * gcc.target/riscv/amo-table-ztso-amo-add-2.c: Ditto. + * gcc.target/riscv/amo-table-ztso-amo-add-3.c: Ditto. + * gcc.target/riscv/amo-table-ztso-amo-add-4.c: Ditto. + * gcc.target/riscv/amo-table-ztso-amo-add-5.c: Ditto. + * gcc.target/riscv/amo-table-ztso-compare-exchange-1.c: Ditto. + * gcc.target/riscv/amo-table-ztso-compare-exchange-2.c: Ditto. + * gcc.target/riscv/amo-table-ztso-compare-exchange-3.c: Ditto. + * gcc.target/riscv/amo-table-ztso-compare-exchange-4.c: Ditto. + * gcc.target/riscv/amo-table-ztso-compare-exchange-5.c: Ditto. + * gcc.target/riscv/amo-table-ztso-compare-exchange-6.c: Ditto. + * gcc.target/riscv/amo-table-ztso-compare-exchange-7.c: Ditto. + * gcc.target/riscv/amo-table-ztso-fence-1.c: Ditto. + * gcc.target/riscv/amo-table-ztso-fence-2.c: Ditto. + * gcc.target/riscv/amo-table-ztso-fence-3.c: Ditto. + * gcc.target/riscv/amo-table-ztso-fence-4.c: Ditto. + * gcc.target/riscv/amo-table-ztso-fence-5.c: Ditto. + * gcc.target/riscv/amo-table-ztso-load-1.c: Ditto. + * gcc.target/riscv/amo-table-ztso-load-2.c: Ditto. + * gcc.target/riscv/amo-table-ztso-load-3.c: Ditto. + * gcc.target/riscv/amo-table-ztso-store-1.c: Ditto. + * gcc.target/riscv/amo-table-ztso-store-2.c: Ditto. + * gcc.target/riscv/amo-table-ztso-store-3.c: Ditto. + * gcc.target/riscv/amo-table-ztso-subword-amo-add-1.c: Ditto. + * gcc.target/riscv/amo-table-ztso-subword-amo-add-2.c: Ditto. + * gcc.target/riscv/amo-table-ztso-subword-amo-add-3.c: Ditto. + * gcc.target/riscv/amo-table-ztso-subword-amo-add-4.c: Ditto. + * gcc.target/riscv/amo-table-ztso-subword-amo-add-5.c: Ditto. + +2023-08-11 Jose E. Marchesi + + * lib/target-supports.exp (check_effective_target_alloca): BPF + target does not support alloca. + * gcc.target/bpf/diag-alloca-1.c: New test. + * gcc.target/bpf/diag-alloca-2.c: Likewise. + * gcc.target/bpf/xbpf-callee-saved-regs-1.c: Remove test. + * gcc.target/bpf/xbpf-callee-saved-regs-2.c: Likewise. + * gcc.target/bpf/regs-availability-1.c: Likewise. + +2023-08-11 Jose E. Marchesi + + * gcc.target/bpf/diag-funargs-inline-1.c: New test. + * gcc.target/bpf/diag-funargs.c: Adapt test. + +2023-08-11 Eric Feng + + PR analyzer/107646 + * gcc.dg/plugin/analyzer_cpython_plugin.c: Analyzer support for + PyList_New, PyList_Append, PyLong_FromLong + * gcc.dg/plugin/plugin.exp: New test. + * lib/target-supports.exp: New procedure. + * gcc.dg/plugin/cpython-plugin-test-2.c: New test. + +2023-08-11 Patrick Palka + + PR c++/110927 + * g++.dg/cpp2a/concepts-requires35.C: New test. + +2023-08-11 Patrick Palka + + PR c++/71954 + * g++.dg/cpp1y/var-templ84.C: New test. + * g++.dg/cpp1y/var-templ84a.C: New test. + +2023-08-11 Richard Biener + + PR tree-optimization/110979 + * gcc.dg/torture/pr110979.c: New testcase. + +2023-08-11 Richard Biener + + * g++.dg/vect/slp-pr87105.cc: Adjust. + * gcc.dg/vect/bb-slp-17.c: Likewise. + * gcc.dg/vect/bb-slp-20.c: Likewise. + * gcc.dg/vect/bb-slp-21.c: Likewise. + * gcc.dg/vect/bb-slp-22.c: Likewise. + * gcc.dg/vect/bb-slp-subgroups-2.c: Likewise. + +2023-08-11 Pan Li + + * gcc.target/riscv/rvv/base/float-point-msub.c: New test. + +2023-08-11 Pan Li + + * gcc.target/riscv/rvv/base/float-point-nmadd.c: New test. + +2023-08-11 Drew Ross + Jakub Jelinek + + PR tree-optimization/109938 + * gcc.c-torture/execute/pr109938.c: New test. + * gcc.dg/tree-ssa/pr109938.c: New test. + +2023-08-11 Pan Li + + * gcc.target/riscv/rvv/base/float-point-madd.c: New test. + +2023-08-11 Pan Li + + * gcc.target/riscv/rvv/base/float-point-nmsac.c: New test. + +2023-08-11 Jakub Jelinek + + * gcc.dg/c11-typeof-2.c: New test. + * gcc.dg/c11-typeof-3.c: New test. + * gcc.dg/gnu11-typeof-3.c: New test. + * gcc.dg/gnu11-typeof-4.c: New test. + +2023-08-11 Andrew Pinski + + PR tree-optimization/110954 + * gcc.c-torture/execute/pr110954-1.c: New test. + +2023-08-11 Martin Uecker + + PR c/84510 + * gcc.dg/Wuseless-cast.c: New test. + +2023-08-11 Pan Li + + * gcc.target/riscv/rvv/base/float-point-msac.c: New test. + +2023-08-10 Jan Hubicka + + PR middle-end/110923 + * gcc.dg/tree-ssa/pr110923.c: New test. + +2023-08-10 Patrick O'Neill + + * gcc.target/riscv/amo-table-ztso-amo-add-1.c: New test. + * gcc.target/riscv/amo-table-ztso-amo-add-2.c: New test. + * gcc.target/riscv/amo-table-ztso-amo-add-3.c: New test. + * gcc.target/riscv/amo-table-ztso-amo-add-4.c: New test. + * gcc.target/riscv/amo-table-ztso-amo-add-5.c: New test. + * gcc.target/riscv/amo-table-ztso-compare-exchange-1.c: New test. + * gcc.target/riscv/amo-table-ztso-compare-exchange-2.c: New test. + * gcc.target/riscv/amo-table-ztso-compare-exchange-3.c: New test. + * gcc.target/riscv/amo-table-ztso-compare-exchange-4.c: New test. + * gcc.target/riscv/amo-table-ztso-compare-exchange-5.c: New test. + * gcc.target/riscv/amo-table-ztso-compare-exchange-6.c: New test. + * gcc.target/riscv/amo-table-ztso-compare-exchange-7.c: New test. + * gcc.target/riscv/amo-table-ztso-fence-1.c: New test. + * gcc.target/riscv/amo-table-ztso-fence-2.c: New test. + * gcc.target/riscv/amo-table-ztso-fence-3.c: New test. + * gcc.target/riscv/amo-table-ztso-fence-4.c: New test. + * gcc.target/riscv/amo-table-ztso-fence-5.c: New test. + * gcc.target/riscv/amo-table-ztso-load-1.c: New test. + * gcc.target/riscv/amo-table-ztso-load-2.c: New test. + * gcc.target/riscv/amo-table-ztso-load-3.c: New test. + * gcc.target/riscv/amo-table-ztso-store-1.c: New test. + * gcc.target/riscv/amo-table-ztso-store-2.c: New test. + * gcc.target/riscv/amo-table-ztso-store-3.c: New test. + * gcc.target/riscv/amo-table-ztso-subword-amo-add-1.c: New test. + * gcc.target/riscv/amo-table-ztso-subword-amo-add-2.c: New test. + * gcc.target/riscv/amo-table-ztso-subword-amo-add-3.c: New test. + * gcc.target/riscv/amo-table-ztso-subword-amo-add-4.c: New test. + * gcc.target/riscv/amo-table-ztso-subword-amo-add-5.c: New test. + +2023-08-10 Jan Hubicka + + * gcc.dg/tree-ssa/phi_on_compare-1.c: Check profile consistency. + +2023-08-10 Pan Li + + * gcc.target/riscv/rvv/base/float-point-nmacc.c: New test. + +2023-08-10 Pan Li + + * gcc.target/riscv/rvv/base/float-point-macc.c: New test. + +2023-08-10 Juzhe-Zhong + + PR target/110964 + * gcc.target/riscv/rvv/autovec/pr110964.c: New test. + +2023-08-09 Juzhe-Zhong + + * gcc.target/riscv/rvv/autovec/gather-scatter/strided_load_run-1.c: + Adapt test. + * gcc.target/riscv/rvv/vsetvl/vlmax_back_prop-24.c: Ditto. + * gcc.target/riscv/rvv/vsetvl/vlmax_back_prop-25.c: Ditto. + * gcc.target/riscv/rvv/vsetvl/vlmax_back_prop-26.c: Ditto. + * gcc.target/riscv/rvv/vsetvl/vlmax_back_prop-36.c: Ditto. + * gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-14.c: Ditto. + * gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-15.c: Ditto. + +2023-08-09 David Malcolm + + * gcc.dg/analyzer/allocation-size-1.c: Update expected results + to reflect splitting of allocation size and assignment messages + from a single event into pairs of events + * gcc.dg/analyzer/allocation-size-2.c: Likewise. + * gcc.dg/analyzer/allocation-size-3.c: Likewise. + * gcc.dg/analyzer/allocation-size-4.c: Likewise. + * gcc.dg/analyzer/allocation-size-multiline-1.c: Likewise. + * gcc.dg/analyzer/allocation-size-multiline-2.c: Likewise. + * gcc.dg/analyzer/allocation-size-multiline-3.c: Likewise. + * gcc.dg/analyzer/memset-1.c (test_1): Verify that the return + value is the initial argument. + * gcc.dg/plugin/analyzer_kernel_plugin.c + (copy_across_boundary_fn::impl_call_pre): Ensure the LHS is set on + the "known zero size" case. + * gcc.dg/plugin/analyzer_known_fns_plugin.c + (known_function_attempt_to_copy::impl_call_pre): Likewise. + +2023-08-09 Andrew Pinski + + PR tree-optimization/110937 + PR tree-optimization/100798 + * gcc.dg/tree-ssa/bool-14.c: New test. + * gcc.dg/tree-ssa/bool-15.c: New test. + * gcc.dg/tree-ssa/phi-opt-33.c: New test. + * gcc.dg/tree-ssa/20030709-2.c: Update testcase + so `a ? -1 : 0` is not used to hit the match + pattern. + +2023-08-09 Carl Love + + * gcc.target/powerpc/vec-cmpne-runnable.c: New execution test. + * gcc.target/powerpc/vec-cmpne.c (define_test_functions, + execute_test_functions): Move to vec-cmpne.h. Add + scan-assembler-times for vcmpequb, vcmpequh, vcmpequw. + * gcc.target/powerpc/vec-cmpne.h: New include file for vec-cmpne.c + and vec-cmpne-runnable.c. Split define_test_functions definition + into define_test_functions and define_init_verify_functions. + +2023-08-09 Juzhe-Zhong + + PR target/110950 + * gcc.target/riscv/rvv/autovec/pr110950.c: New test. + +2023-08-08 Jeff Law + + * gcc.target/riscv/zicond-ice-1.c: New test. + +2023-08-08 Nathaniel Shead + + PR c++/100482 + * g++.dg/cpp0x/decltype-100482.C: New test. + +2023-08-08 Uros Bizjak + + PR target/110832 + * gcc.target/i386/pr110832-1.c: New test. + * gcc.target/i386/pr110832-2.c: New test. + * gcc.target/i386/pr110832-3.c: New test. + +2023-08-08 Andrew Pinski + + PR tree-optimization/103281 + PR tree-optimization/28794 + * gcc.dg/tree-ssa/pr103281-1.c: New test. + * gcc.dg/tree-ssa/vrp-compare-1.c: New test. + +2023-08-08 Pan Li + + * gcc.target/riscv/rvv/base/float-point-single-rsub.c: Enhance + cases. + * gcc.target/riscv/rvv/base/float-point-single-sub.c: Ditto. + +2023-08-08 Juzhe-Zhong + + * gcc.target/riscv/rvv/rvv.exp: Add condition tests. + * gcc.target/riscv/rvv/autovec/cond/cond_arith-1.c: New test. + * gcc.target/riscv/rvv/autovec/cond/cond_arith-2.c: New test. + * gcc.target/riscv/rvv/autovec/cond/cond_arith-3.c: New test. + * gcc.target/riscv/rvv/autovec/cond/cond_arith-4.c: New test. + * gcc.target/riscv/rvv/autovec/cond/cond_arith-5.c: New test. + * gcc.target/riscv/rvv/autovec/cond/cond_arith-6.c: New test. + * gcc.target/riscv/rvv/autovec/cond/cond_arith-7.c: New test. + * gcc.target/riscv/rvv/autovec/cond/cond_arith-8.c: New test. + * gcc.target/riscv/rvv/autovec/cond/cond_arith-9.c: New test. + * gcc.target/riscv/rvv/autovec/cond/cond_arith_run-1.c: New test. + * gcc.target/riscv/rvv/autovec/cond/cond_arith_run-2.c: New test. + * gcc.target/riscv/rvv/autovec/cond/cond_arith_run-3.c: New test. + * gcc.target/riscv/rvv/autovec/cond/cond_arith_run-4.c: New test. + * gcc.target/riscv/rvv/autovec/cond/cond_arith_run-5.c: New test. + * gcc.target/riscv/rvv/autovec/cond/cond_arith_run-6.c: New test. + * gcc.target/riscv/rvv/autovec/cond/cond_arith_run-7.c: New test. + * gcc.target/riscv/rvv/autovec/cond/cond_arith_run-8.c: New test. + * gcc.target/riscv/rvv/autovec/cond/cond_arith_run-9.c: New test. + * gcc.target/riscv/rvv/autovec/cond/cond_fadd-1.c: New test. + * gcc.target/riscv/rvv/autovec/cond/cond_fadd-2.c: New test. + * gcc.target/riscv/rvv/autovec/cond/cond_fadd-3.c: New test. + * gcc.target/riscv/rvv/autovec/cond/cond_fadd-4.c: New test. + * gcc.target/riscv/rvv/autovec/cond/cond_fadd_run-1.c: New test. + * gcc.target/riscv/rvv/autovec/cond/cond_fadd_run-2.c: New test. + * gcc.target/riscv/rvv/autovec/cond/cond_fadd_run-3.c: New test. + * gcc.target/riscv/rvv/autovec/cond/cond_fadd_run-4.c: New test. + * gcc.target/riscv/rvv/autovec/cond/cond_fma_fnma-1.c: New test. + * gcc.target/riscv/rvv/autovec/cond/cond_fma_fnma-2.c: New test. + * gcc.target/riscv/rvv/autovec/cond/cond_fma_fnma-3.c: New test. + * gcc.target/riscv/rvv/autovec/cond/cond_fma_fnma-4.c: New test. + * gcc.target/riscv/rvv/autovec/cond/cond_fma_fnma-5.c: New test. + * gcc.target/riscv/rvv/autovec/cond/cond_fma_fnma-6.c: New test. + * gcc.target/riscv/rvv/autovec/cond/cond_fma_fnma-7.c: New test. + * gcc.target/riscv/rvv/autovec/cond/cond_fma_fnma-8.c: New test. + * gcc.target/riscv/rvv/autovec/cond/cond_fma_fnma_run-1.c: New test. + * gcc.target/riscv/rvv/autovec/cond/cond_fma_fnma_run-2.c: New test. + * gcc.target/riscv/rvv/autovec/cond/cond_fma_fnma_run-3.c: New test. + * gcc.target/riscv/rvv/autovec/cond/cond_fma_fnma_run-4.c: New test. + * gcc.target/riscv/rvv/autovec/cond/cond_fma_fnma_run-5.c: New test. + * gcc.target/riscv/rvv/autovec/cond/cond_fma_fnma_run-6.c: New test. + * gcc.target/riscv/rvv/autovec/cond/cond_fma_fnma_run-7.c: New test. + * gcc.target/riscv/rvv/autovec/cond/cond_fma_fnma_run-8.c: New test. + * gcc.target/riscv/rvv/autovec/cond/cond_fmax-1.c: New test. + * gcc.target/riscv/rvv/autovec/cond/cond_fmax-2.c: New test. + * gcc.target/riscv/rvv/autovec/cond/cond_fmax-3.c: New test. + * gcc.target/riscv/rvv/autovec/cond/cond_fmax-4.c: New test. + * gcc.target/riscv/rvv/autovec/cond/cond_fmax_run-1.c: New test. + * gcc.target/riscv/rvv/autovec/cond/cond_fmax_run-2.c: New test. + * gcc.target/riscv/rvv/autovec/cond/cond_fmax_run-3.c: New test. + * gcc.target/riscv/rvv/autovec/cond/cond_fmax_run-4.c: New test. + * gcc.target/riscv/rvv/autovec/cond/cond_fmin-1.c: New test. + * gcc.target/riscv/rvv/autovec/cond/cond_fmin-2.c: New test. + * gcc.target/riscv/rvv/autovec/cond/cond_fmin-3.c: New test. + * gcc.target/riscv/rvv/autovec/cond/cond_fmin-4.c: New test. + * gcc.target/riscv/rvv/autovec/cond/cond_fmin_run-1.c: New test. + * gcc.target/riscv/rvv/autovec/cond/cond_fmin_run-2.c: New test. + * gcc.target/riscv/rvv/autovec/cond/cond_fmin_run-3.c: New test. + * gcc.target/riscv/rvv/autovec/cond/cond_fmin_run-4.c: New test. + * gcc.target/riscv/rvv/autovec/cond/cond_fms_fnms-1.c: New test. + * gcc.target/riscv/rvv/autovec/cond/cond_fms_fnms-2.c: New test. + * gcc.target/riscv/rvv/autovec/cond/cond_fms_fnms-3.c: New test. + * gcc.target/riscv/rvv/autovec/cond/cond_fms_fnms-4.c: New test. + * gcc.target/riscv/rvv/autovec/cond/cond_fms_fnms-5.c: New test. + * gcc.target/riscv/rvv/autovec/cond/cond_fms_fnms-6.c: New test. + * gcc.target/riscv/rvv/autovec/cond/cond_fms_fnms_run-1.c: New test. + * gcc.target/riscv/rvv/autovec/cond/cond_fms_fnms_run-2.c: New test. + * gcc.target/riscv/rvv/autovec/cond/cond_fms_fnms_run-3.c: New test. + * gcc.target/riscv/rvv/autovec/cond/cond_fms_fnms_run-4.c: New test. + * gcc.target/riscv/rvv/autovec/cond/cond_fms_fnms_run-5.c: New test. + * gcc.target/riscv/rvv/autovec/cond/cond_fms_fnms_run-6.c: New test. + * gcc.target/riscv/rvv/autovec/cond/cond_fmul-1.c: New test. + * gcc.target/riscv/rvv/autovec/cond/cond_fmul-2.c: New test. + * gcc.target/riscv/rvv/autovec/cond/cond_fmul-3.c: New test. + * gcc.target/riscv/rvv/autovec/cond/cond_fmul-4.c: New test. + * gcc.target/riscv/rvv/autovec/cond/cond_fmul_run-1.c: New test. + * gcc.target/riscv/rvv/autovec/cond/cond_fmul_run-2.c: New test. + * gcc.target/riscv/rvv/autovec/cond/cond_fmul_run-3.c: New test. + * gcc.target/riscv/rvv/autovec/cond/cond_fmul_run-4.c: New test. + * gcc.target/riscv/rvv/autovec/cond/cond_logical-1.c: New test. + * gcc.target/riscv/rvv/autovec/cond/cond_logical-2.c: New test. + * gcc.target/riscv/rvv/autovec/cond/cond_logical-3.c: New test. + * gcc.target/riscv/rvv/autovec/cond/cond_logical-4.c: New test. + * gcc.target/riscv/rvv/autovec/cond/cond_logical-5.c: New test. + * gcc.target/riscv/rvv/autovec/cond/cond_logical_run-1.c: New test. + * gcc.target/riscv/rvv/autovec/cond/cond_logical_run-2.c: New test. + * gcc.target/riscv/rvv/autovec/cond/cond_logical_run-3.c: New test. + * gcc.target/riscv/rvv/autovec/cond/cond_logical_run-4.c: New test. + * gcc.target/riscv/rvv/autovec/cond/cond_logical_run-5.c: New test. + * gcc.target/riscv/rvv/autovec/cond/cond_shift-1.c: New test. + * gcc.target/riscv/rvv/autovec/cond/cond_shift-2.c: New test. + * gcc.target/riscv/rvv/autovec/cond/cond_shift-3.c: New test. + * gcc.target/riscv/rvv/autovec/cond/cond_shift-4.c: New test. + * gcc.target/riscv/rvv/autovec/cond/cond_shift-5.c: New test. + * gcc.target/riscv/rvv/autovec/cond/cond_shift-6.c: New test. + * gcc.target/riscv/rvv/autovec/cond/cond_shift-7.c: New test. + * gcc.target/riscv/rvv/autovec/cond/cond_shift-8.c: New test. + * gcc.target/riscv/rvv/autovec/cond/cond_shift-9.c: New test. + * gcc.target/riscv/rvv/autovec/cond/cond_shift_run-1.c: New test. + * gcc.target/riscv/rvv/autovec/cond/cond_shift_run-2.c: New test. + * gcc.target/riscv/rvv/autovec/cond/cond_shift_run-3.c: New test. + * gcc.target/riscv/rvv/autovec/cond/cond_shift_run-4.c: New test. + * gcc.target/riscv/rvv/autovec/cond/cond_shift_run-5.c: New test. + * gcc.target/riscv/rvv/autovec/cond/cond_shift_run-6.c: New test. + * gcc.target/riscv/rvv/autovec/cond/cond_shift_run-7.c: New test. + * gcc.target/riscv/rvv/autovec/cond/cond_shift_run-8.c: New test. + * gcc.target/riscv/rvv/autovec/cond/cond_shift_run-9.c: New test. + * gcc.target/riscv/rvv/autovec/reduc/reduc_call-1.c: New test. + * gcc.target/riscv/rvv/autovec/reduc/reduc_call-2.c: New test. + * gcc.target/riscv/rvv/autovec/reduc/reduc_call-3.c: New test. + * gcc.target/riscv/rvv/autovec/reduc/reduc_call-4.c: New test. + * gcc.target/riscv/rvv/autovec/reduc/reduc_call-5.c: New test. + +2023-08-08 Richard Biener + + PR tree-optimization/49955 + * gfortran.dg/vect/pr49955.f: New testcase. + +2023-08-08 Richard Biener + + PR tree-optimization/110924 + * gcc.dg/torture/pr110924.c: New testcase. + +2023-08-08 yulong + + * gcc.target/riscv/rvv/base/vslide1down-1.c: New test. + * gcc.target/riscv/rvv/base/vslide1down-2.c: New test. + * gcc.target/riscv/rvv/base/vslide1down-3.c: New test. + * gcc.target/riscv/rvv/base/vslide1up-1.c: New test. + * gcc.target/riscv/rvv/base/vslide1up-2.c: New test. + * gcc.target/riscv/rvv/base/vslide1up-3.c: New test. + +2023-08-08 Stefan Schulze Frielinghaus + + PR rtl-optimization/110869 + * gcc.dg/cmp-mem-const-1.c: Use optimization level 2. + * gcc.dg/cmp-mem-const-2.c: Dito. + * gcc.dg/cmp-mem-const-3.c: Exclude sparc from this test. + * gcc.dg/cmp-mem-const-4.c: Dito. + * gcc.dg/cmp-mem-const-5.c: Dito. + * gcc.dg/cmp-mem-const-6.c: Dito. + +2023-08-08 Juzhe-Zhong + + * gcc.target/riscv/rvv/autovec/vls/def.h: Ditto. + * gcc.target/riscv/rvv/autovec/vls/neg-1.c: New test. + +2023-08-08 Juzhe-Zhong + + * gcc.target/riscv/rvv/autovec/vls/def.h: Add VLS shift. + * gcc.target/riscv/rvv/autovec/vls/shift-1.c: New test. + * gcc.target/riscv/rvv/autovec/vls/shift-2.c: New test. + * gcc.target/riscv/rvv/autovec/vls/shift-3.c: New test. + * gcc.target/riscv/rvv/autovec/vls/shift-4.c: New test. + * gcc.target/riscv/rvv/autovec/vls/shift-5.c: New test. + * gcc.target/riscv/rvv/autovec/vls/shift-6.c: New test. + +2023-08-07 Juzhe-Zhong + + * gcc.target/riscv/rvv/autovec/vls/def.h: Add basic operations. + * gcc.target/riscv/rvv/autovec/vls/and-1.c: New test. + * gcc.target/riscv/rvv/autovec/vls/and-2.c: New test. + * gcc.target/riscv/rvv/autovec/vls/and-3.c: New test. + * gcc.target/riscv/rvv/autovec/vls/div-1.c: New test. + * gcc.target/riscv/rvv/autovec/vls/ior-1.c: New test. + * gcc.target/riscv/rvv/autovec/vls/ior-2.c: New test. + * gcc.target/riscv/rvv/autovec/vls/ior-3.c: New test. + * gcc.target/riscv/rvv/autovec/vls/max-1.c: New test. + * gcc.target/riscv/rvv/autovec/vls/min-1.c: New test. + * gcc.target/riscv/rvv/autovec/vls/minus-1.c: New test. + * gcc.target/riscv/rvv/autovec/vls/minus-2.c: New test. + * gcc.target/riscv/rvv/autovec/vls/minus-3.c: New test. + * gcc.target/riscv/rvv/autovec/vls/mod-1.c: New test. + * gcc.target/riscv/rvv/autovec/vls/mult-1.c: New test. + * gcc.target/riscv/rvv/autovec/vls/plus-1.c: New test. + * gcc.target/riscv/rvv/autovec/vls/plus-2.c: New test. + * gcc.target/riscv/rvv/autovec/vls/plus-3.c: New test. + +2023-08-07 Martin Jambor + + PR ipa/110378 + * g++.dg/ipa/pr110378-1.C: New test. + +2023-08-07 Andrew Pinski + + PR tree-optimization/109959 + * gcc.dg/tree-ssa/builtin-sprintf-warn-23.c: Remove xfail. + * c-c++-common/Wrestrict.c: Update test and remove some xfail. + * gcc.dg/tree-ssa/cmpeq-1.c: New test. + * gcc.dg/tree-ssa/cmpeq-2.c: New test. + * gcc.dg/tree-ssa/cmpeq-3.c: New test. + +2023-08-07 liuhongt + + * gcc.target/i386/pr110762-v4hf.c: New test. + +2023-08-07 Juzhe-Zhong + + * gcc.target/riscv/rvv/autovec/binop/narrow-1.c: Adapt testcase. + +2023-08-07 Jan Hubicka + + PR tree-optimization/106293 + * gcc.dg/vect/vect-cond-11.c: Check profile consistency. + * gcc.dg/vect/vect-widen-mult-extern-1.c: Check profile consistency. + +2023-08-07 Andrew Pinski + + PR tree-optimization/96695 + * gcc.dg/pr96695-1.c: New test. + * gcc.dg/pr96695-10.c: New test. + * gcc.dg/pr96695-11.c: New test. + * gcc.dg/pr96695-12.c: New test. + * gcc.dg/pr96695-2.c: New test. + * gcc.dg/pr96695-3.c: New test. + * gcc.dg/pr96695-4.c: New test. + * gcc.dg/pr96695-5.c: New test. + * gcc.dg/pr96695-6.c: New test. + * gcc.dg/pr96695-7.c: New test. + * gcc.dg/pr96695-8.c: New test. + * gcc.dg/pr96695-9.c: New test. + 2023-08-06 Roger Sayle PR target/110792 diff --git a/gcc/testsuite/gcc.dg/analyzer/aliasing-3.c b/gcc/testsuite/c-c++-common/analyzer/aliasing-3.c similarity index 89% rename from gcc/testsuite/gcc.dg/analyzer/aliasing-3.c rename to gcc/testsuite/c-c++-common/analyzer/aliasing-3.c index 003077ad5c1a..30772dca454f 100644 --- a/gcc/testsuite/gcc.dg/analyzer/aliasing-3.c +++ b/gcc/testsuite/c-c++-common/analyzer/aliasing-3.c @@ -1,6 +1,4 @@ -#include "analyzer-decls.h" - -#define NULL ((void *)0) +#include "../../gcc.dg/analyzer/analyzer-decls.h" struct s1 { @@ -39,7 +37,7 @@ static struct s2 *p2_glob = NULL; void test_2 (struct s2 **pp2, struct s2 *p2_parm) { /* Ensure that p2_glob is modified. */ - p2_glob = __builtin_malloc (sizeof (struct s2)); + p2_glob = (struct s2 *) __builtin_malloc (sizeof (struct s2)); if (!p2_glob) return; @@ -61,7 +59,7 @@ struct s3 *p3_glob = NULL; void test_3 (struct s3 **pp3, struct s3 *p3_parm) { - p3_glob = __builtin_malloc (sizeof (struct s3)); + p3_glob = (struct s3 *) __builtin_malloc (sizeof (struct s3)); if (!p3_glob) return; diff --git a/gcc/testsuite/gcc.dg/analyzer/aliasing-pr106473.c b/gcc/testsuite/c-c++-common/analyzer/aliasing-pr106473.c similarity index 53% rename from gcc/testsuite/gcc.dg/analyzer/aliasing-pr106473.c rename to gcc/testsuite/c-c++-common/analyzer/aliasing-pr106473.c index afd1492252e0..4affa27b26cd 100644 --- a/gcc/testsuite/gcc.dg/analyzer/aliasing-pr106473.c +++ b/gcc/testsuite/c-c++-common/analyzer/aliasing-pr106473.c @@ -1,5 +1,5 @@ void foo(char **args[], int *argc) { *argc = 1; - (*args)[0] = __builtin_malloc(42); + (*args)[0] = (char *) __builtin_malloc(42); } diff --git a/gcc/testsuite/c-c++-common/analyzer/allocation-size-multiline-1.c b/gcc/testsuite/c-c++-common/analyzer/allocation-size-multiline-1.c new file mode 100644 index 000000000000..de1a49c436e8 --- /dev/null +++ b/gcc/testsuite/c-c++-common/analyzer/allocation-size-multiline-1.c @@ -0,0 +1,96 @@ +/* { dg-additional-options "-fdiagnostics-path-format=inline-events -fdiagnostics-show-caret" } */ + +#include + +void test_constant_1 (void) +{ + int32_t *ptr = (int32_t *) __builtin_malloc (1); /* { dg-warning "allocated buffer size is not a multiple of the pointee's size" } */ + __builtin_free (ptr); +} + +/* { dg-begin-multiline-output "" } + int32_t *ptr = (int32_t *) __builtin_malloc (1); + ^~~~~~~~~~~~~~~~~~~~ + 'test_constant_1': events 1-2 + | + | int32_t *ptr = (int32_t *) __builtin_malloc (1); + | ^~~~~~~~~~~~~~~~~~~~ + | | + | (1) allocated 1 byte here + | (2) assigned to 'int32_t *' + | + { dg-end-multiline-output "" { target c } } */ +/* { dg-begin-multiline-output "" } + int32_t *ptr = (int32_t *) __builtin_malloc (1); + ~~~~~~~~~~~~~~~~~^~~ + 'void test_constant_1()': events 1-2 + | + | int32_t *ptr = (int32_t *) __builtin_malloc (1); + | ~~~~~~~~~~~~~~~~~^~~ + | | + | (1) allocated 1 byte here + | (2) assigned to 'int32_t*' {aka '{re:long :re?}int*'} here; 'sizeof (int32_t {aka {re:long :re?}int})' is '4' + | + { dg-end-multiline-output "" { target c++ } } */ + +void test_constant_2 (void) +{ + int32_t *ptr = (int32_t *) __builtin_malloc (2); /* { dg-warning "allocated buffer size is not a multiple of the pointee's size" } */ + __builtin_free (ptr); +} + +/* { dg-begin-multiline-output "" } + int32_t *ptr = (int32_t *) __builtin_malloc (2); + ^~~~~~~~~~~~~~~~~~~~ + 'test_constant_2': events 1-2 + | + | int32_t *ptr = (int32_t *) __builtin_malloc (2); + | ^~~~~~~~~~~~~~~~~~~~ + | | + | (1) allocated 2 bytes here + | (2) assigned to 'int32_t *' + | + { dg-end-multiline-output "" { target c } } */ + +/* { dg-begin-multiline-output "" } + int32_t *ptr = (int32_t *) __builtin_malloc (2); + ~~~~~~~~~~~~~~~~~^~~ + 'void test_constant_2()': events 1-2 + | + | int32_t *ptr = (int32_t *) __builtin_malloc (2); + | ~~~~~~~~~~~~~~~~~^~~ + | | + | (1) allocated 2 bytes here + | (2) assigned to 'int32_t*' {aka '{re:long :re?}int*'} here; 'sizeof (int32_t {aka {re:long :re?}int})' is '4' + | + { dg-end-multiline-output "" { target c++ } } */ + +void test_symbolic (int n) +{ + int32_t *ptr = (int32_t *) __builtin_malloc (n * 2); /* { dg-warning "allocated buffer size is not a multiple of the pointee's size" } */ + __builtin_free (ptr); +} + +/* { dg-begin-multiline-output "" } + int32_t *ptr = (int32_t *) __builtin_malloc (n * 2); + ^~~~~~~~~~~~~~~~~~~~~~~~ + 'test_symbolic': event 1 + | + | int32_t *ptr = (int32_t *) __builtin_malloc (n * 2); + | ^~~~~~~~~~~~~~~~~~~~~~~~ + | | + | (1) allocated 'n * 2' bytes and assigned to 'int32_t *' + | + { dg-end-multiline-output "" { target c } } */ + +/* { dg-begin-multiline-output "" } + int32_t *ptr = (int32_t *) __builtin_malloc (n * 2); + ~~~~~~~~~~~~~~~~~^~~~~~~ + 'void test_symbolic(int)': event 1 + | + | int32_t *ptr = (int32_t *) __builtin_malloc (n * 2); + | ~~~~~~~~~~~~~~~~~^~~~~~~ + | | + | (1) allocated '(n * 2)' bytes and assigned to 'int32_t*' {aka '{re:long :re?}int*'} here; 'sizeof (int32_t {aka {re:long :re?}int})' is '4' + | + { dg-end-multiline-output "" { target c++ } } */ diff --git a/gcc/testsuite/c-c++-common/analyzer/allocation-size-multiline-2.c b/gcc/testsuite/c-c++-common/analyzer/allocation-size-multiline-2.c new file mode 100644 index 000000000000..a5def2764fe6 --- /dev/null +++ b/gcc/testsuite/c-c++-common/analyzer/allocation-size-multiline-2.c @@ -0,0 +1,98 @@ +/* { dg-additional-options "-fdiagnostics-path-format=inline-events -fdiagnostics-show-caret -fanalyzer-fine-grained" } */ +/* { dg-require-effective-target alloca } */ + +#include + +void test_constant_1 (void) +{ + int32_t *ptr = (int32_t *) __builtin_alloca (1); /* { dg-warning "allocated buffer size is not a multiple of the pointee's size" } */ +} + +/* { dg-begin-multiline-output "" } + int32_t *ptr = (int32_t *) __builtin_alloca (1); + ^~~~~~~~~~~~~~~~~~~~ + 'test_constant_1': events 1-2 + | + | int32_t *ptr = (int32_t *) __builtin_alloca (1); + | ^~~~~~~~~~~~~~~~~~~~ + | | + | (1) allocated 1 byte here + | (2) assigned to 'int32_t *' + | + { dg-end-multiline-output "" { target c } } */ +/* { dg-begin-multiline-output "" } + int32_t *ptr = (int32_t *) __builtin_alloca (1); + ~~~~~~~~~~~~~~~~~^~~ + 'void test_constant_1()': events 1-2 + | + | int32_t *ptr = (int32_t *) __builtin_alloca (1); + | ~~~~~~~~~~~~~~~~~^~~ + | | + | (1) allocated 1 byte here + | (2) assigned to 'int32_t*' {aka '{re:long :re?}int*'} here; 'sizeof (int32_t {aka {re:long :re?}int})' is '4' + | + { dg-end-multiline-output "" { target c++ } } */ + +void test_constant_2 (void) +{ + int32_t *ptr = (int32_t *) __builtin_alloca (2); /* { dg-warning "allocated buffer size is not a multiple of the pointee's size" } */ +} + +/* { dg-begin-multiline-output "" } + int32_t *ptr = (int32_t *) __builtin_alloca (2); + ^~~~~~~~~~~~~~~~~~~~ + 'test_constant_2': events 1-2 + | + | int32_t *ptr = (int32_t *) __builtin_alloca (2); + | ^~~~~~~~~~~~~~~~~~~~ + | | + | (1) allocated 2 bytes here + | (2) assigned to 'int32_t *' + | + { dg-end-multiline-output "" { target c } } */ +/* { dg-begin-multiline-output "" } + int32_t *ptr = (int32_t *) __builtin_alloca (2); + ~~~~~~~~~~~~~~~~~^~~ + 'void test_constant_2()': events 1-2 + | + | int32_t *ptr = (int32_t *) __builtin_alloca (2); + | ~~~~~~~~~~~~~~~~~^~~ + | | + | (1) allocated 2 bytes here + | (2) assigned to 'int32_t*' {aka '{re:long :re?}int*'} here; 'sizeof (int32_t {aka {re:long :re?}int})' is '4' + | + { dg-end-multiline-output "" { target c++ } } */ + +void test_symbolic (int n) +{ + int32_t *ptr = (int32_t *) __builtin_alloca (n * 2); /* { dg-warning "allocated buffer size is not a multiple of the pointee's size" } */ +} + +/* { dg-begin-multiline-output "" } + int32_t *ptr = (int32_t *) __builtin_alloca (n * 2); + ^~~~~~~~~~~~~~~~~~~~~~~~ + 'test_symbolic': events 1-2 + | + | int32_t *ptr = (int32_t *) __builtin_alloca (n * 2); + | ^~~~~~~~~~~~~~~~~~~~~~~~ + | | + | (1) allocated 'n * 2' bytes here + | (2) assigned to 'int32_t *' + | + { dg-end-multiline-output "" { target c } } */ +/* { dg-begin-multiline-output "" } + int32_t *ptr = (int32_t *) __builtin_alloca (n * 2); + ~~~~~~~~~~~~~~~~~^~~~~~~ + 'void test_symbolic(int)': events 1-2 + | + | int32_t *ptr = (int32_t *) __builtin_alloca (n * 2); + | ~~~~~~~~~~~~~~~~~^~~~~~~ + | | + | (1) allocated '(n * 2)' bytes here + | (2) assigned to 'int32_t*' {aka '{re:long :re?}int*'} here; 'sizeof (int32_t {aka {re:long :re?}int})' is '4' + | + { dg-end-multiline-output "" { target c++ } } */ + +/* FIXME: am getting a duplicate warning here for some reason + without -fanalyzer-fine-grained (PR PR analyzer/107851). */ + diff --git a/gcc/testsuite/c-c++-common/analyzer/allocation-size-multiline-3.c b/gcc/testsuite/c-c++-common/analyzer/allocation-size-multiline-3.c new file mode 100644 index 000000000000..3cf7fb004240 --- /dev/null +++ b/gcc/testsuite/c-c++-common/analyzer/allocation-size-multiline-3.c @@ -0,0 +1,68 @@ +/* Verify that we warn for incorrect uses of "alloca" (which may be in a + macro in a system header), and that the output looks correct. */ + +/* { dg-additional-options "-fdiagnostics-path-format=inline-events -fdiagnostics-show-caret -fanalyzer-fine-grained" } */ +/* { dg-require-effective-target alloca } */ + +#include +#include "../../gcc.dg/analyzer/test-alloca.h" + +void test_constant_99 (void) +{ + int32_t *ptr = (int32_t *) alloca (99); /* { dg-warning "allocated buffer size is not a multiple of the pointee's size" } */ +} + +/* { dg-begin-multiline-output "" } + int32_t *ptr = (int32_t *) alloca (99); + ^~~~~~ + 'test_constant_99': events 1-2 + | + | int32_t *ptr = (int32_t *) alloca (99); + | ^~~~~~ + | | + | (1) allocated 99 bytes here + | (2) assigned to 'int32_t *' {aka '{re:long :re?}int *'} here; 'sizeof (int32_t {aka {re:long :re?}int})' is '4' + | + { dg-end-multiline-output "" { target c } } */ +/* { dg-begin-multiline-output "" } + int32_t *ptr = (int32_t *) alloca (99); + ^~~~~~ + 'void test_constant_99()': events 1-2 + | + | int32_t *ptr = (int32_t *) alloca (99); + | ^~~~~~ + | | + | (1) allocated 99 bytes here + | (2) assigned to 'int32_t*' {aka '{re:long :re?}int*'} here; 'sizeof (int32_t {aka {re:long :re?}int})' is '4' + | + { dg-end-multiline-output "" { target c++ } } */ + +void test_symbolic (int n) +{ + int32_t *ptr = (int32_t *) alloca (n * 2); /* { dg-warning "allocated buffer size is not a multiple of the pointee's size" } */ +} + +/* { dg-begin-multiline-output "" } + int32_t *ptr = (int32_t *) alloca (n * 2); + ^~~~~~ + 'test_symbolic': events 1-2 + | + | int32_t *ptr = (int32_t *) alloca (n * 2); + | ^~~~~~ + | | + | (1) allocated 'n * 2' bytes here + | (2) assigned to 'int32_t *' {aka '{re:long :re?}int *'} here; 'sizeof (int32_t {aka {re:long :re?}int})' is '4' + | + { dg-end-multiline-output "" { target c } } */ +/* { dg-begin-multiline-output "" } + int32_t *ptr = (int32_t *) alloca (n * 2); + ^~~~~~ + 'void test_symbolic(int)': events 1-2 + | + | int32_t *ptr = (int32_t *) alloca (n * 2); + | ^~~~~~ + | | + | (1) allocated '(n * 2)' bytes here + | (2) assigned to 'int32_t*' {aka '{re:long :re?}int*'} here; 'sizeof (int32_t {aka {re:long :re?}int})' is '4' + | + { dg-end-multiline-output "" { target c++ } } */ diff --git a/gcc/testsuite/gcc.dg/analyzer/asm-x86-dyndbg-2.c b/gcc/testsuite/c-c++-common/analyzer/asm-x86-dyndbg-2.c similarity index 96% rename from gcc/testsuite/gcc.dg/analyzer/asm-x86-dyndbg-2.c rename to gcc/testsuite/c-c++-common/analyzer/asm-x86-dyndbg-2.c index 8111709206f2..d5e748c9acd7 100644 --- a/gcc/testsuite/gcc.dg/analyzer/asm-x86-dyndbg-2.c +++ b/gcc/testsuite/c-c++-common/analyzer/asm-x86-dyndbg-2.c @@ -8,9 +8,11 @@ /* Adapted from various files in the Linux kernel, all of which have: */ /* SPDX-License-Identifier: GPL-2.0 */ -typedef _Bool bool; -#define true 1 -#define false 0 +#ifndef __cplusplus + typedef _Bool bool; + #define true 1 + #define false 0 +#endif typedef struct {} atomic_t; diff --git a/gcc/testsuite/gcc.dg/analyzer/asm-x86-lp64-2.c b/gcc/testsuite/c-c++-common/analyzer/asm-x86-lp64-2.c similarity index 94% rename from gcc/testsuite/gcc.dg/analyzer/asm-x86-lp64-2.c rename to gcc/testsuite/c-c++-common/analyzer/asm-x86-lp64-2.c index 2864ab69d2ab..37c487a69c26 100644 --- a/gcc/testsuite/gcc.dg/analyzer/asm-x86-lp64-2.c +++ b/gcc/testsuite/c-c++-common/analyzer/asm-x86-lp64-2.c @@ -3,7 +3,9 @@ /* Adapted from Linux x86: page_ref_dec_and_test.c (GPL-2.0). */ -typedef _Bool bool; +#ifndef __cplusplus + typedef _Bool bool; +#endif typedef struct { int counter; diff --git a/gcc/testsuite/gcc.dg/analyzer/atomic-builtins-haproxy-proxy.c b/gcc/testsuite/c-c++-common/analyzer/atomic-builtins-haproxy-proxy.c similarity index 95% rename from gcc/testsuite/gcc.dg/analyzer/atomic-builtins-haproxy-proxy.c rename to gcc/testsuite/c-c++-common/analyzer/atomic-builtins-haproxy-proxy.c index 72953a561b87..fbe89f7dfbbc 100644 --- a/gcc/testsuite/gcc.dg/analyzer/atomic-builtins-haproxy-proxy.c +++ b/gcc/testsuite/c-c++-common/analyzer/atomic-builtins-haproxy-proxy.c @@ -37,7 +37,7 @@ proxy_capture_error(struct proxy* proxy, /* [...snip...] */ - es = malloc(sizeof(*es)); + es = (struct error_snapshot *) malloc(sizeof(*es)); if (!es) return; diff --git a/gcc/testsuite/gcc.dg/analyzer/atomic-builtins-qemu-sockets.c b/gcc/testsuite/c-c++-common/analyzer/atomic-builtins-qemu-sockets.c similarity index 74% rename from gcc/testsuite/gcc.dg/analyzer/atomic-builtins-qemu-sockets.c rename to gcc/testsuite/c-c++-common/analyzer/atomic-builtins-qemu-sockets.c index cd90f8f263d9..05ac339ada7b 100644 --- a/gcc/testsuite/gcc.dg/analyzer/atomic-builtins-qemu-sockets.c +++ b/gcc/testsuite/c-c++-common/analyzer/atomic-builtins-qemu-sockets.c @@ -5,7 +5,7 @@ struct foo { void * test (const char *str) { - struct foo *p = __builtin_malloc(sizeof(struct foo)); + struct foo *p = (struct foo *) __builtin_malloc(sizeof(struct foo)); if (!p) return p; diff --git a/gcc/testsuite/gcc.dg/analyzer/attr-malloc-6.c b/gcc/testsuite/c-c++-common/analyzer/attr-malloc-6.c similarity index 88% rename from gcc/testsuite/gcc.dg/analyzer/attr-malloc-6.c rename to gcc/testsuite/c-c++-common/analyzer/attr-malloc-6.c index bd28107d0d74..1665d4128f59 100644 --- a/gcc/testsuite/gcc.dg/analyzer/attr-malloc-6.c +++ b/gcc/testsuite/c-c++-common/analyzer/attr-malloc-6.c @@ -74,7 +74,7 @@ void warn_fdopen (void) { FILE *q = fdopen (0); // { dg-message "allocated here" } - q = realloc (q, 7); // { dg-warning "'realloc' called on 'q' returned from a mismatched allocation function" } + q = (FILE *) realloc (q, 7); // { dg-warning "'realloc' called on 'q' returned from a mismatched allocation function" } sink (q); } } @@ -117,7 +117,7 @@ void warn_fopen (void) { FILE *q = fdopen (0); - q = realloc (q, 7); // { dg-warning "'realloc' called on 'q' returned from a mismatched allocation function" } + q = (FILE *) realloc (q, 7); // { dg-warning "'realloc' called on 'q' returned from a mismatched allocation function" } sink (q); } } @@ -170,18 +170,18 @@ void test_tmpfile (void) void warn_malloc (void) { { - FILE *p = malloc (100); // { dg-message "allocated here" } + FILE *p = (FILE *) malloc (100); // { dg-message "allocated here" } fclose (p); // { dg-warning "'p' should have been deallocated with 'free' but was deallocated with 'fclose'" } } { - FILE *p = malloc (100); // { dg-message "allocated here" } + FILE *p = (FILE *) malloc (100); // { dg-message "allocated here" } p = freopen ("1", "r", p);// { dg-warning "'p' should have been deallocated with 'free' but was deallocated with 'freopen'" } fclose (p); } { - FILE *p = malloc (100); // { dg-message "allocated here" } + FILE *p = (FILE *) malloc (100); // { dg-message "allocated here" } pclose (p); // { dg-warning "'p' should have been deallocated with 'free' but was deallocated with 'pclose'" } } } @@ -222,7 +222,7 @@ void test_acquire (void) { FILE *p = acquire (); // { dg-message "allocated here \\(expects deallocation with 'release'\\)" } - p = realloc (p, 123); // { dg-warning "'p' should have been deallocated with 'release' but was deallocated with 'realloc'" } + p = (FILE *) realloc (p, 123); // { dg-warning "'p' should have been deallocated with 'release' but was deallocated with 'realloc'" } sink (p); } } diff --git a/gcc/testsuite/gcc.dg/analyzer/attr-malloc-CVE-2019-19078-usb-leak.c b/gcc/testsuite/c-c++-common/analyzer/attr-malloc-CVE-2019-19078-usb-leak.c similarity index 97% rename from gcc/testsuite/gcc.dg/analyzer/attr-malloc-CVE-2019-19078-usb-leak.c rename to gcc/testsuite/c-c++-common/analyzer/attr-malloc-CVE-2019-19078-usb-leak.c index e086843c42b6..24fb46bd5a9b 100644 --- a/gcc/testsuite/gcc.dg/analyzer/attr-malloc-CVE-2019-19078-usb-leak.c +++ b/gcc/testsuite/c-c++-common/analyzer/attr-malloc-CVE-2019-19078-usb-leak.c @@ -3,7 +3,10 @@ typedef unsigned char u8; typedef unsigned short u16; -typedef _Bool bool; + +#ifndef __cplusplus + typedef _Bool bool; +#endif #define ENOMEM 12 #define EINVAL 22 @@ -149,7 +152,7 @@ static int ath10k_usb_hif_tx_sg(struct ath10k *ar, u8 pipe_id, goto err; } - skb = items[i].transfer_context; + skb = (struct sk_buff *) items[i].transfer_context; urb_context->skb = skb; urb = usb_alloc_urb(0, GFP_ATOMIC); /* { dg-message "allocated here" } */ @@ -209,7 +212,7 @@ static const struct ath10k_hif_ops ath10k_usb_hif_ops = { /* Simulate code to register the callback. */ extern void callback_registration (const void *); -int ath10k_usb_probe(void) +void ath10k_usb_probe(void) { callback_registration(&ath10k_usb_hif_ops); } diff --git a/gcc/testsuite/gcc.dg/analyzer/attr-tainted_args-1.c b/gcc/testsuite/c-c++-common/analyzer/attr-tainted_args-1.c similarity index 94% rename from gcc/testsuite/gcc.dg/analyzer/attr-tainted_args-1.c rename to gcc/testsuite/c-c++-common/analyzer/attr-tainted_args-1.c index e1d87c9cece1..0ff344699671 100644 --- a/gcc/testsuite/gcc.dg/analyzer/attr-tainted_args-1.c +++ b/gcc/testsuite/c-c++-common/analyzer/attr-tainted_args-1.c @@ -1,7 +1,7 @@ // TODO: remove need for this option /* { dg-additional-options "-fanalyzer-checker=taint" } */ -#include "analyzer-decls.h" +#include "../../gcc.dg/analyzer/analyzer-decls.h" struct arg_buf { @@ -23,7 +23,7 @@ test_1 (int i, void *p, char *q) __analyzer_dump_state ("taint", q); /* { dg-warning "state: 'tainted'" } */ __analyzer_dump_state ("taint", *q); /* { dg-warning "state: 'tainted'" } */ - struct arg_buf *args = p; + struct arg_buf *args = (struct arg_buf *) p; __analyzer_dump_state ("taint", args->i); /* { dg-warning "state: 'tainted'" } */ __analyzer_dump_state ("taint", args->j); /* { dg-warning "state: 'tainted'" } */ } @@ -49,7 +49,7 @@ test_2a (int i, void *p, char *q) __analyzer_dump_state ("taint", p); /* { dg-warning "state: 'start'" } */ __analyzer_dump_state ("taint", q); /* { dg-warning "state: 'start'" } */ - struct arg_buf *args = p; + struct arg_buf *args = (struct arg_buf *) p; __analyzer_dump_state ("taint", args->i); /* { dg-warning "state: 'start'" } */ __analyzer_dump_state ("taint", args->j); /* { dg-warning "state: 'start'" } */ } diff --git a/gcc/testsuite/gcc.dg/analyzer/call-summaries-pr107158.c b/gcc/testsuite/c-c++-common/analyzer/call-summaries-pr107158.c similarity index 95% rename from gcc/testsuite/gcc.dg/analyzer/call-summaries-pr107158.c rename to gcc/testsuite/c-c++-common/analyzer/call-summaries-pr107158.c index 54f442f0ad41..d4cf079cef84 100644 --- a/gcc/testsuite/gcc.dg/analyzer/call-summaries-pr107158.c +++ b/gcc/testsuite/c-c++-common/analyzer/call-summaries-pr107158.c @@ -25,7 +25,7 @@ __attribute__((__noreturn__)) void failed(const char *message); static char *string_dup(const char *string) { char *buf; - if ((buf = malloc(strlen(string) + 1)) == ((void *)0)) + if ((buf = (char *) malloc(strlen(string) + 1)) == ((void *)0)) failed("malloc() failed"); return strcpy(buf, string); @@ -37,7 +37,7 @@ static void store_data(const char *name, const char *type) { if ((p = (struct mydata *)malloc(sizeof(struct mydata))) == ((void *)0)) failed("malloc() failed"); - p->link = ((void *)0); + p->link = (struct mydata *)((void *)0); p->name = string_dup(name); p->type = string_dup(type); diff --git a/gcc/testsuite/gcc.dg/analyzer/calloc-1.c b/gcc/testsuite/c-c++-common/analyzer/calloc-1.c similarity index 87% rename from gcc/testsuite/gcc.dg/analyzer/calloc-1.c rename to gcc/testsuite/c-c++-common/analyzer/calloc-1.c index bc28128671f9..6bd658ec94a4 100644 --- a/gcc/testsuite/gcc.dg/analyzer/calloc-1.c +++ b/gcc/testsuite/c-c++-common/analyzer/calloc-1.c @@ -1,9 +1,6 @@ -#include "analyzer-decls.h" - +#include "../../gcc.dg/analyzer/analyzer-decls.h" typedef __SIZE_TYPE__ size_t; -#define NULL ((void *)0) - extern void *calloc (size_t __nmemb, size_t __size) __attribute__ ((__nothrow__ , __leaf__)) __attribute__ ((__malloc__)) @@ -13,7 +10,7 @@ char *test_1 (size_t sz) { char *p; - p = calloc (1, 3); + p = (char *) calloc (1, 3); if (!p) return NULL; diff --git a/gcc/testsuite/gcc.dg/analyzer/compound-assignment-5.c b/gcc/testsuite/c-c++-common/analyzer/compound-assignment-5.c similarity index 83% rename from gcc/testsuite/gcc.dg/analyzer/compound-assignment-5.c rename to gcc/testsuite/c-c++-common/analyzer/compound-assignment-5.c index ccf8fe392bfa..3ce2b72c8ff3 100644 --- a/gcc/testsuite/gcc.dg/analyzer/compound-assignment-5.c +++ b/gcc/testsuite/c-c++-common/analyzer/compound-assignment-5.c @@ -1,4 +1,4 @@ -#include "analyzer-decls.h" +#include "../../gcc.dg/analyzer/analyzer-decls.h" struct coord { @@ -23,7 +23,7 @@ void test_1 (void) /* Copying from an on-stack array to a global array. */ -struct coord glob_arr[16]; +struct coord glob_arr2[16]; void test_2 (void) { @@ -31,32 +31,30 @@ void test_2 (void) arr[3].x = 5; arr[3].y = 6; - glob_arr[7] = arr[3]; + glob_arr2[7] = arr[3]; - __analyzer_eval (glob_arr[7].x == 5); /* { dg-warning "TRUE" } */ - __analyzer_eval (glob_arr[7].y == 6); /* { dg-warning "TRUE" } */ + __analyzer_eval (glob_arr2[7].x == 5); /* { dg-warning "TRUE" } */ + __analyzer_eval (glob_arr2[7].y == 6); /* { dg-warning "TRUE" } */ } /* Copying from a partially initialized on-stack array to a global array. */ -struct coord glob_arr[16]; +struct coord glob_arr3[16]; void test_3 (void) { struct coord arr[16]; arr[3].y = 6; - glob_arr[7] = arr[3]; // or should the uninit warning be here? + glob_arr3[7] = arr[3]; // or should the uninit warning be here? - __analyzer_eval (glob_arr[7].x); /* { dg-warning "uninitialized" "uninit" { xfail *-*-* } } */ + __analyzer_eval (glob_arr3[7].x); /* { dg-warning "uninitialized" "uninit" { xfail *-*-* } } */ /* { dg-bogus "UNKNOWN" "unknown" { xfail *-*-* } .-1 } */ - __analyzer_eval (glob_arr[7].y == 6); /* { dg-warning "TRUE" } */ + __analyzer_eval (glob_arr3[7].y == 6); /* { dg-warning "TRUE" } */ } /* Symbolic bindings: copying from one array to another. */ -struct coord glob_arr[16]; - void test_4 (int i) { struct coord arr_a[16]; @@ -77,8 +75,6 @@ void test_4 (int i) /* Symbolic bindings: copying within an array: symbolic src and dest */ -struct coord glob_arr[16]; - void test_5a (int i, int j) { struct coord arr[16]; @@ -95,8 +91,6 @@ void test_5a (int i, int j) /* Symbolic bindings: copying within an array: symbolic src, concrete dest. */ -struct coord glob_arr[16]; - void test_5b (int i) { struct coord arr[16]; @@ -113,8 +107,6 @@ void test_5b (int i) /* Symbolic bindings: copying within an array: concrete src, symbolic dest. */ -struct coord glob_arr[16]; - void test_5c (int i) { struct coord arr[16]; @@ -132,10 +124,12 @@ void test_5c (int i) /* No info on the subregion being copied, and hence binding_cluster2::maybe_get_compound_binding should return NULL. */ +struct coord glob_arr6[16]; + void test_6 (void) { struct coord arr[16]; - arr[7] = glob_arr[3]; + arr[7] = glob_arr6[3]; __analyzer_eval (arr[7].x == 5); /* { dg-warning "UNKNOWN" } */ __analyzer_eval (arr[7].y == 6); /* { dg-warning "UNKNOWN" } */ diff --git a/gcc/testsuite/gcc.dg/analyzer/coreutils-cksum-pr108664.c b/gcc/testsuite/c-c++-common/analyzer/coreutils-cksum-pr108664.c similarity index 97% rename from gcc/testsuite/gcc.dg/analyzer/coreutils-cksum-pr108664.c rename to gcc/testsuite/c-c++-common/analyzer/coreutils-cksum-pr108664.c index 62698f3d148e..7ae4e6b06bea 100644 --- a/gcc/testsuite/gcc.dg/analyzer/coreutils-cksum-pr108664.c +++ b/gcc/testsuite/c-c++-common/analyzer/coreutils-cksum-pr108664.c @@ -7,6 +7,11 @@ typedef long unsigned int size_t; typedef unsigned int __uint32_t; typedef unsigned long int __uintmax_t; typedef struct _IO_FILE FILE; + +#ifndef __cplusplus + typedef _Bool bool; +#endif + extern size_t fread_unlocked(void* __restrict __ptr, size_t __size, @@ -30,7 +35,7 @@ __errno_location(void) __attribute__((__nothrow__, __leaf__)) __attribute__((__const__)); extern uint_fast32_t const crctab[8][256]; -static _Bool +static bool cksum_slice8(FILE* fp, uint_fast32_t* crc_out, uintmax_t* length_out) { uint32_t buf[(1 << 16) / sizeof(uint32_t)]; diff --git a/gcc/testsuite/gcc.dg/analyzer/coreutils-sum-pr108666.c b/gcc/testsuite/c-c++-common/analyzer/coreutils-sum-pr108666.c similarity index 97% rename from gcc/testsuite/gcc.dg/analyzer/coreutils-sum-pr108666.c rename to gcc/testsuite/c-c++-common/analyzer/coreutils-sum-pr108666.c index 9d13fce85319..5684d1b02d45 100644 --- a/gcc/testsuite/gcc.dg/analyzer/coreutils-sum-pr108666.c +++ b/gcc/testsuite/c-c++-common/analyzer/coreutils-sum-pr108666.c @@ -35,7 +35,7 @@ bsd_sum_stream(FILE* stream, void* resstream, uintmax_t* length) int checksum = 0; uintmax_t total_bytes = 0; static const size_t buffer_length = 32768; - uint8_t* buffer = malloc(buffer_length); + uint8_t* buffer = (uint8_t *) malloc(buffer_length); if (!buffer) return -1; diff --git a/gcc/testsuite/c-c++-common/analyzer/data-model-11.c b/gcc/testsuite/c-c++-common/analyzer/data-model-11.c new file mode 100644 index 000000000000..0e64e5bf3baa --- /dev/null +++ b/gcc/testsuite/c-c++-common/analyzer/data-model-11.c @@ -0,0 +1,6 @@ +int test (void) +{ + const unsigned char *s = (const unsigned char *) "abc"; + const signed char *t = (const signed char *) "xyz"; + return s[1] + t[1]; +} diff --git a/gcc/testsuite/gcc.dg/analyzer/deref-before-check-pr108455-1.c b/gcc/testsuite/c-c++-common/analyzer/deref-before-check-pr108455-1.c similarity index 94% rename from gcc/testsuite/gcc.dg/analyzer/deref-before-check-pr108455-1.c rename to gcc/testsuite/c-c++-common/analyzer/deref-before-check-pr108455-1.c index d7d873edc51d..5f2ca9669313 100644 --- a/gcc/testsuite/gcc.dg/analyzer/deref-before-check-pr108455-1.c +++ b/gcc/testsuite/c-c++-common/analyzer/deref-before-check-pr108455-1.c @@ -19,7 +19,7 @@ int test_1 (void) { } data = could_fail_2 (fd); - hdr = data; + hdr = (struct header *) data; if (hdr->signature != 42) { ret = -2; diff --git a/gcc/testsuite/gcc.dg/analyzer/deref-before-check-pr108455-git-pack-revindex.c b/gcc/testsuite/c-c++-common/analyzer/deref-before-check-pr108455-git-pack-revindex.c similarity index 98% rename from gcc/testsuite/gcc.dg/analyzer/deref-before-check-pr108455-git-pack-revindex.c rename to gcc/testsuite/c-c++-common/analyzer/deref-before-check-pr108455-git-pack-revindex.c index 7553f86051d6..7431bd11c428 100644 --- a/gcc/testsuite/gcc.dg/analyzer/deref-before-check-pr108455-git-pack-revindex.c +++ b/gcc/testsuite/c-c++-common/analyzer/deref-before-check-pr108455-git-pack-revindex.c @@ -95,7 +95,7 @@ int load_revindex_from_disk(char *revindex_name, uint32_t num_objects, } data = xmmap(((void *)0), revindex_size, 0x1, 0x02, fd, 0); - hdr = data; + hdr = (struct revindex_header *) data; if (git_bswap32(hdr->signature) != 0x52494458) { ret = diff --git a/gcc/testsuite/gcc.dg/analyzer/deref-before-check-pr108475-1.c b/gcc/testsuite/c-c++-common/analyzer/deref-before-check-pr108475-1.c similarity index 94% rename from gcc/testsuite/gcc.dg/analyzer/deref-before-check-pr108475-1.c rename to gcc/testsuite/c-c++-common/analyzer/deref-before-check-pr108475-1.c index fa3beaaa15ff..0d5edf821f23 100644 --- a/gcc/testsuite/gcc.dg/analyzer/deref-before-check-pr108475-1.c +++ b/gcc/testsuite/c-c++-common/analyzer/deref-before-check-pr108475-1.c @@ -1,6 +1,7 @@ /* Reduced from haproxy-2.7.1: src/tcpcheck.c. */ -#define NULL ((void *)0) +#include "../../gcc.dg/analyzer/analyzer-decls.h" + int test_1 (char **args, int cur_arg) diff --git a/gcc/testsuite/gcc.dg/analyzer/deref-before-check-pr108475-haproxy-tcpcheck.c b/gcc/testsuite/c-c++-common/analyzer/deref-before-check-pr108475-haproxy-tcpcheck.c similarity index 96% rename from gcc/testsuite/gcc.dg/analyzer/deref-before-check-pr108475-haproxy-tcpcheck.c rename to gcc/testsuite/c-c++-common/analyzer/deref-before-check-pr108475-haproxy-tcpcheck.c index 1180e17e5552..7123cf5196b7 100644 --- a/gcc/testsuite/gcc.dg/analyzer/deref-before-check-pr108475-haproxy-tcpcheck.c +++ b/gcc/testsuite/c-c++-common/analyzer/deref-before-check-pr108475-haproxy-tcpcheck.c @@ -3,7 +3,9 @@ /* { dg-additional-options "-Wno-analyzer-too-complex" } */ typedef __SIZE_TYPE__ size_t; -#define NULL ((void *)0) + +#include "../../gcc.dg/analyzer/analyzer-decls.h" + extern void *calloc(size_t __nmemb, size_t __size) __attribute__((__nothrow__, __leaf__)) __attribute__((__malloc__)) @@ -86,7 +88,7 @@ void free_tcpcheck(struct tcpcheck_rule *rule, int in_pool); void free_tcpcheck_http_hdr(struct tcpcheck_http_hdr *hdr); #define ist(str) ({ \ - char *__x = (void *)(str); \ + char *__x = (char *) ((void *)(str)); \ (struct ist){ \ .ptr = __x, \ .len = __builtin_constant_p(str) ? \ @@ -114,7 +116,7 @@ struct tcpcheck_rule *proxy_parse_httpchk_req(char **args, int cur_arg, goto error; } - chk = calloc(1, sizeof(*chk)); + chk = (struct tcpcheck_rule *) calloc(1, sizeof(*chk)); if (!chk) { /* [...snip...] */ goto error; diff --git a/gcc/testsuite/gcc.dg/analyzer/deref-before-check-pr109060-haproxy-cfgparse.c b/gcc/testsuite/c-c++-common/analyzer/deref-before-check-pr109060-haproxy-cfgparse.c similarity index 97% rename from gcc/testsuite/gcc.dg/analyzer/deref-before-check-pr109060-haproxy-cfgparse.c rename to gcc/testsuite/c-c++-common/analyzer/deref-before-check-pr109060-haproxy-cfgparse.c index 4f50882eb8ac..1d28e10747cd 100644 --- a/gcc/testsuite/gcc.dg/analyzer/deref-before-check-pr109060-haproxy-cfgparse.c +++ b/gcc/testsuite/c-c++-common/analyzer/deref-before-check-pr109060-haproxy-cfgparse.c @@ -51,7 +51,7 @@ parse_process_number(const char* arg, else if (strcmp(arg, "even") == 0) *proc |= (~0UL / 3UL) << 1; else { - const char *p, *dash = ((void*)0); + const char *p, *dash = (const char *) ((void*)0); unsigned int low, high; for (p = arg; *p; p++) { diff --git a/gcc/testsuite/gcc.dg/analyzer/deref-before-check-pr109239-linux-bus.c b/gcc/testsuite/c-c++-common/analyzer/deref-before-check-pr109239-linux-bus.c similarity index 96% rename from gcc/testsuite/gcc.dg/analyzer/deref-before-check-pr109239-linux-bus.c rename to gcc/testsuite/c-c++-common/analyzer/deref-before-check-pr109239-linux-bus.c index 49b6420cc6b5..add7731c6b00 100644 --- a/gcc/testsuite/gcc.dg/analyzer/deref-before-check-pr109239-linux-bus.c +++ b/gcc/testsuite/c-c++-common/analyzer/deref-before-check-pr109239-linux-bus.c @@ -1,7 +1,8 @@ /* Reduced from linux-5.10.162's drivers-base-bus.c */ /* { dg-additional-options "-fno-delete-null-pointer-checks -O2" } */ -#define NULL ((void*)0) +#include "../../gcc.dg/analyzer/analyzer-decls.h" + typedef unsigned int __kernel_size_t; typedef int __kernel_ssize_t; @@ -57,7 +58,7 @@ struct kset* to_kset(struct kobject* kobj) { return kobj ? ({ - void* __mptr = (void*)(kobj); + char* __mptr = (char*)(kobj); ((struct kset*)(__mptr - __builtin_offsetof(struct kset, kobj))); }) : NULL; } diff --git a/gcc/testsuite/gcc.dg/analyzer/deref-before-check-pr77425.c b/gcc/testsuite/c-c++-common/analyzer/deref-before-check-pr77425.c similarity index 94% rename from gcc/testsuite/gcc.dg/analyzer/deref-before-check-pr77425.c rename to gcc/testsuite/c-c++-common/analyzer/deref-before-check-pr77425.c index 1ceea97b4224..c9be77c0553e 100644 --- a/gcc/testsuite/gcc.dg/analyzer/deref-before-check-pr77425.c +++ b/gcc/testsuite/c-c++-common/analyzer/deref-before-check-pr77425.c @@ -1,7 +1,9 @@ /* Fixed in r7-2945-g61f46d0e6dd568. Simplified from gcc/ipa-devirt.c. */ -#define NULL ((void *)0) +#include "../../gcc.dg/analyzer/analyzer-decls.h" + + typedef struct odr_type_d { /* .... */ int id; diff --git a/gcc/testsuite/gcc.dg/analyzer/exec-1.c b/gcc/testsuite/c-c++-common/analyzer/exec-1.c similarity index 59% rename from gcc/testsuite/gcc.dg/analyzer/exec-1.c rename to gcc/testsuite/c-c++-common/analyzer/exec-1.c index 6b71118bd546..25b88995515f 100644 --- a/gcc/testsuite/gcc.dg/analyzer/exec-1.c +++ b/gcc/testsuite/c-c++-common/analyzer/exec-1.c @@ -1,4 +1,10 @@ -#define NULL ((void *)0) +#include "../../gcc.dg/analyzer/analyzer-decls.h" + +#ifdef __cplusplus + #define CONST_CAST(type) const_cast +#else + #define CONST_CAST(type) +#endif extern int execl(const char *pathname, const char *arg, ...); extern int execlp(const char *file, const char *arg, ...); @@ -19,25 +25,25 @@ int test_execlpl_ls_al () int test_execle_ls_al () { - const char *env[3] = {"FOO=BAR", "BAZ", NULL}; + char * env[3] = {CONST_CAST(char *)("FOO=BAR"), CONST_CAST(char *)("BAZ"), NULL}; return execl ("/usr/bin/ls", "ls", "-al", NULL, env); } int test_execv_ls_al () { - char *argv[3] = {"ls", "-al", NULL}; + char * argv[3] = {CONST_CAST(char *)("ls"), CONST_CAST(char *)("-al"), NULL}; return execv ("/usr/bin/ls", argv); } int test_execvp_ls_al () { - char *argv[3] = {"ls", "-al", NULL}; + char *argv[3] = {CONST_CAST(char *)("ls"), CONST_CAST(char *)("-al"), NULL}; return execvp ("ls", argv); } int test_execvpe_ls_al () { - char *env[3] = {"FOO=BAR", "BAZ", NULL}; - char *argv[3] = {"ls", "-al", NULL}; + char *env[3] = {CONST_CAST(char *)("FOO=BAR"), CONST_CAST(char *)("BAZ"), NULL}; + char *argv[3] = {CONST_CAST(char *)("ls"), CONST_CAST(char *)("-al"), NULL}; return execvpe ("ls", argv, env); } diff --git a/gcc/testsuite/gcc.dg/analyzer/feasibility-3.c b/gcc/testsuite/c-c++-common/analyzer/feasibility-3.c similarity index 92% rename from gcc/testsuite/gcc.dg/analyzer/feasibility-3.c rename to gcc/testsuite/c-c++-common/analyzer/feasibility-3.c index 0c0bd14fa54a..2fcd064e801f 100644 --- a/gcc/testsuite/gcc.dg/analyzer/feasibility-3.c +++ b/gcc/testsuite/c-c++-common/analyzer/feasibility-3.c @@ -4,7 +4,9 @@ /* Types. */ typedef unsigned char u8; +#ifndef __cplusplus typedef _Bool bool; +#endif typedef unsigned int gfp_t; struct file; @@ -67,7 +69,7 @@ static inline bool pde_is_permanent(const struct proc_dir_entry *pde) static inline struct proc_inode *PROC_I(const struct inode *inode) { - void *__mptr = (void *)(inode); + char *__mptr = (char *)(inode); return ((struct proc_inode *)(__mptr - __builtin_offsetof(struct proc_inode, vfs_inode))); } @@ -89,8 +91,11 @@ static int proc_reg_open(struct inode *inode, struct file *file) { struct proc_dir_entry *pde = PDE(inode); int rv = 0; - typeof(((struct proc_ops*)0)->proc_open) open; - typeof(((struct proc_ops*)0)->proc_release) release; + + + int (*open)(struct inode *, struct file *); + int (*release)(struct inode *, struct file *); + struct pde_opener *pdeo; if (pde_is_permanent(pde)) { @@ -104,7 +109,7 @@ static int proc_reg_open(struct inode *inode, struct file *file) release = pde->proc_ops->proc_release; if (release) { - pdeo = kmem_cache_alloc(pde_opener_cache, + pdeo = (struct pde_opener *) kmem_cache_alloc(pde_opener_cache, ((( gfp_t)(0x400u|0x800u)) | (( gfp_t)0x40u) | (( gfp_t)0x80u))); diff --git a/gcc/testsuite/gcc.dg/analyzer/fields.c b/gcc/testsuite/c-c++-common/analyzer/fields.c similarity index 92% rename from gcc/testsuite/gcc.dg/analyzer/fields.c rename to gcc/testsuite/c-c++-common/analyzer/fields.c index 0bf877fcf1e7..18595307c9bd 100644 --- a/gcc/testsuite/gcc.dg/analyzer/fields.c +++ b/gcc/testsuite/c-c++-common/analyzer/fields.c @@ -30,7 +30,7 @@ recvauth_common (int problem) krb5_error error; const char *message = error_message(problem); error.text.length = strlen(message) + 1; - if (!(error.text.data = malloc(error.text.length))) { + if (!(error.text.data = (char *) malloc(error.text.length))) { goto cleanup; } free(error.text.data); diff --git a/gcc/testsuite/gcc.dg/analyzer/function-ptr-5.c b/gcc/testsuite/c-c++-common/analyzer/function-ptr-5.c similarity index 94% rename from gcc/testsuite/gcc.dg/analyzer/function-ptr-5.c rename to gcc/testsuite/c-c++-common/analyzer/function-ptr-5.c index 3c46f2890821..2b83978c1ada 100644 --- a/gcc/testsuite/gcc.dg/analyzer/function-ptr-5.c +++ b/gcc/testsuite/c-c++-common/analyzer/function-ptr-5.c @@ -1,4 +1,4 @@ -#define NULL ((void *)0) +#include "../../gcc.dg/analyzer/analyzer-decls.h" void calling_null_fn_ptr_1 (void) { diff --git a/gcc/testsuite/gcc.dg/analyzer/infinite-recursion-pr108524-1.c b/gcc/testsuite/c-c++-common/analyzer/infinite-recursion-pr108524-1.c similarity index 98% rename from gcc/testsuite/gcc.dg/analyzer/infinite-recursion-pr108524-1.c rename to gcc/testsuite/c-c++-common/analyzer/infinite-recursion-pr108524-1.c index d9221fa8dc5a..26fc8d2e8d4f 100644 --- a/gcc/testsuite/gcc.dg/analyzer/infinite-recursion-pr108524-1.c +++ b/gcc/testsuite/c-c++-common/analyzer/infinite-recursion-pr108524-1.c @@ -3,7 +3,9 @@ /* { dg-additional-options "-fno-analyzer-call-summaries -Wno-analyzer-too-complex" } */ -#define NULL ((void *)0) +#include "../../gcc.dg/analyzer/analyzer-decls.h" + + typedef __builtin_va_list va_list; typedef struct _GQueue GQueue; diff --git a/gcc/testsuite/gcc.dg/analyzer/infinite-recursion-pr108524-2.c b/gcc/testsuite/c-c++-common/analyzer/infinite-recursion-pr108524-2.c similarity index 94% rename from gcc/testsuite/gcc.dg/analyzer/infinite-recursion-pr108524-2.c rename to gcc/testsuite/c-c++-common/analyzer/infinite-recursion-pr108524-2.c index 58f6d2f44636..d483d7e643c2 100644 --- a/gcc/testsuite/gcc.dg/analyzer/infinite-recursion-pr108524-2.c +++ b/gcc/testsuite/c-c++-common/analyzer/infinite-recursion-pr108524-2.c @@ -62,7 +62,7 @@ void test_5 (struct st2 *p) void test_6 (struct st2 *p) { - struct st2 *q = __builtin_malloc (p->i); + struct st2 *q = (struct st2 *) __builtin_malloc (p->i); if (!q) return; q->i = p->i; @@ -72,7 +72,7 @@ void test_6 (struct st2 *p) void test_7 (struct st2 *p) { - struct st2 *q = __builtin_malloc (p->i); + struct st2 *q = (struct st2 *) __builtin_malloc (p->i); q->i = p->i; /* { dg-warning "dereference of possibly-NULL 'q'" } */ test_7 (q); __builtin_free (q); diff --git a/gcc/testsuite/gcc.dg/analyzer/infinite-recursion-pr108524-qobject-json-parser.c b/gcc/testsuite/c-c++-common/analyzer/infinite-recursion-pr108524-qobject-json-parser.c similarity index 99% rename from gcc/testsuite/gcc.dg/analyzer/infinite-recursion-pr108524-qobject-json-parser.c rename to gcc/testsuite/c-c++-common/analyzer/infinite-recursion-pr108524-qobject-json-parser.c index b40326fc252d..64ea62edd658 100644 --- a/gcc/testsuite/gcc.dg/analyzer/infinite-recursion-pr108524-qobject-json-parser.c +++ b/gcc/testsuite/c-c++-common/analyzer/infinite-recursion-pr108524-qobject-json-parser.c @@ -3,7 +3,9 @@ /* { dg-additional-options "-fno-analyzer-call-summaries -Wno-analyzer-too-complex" } */ -#define NULL ((void *)0) +#include "../../gcc.dg/analyzer/analyzer-decls.h" + + typedef __builtin_va_list va_list; typedef __SIZE_TYPE__ size_t; diff --git a/gcc/testsuite/gcc.dg/analyzer/init.c b/gcc/testsuite/c-c++-common/analyzer/init.c similarity index 97% rename from gcc/testsuite/gcc.dg/analyzer/init.c rename to gcc/testsuite/c-c++-common/analyzer/init.c index e51d88e9ff92..cd3c16f47662 100644 --- a/gcc/testsuite/gcc.dg/analyzer/init.c +++ b/gcc/testsuite/c-c++-common/analyzer/init.c @@ -5,7 +5,7 @@ gimple assign stmts, with just "zero-init everything" CONSTRUCTORs and "clobber" CONSTRUCTORs. */ -#include "analyzer-decls.h" +#include "../../gcc.dg/analyzer/analyzer-decls.h" struct coord { @@ -95,7 +95,7 @@ void test_9 (void) void test_10 (void) { - struct coord c[2] = {{.y = 4, .x = 3}, {5, 6}}; + struct coord c[2] = {{.x = 3, .y = 4}, {5, 6}}; __analyzer_eval (c[0].x == 3); /* { dg-warning "TRUE" } */ __analyzer_eval (c[0].y == 4); /* { dg-warning "TRUE" } */ __analyzer_eval (c[1].x == 5); /* { dg-warning "TRUE" } */ diff --git a/gcc/testsuite/gcc.dg/analyzer/inlining-3-multiline.c b/gcc/testsuite/c-c++-common/analyzer/inlining-3-multiline.c similarity index 55% rename from gcc/testsuite/gcc.dg/analyzer/inlining-3-multiline.c rename to gcc/testsuite/c-c++-common/analyzer/inlining-3-multiline.c index 15a2dd8f0e13..fbd20e949b60 100644 --- a/gcc/testsuite/gcc.dg/analyzer/inlining-3-multiline.c +++ b/gcc/testsuite/c-c++-common/analyzer/inlining-3-multiline.c @@ -4,8 +4,8 @@ /* { dg-additional-options "-O2 -fdiagnostics-show-path-depths" } */ /* { dg-additional-options "-fdiagnostics-path-format=inline-events -fdiagnostics-show-caret" } */ +#include "../../gcc.dg/analyzer/analyzer-decls.h" typedef __SIZE_TYPE__ size_t; -#define NULL ((void *)0) struct input_file_st { @@ -61,4 +61,39 @@ test (const input_file *inpf) | (4) ...to here | (5) argument 1 ('') NULL where non-null expected | - { dg-end-multiline-output "" } */ + { dg-end-multiline-output "" { target c } } */ + + +/* { dg-begin-multiline-output "" } + return __builtin_strlen (f); + ~~~~~~~~~~~~~~~~~^~~ + 'size_t test(const input_file*)': events 1-2 (depth 1) + | + | test (const input_file *inpf) + | ^~~~ + | | + | (1) entry to 'test' + | + | const char *f = get_input_file_name (inpf); + | ~ + | | + | (2) inlined call to 'get_input_file_name' from 'test' + | + +--> 'const char* get_input_file_name(const input_file*)': event 3 (depth 2) + | + | if (inpf) + | ^~ + | | + | (3) following 'false' branch (when 'inpf' is NULL)... + | + <------+ + | + 'size_t test(const input_file*)': events 4-5 (depth 1) + | + | return __builtin_strlen (f); + | ~~~~~~~~~~~~~~~~~^~~ + | | + | (4) ...to here + | (5) argument 1 ('') NULL where non-null expected + | + { dg-end-multiline-output "" { target c++ } } */ \ No newline at end of file diff --git a/gcc/testsuite/gcc.dg/analyzer/inlining-3.c b/gcc/testsuite/c-c++-common/analyzer/inlining-3.c similarity index 51% rename from gcc/testsuite/gcc.dg/analyzer/inlining-3.c rename to gcc/testsuite/c-c++-common/analyzer/inlining-3.c index 7a292ac87fa0..0345585bed2a 100644 --- a/gcc/testsuite/gcc.dg/analyzer/inlining-3.c +++ b/gcc/testsuite/c-c++-common/analyzer/inlining-3.c @@ -3,8 +3,9 @@ /* { dg-additional-options "-O2 -fdiagnostics-show-path-depths" } */ +#include "../../gcc.dg/analyzer/analyzer-decls.h" typedef __SIZE_TYPE__ size_t; -#define NULL ((void *)0) + struct input_file_st { @@ -16,7 +17,9 @@ typedef struct input_file_st input_file; static inline const char* get_input_file_name (const input_file *inpf) { - if (inpf) /* { dg-message "following 'false' branch \\(when 'inpf' is NULL\\)\\.\\.\\. \\(fndecl 'get_input_file_name', depth 2\\)" } */ + if (inpf) + /* { dg-message "following 'false' branch \\(when 'inpf' is NULL\\)\\.\\.\\. \\(fndecl 'get_input_file_name', depth 2\\)" "" { target c } .-1 } */ + /* { dg-message "following 'false' branch \\(when 'inpf' is NULL\\)\\.\\.\\. \\(fndecl 'const char\\* get_input_file_name\\(const input_file\\*\\)', depth 2\\)" "" { target c++ } .-2 } */ return inpf->inpname; return NULL; } @@ -26,5 +29,6 @@ test (const input_file *inpf) { const char *f = get_input_file_name (inpf); return __builtin_strlen (f); /* { dg-warning "use of NULL" "warning" } */ - /* { dg-message "NULL where non-null expected \\(fndecl 'test', depth 1\\)" "message" { target *-*-* } .-1 } */ + /* { dg-message "NULL where non-null expected \\(fndecl 'test', depth 1\\)" "message" { target c } .-1 } */ + /* { dg-message "NULL where non-null expected \\(fndecl 'size_t test\\(const input_file\\*\\)', depth 1\\)" "message" { target c++ } .-2 } */ } diff --git a/gcc/testsuite/gcc.dg/analyzer/inlining-4-multiline.c b/gcc/testsuite/c-c++-common/analyzer/inlining-4-multiline.c similarity index 54% rename from gcc/testsuite/gcc.dg/analyzer/inlining-4-multiline.c rename to gcc/testsuite/c-c++-common/analyzer/inlining-4-multiline.c index 0413c39af038..c870a9f654d9 100644 --- a/gcc/testsuite/gcc.dg/analyzer/inlining-4-multiline.c +++ b/gcc/testsuite/c-c++-common/analyzer/inlining-4-multiline.c @@ -4,7 +4,8 @@ /* { dg-additional-options "-O2 -fdiagnostics-show-path-depths" } */ /* { dg-additional-options "-fdiagnostics-path-format=inline-events -fdiagnostics-show-caret" } */ -#define NULL ((void *)0) +#include "../../gcc.dg/analyzer/analyzer-decls.h" + static inline const char* inner (int flag) @@ -69,4 +70,48 @@ outer (int flag) | | | (6) dereference of NULL '' | - { dg-end-multiline-output "" } */ + { dg-end-multiline-output "" { target c } } */ +/* { dg-begin-multiline-output "" } + return *middle (flag); + ^ + 'char outer(int)': events 1-2 (depth 1) + | + | outer (int flag) + | ^~~~~ + | | + | (1) entry to 'outer' + | + | return *middle (flag); + | ~ + | | + | (2) inlined call to 'middle' from 'outer' + | + +--> 'const char* middle(int)': event 3 (depth 2) + | + | return inner (flag); + | ^ + | | + | (3) inlined call to 'inner' from 'middle' + | + +--> 'const char* inner(int)': event 4 (depth 3) + | + | if (flag) + | ^~ + | | + | (4) following 'true' branch (when 'flag != 0')... + | + <-------------+ + | + 'char outer(int)': event 5 (depth 1) + | + |cc1plus: + | (5): ...to here + | + 'char outer(int)': event 6 (depth 1) + | + | return *middle (flag); + | ^ + | | + | (6) dereference of NULL '' + | + { dg-end-multiline-output "" { target c++ } } */ diff --git a/gcc/testsuite/gcc.dg/analyzer/inlining-4.c b/gcc/testsuite/c-c++-common/analyzer/inlining-4.c similarity index 51% rename from gcc/testsuite/gcc.dg/analyzer/inlining-4.c rename to gcc/testsuite/c-c++-common/analyzer/inlining-4.c index f4e42084c918..85b42445d26e 100644 --- a/gcc/testsuite/gcc.dg/analyzer/inlining-4.c +++ b/gcc/testsuite/c-c++-common/analyzer/inlining-4.c @@ -3,12 +3,14 @@ /* { dg-additional-options "-O2 -fdiagnostics-show-path-depths" } */ -#define NULL ((void *)0) +#include "../../gcc.dg/analyzer/analyzer-decls.h" static inline const char* inner (int flag) { - if (flag) /* { dg-message "following 'true' branch \\(when 'flag != 0'\\)\\.\\.\\. \\(fndecl 'inner', depth 3\\)" } */ + if (flag) + /* { dg-message "following 'true' branch \\(when 'flag != 0'\\)\\.\\.\\. \\(fndecl 'inner', depth 3\\)" "" { target c } .-1 } */ + /* { dg-message "following 'true' branch \\(when 'flag != 0'\\)\\.\\.\\. \\(fndecl 'const char\\* inner\\(int\\)', depth 3\\)" "" { target c++ } .-2 } */ return NULL; return "foo"; } @@ -23,5 +25,6 @@ char outer (int flag) { return *middle (flag); /* { dg-warning "dereference of NULL" "warning" } */ - /* { dg-message "\\(fndecl 'outer', depth 1\\)" "message" { target *-*-* } .-1 } */ + /* { dg-message "\\(fndecl 'outer', depth 1\\)" "message" { target c } .-1 } */ + /* { dg-message "\\(fndecl 'char outer\\(int\\)', depth 1\\)" "message" { target c++ } .-2 } */ } diff --git a/gcc/testsuite/gcc.dg/analyzer/leak-pr105906.c b/gcc/testsuite/c-c++-common/analyzer/leak-pr105906.c similarity index 81% rename from gcc/testsuite/gcc.dg/analyzer/leak-pr105906.c rename to gcc/testsuite/c-c++-common/analyzer/leak-pr105906.c index 72901e4d1eb6..a37aa59ca7b1 100644 --- a/gcc/testsuite/gcc.dg/analyzer/leak-pr105906.c +++ b/gcc/testsuite/c-c++-common/analyzer/leak-pr105906.c @@ -1,6 +1,7 @@ /* { dg-additional-options "-Wno-analyzer-too-complex" } */ -#define NULL ((void *)0) +#include "../../gcc.dg/analyzer/analyzer-decls.h" + #define LEN 64 @@ -13,7 +14,7 @@ epystr_explode(const char *delim, char *str) if (str == NULL || delim == NULL) return NULL; - out = __builtin_malloc(LEN * sizeof(char *)); + out = (char **) __builtin_malloc(LEN * sizeof(char *)); if (out == NULL) return NULL; diff --git a/gcc/testsuite/gcc.dg/analyzer/leak-pr108045-with-call-summaries.c b/gcc/testsuite/c-c++-common/analyzer/leak-pr108045-with-call-summaries.c similarity index 87% rename from gcc/testsuite/gcc.dg/analyzer/leak-pr108045-with-call-summaries.c rename to gcc/testsuite/c-c++-common/analyzer/leak-pr108045-with-call-summaries.c index d63be06a9bbb..e4be5093641b 100644 --- a/gcc/testsuite/gcc.dg/analyzer/leak-pr108045-with-call-summaries.c +++ b/gcc/testsuite/c-c++-common/analyzer/leak-pr108045-with-call-summaries.c @@ -1,7 +1,7 @@ /* { dg-additional-options "-fanalyzer-call-summaries" } */ typedef __SIZE_TYPE__ size_t; -#define NULL ((void *)0) +#include "../../gcc.dg/analyzer/analyzer-decls.h" /* data structures */ @@ -31,7 +31,7 @@ struct screen_s *screen_create(size_t cols, size_t rows) { struct screen_s *result = NULL; - result = __builtin_calloc(1, sizeof(*result)); + result = (struct screen_s *) __builtin_calloc(1, sizeof(*result)); if (!result) return NULL; @@ -39,7 +39,7 @@ struct screen_s *screen_create(size_t cols, size_t rows) result->rows = rows; /* make one allocation which will be accessed like a 2D array */ - result->data = __builtin_calloc(rows, sizeof(result->data) + sizeof(*result->data) * cols); + result->data = (char **) __builtin_calloc(rows, sizeof(result->data) + sizeof(*result->data) * cols); if (!result->data) { __builtin_free(result); return NULL; @@ -91,7 +91,7 @@ void resize_screen(size_t cols, size_t rows) int main(void) { - ctx = __builtin_calloc(1, sizeof(*ctx)); + ctx = (struct context_s *) __builtin_calloc(1, sizeof(*ctx)); if (!ctx) __builtin_abort(); diff --git a/gcc/testsuite/gcc.dg/analyzer/leak-pr108045-without-call-summaries.c b/gcc/testsuite/c-c++-common/analyzer/leak-pr108045-without-call-summaries.c similarity index 87% rename from gcc/testsuite/gcc.dg/analyzer/leak-pr108045-without-call-summaries.c rename to gcc/testsuite/c-c++-common/analyzer/leak-pr108045-without-call-summaries.c index ae7a7d5c1594..3196e99ba37f 100644 --- a/gcc/testsuite/gcc.dg/analyzer/leak-pr108045-without-call-summaries.c +++ b/gcc/testsuite/c-c++-common/analyzer/leak-pr108045-without-call-summaries.c @@ -2,7 +2,7 @@ /* { dg-additional-options "-Wno-analyzer-too-complex" } */ typedef __SIZE_TYPE__ size_t; -#define NULL ((void *)0) +#include "../../gcc.dg/analyzer/analyzer-decls.h" /* data structures */ @@ -32,7 +32,7 @@ struct screen_s *screen_create(size_t cols, size_t rows) { struct screen_s *result = NULL; - result = __builtin_calloc(1, sizeof(*result)); + result = (struct screen_s *) __builtin_calloc(1, sizeof(*result)); if (!result) return NULL; @@ -40,7 +40,7 @@ struct screen_s *screen_create(size_t cols, size_t rows) result->rows = rows; /* make one allocation which will be accessed like a 2D array */ - result->data = __builtin_calloc(rows, sizeof(result->data) + sizeof(*result->data) * cols); + result->data = (char **) __builtin_calloc(rows, sizeof(result->data) + sizeof(*result->data) * cols); if (!result->data) { __builtin_free(result); return NULL; @@ -92,7 +92,7 @@ void resize_screen(size_t cols, size_t rows) int main(void) { - ctx = __builtin_calloc(1, sizeof(*ctx)); + ctx = (struct context_s *) __builtin_calloc(1, sizeof(*ctx)); if (!ctx) __builtin_abort(); diff --git a/gcc/testsuite/gcc.dg/analyzer/leak-pr109059-1.c b/gcc/testsuite/c-c++-common/analyzer/leak-pr109059-1.c similarity index 93% rename from gcc/testsuite/gcc.dg/analyzer/leak-pr109059-1.c rename to gcc/testsuite/c-c++-common/analyzer/leak-pr109059-1.c index 033ab79460e6..ae196d75b935 100644 --- a/gcc/testsuite/gcc.dg/analyzer/leak-pr109059-1.c +++ b/gcc/testsuite/c-c++-common/analyzer/leak-pr109059-1.c @@ -27,7 +27,7 @@ cfg_register_postparser(char* name, int (*func)()) { struct cfg_postparser* cp; - cp = calloc(1, sizeof(*cp)); + cp = (struct cfg_postparser *) calloc(1, sizeof(*cp)); if (!cp) { /* [...snip...] */ return 0; diff --git a/gcc/testsuite/gcc.dg/analyzer/leak-pr109059-2.c b/gcc/testsuite/c-c++-common/analyzer/leak-pr109059-2.c similarity index 92% rename from gcc/testsuite/gcc.dg/analyzer/leak-pr109059-2.c rename to gcc/testsuite/c-c++-common/analyzer/leak-pr109059-2.c index 125bce84864f..26329ffac46f 100644 --- a/gcc/testsuite/gcc.dg/analyzer/leak-pr109059-2.c +++ b/gcc/testsuite/c-c++-common/analyzer/leak-pr109059-2.c @@ -26,7 +26,7 @@ test_1 (char* name) { struct cfg_postparser* cp; - cp = calloc(1, sizeof(*cp)); + cp = (struct cfg_postparser*) calloc(1, sizeof(*cp)); if (!cp) { /* [...snip...] */ return 0; diff --git a/gcc/testsuite/gcc.dg/analyzer/malloc-2.c b/gcc/testsuite/c-c++-common/analyzer/malloc-2.c similarity index 89% rename from gcc/testsuite/gcc.dg/analyzer/malloc-2.c rename to gcc/testsuite/c-c++-common/analyzer/malloc-2.c index bb93c53d3e0f..ed68209da727 100644 --- a/gcc/testsuite/gcc.dg/analyzer/malloc-2.c +++ b/gcc/testsuite/c-c++-common/analyzer/malloc-2.c @@ -16,7 +16,7 @@ void test_1 (void) int *test_2 (void) { - int *i = malloc (sizeof (int)); /* { dg-message "\\(1\\) this call could return NULL" } */ + int *i = (int *) malloc (sizeof (int)); /* { dg-message "\\(1\\) this call could return NULL" } */ *i = 42; /* { dg-warning "dereference of possibly-NULL 'i'" "warning" } */ /* { dg-message "\\(2\\) 'i' could be NULL: unchecked value from \\(1\\)" "event" { target *-*-* } .-1 } */ return i; diff --git a/gcc/testsuite/gcc.dg/analyzer/memcpy-2.c b/gcc/testsuite/c-c++-common/analyzer/memcpy-2.c similarity index 79% rename from gcc/testsuite/gcc.dg/analyzer/memcpy-2.c rename to gcc/testsuite/c-c++-common/analyzer/memcpy-2.c index 51e4a6949517..25b0a5e4ff48 100644 --- a/gcc/testsuite/gcc.dg/analyzer/memcpy-2.c +++ b/gcc/testsuite/c-c++-common/analyzer/memcpy-2.c @@ -1,8 +1,9 @@ /* { dg-additional-options "-Wno-stringop-overflow -Wno-analyzer-out-of-bounds" } */ -void -main (int c, void *v) +int +test (int c, void *v) { static char a[] = ""; __builtin_memcpy (v, a, -1); + return 0; } diff --git a/gcc/testsuite/gcc.dg/analyzer/null-deref-pr108251-smp_fetch_ssl_fc_has_early-O2.c b/gcc/testsuite/c-c++-common/analyzer/null-deref-pr108251-smp_fetch_ssl_fc_has_early-O2.c similarity index 93% rename from gcc/testsuite/gcc.dg/analyzer/null-deref-pr108251-smp_fetch_ssl_fc_has_early-O2.c rename to gcc/testsuite/c-c++-common/analyzer/null-deref-pr108251-smp_fetch_ssl_fc_has_early-O2.c index cb46827ab65c..c46ffe91a6b4 100644 --- a/gcc/testsuite/gcc.dg/analyzer/null-deref-pr108251-smp_fetch_ssl_fc_has_early-O2.c +++ b/gcc/testsuite/c-c++-common/analyzer/null-deref-pr108251-smp_fetch_ssl_fc_has_early-O2.c @@ -61,12 +61,12 @@ static inline enum obj_type obj_type(const enum obj_type *t) } static inline struct connection *__objt_conn(enum obj_type *t) { - return ((struct connection *)(((void *)(t)) - ((long)&((struct connection *)0)->obj_type))); + return ((struct connection *)(((char *)(t)) - ((long)&((struct connection *)0)->obj_type))); } static inline struct connection *objt_conn(enum obj_type *t) { if (!t || *t != OBJ_TYPE_CONN) - return ((void *)0); + return (struct connection *)((void *)0); return __objt_conn(t); } struct session { @@ -80,7 +80,7 @@ SSL *ssl_sock_get_ssl_object(struct connection *conn); /*****************************************************************************/ int -smp_fetch_ssl_fc_has_early(const struct arg *args, struct sample *smp, const char *kw, void *private) +smp_fetch_ssl_fc_has_early(const struct arg *args, struct sample *smp, const char *kw, void *Private) { SSL *ssl; struct connection *conn; diff --git a/gcc/testsuite/gcc.dg/analyzer/null-deref-pr108251-smp_fetch_ssl_fc_has_early.c b/gcc/testsuite/c-c++-common/analyzer/null-deref-pr108251-smp_fetch_ssl_fc_has_early.c similarity index 93% rename from gcc/testsuite/gcc.dg/analyzer/null-deref-pr108251-smp_fetch_ssl_fc_has_early.c rename to gcc/testsuite/c-c++-common/analyzer/null-deref-pr108251-smp_fetch_ssl_fc_has_early.c index fbacb6ca2d32..ef34a76c50d6 100644 --- a/gcc/testsuite/gcc.dg/analyzer/null-deref-pr108251-smp_fetch_ssl_fc_has_early.c +++ b/gcc/testsuite/c-c++-common/analyzer/null-deref-pr108251-smp_fetch_ssl_fc_has_early.c @@ -60,12 +60,12 @@ static inline enum obj_type obj_type(const enum obj_type *t) } static inline struct connection *__objt_conn(enum obj_type *t) { - return ((struct connection *)(((void *)(t)) - ((long)&((struct connection *)0)->obj_type))); + return ((struct connection *)(((char *)(t)) - ((long)&((struct connection *)0)->obj_type))); } static inline struct connection *objt_conn(enum obj_type *t) { if (!t || *t != OBJ_TYPE_CONN) - return ((void *)0); + return (struct connection *) ((void *)0); return __objt_conn(t); } struct session { @@ -79,7 +79,7 @@ SSL *ssl_sock_get_ssl_object(struct connection *conn); /*****************************************************************************/ int -smp_fetch_ssl_fc_has_early(const struct arg *args, struct sample *smp, const char *kw, void *private) +smp_fetch_ssl_fc_has_early(const struct arg *args, struct sample *smp, const char *kw, void *Private) { SSL *ssl; struct connection *conn; diff --git a/gcc/testsuite/gcc.dg/analyzer/null-deref-pr108806-qemu.c b/gcc/testsuite/c-c++-common/analyzer/null-deref-pr108806-qemu.c similarity index 97% rename from gcc/testsuite/gcc.dg/analyzer/null-deref-pr108806-qemu.c rename to gcc/testsuite/c-c++-common/analyzer/null-deref-pr108806-qemu.c index 3ab72c053af7..f7f6923927fc 100644 --- a/gcc/testsuite/gcc.dg/analyzer/null-deref-pr108806-qemu.c +++ b/gcc/testsuite/c-c++-common/analyzer/null-deref-pr108806-qemu.c @@ -1,6 +1,6 @@ /* Reduced from qemu-7.2.0's hw/intc/omap_intc.c */ -#define NULL ((void*)0) +#include "../../gcc.dg/analyzer/analyzer-decls.h" typedef unsigned char __uint8_t; typedef unsigned int __uint32_t; diff --git a/gcc/testsuite/gcc.dg/analyzer/null-deref-pr108830.c b/gcc/testsuite/c-c++-common/analyzer/null-deref-pr108830.c similarity index 92% rename from gcc/testsuite/gcc.dg/analyzer/null-deref-pr108830.c rename to gcc/testsuite/c-c++-common/analyzer/null-deref-pr108830.c index 417ab00794de..0c95148ebd57 100644 --- a/gcc/testsuite/gcc.dg/analyzer/null-deref-pr108830.c +++ b/gcc/testsuite/c-c++-common/analyzer/null-deref-pr108830.c @@ -2,7 +2,7 @@ /* { dg-additional-options "-Wno-analyzer-too-complex" } */ -#define NULL ((void*)0) +#include "../../gcc.dg/analyzer/analyzer-decls.h" typedef __SIZE_TYPE__ size_t; @@ -43,7 +43,7 @@ struct apr_hash_t static apr_hash_entry_t** alloc_array(apr_hash_t* ht, unsigned int max) { - return memset(apr_palloc(ht->pool, sizeof(*ht->array) * (max + 1)), + return (apr_hash_entry_t **) memset(apr_palloc(ht->pool, sizeof(*ht->array) * (max + 1)), 0, sizeof(*ht->array) * (max + 1)); } @@ -57,7 +57,7 @@ apr_hash_merge(apr_pool_t* p, apr_hash_entry_t* new_vals = NULL; apr_hash_entry_t* iter; unsigned int i, j, k; - res = apr_palloc(p, sizeof(apr_hash_t)); + res = (apr_hash_t *) apr_palloc(p, sizeof(apr_hash_t)); res->pool = p; res->free = NULL; res->hash_func = base->hash_func; @@ -69,7 +69,7 @@ apr_hash_merge(apr_pool_t* p, res->seed = base->seed; res->array = alloc_array(res, res->max); if (base->count + overlay->count) { - new_vals = + new_vals = (apr_hash_entry_t *) apr_palloc(p, sizeof(apr_hash_entry_t) * (base->count + overlay->count)); } j = 0; diff --git a/gcc/testsuite/c-c++-common/analyzer/overlapping-buffers.c b/gcc/testsuite/c-c++-common/analyzer/overlapping-buffers.c new file mode 100644 index 000000000000..5808b3304cfc --- /dev/null +++ b/gcc/testsuite/c-c++-common/analyzer/overlapping-buffers.c @@ -0,0 +1,147 @@ +/* Test of -Wanalyzer-overlapping-buffers. */ + +#include + +/* Use noinline functions to hide these calls from the optimizer, to avoid + undefined behavior being optimized away to GIMPLE_NOP before the analyzer + sees it. */ + +char * __attribute__((noinline)) +call_strcat_symbolic_1 (char *dest, const char *src) +{ + return strcat (dest, src); /* { dg-warning "overlapping buffers" } */ +} + +void test_strcat_symbolic_1 (char *p) +{ + call_strcat_symbolic_1 (p, p); +} + +char * __attribute__((noinline)) +call_strcpy_symbolic_1 (char *dest, const char *src) +{ + return strcpy (dest, src); /* { dg-warning "overlapping buffers" } */ +} + +void test_strcpy_symbolic_1 (char *p) +{ + call_strcpy_symbolic_1 (p, p); +} + +void * __attribute__((noinline)) +call_memcpy_concrete_1 (void *dest, const void *src, size_t n) +{ + return memcpy (dest, src, n); /* { dg-warning "overlapping buffers" } */ +} + +void test_memcpy_concrete_1 (void *p) +{ + call_memcpy_concrete_1 (p, p, 10); +} + +void * __attribute__((noinline)) +call_memcpy_symbolic_1 (void *dest, const void *src, size_t n) +{ + return memcpy (dest, src, n); /* { dg-warning "overlapping buffers" } */ +} + +void test_memcpy_symbolic_1 (void *p, size_t n) +{ + call_memcpy_symbolic_1 (p, p, n); +} + +/* Intersecting vs non-intersecting parts of the same buffer. */ + +void * __attribute__((noinline)) +call_memcpy_nonintersecting_concrete_1 (void *dest, const void *src, size_t n) +{ + return memcpy (dest, src, n); /* { dg-bogus "overlapping buffers" } */ +} + +void test_memcpy_nonintersecting_concrete_1 (char *p) +{ + call_memcpy_nonintersecting_concrete_1 (p, p + 10, 10); +} + +void * __attribute__((noinline)) +call_memcpy_nonintersecting_concrete_2 (void *dest, const void *src, size_t n) +{ + return memcpy (dest, src, n); /* { dg-bogus "overlapping buffers" } */ +} + +void test_memcpy_nonintersecting_concrete_2 (char *p) +{ + call_memcpy_nonintersecting_concrete_2 (p + 10, p, 10); +} + +void * __attribute__((noinline)) +call_memcpy_intersecting_concrete_1 (void *dest, const void *src, size_t n) +{ + return memcpy (dest, src, n); /* { dg-warning "overlapping buffers" } */ +} + +void test_memcpy_intersecting_concrete_1 (char *p) +{ + call_memcpy_intersecting_concrete_1 (p, p + 9, 10); +} + +void * __attribute__((noinline)) +call_memcpy_intersecting_concrete_2 (void *dest, const void *src, size_t n) +{ + return memcpy (dest, src, n); /* { dg-warning "overlapping buffers" } */ +} + +void test_memcpy_intersecting_concrete_2 (char *p) +{ + call_memcpy_intersecting_concrete_2 (p + 9, p, 10); +} + +void * __attribute__((noinline)) +call_memcpy_intersecting_symbolic_1 (void *dest, const void *src, size_t n) +{ + return memcpy (dest, src, n); /* { dg-warning "overlapping buffers" "" { xfail *-*-* } } */ + // TODO(xfail) +} + +void test_memcpy_intersecting_symbolic_1 (char *p, size_t n) +{ + call_memcpy_intersecting_symbolic_1 (p, p + 1, n); +} + +void * __attribute__((noinline)) +call_memcpy_nonintersecting_symbolic_1 (void *dest, const void *src, size_t n) +{ + return memcpy (dest, src, n); /* { dg-bogus "overlapping buffers" } */ +} + +void test_memcpy_nonintersecting_symbolic_1 (char *p, size_t n) +{ + call_memcpy_nonintersecting_symbolic_1 (p, p + n, n); +} + +void * __attribute__((noinline)) +call_memcpy_nonintersecting_symbolic_2 (void *dest, const void *src, size_t n) +{ + return memcpy (dest, src, n); /* { dg-bogus "overlapping buffers" } */ +} + +void test_memcpy_nonintersecting_symbolic_2 (char *p, size_t n) +{ + call_memcpy_nonintersecting_symbolic_2 (p + n, p, n); +} +/* It's OK for memmove's arguments to overlap. */ + +void * __attribute__((noinline)) +call_memmove_symbolic_1 (void *dest, const void *src, size_t n) +{ + return memmove (dest, src, n); /* { dg-bogus "overlapping buffers" } */ +} + +void test_memmove_symbolic_1 (void *p, size_t n) +{ + call_memmove_symbolic_1 (p, p, n); +} + +/* TODO: + - strncpy + */ diff --git a/gcc/testsuite/gcc.dg/analyzer/pr101962.c b/gcc/testsuite/c-c++-common/analyzer/pr101962.c similarity index 95% rename from gcc/testsuite/gcc.dg/analyzer/pr101962.c rename to gcc/testsuite/c-c++-common/analyzer/pr101962.c index 5eb7cf0b995e..32cef1617c1b 100644 --- a/gcc/testsuite/gcc.dg/analyzer/pr101962.c +++ b/gcc/testsuite/c-c++-common/analyzer/pr101962.c @@ -1,6 +1,5 @@ -#include "analyzer-decls.h" +#include "../../gcc.dg/analyzer/analyzer-decls.h" -#define NULL ((void *)0) /* Verify that the analyzer makes the simplifying assumption that we don't hit NULL when incrementing pointers to non-NULL memory regions. */ @@ -35,7 +34,7 @@ maybe_inc_char_ptr (const char *ptr) return ++ptr; } -char +void test_s (void) { const char *msg = "hello world"; diff --git a/gcc/testsuite/gcc.dg/analyzer/pr103217-2.c b/gcc/testsuite/c-c++-common/analyzer/pr103217-2.c similarity index 94% rename from gcc/testsuite/gcc.dg/analyzer/pr103217-2.c rename to gcc/testsuite/c-c++-common/analyzer/pr103217-2.c index aa8bca7ce5f0..69ba6454e57e 100644 --- a/gcc/testsuite/gcc.dg/analyzer/pr103217-2.c +++ b/gcc/testsuite/c-c++-common/analyzer/pr103217-2.c @@ -30,7 +30,7 @@ struct test { }; int main(int argc, char *argv[]) { - struct test *options = calloc(1, sizeof(*options)); + struct test *options = (struct test *) calloc(1, sizeof(*options)); int rc; if (!options) abort(); diff --git a/gcc/testsuite/gcc.dg/analyzer/pr103217.c b/gcc/testsuite/c-c++-common/analyzer/pr103217.c similarity index 94% rename from gcc/testsuite/gcc.dg/analyzer/pr103217.c rename to gcc/testsuite/c-c++-common/analyzer/pr103217.c index 08889acb2c91..ae298ccaebbe 100644 --- a/gcc/testsuite/gcc.dg/analyzer/pr103217.c +++ b/gcc/testsuite/c-c++-common/analyzer/pr103217.c @@ -13,7 +13,7 @@ extern char *optarg; extern void free (void *__ptr) __attribute__ ((__nothrow__ , __leaf__)); -#define NULL ((void *)0) +#include "../../gcc.dg/analyzer/analyzer-decls.h" char *xstrdup(const char *src) { char *val = strdup(src); diff --git a/gcc/testsuite/gcc.dg/analyzer/pr104029.c b/gcc/testsuite/c-c++-common/analyzer/pr104029.c similarity index 97% rename from gcc/testsuite/gcc.dg/analyzer/pr104029.c rename to gcc/testsuite/c-c++-common/analyzer/pr104029.c index adf15ed356f7..873f0eb16b7e 100644 --- a/gcc/testsuite/gcc.dg/analyzer/pr104029.c +++ b/gcc/testsuite/c-c++-common/analyzer/pr104029.c @@ -23,7 +23,7 @@ int heapsort(void *vbase, size_t nmemb, size_t size, t_compfunc compar) { return (-1); } - k = my_malloc1(__FILE__, __LINE__, size); + k = (char *) my_malloc1(__FILE__, __LINE__, size); abase = (char *)vbase - size; diff --git a/gcc/testsuite/gcc.dg/analyzer/pr104062.c b/gcc/testsuite/c-c++-common/analyzer/pr104062.c similarity index 70% rename from gcc/testsuite/gcc.dg/analyzer/pr104062.c rename to gcc/testsuite/c-c++-common/analyzer/pr104062.c index 7129c27f60b9..9b44893dd4ba 100644 --- a/gcc/testsuite/gcc.dg/analyzer/pr104062.c +++ b/gcc/testsuite/c-c++-common/analyzer/pr104062.c @@ -7,7 +7,7 @@ realloc (void *, __SIZE_TYPE__); void foo (void) { - int *ap5 = calloc (4, sizeof *ap5); - int *ap7 = realloc (ap5, sizeof *ap5); + int *ap5 = (int *) calloc (4, sizeof *ap5); + int *ap7 = (int *) realloc (ap5, sizeof *ap5); } /* { dg-warning "leak of 'ap5'" "leak of ap5" } */ /* { dg-warning "leak of 'ap7'" "leak of ap7" { target *-*-* } .-1 } */ diff --git a/gcc/testsuite/gcc.dg/analyzer/pr105783.c b/gcc/testsuite/c-c++-common/analyzer/pr105783.c similarity index 85% rename from gcc/testsuite/gcc.dg/analyzer/pr105783.c rename to gcc/testsuite/c-c++-common/analyzer/pr105783.c index 00f44d04b64a..f17519415cef 100644 --- a/gcc/testsuite/gcc.dg/analyzer/pr105783.c +++ b/gcc/testsuite/c-c++-common/analyzer/pr105783.c @@ -1,11 +1,15 @@ /* { dg-additional-options "-O" } */ +#ifndef __cplusplus +typedef _Bool bool; +#endif + struct ss_s { union out_or_counting_u { char *newstr; unsigned long long cnt; } uu; - _Bool counting; + bool counting; }; struct ss_s ss_init(void) { diff --git a/gcc/testsuite/gcc.dg/analyzer/pr107345.c b/gcc/testsuite/c-c++-common/analyzer/pr107345.c similarity index 73% rename from gcc/testsuite/gcc.dg/analyzer/pr107345.c rename to gcc/testsuite/c-c++-common/analyzer/pr107345.c index 540596d1182b..ea1925bfa190 100644 --- a/gcc/testsuite/gcc.dg/analyzer/pr107345.c +++ b/gcc/testsuite/c-c++-common/analyzer/pr107345.c @@ -9,7 +9,8 @@ int main() { int g = 0; int *h[2][1]; h[1][0] = f; - if (g == (h[1][0])) { /* { dg-warning "comparison between pointer and integer" } */ + if (g == (h[1][0])) { /* { dg-warning "comparison between pointer and integer" "" { target c } } */ + /* { dg-error "ISO C\\+\\+ forbids comparison between pointer and integer" "" { target c++ } .-1 } */ unsigned int *i = 0; } printf("NPD_FLAG: %d\n ", *f); diff --git a/gcc/testsuite/c-c++-common/analyzer/pr93457.c b/gcc/testsuite/c-c++-common/analyzer/pr93457.c new file mode 100644 index 000000000000..71b3962980d2 --- /dev/null +++ b/gcc/testsuite/c-c++-common/analyzer/pr93457.c @@ -0,0 +1,12 @@ +/* { dg-do compile } */ + +void +p5 (const void *); + +void +s5 (const void *cl) +{ + p5 (&cl[1]); /* { dg-warning "dereferencing 'void \\*' pointer" "" { target c } } */ + /* { dg-warning "pointer of type 'void \\*' used in arithmetic" "" { target c++ } .-1 } */ + /* { dg-error "'const void\\*' is not a pointer-to-object type" "" { target c++ } .-2 } */ +} diff --git a/gcc/testsuite/gcc.dg/analyzer/pr93695-1.c b/gcc/testsuite/c-c++-common/analyzer/pr93695-1.c similarity index 83% rename from gcc/testsuite/gcc.dg/analyzer/pr93695-1.c rename to gcc/testsuite/c-c++-common/analyzer/pr93695-1.c index e0500c49be72..529c60131ca4 100644 --- a/gcc/testsuite/gcc.dg/analyzer/pr93695-1.c +++ b/gcc/testsuite/c-c++-common/analyzer/pr93695-1.c @@ -11,7 +11,7 @@ test_1 (void) int i; for (i = 0; i < ARRAY_SIZE (p); ++i) - p[i] = __builtin_malloc (sizeof (i)); + p[i] = (int *) __builtin_malloc (sizeof (i)); for (i = 0; i < ARRAY_SIZE (p); ++i) __builtin_free (p [i]); @@ -28,7 +28,7 @@ test_2 (int n) return; for (i = 0; i < n; ++i) - p[i] = __builtin_malloc (sizeof (i)); + p[i] = (int *) __builtin_malloc (sizeof (i)); for (i = 0; i < n; ++i) __builtin_free (p [i]); @@ -41,7 +41,7 @@ test_3 (int **p, int n) { int i; for (i = 0; i < n; ++i) - p[i] = __builtin_malloc (sizeof (i)); + p[i] = (int *) __builtin_malloc (sizeof (i)); } void diff --git a/gcc/testsuite/gcc.dg/analyzer/pr94596.c b/gcc/testsuite/c-c++-common/analyzer/pr94596.c similarity index 92% rename from gcc/testsuite/gcc.dg/analyzer/pr94596.c rename to gcc/testsuite/c-c++-common/analyzer/pr94596.c index 055d20980647..10ea549924e0 100644 --- a/gcc/testsuite/gcc.dg/analyzer/pr94596.c +++ b/gcc/testsuite/c-c++-common/analyzer/pr94596.c @@ -16,15 +16,18 @@ * limitations under the License. */ +#include "../../gcc.dg/analyzer/analyzer-decls.h" typedef __SIZE_TYPE__ size_t; -#define NULL ((void *)0) + +#ifndef __cplusplus #define false 0 +#endif #define OBJECT_OFFSETOF(OBJECT, MEMBER)\ - __builtin_offsetof(typeof(*(OBJECT)), MEMBER) + __builtin_offsetof(struct zone_limit, MEMBER) #define OBJECT_CONTAINING(POINTER, OBJECT, MEMBER) \ - ((typeof(OBJECT)) (void *) \ + ((struct zone_limit *) (void *) \ ((char *) (POINTER) - OBJECT_OFFSETOF(OBJECT, MEMBER))) #define ASSIGN_CONTAINER(OBJECT, POINTER, MEMBER) \ diff --git a/gcc/testsuite/gcc.dg/analyzer/pr94839.c b/gcc/testsuite/c-c++-common/analyzer/pr94839.c similarity index 82% rename from gcc/testsuite/gcc.dg/analyzer/pr94839.c rename to gcc/testsuite/c-c++-common/analyzer/pr94839.c index 46c8bb98bd23..26e7e616cf6d 100644 --- a/gcc/testsuite/gcc.dg/analyzer/pr94839.c +++ b/gcc/testsuite/c-c++-common/analyzer/pr94839.c @@ -13,7 +13,7 @@ int bitmap_create(struct bitmap *bm, int min, int max) bm->min = min; bm->max = max; - bm->vec = __builtin_calloc(sz, sizeof(int)); + bm->vec = (int *) __builtin_calloc(sz, sizeof(int)); if (!bm->vec) return (-12); return 0; /* { dg-bogus "leak" } */ diff --git a/gcc/testsuite/gcc.dg/analyzer/pr95240.c b/gcc/testsuite/c-c++-common/analyzer/pr95240.c similarity index 89% rename from gcc/testsuite/gcc.dg/analyzer/pr95240.c rename to gcc/testsuite/c-c++-common/analyzer/pr95240.c index c84c64de8b83..afd831b3d265 100644 --- a/gcc/testsuite/gcc.dg/analyzer/pr95240.c +++ b/gcc/testsuite/c-c++-common/analyzer/pr95240.c @@ -8,7 +8,7 @@ static char *activeTroubleArray; int initActiveTroubleArray () { - activeTroubleArray = calloc (1, 1); + activeTroubleArray = (char *) calloc (1, 1); return activeTroubleArray ? 0 : 1; } diff --git a/gcc/testsuite/gcc.dg/analyzer/pr96639.c b/gcc/testsuite/c-c++-common/analyzer/pr96639.c similarity index 80% rename from gcc/testsuite/gcc.dg/analyzer/pr96639.c rename to gcc/testsuite/c-c++-common/analyzer/pr96639.c index aedf0464dc93..b95217df6c41 100644 --- a/gcc/testsuite/gcc.dg/analyzer/pr96639.c +++ b/gcc/testsuite/c-c++-common/analyzer/pr96639.c @@ -3,7 +3,7 @@ void *calloc (__SIZE_TYPE__, __SIZE_TYPE__); int x7 (void) { - int **md = calloc (1, sizeof (void *)); + int **md = (int **) calloc (1, sizeof (void *)); return md[0][0]; /* { dg-warning "possibly-NULL" "unchecked deref" } */ /* { dg-warning "leak of 'md'" "leak" { target *-*-* } .-1 } */ diff --git a/gcc/testsuite/gcc.dg/analyzer/pr96653.c b/gcc/testsuite/c-c++-common/analyzer/pr96653.c similarity index 98% rename from gcc/testsuite/gcc.dg/analyzer/pr96653.c rename to gcc/testsuite/c-c++-common/analyzer/pr96653.c index e5e387c44a51..75f3d23aa986 100644 --- a/gcc/testsuite/gcc.dg/analyzer/pr96653.c +++ b/gcc/testsuite/c-c++-common/analyzer/pr96653.c @@ -753,7 +753,7 @@ const char *v4l2_ctrl_get_name(u32 id) { case ((0x00a30000 | 0x900) + 4): return "MD Region Grid"; default: - return ((void *)0); + return (const char *) ((void *)0); } } @@ -989,40 +989,40 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type, *type = V4L2_CTRL_TYPE_U32; break; case ((0x00990000 | 0x900) + 250): - *type = 0x0103; + *type = (enum v4l2_ctrl_type) 0x0103; break; case ((0x00990000 | 0x900) + 251): - *type = 0x0104; + *type = (enum v4l2_ctrl_type) 0x0104; break; case ((0x00990000 | 0x900) + 292): - *type = 0x0105; + *type = (enum v4l2_ctrl_type) 0x0105; break; case ((0x00990000 | 0x900) + 1000): - *type = 0x0110; + *type = (enum v4l2_ctrl_type) 0x0110; break; case ((0x00990000 | 0x900) + 1001): - *type = 0x0111; + *type = (enum v4l2_ctrl_type) 0x0111; break; case ((0x00990000 | 0x900) + 1002): - *type = 0x0112; + *type = (enum v4l2_ctrl_type) 0x0112; break; case ((0x00990000 | 0x900) + 1003): - *type = 0x0113; + *type = (enum v4l2_ctrl_type) 0x0113; break; case ((0x00990000 | 0x900) + 1004): - *type = 0x0114; + *type = (enum v4l2_ctrl_type) 0x0114; break; case ((0x00990000 | 0x900) + 2000): - *type = 0x301; + *type = (enum v4l2_ctrl_type) 0x301; break; case ((0x00990000 | 0x900) + 1008): - *type = 0x0120; + *type = (enum v4l2_ctrl_type) 0x0120; break; case ((0x00990000 | 0x900) + 1009): - *type = 0x0121; + *type = (enum v4l2_ctrl_type) 0x0121; break; case ((0x00990000 | 0x900) + 1010): - *type = 0x0122; + *type = (enum v4l2_ctrl_type) 0x0122; break; case ((0x009e0000 | 0x900) + 8): *type = V4L2_CTRL_TYPE_AREA; diff --git a/gcc/testsuite/gcc.dg/analyzer/pr96792.c b/gcc/testsuite/c-c++-common/analyzer/pr96792.c similarity index 93% rename from gcc/testsuite/gcc.dg/analyzer/pr96792.c rename to gcc/testsuite/c-c++-common/analyzer/pr96792.c index 7757645a1339..accaf22ba705 100644 --- a/gcc/testsuite/gcc.dg/analyzer/pr96792.c +++ b/gcc/testsuite/c-c++-common/analyzer/pr96792.c @@ -1,4 +1,4 @@ -#define NULL (void *)0 +#include "../../gcc.dg/analyzer/analyzer-decls.h" struct block { diff --git a/gcc/testsuite/gcc.dg/analyzer/pr96841.c b/gcc/testsuite/c-c++-common/analyzer/pr96841.c similarity index 89% rename from gcc/testsuite/gcc.dg/analyzer/pr96841.c rename to gcc/testsuite/c-c++-common/analyzer/pr96841.c index 14f3f7a86a33..b2951a0651ce 100644 --- a/gcc/testsuite/gcc.dg/analyzer/pr96841.c +++ b/gcc/testsuite/c-c++-common/analyzer/pr96841.c @@ -1,4 +1,4 @@ -/* { dg-additional-options "-O1 -Wno-builtin-declaration-mismatch" } */ +/* { dg-additional-options "-O1 -Wno-builtin-declaration-mismatch -Wno-analyzer-too-complex" } */ int l8 (void); diff --git a/gcc/testsuite/c-c++-common/analyzer/pr97568.c b/gcc/testsuite/c-c++-common/analyzer/pr97568.c new file mode 100644 index 000000000000..da97b9ddc4fd --- /dev/null +++ b/gcc/testsuite/c-c++-common/analyzer/pr97568.c @@ -0,0 +1,31 @@ +#include "../../gcc.dg/analyzer/analyzer-decls.h" + + +extern int *const p1; + +int *const p2 = NULL; + +int v3; +extern int *const p3 = &v3; /* { dg-warning "'p3' initialized and declared 'extern'" "C FE warning" { target c } } */ + +int v4; +int *const p4 = &v4; + +int main (void) +{ + __analyzer_describe (0, p1); /* { dg-message "INIT_VAL\\(p1\\)" "" { target c } } */ + /* { dg-message "INIT_VAL\\(int\\* const p1\\)" "" { target c++ } .-1 } */ + __analyzer_eval (p1 == NULL); /* { dg-message "UNKNOWN" } */ + + __analyzer_eval (p2 == NULL); /* { dg-message "TRUE" } */ + + __analyzer_describe (0, p3); /* { dg-message "&v3" "" { target c } } */ + /* { dg-message "&int v3" "" { target c++ } .-1 } */ + __analyzer_eval (p3 == NULL); /* { dg-message "FALSE" } */ + + __analyzer_describe (0, p4); /* { dg-message "&v4" "" { target c } } */ + /* { dg-message "&int v4" "" { target c++ } .-1 } */ + __analyzer_eval (p4 == NULL); /* { dg-message "FALSE" } */ + + return p1[0]; +} diff --git a/gcc/testsuite/gcc.dg/analyzer/pr98564.c b/gcc/testsuite/c-c++-common/analyzer/pr98564.c similarity index 59% rename from gcc/testsuite/gcc.dg/analyzer/pr98564.c rename to gcc/testsuite/c-c++-common/analyzer/pr98564.c index 74b1abec6bf2..a404e358cd29 100644 --- a/gcc/testsuite/gcc.dg/analyzer/pr98564.c +++ b/gcc/testsuite/c-c++-common/analyzer/pr98564.c @@ -2,5 +2,5 @@ void *calloc (__SIZE_TYPE__, __SIZE_TYPE__); void test_1 (void) { - int *p = calloc (0, 1); /* { dg-message "allocated here" } */ + int *p = (int *) calloc (0, 1); /* { dg-message "allocated here" } */ } /* { dg-warning "leak of 'p'" } */ diff --git a/gcc/testsuite/gcc.dg/analyzer/pr98628.c b/gcc/testsuite/c-c++-common/analyzer/pr98628.c similarity index 100% rename from gcc/testsuite/gcc.dg/analyzer/pr98628.c rename to gcc/testsuite/c-c++-common/analyzer/pr98628.c index fa0ca961c465..f339c495fd4c 100644 --- a/gcc/testsuite/gcc.dg/analyzer/pr98628.c +++ b/gcc/testsuite/c-c++-common/analyzer/pr98628.c @@ -1,12 +1,12 @@ /* { dg-additional-options "-O1" } */ void foo(void *); -struct chanset_t help_subst_chan; -struct chanset_t *help_subst_chan_0_0; struct chanset_t { struct chanset_t *next; char dname[]; }; +struct chanset_t help_subst_chan; +struct chanset_t *help_subst_chan_0_0; void help_subst(char *writeidx) { for (;; help_subst_chan = *help_subst_chan_0_0) { foo(help_subst_chan.next->dname); diff --git a/gcc/testsuite/gcc.dg/analyzer/pr98969.c b/gcc/testsuite/c-c++-common/analyzer/pr98969.c similarity index 61% rename from gcc/testsuite/gcc.dg/analyzer/pr98969.c rename to gcc/testsuite/c-c++-common/analyzer/pr98969.c index e4e4f0591979..4fe76012f005 100644 --- a/gcc/testsuite/gcc.dg/analyzer/pr98969.c +++ b/gcc/testsuite/c-c++-common/analyzer/pr98969.c @@ -7,14 +7,15 @@ void test_1 (__UINTPTR_TYPE__ i) { struct foo *f = (struct foo *)i; - f->expr = __builtin_malloc (1024); + f->expr = (char *) __builtin_malloc (1024); } /* { dg-bogus "leak" } */ void test_2 (__UINTPTR_TYPE__ i) { __builtin_free (((struct foo *)i)->expr); - __builtin_free (((struct foo *)i)->expr); /* { dg-warning "double-'free' of '\\*\\(\\(struct foo \\*\\)i\\)\\.expr'" } */ + __builtin_free (((struct foo *)i)->expr); /* { dg-warning "double-'free' of '\\*\\(\\(struct foo \\*\\)i\\)\\.expr'" "" { target c } } */ + /* { dg-warning "double-'free' of '\\*\\(\\(foo\\*\\)i\\)\\.foo::expr'" "" { target c++ } .-1 } */ } void diff --git a/gcc/testsuite/gcc.dg/analyzer/pr99193-2.c b/gcc/testsuite/c-c++-common/analyzer/pr99193-2.c similarity index 91% rename from gcc/testsuite/gcc.dg/analyzer/pr99193-2.c rename to gcc/testsuite/c-c++-common/analyzer/pr99193-2.c index 40e61817503f..12326ef61f1c 100644 --- a/gcc/testsuite/gcc.dg/analyzer/pr99193-2.c +++ b/gcc/testsuite/c-c++-common/analyzer/pr99193-2.c @@ -3,6 +3,8 @@ Based on https://github.com/libguestfs/libguestfs/blob/f19fd566f6387ce7e4d82409528c9dde374d25e0/df/main.c#L404 which is GPLv2 or later. */ +/* { dg-additional-options "-Wno-analyzer-too-complex" } */ + typedef __SIZE_TYPE__ size_t; typedef __builtin_va_list va_list; @@ -56,7 +58,7 @@ make_display_name (struct drv *drvs) ret = single_drive_display_name (drvs); len = __builtin_strlen (ret); - ret = realloc (ret, len + pluses + 1); /* { dg-bogus "'free'" } */ + ret = (char *) realloc (ret, len + pluses + 1); /* { dg-bogus "'free'" } */ if (ret == NULL) error (EXIT_FAILURE, errno, "realloc"); for (i = len; i < len + pluses; ++i) diff --git a/gcc/testsuite/gcc.dg/analyzer/pr99193-3.c b/gcc/testsuite/c-c++-common/analyzer/pr99193-3.c similarity index 91% rename from gcc/testsuite/gcc.dg/analyzer/pr99193-3.c rename to gcc/testsuite/c-c++-common/analyzer/pr99193-3.c index d64b0458e9eb..696ded007388 100644 --- a/gcc/testsuite/gcc.dg/analyzer/pr99193-3.c +++ b/gcc/testsuite/c-c++-common/analyzer/pr99193-3.c @@ -8,7 +8,7 @@ typedef __SIZE_TYPE__ size_t; typedef __builtin_va_list va_list; -#define NULL ((void *)0) +#include "../../gcc.dg/analyzer/analyzer-decls.h" extern void free (void *); extern void *realloc (void *__ptr, size_t __size) @@ -35,7 +35,7 @@ debug_help (const char **cmds, size_t argc, char *const *const argv) len = __builtin_strlen (r); for (i = 0; cmds[i] != NULL; ++i) { len += __builtin_strlen (cmds[i]) + 1; - p = realloc (r, len + 1); /* { dg-bogus "'free'" } */ + p = (char *) realloc (r, len + 1); /* { dg-bogus "'free'" } */ if (p == NULL) { free (r); return NULL; diff --git a/gcc/testsuite/gcc.dg/analyzer/pr99716-1.c b/gcc/testsuite/c-c++-common/analyzer/pr99716-1.c similarity index 93% rename from gcc/testsuite/gcc.dg/analyzer/pr99716-1.c rename to gcc/testsuite/c-c++-common/analyzer/pr99716-1.c index 2ccdcc73a5c2..41be8cab0480 100644 --- a/gcc/testsuite/gcc.dg/analyzer/pr99716-1.c +++ b/gcc/testsuite/c-c++-common/analyzer/pr99716-1.c @@ -4,7 +4,8 @@ FILE* fopen (const char*, const char*); int fclose (FILE*); int fprintf (FILE *, const char *, ...); -#define NULL ((void *)0) +#include "../../gcc.dg/analyzer/analyzer-decls.h" + void test_1 (void) diff --git a/gcc/testsuite/gcc.dg/analyzer/pr99774-1.c b/gcc/testsuite/c-c++-common/analyzer/pr99774-1.c similarity index 94% rename from gcc/testsuite/gcc.dg/analyzer/pr99774-1.c rename to gcc/testsuite/c-c++-common/analyzer/pr99774-1.c index a0bca8b1fe25..184baeef935d 100644 --- a/gcc/testsuite/gcc.dg/analyzer/pr99774-1.c +++ b/gcc/testsuite/c-c++-common/analyzer/pr99774-1.c @@ -42,7 +42,7 @@ int vu_check_queue_inflights(VuVirtq *vq) { int i = 0; if (vq->inuse) { - vq->resubmit_list = calloc(vq->inuse, sizeof(VuVirtqInflightDesc)); + vq->resubmit_list = (VuVirtqInflightDesc *) calloc(vq->inuse, sizeof(VuVirtqInflightDesc)); if (!vq->resubmit_list) { return -1; } diff --git a/gcc/testsuite/gcc.dg/analyzer/realloc-1.c b/gcc/testsuite/c-c++-common/analyzer/realloc-1.c similarity index 84% rename from gcc/testsuite/gcc.dg/analyzer/realloc-1.c rename to gcc/testsuite/c-c++-common/analyzer/realloc-1.c index 9951e118efeb..75e0b10e964b 100644 --- a/gcc/testsuite/gcc.dg/analyzer/realloc-1.c +++ b/gcc/testsuite/c-c++-common/analyzer/realloc-1.c @@ -20,14 +20,14 @@ void *test_1 (void *ptr) return realloc (ptr, 1024); } -void *test_2 (void *ptr) +void test_2 (void *ptr) { void *p = malloc (1024); /* { dg-message "allocated here" } */ p = realloc (p, 4096); /* { dg-message "when 'realloc' fails" } */ free (p); } /* { dg-warning "leak of 'p'" } */ // ideally this would be on the realloc stmt -void *test_3 (void *ptr) +void test_3 (void *ptr) { void *p = malloc (1024); void *q = realloc (p, 4096); @@ -45,7 +45,7 @@ void *test_4 (void) int *test_5 (int *p) { *p = 42; - int *q = realloc (p, sizeof(int) * 4); /* { dg-message "when 'realloc' fails" } */ + int *q = (int *) realloc (p, sizeof(int) * 4); /* { dg-message "when 'realloc' fails" } */ *q = 43; /* { dg-warning "dereference of NULL 'q'" } */ return q; } @@ -60,7 +60,7 @@ void test_6 (size_t sz) void *test_7 (size_t sz) { char buf[100]; /* { dg-message "region created on stack here" } */ - void *p = realloc (&buf, sz); /* { dg-warning "'realloc' of '&buf' which points to memory on the stack" } */ + void *p = realloc (&buf, sz); /* { dg-warning "'realloc' of '& ?buf' which points to memory on the stack" } */ return p; } @@ -91,5 +91,6 @@ void test_9 (void *p) void test_10 (char *s, int n) { - __builtin_realloc(s, n); /* { dg-warning "ignoring return value of '__builtin_realloc' declared with attribute 'warn_unused_result'" } */ + __builtin_realloc(s, n); /* { dg-warning "ignoring return value of '__builtin_realloc' declared with attribute 'warn_unused_result'" "" { target c } } */ + /* { dg-warning "ignoring return value of 'void\\* __builtin_realloc\\(void\\*, (long )?unsigned int\\)' declared with attribute 'warn_unused_result'" "" { target c++ } .-1 } */ } /* { dg-warning "leak" } */ diff --git a/gcc/testsuite/gcc.dg/analyzer/realloc-2.c b/gcc/testsuite/c-c++-common/analyzer/realloc-2.c similarity index 95% rename from gcc/testsuite/gcc.dg/analyzer/realloc-2.c rename to gcc/testsuite/c-c++-common/analyzer/realloc-2.c index ab3e4b6628a3..e608e0e19c38 100644 --- a/gcc/testsuite/gcc.dg/analyzer/realloc-2.c +++ b/gcc/testsuite/c-c++-common/analyzer/realloc-2.c @@ -1,11 +1,9 @@ /* { dg-additional-options "-fno-analyzer-suppress-followups" } */ -#include "analyzer-decls.h" +#include "../../gcc.dg/analyzer/analyzer-decls.h" typedef __SIZE_TYPE__ size_t; -#define NULL ((void *)0) - extern void *malloc (size_t __size) __attribute__ ((__nothrow__ , __leaf__)) __attribute__ ((__malloc__)) @@ -21,7 +19,7 @@ char *test_8 (size_t sz) { char *p, *q; - p = malloc (3); + p = (char *) malloc (3); if (!p) return NULL; @@ -35,7 +33,7 @@ char *test_8 (size_t sz) __analyzer_eval (p[1] == 'b'); /* { dg-warning "TRUE" } */ __analyzer_eval (p[2] == 'c'); /* { dg-warning "TRUE" } */ - q = realloc (p, 6); + q = (char *) realloc (p, 6); /* We should have 3 nodes, corresponding to "failure", "success without moving", and "success with moving". */ diff --git a/gcc/testsuite/gcc.dg/analyzer/realloc-3.c b/gcc/testsuite/c-c++-common/analyzer/realloc-3.c similarity index 96% rename from gcc/testsuite/gcc.dg/analyzer/realloc-3.c rename to gcc/testsuite/c-c++-common/analyzer/realloc-3.c index eec61497d5b4..b38013569e49 100644 --- a/gcc/testsuite/gcc.dg/analyzer/realloc-3.c +++ b/gcc/testsuite/c-c++-common/analyzer/realloc-3.c @@ -1,10 +1,9 @@ /* { dg-additional-options "-fno-analyzer-suppress-followups" } */ -#include "analyzer-decls.h" +#include "../../gcc.dg/analyzer/analyzer-decls.h" typedef __SIZE_TYPE__ size_t; -#define NULL ((void *)0) extern void *calloc (size_t __nmemb, size_t __size) __attribute__ ((__nothrow__ , __leaf__)) @@ -27,7 +26,7 @@ char *test_8 (size_t sz) { char *p, *q; - p = calloc (1, 3); + p = (char *) calloc (1, 3); if (!p) return NULL; @@ -37,7 +36,7 @@ char *test_8 (size_t sz) __analyzer_eval (p[1] == 0); /* { dg-warning "TRUE" } */ __analyzer_eval (p[2] == 0); /* { dg-warning "TRUE" } */ - q = realloc (p, 6); + q = (char *) realloc (p, 6); /* We should have 3 nodes, corresponding to "failure", "success without moving", and "success with moving". */ diff --git a/gcc/testsuite/gcc.dg/analyzer/realloc-4.c b/gcc/testsuite/c-c++-common/analyzer/realloc-4.c similarity index 97% rename from gcc/testsuite/gcc.dg/analyzer/realloc-4.c rename to gcc/testsuite/c-c++-common/analyzer/realloc-4.c index ac338ec04973..7e9a8edcac85 100644 --- a/gcc/testsuite/gcc.dg/analyzer/realloc-4.c +++ b/gcc/testsuite/c-c++-common/analyzer/realloc-4.c @@ -1,8 +1,7 @@ -#include "analyzer-decls.h" +#include "../../gcc.dg/analyzer/analyzer-decls.h" typedef __SIZE_TYPE__ size_t; -#define NULL ((void *)0) extern void *calloc (size_t __nmemb, size_t __size) __attribute__ ((__nothrow__ , __leaf__)) @@ -34,7 +33,7 @@ char *test_8 (char *p, size_t sz) __analyzer_eval (p[1] == 'b'); /* { dg-warning "TRUE" } */ __analyzer_eval (p[2] == 'c'); /* { dg-warning "TRUE" } */ - q = realloc (p, 6); + q = (char *) realloc (p, 6); /* We should have 3 nodes, corresponding to "failure", "success without moving", and "success with moving". */ diff --git a/gcc/testsuite/gcc.dg/analyzer/realloc-5.c b/gcc/testsuite/c-c++-common/analyzer/realloc-5.c similarity index 90% rename from gcc/testsuite/gcc.dg/analyzer/realloc-5.c rename to gcc/testsuite/c-c++-common/analyzer/realloc-5.c index f65f2c6ca251..d469ae9306b5 100644 --- a/gcc/testsuite/gcc.dg/analyzer/realloc-5.c +++ b/gcc/testsuite/c-c++-common/analyzer/realloc-5.c @@ -1,10 +1,9 @@ /* { dg-additional-options "-fno-analyzer-suppress-followups" } */ -#include "analyzer-decls.h" +#include "../../gcc.dg/analyzer/analyzer-decls.h" typedef __SIZE_TYPE__ size_t; -#define NULL ((void *)0) extern void *malloc (size_t __size) __attribute__ ((__nothrow__ , __leaf__)) @@ -22,12 +21,12 @@ extern void *memset (void *__ptr, int __value, size_t __size); void test_1 () { - char *p = malloc (16); + char *p = (char *) malloc (16); if (!p) return; memset (p, 1, 16); - char *q = realloc (p, 8); + char *q = (char *) realloc (p, 8); if (!q) { free (p); diff --git a/gcc/testsuite/gcc.dg/analyzer/realloc-pr110014.c b/gcc/testsuite/c-c++-common/analyzer/realloc-pr110014.c similarity index 70% rename from gcc/testsuite/gcc.dg/analyzer/realloc-pr110014.c rename to gcc/testsuite/c-c++-common/analyzer/realloc-pr110014.c index d76b87814136..e25722a3328a 100644 --- a/gcc/testsuite/gcc.dg/analyzer/realloc-pr110014.c +++ b/gcc/testsuite/c-c++-common/analyzer/realloc-pr110014.c @@ -8,18 +8,18 @@ slurp (long *buffer, unsigned long file_size) unsigned long cc; if (!__builtin_add_overflow (file_size - file_size % sizeof (long), 2 * sizeof (long), &cc)) - buffer = realloc (buffer, cc); + buffer = (long *) realloc (buffer, cc); return buffer; } long * slurp1 (long *buffer, unsigned long file_size) { - return realloc (buffer, file_size - file_size % sizeof (long)); + return (long *) realloc (buffer, file_size - file_size % sizeof (long)); } long * slurp2 (long *buffer, unsigned long file_size) { - return realloc (buffer, (file_size / sizeof (long)) * sizeof (long)); + return (long *) realloc (buffer, (file_size / sizeof (long)) * sizeof (long)); } diff --git a/gcc/testsuite/gcc.dg/analyzer/snprintf-concat.c b/gcc/testsuite/c-c++-common/analyzer/snprintf-concat.c similarity index 81% rename from gcc/testsuite/gcc.dg/analyzer/snprintf-concat.c rename to gcc/testsuite/c-c++-common/analyzer/snprintf-concat.c index a557dee6e440..c40440c49056 100644 --- a/gcc/testsuite/gcc.dg/analyzer/snprintf-concat.c +++ b/gcc/testsuite/c-c++-common/analyzer/snprintf-concat.c @@ -1,5 +1,5 @@ typedef __SIZE_TYPE__ size_t; -#define NULL ((void *)0) +#include "../../gcc.dg/analyzer/analyzer-decls.h" extern size_t strlen(const char* __s) __attribute__((__nothrow__, __leaf__)) @@ -17,7 +17,7 @@ char * test_1 (const char *a, const char *b) { size_t sz = strlen (a) + strlen (b) + 2; - char *p = malloc (sz); + char *p = (char *) malloc (sz); if (!p) return NULL; snprintf (p, sz, "%s/%s", a, b); @@ -28,7 +28,7 @@ void test_2 (const char *a, const char *b) { size_t sz = strlen (a) + strlen (b) + 2; - char *p = malloc (sz); /* { dg-message "allocated here" "PR 107017" { xfail *-*-* } } */ + char *p = (char *) malloc (sz); /* { dg-message "allocated here" "PR 107017" { xfail *-*-* } } */ if (!p) return; snprintf (p, sz, "%s/%s", a, b); /* { dg-warning "leak of 'p'" "PR 107017" { xfail *-*-* } } */ diff --git a/gcc/testsuite/gcc.dg/analyzer/sock-1.c b/gcc/testsuite/c-c++-common/analyzer/sock-1.c similarity index 91% rename from gcc/testsuite/gcc.dg/analyzer/sock-1.c rename to gcc/testsuite/c-c++-common/analyzer/sock-1.c index 0f3e822492f0..e5e2f23bba0c 100644 --- a/gcc/testsuite/gcc.dg/analyzer/sock-1.c +++ b/gcc/testsuite/c-c++-common/analyzer/sock-1.c @@ -5,7 +5,9 @@ typedef __u32 u32; typedef __s64 s64; typedef __u64 u64; typedef long long __kernel_time64_t; +#ifndef __cplusplus typedef _Bool bool; +#endif typedef __s64 time64_t; struct __kernel_timespec { __kernel_time64_t tv_sec; @@ -76,12 +78,12 @@ struct sock { static ktime_t sock_read_timestamp(struct sock *sk) { - return *(const volatile typeof(sk->sk_stamp) *)&(sk->sk_stamp); + return *(const volatile ktime_t *)&(sk->sk_stamp); } static void sock_write_timestamp(struct sock *sk, ktime_t kt) { - *(volatile typeof(sk->sk_stamp) *)&(sk->sk_stamp) = kt; + *(volatile ktime_t *)&(sk->sk_stamp) = kt; } /* [...snip...] */ @@ -108,5 +110,5 @@ int sock_gettstamp(struct socket *sock, void *userstamp, if (time32) return put_old_timespec32(&ts, userstamp); - return put_timespec64(&ts, userstamp); + return put_timespec64(&ts, (struct __kernel_timespec *) userstamp); } diff --git a/gcc/testsuite/c-c++-common/analyzer/sprintf-2.c b/gcc/testsuite/c-c++-common/analyzer/sprintf-2.c new file mode 100644 index 000000000000..4e101306ae16 --- /dev/null +++ b/gcc/testsuite/c-c++-common/analyzer/sprintf-2.c @@ -0,0 +1,59 @@ +/* See e.g. https://en.cppreference.com/w/c/io/fprintf + and https://www.man7.org/linux/man-pages/man3/sprintf.3.html */ + +extern int +sprintf(char* dst, const char* fmt, ...) + __attribute__((__nothrow__)); + +#include "../../gcc.dg/analyzer/analyzer-decls.h" + +int +test_passthrough (char* dst, const char* fmt) +{ + /* This assumes that fmt doesn't have any arguments. */ + return sprintf (dst, fmt); +} + +void +test_known (void) +{ + char buf[10]; + int res = sprintf (buf, "foo"); + /* TODO: ideally we would know the value of "res" is 3, + and known the content and strlen of "buf" after the call */ +} + +int +test_null_dst (void) +{ + return sprintf (NULL, "hello world"); /* { dg-warning "use of NULL where non-null expected" } */ +} + +int +test_null_fmt (char *dst) +{ + return sprintf (dst, NULL); /* { dg-warning "use of NULL where non-null expected" } */ +} + +int +test_uninit_dst (void) +{ + char *dst; + return sprintf (dst, "hello world"); /* { dg-warning "use of uninitialized value 'dst'" } */ +} + +int +test_uninit_fmt_ptr (char *dst) +{ + const char *fmt; + return sprintf (dst, fmt); /* { dg-warning "use of uninitialized value 'fmt'" } */ +} + +void +test_strlen_1 (void) +{ + char buf[10]; + sprintf (buf, "msg: %s\n", "abc"); + __analyzer_eval (__builtin_strlen (buf) == 8); /* { dg-warning "UNKNOWN" } */ + // TODO: ideally would be TRUE +} diff --git a/gcc/testsuite/gcc.dg/analyzer/sprintf-concat.c b/gcc/testsuite/c-c++-common/analyzer/sprintf-concat.c similarity index 82% rename from gcc/testsuite/gcc.dg/analyzer/sprintf-concat.c rename to gcc/testsuite/c-c++-common/analyzer/sprintf-concat.c index 0094f3e64496..ad744588bc0c 100644 --- a/gcc/testsuite/gcc.dg/analyzer/sprintf-concat.c +++ b/gcc/testsuite/c-c++-common/analyzer/sprintf-concat.c @@ -1,5 +1,5 @@ typedef __SIZE_TYPE__ size_t; -#define NULL ((void *)0) +#include "../../gcc.dg/analyzer/analyzer-decls.h" extern size_t strlen(const char* __s) __attribute__((__nothrow__, __leaf__)) @@ -17,7 +17,7 @@ char * test_1 (const char *a, const char *b) { size_t sz = strlen (a) + strlen (b) + 2; - char *p = malloc (sz); + char *p = (char *) malloc (sz); if (!p) return NULL; sprintf (p, "%s/%s", a, b); @@ -28,7 +28,7 @@ void test_2 (const char *a, const char *b) { size_t sz = strlen (a) + strlen (b) + 2; - char *p = malloc (sz); /* { dg-message "allocated here" } */ + char *p = (char *) malloc (sz); /* { dg-message "allocated here" } */ if (!p) return; sprintf (p, "%s/%s", a, b); /* { dg-warning "leak of 'p' " } */ diff --git a/gcc/testsuite/gcc.dg/analyzer/string-ops-concat-pair.c b/gcc/testsuite/c-c++-common/analyzer/string-ops-concat-pair.c similarity index 83% rename from gcc/testsuite/gcc.dg/analyzer/string-ops-concat-pair.c rename to gcc/testsuite/c-c++-common/analyzer/string-ops-concat-pair.c index f5bcd67594fa..254730b2ad4e 100644 --- a/gcc/testsuite/gcc.dg/analyzer/string-ops-concat-pair.c +++ b/gcc/testsuite/c-c++-common/analyzer/string-ops-concat-pair.c @@ -1,5 +1,5 @@ typedef __SIZE_TYPE__ size_t; -#define NULL ((void *)0) +#include "../../gcc.dg/analyzer/analyzer-decls.h" /* Concatenating a pair of strings. */ @@ -9,7 +9,7 @@ char * alloc_dup_of_concatenated_pair_1_correct (const char *x, const char *y) { size_t sz = __builtin_strlen (x) + __builtin_strlen (y) + 1; - char *result = __builtin_malloc (sz); + char *result = (char *) __builtin_malloc (sz); if (!result) return NULL; __builtin_memcpy (result, x, __builtin_strlen (x)); @@ -25,7 +25,7 @@ alloc_dup_of_concatenated_pair_1_incorrect (const char *x, const char *y) { /* Forgetting to add space for the terminator here. */ size_t sz = __builtin_strlen (x) + __builtin_strlen (y); - char *result = __builtin_malloc (sz); + char *result = (char *) __builtin_malloc (sz); if (!result) return NULL; __builtin_memcpy (result, x, __builtin_strlen (x)); @@ -42,7 +42,7 @@ alloc_dup_of_concatenated_pair_2_correct (const char *x, const char *y) size_t len_x = __builtin_strlen (x); size_t len_y = __builtin_strlen (y); size_t sz = len_x + len_y + 1; - char *result = __builtin_malloc (sz); + char *result = (char *) __builtin_malloc (sz); if (!result) return NULL; __builtin_memcpy (result, x, len_x); @@ -57,7 +57,8 @@ alloc_dup_of_concatenated_pair_2_incorrect (const char *x, const char *y) size_t len_x = __builtin_strlen (x); size_t len_y = __builtin_strlen (y); size_t sz = len_x + len_y; /* Forgetting to add space for the terminator. */ - char *result = __builtin_malloc (sz); /* { dg-message "capacity: 'len_x \\+ len_y' bytes" } */ + char *result = (char *) __builtin_malloc (sz); /* { dg-message "capacity: 'len_x \\+ len_y' bytes" "" { target c } } */ + /* { dg-message "capacity: '\\(len_x \\+ len_y\\)' bytes" "" { target c++ } .-1 } */ if (!result) return NULL; __builtin_memcpy (result, x, len_x); diff --git a/gcc/testsuite/gcc.dg/analyzer/string-ops-dup.c b/gcc/testsuite/c-c++-common/analyzer/string-ops-dup.c similarity index 83% rename from gcc/testsuite/gcc.dg/analyzer/string-ops-dup.c rename to gcc/testsuite/c-c++-common/analyzer/string-ops-dup.c index 44c4e9dc67e6..d7ec088f0f7d 100644 --- a/gcc/testsuite/gcc.dg/analyzer/string-ops-dup.c +++ b/gcc/testsuite/c-c++-common/analyzer/string-ops-dup.c @@ -1,5 +1,5 @@ typedef __SIZE_TYPE__ size_t; -#define NULL ((void *)0) +#include "../../gcc.dg/analyzer/analyzer-decls.h" /* Duplicating a string. */ @@ -9,7 +9,7 @@ char * alloc_dup_1_correct (const char *x) { size_t sz = __builtin_strlen (x) + 1; - char *result = __builtin_malloc (sz); + char *result = (char *) __builtin_malloc (sz); if (!result) return NULL; __builtin_memcpy (result, x, __builtin_strlen (x)); @@ -24,7 +24,7 @@ alloc_dup_1_incorrect (const char *x, const char *y) { /* Forgetting to add space for the terminator here. */ size_t sz = __builtin_strlen (x) + 1; - char *result = __builtin_malloc (sz); + char *result = (char *) __builtin_malloc (sz); if (!result) return NULL; __builtin_memcpy (result, x, __builtin_strlen (x)); @@ -39,7 +39,7 @@ alloc_dup_2_correct (const char *x) { size_t len_x = __builtin_strlen (x); size_t sz = len_x + 1; - char *result = __builtin_malloc (sz); + char *result = (char *) __builtin_malloc (sz); if (!result) return NULL; __builtin_memcpy (result, x, len_x); @@ -52,7 +52,7 @@ alloc_dup_of_concatenated_pair_2_incorrect (const char *x, const char *y) { size_t len_x = __builtin_strlen (x); size_t sz = len_x; /* Forgetting to add space for the terminator. */ - char *result = __builtin_malloc (sz); /* { dg-message "capacity: 'len_x' bytes" } */ + char *result = (char *) __builtin_malloc (sz); /* { dg-message "capacity: 'len_x' bytes" } */ if (!result) return NULL; __builtin_memcpy (result, x, len_x); diff --git a/gcc/testsuite/gcc.dg/analyzer/switch-enum-pr105273-git-vreportf-2.c b/gcc/testsuite/c-c++-common/analyzer/switch-enum-pr105273-git-vreportf-2.c similarity index 94% rename from gcc/testsuite/gcc.dg/analyzer/switch-enum-pr105273-git-vreportf-2.c rename to gcc/testsuite/c-c++-common/analyzer/switch-enum-pr105273-git-vreportf-2.c index 336222759e32..bb1ef0856912 100644 --- a/gcc/testsuite/gcc.dg/analyzer/switch-enum-pr105273-git-vreportf-2.c +++ b/gcc/testsuite/c-c++-common/analyzer/switch-enum-pr105273-git-vreportf-2.c @@ -34,7 +34,7 @@ static void __analyzer_vreportf(enum usage_kind kind) int main(void) { - __analyzer_vreportf(42); + __analyzer_vreportf((enum usage_kind) 42); return 0; } diff --git a/gcc/testsuite/gcc.dg/analyzer/symbolic-12.c b/gcc/testsuite/c-c++-common/analyzer/symbolic-12.c similarity index 88% rename from gcc/testsuite/gcc.dg/analyzer/symbolic-12.c rename to gcc/testsuite/c-c++-common/analyzer/symbolic-12.c index d7c50de9f270..26d9d1df93a3 100644 --- a/gcc/testsuite/gcc.dg/analyzer/symbolic-12.c +++ b/gcc/testsuite/c-c++-common/analyzer/symbolic-12.c @@ -1,4 +1,4 @@ -#include "analyzer-decls.h" +#include "../../gcc.dg/analyzer/analyzer-decls.h" void external_fn(void); @@ -10,7 +10,7 @@ struct st_1 void test_1a (void *p, unsigned next_off) { - struct st_1 *r = p; + struct st_1 *r = (struct st_1 *) p; external_fn(); @@ -24,7 +24,7 @@ void test_1a (void *p, unsigned next_off) void test_1b (void *p, unsigned next_off) { - struct st_1 *r = p; + struct st_1 *r = (struct st_1 *) p; if (next_off >= r->size) return; @@ -58,7 +58,7 @@ void test_1d (struct st_1 *r, unsigned next_off) void test_1e (void *p, unsigned next_off) { - struct st_1 *r = p; + struct st_1 *r = (struct st_1 *) p; while (1) { @@ -79,7 +79,7 @@ struct st_2 void test_2a (void *p, unsigned next_off) { - struct st_2 *r = p; + struct st_2 *r = (struct st_2 *) p; external_fn(); @@ -93,7 +93,7 @@ void test_2a (void *p, unsigned next_off) void test_2b (void *p, unsigned next_off, int idx) { - struct st_2 *r = p; + struct st_2 *r = (struct st_2 *) p; external_fn(); diff --git a/gcc/testsuite/gcc.dg/analyzer/uninit-alloca.c b/gcc/testsuite/c-c++-common/analyzer/uninit-alloca.c similarity index 57% rename from gcc/testsuite/gcc.dg/analyzer/uninit-alloca.c rename to gcc/testsuite/c-c++-common/analyzer/uninit-alloca.c index 5dd3f8522d2d..d8c842171a81 100644 --- a/gcc/testsuite/gcc.dg/analyzer/uninit-alloca.c +++ b/gcc/testsuite/c-c++-common/analyzer/uninit-alloca.c @@ -2,6 +2,6 @@ int test_1 (void) { - int *p = __builtin_alloca (sizeof (int)); /* { dg-message "region created on stack here" } */ + int *p = (int *) __builtin_alloca (sizeof (int)); /* { dg-message "region created on stack here" } */ return *p; /* { dg-warning "use of uninitialized value '\\*p'" } */ } diff --git a/gcc/testsuite/gcc.dg/analyzer/untracked-2.c b/gcc/testsuite/c-c++-common/analyzer/untracked-2.c similarity index 76% rename from gcc/testsuite/gcc.dg/analyzer/untracked-2.c rename to gcc/testsuite/c-c++-common/analyzer/untracked-2.c index 565a9ccd58ea..8c6d9d6f0235 100644 --- a/gcc/testsuite/gcc.dg/analyzer/untracked-2.c +++ b/gcc/testsuite/c-c++-common/analyzer/untracked-2.c @@ -2,6 +2,6 @@ typedef unsigned char u8; extern int foo(const u8 *key, unsigned int keylen); int test (void) { - static const u8 default_salt[64]; + static const u8 default_salt[64] = {}; return foo(default_salt, 64); } diff --git a/gcc/testsuite/gcc.dg/analyzer/vasprintf-1.c b/gcc/testsuite/c-c++-common/analyzer/vasprintf-1.c similarity index 96% rename from gcc/testsuite/gcc.dg/analyzer/vasprintf-1.c rename to gcc/testsuite/c-c++-common/analyzer/vasprintf-1.c index 061cd008c133..5e8ee9f233bb 100644 --- a/gcc/testsuite/gcc.dg/analyzer/vasprintf-1.c +++ b/gcc/testsuite/c-c++-common/analyzer/vasprintf-1.c @@ -1,6 +1,7 @@ /* { dg-additional-options "-Wno-analyzer-too-complex" } */ -#define NULL ((void *)0) +#include "../../gcc.dg/analyzer/analyzer-decls.h" + extern int printf (const char *__restrict __format, ...); extern int vasprintf (char **__restrict __ptr, const char *__restrict __f, diff --git a/gcc/testsuite/gcc.dg/analyzer/write-to-const-1.c b/gcc/testsuite/c-c++-common/analyzer/write-to-const-1.c similarity index 91% rename from gcc/testsuite/gcc.dg/analyzer/write-to-const-1.c rename to gcc/testsuite/c-c++-common/analyzer/write-to-const-1.c index dc724e29185a..c74442af267b 100644 --- a/gcc/testsuite/gcc.dg/analyzer/write-to-const-1.c +++ b/gcc/testsuite/c-c++-common/analyzer/write-to-const-1.c @@ -9,7 +9,7 @@ int test_1 (void) /* Example of writing to a subregion (an element within a const array). */ -const int c2[10]; /* { dg-message "declared here" } */ +const int c2[10] = {}; /* { dg-message "declared here" } */ int test_2 (void) { ((int*) &c2)[5] = 10; /* { dg-warning "write to 'const' object 'c2'" } */ diff --git a/gcc/testsuite/gcc.dg/analyzer/write-to-string-literal-1.c b/gcc/testsuite/c-c++-common/analyzer/write-to-string-literal-1.c similarity index 73% rename from gcc/testsuite/gcc.dg/analyzer/write-to-string-literal-1.c rename to gcc/testsuite/c-c++-common/analyzer/write-to-string-literal-1.c index 092500e066fd..46e907a85609 100644 --- a/gcc/testsuite/gcc.dg/analyzer/write-to-string-literal-1.c +++ b/gcc/testsuite/c-c++-common/analyzer/write-to-string-literal-1.c @@ -1,10 +1,16 @@ #include +#ifdef __cplusplus +#define CONST_CAST(type) const_cast +#else +#define CONST_CAST(type) +#endif + /* PR analyzer/95007. */ void test_1 (void) { - char *s = "foo"; + char *s = CONST_CAST(char *)("foo"); s[0] = 'g'; /* { dg-warning "write to string literal" } */ } @@ -12,9 +18,12 @@ void test_1 (void) void test_2 (void) { - memcpy ("abc", "def", 3); /* { dg-warning "write to string literal" } */ + // Technically irrelevant for C++ as fpermissive will warn about invalid conversion. + memcpy (CONST_CAST(char *)("abc"), "def", 3); /* { dg-warning "write to string literal" } */ } +/* PR c/83347. */ + static char * __attribute__((noinline)) called_by_test_3 (void) { diff --git a/gcc/testsuite/gcc.dg/analyzer/write-to-string-literal-4-disabled.c b/gcc/testsuite/c-c++-common/analyzer/write-to-string-literal-4-disabled.c similarity index 94% rename from gcc/testsuite/gcc.dg/analyzer/write-to-string-literal-4-disabled.c rename to gcc/testsuite/c-c++-common/analyzer/write-to-string-literal-4-disabled.c index fa21af133410..868c39368e1d 100644 --- a/gcc/testsuite/gcc.dg/analyzer/write-to-string-literal-4-disabled.c +++ b/gcc/testsuite/c-c++-common/analyzer/write-to-string-literal-4-disabled.c @@ -16,7 +16,7 @@ void test (int flag) char *buf; if (flag) - buf = __builtin_malloc (1024); + buf = (char *) __builtin_malloc (1024); else buf = (char *)""; /* { dg-bogus "here" } */ diff --git a/gcc/testsuite/c-c++-common/analyzer/write-to-string-literal-4.c b/gcc/testsuite/c-c++-common/analyzer/write-to-string-literal-4.c new file mode 100644 index 000000000000..971e8f385740 --- /dev/null +++ b/gcc/testsuite/c-c++-common/analyzer/write-to-string-literal-4.c @@ -0,0 +1,26 @@ +typedef __SIZE_TYPE__ size_t; + +int getrandom (void *__buffer, size_t __length, /* { dg-line getrandom } */ + unsigned int __flags) + __attribute__ ((access (__write_only__, 1, 2))); + +/* { dg-message "parameter 1 of 'getrandom' marked with attribute 'access \\(write_only, 1, 2\\)'" "" { target c} getrandom } */ +/* { dg-message "parameter 1 of 'int getrandom\\(void\\*, size_t, unsigned int\\)' marked with attribute 'access \\(write_only, 1, 2\\)'" "" { target c++ } getrandom } */ + +#define GRND_RANDOM 0x02 + +void test (int flag) +{ + char *buf; + + if (flag) + buf = (char *) __builtin_malloc (1024); + else + buf = (char *)""; /* { dg-message "here" } */ + + if (getrandom(buf, 16, GRND_RANDOM)) /* { dg-warning "write to string literal" } */ + __builtin_printf("%s\n", buf); + + if (flag) + __builtin_free (buf); +} diff --git a/gcc/testsuite/gcc.dg/analyzer/write-to-string-literal-5.c b/gcc/testsuite/c-c++-common/analyzer/write-to-string-literal-5.c similarity index 59% rename from gcc/testsuite/gcc.dg/analyzer/write-to-string-literal-5.c rename to gcc/testsuite/c-c++-common/analyzer/write-to-string-literal-5.c index 42efc49fb22e..a949f15323d3 100644 --- a/gcc/testsuite/gcc.dg/analyzer/write-to-string-literal-5.c +++ b/gcc/testsuite/c-c++-common/analyzer/write-to-string-literal-5.c @@ -4,11 +4,13 @@ /* { dg-additional-options "-fanalyzer-show-duplicate-count" } */ /* { dg-require-effective-target alloca } */ -#include "analyzer-decls.h" +#include "../../gcc.dg/analyzer/analyzer-decls.h" typedef __SIZE_TYPE__ size_t; -int getrandom (void *__buffer, size_t __length, /* { dg-message "parameter 1 of 'getrandom' marked with attribute 'access \\(write_only, 1, 2\\)'" } */ +int getrandom (void *__buffer, size_t __length, + /* { dg-message "parameter 1 of 'getrandom' marked with attribute 'access \\(write_only, 1, 2\\)'" "" { target c } .-1 } */ + /* { dg-message "parameter 1 of 'int getrandom\\(void\\*, size_t, unsigned int\\)' marked with attribute 'access \\(write_only, 1, 2\\)'" "" { target c++ } .-2 } */ unsigned int __flags) __attribute__ ((access (__write_only__, 1, 2))); @@ -18,9 +20,9 @@ void *test (int flag) { char *ptr; if (flag) - ptr = __builtin_malloc (1024); + ptr = (char *) __builtin_malloc (1024); else - ptr = __builtin_alloca (1024); + ptr = (char *) __builtin_alloca (1024); __analyzer_dump_exploded_nodes (0); /* { dg-warning "2 processed enodes" } */ diff --git a/gcc/testsuite/c-c++-common/goacc/collapse-1.c b/gcc/testsuite/c-c++-common/goacc/collapse-1.c index 11b143839839..0feac8f8ddbe 100644 --- a/gcc/testsuite/c-c++-common/goacc/collapse-1.c +++ b/gcc/testsuite/c-c++-common/goacc/collapse-1.c @@ -8,8 +8,8 @@ f1 (void) { #pragma acc parallel #pragma acc loop collapse (2) - for (i = 0; i < 5; i++) - ; /* { dg-error "not enough perfectly nested" } */ + for (i = 0; i < 5; i++) /* { dg-error "not enough nested loops" } */ + ; { for (j = 0; j < 5; j++) ; @@ -38,9 +38,9 @@ f3 (void) { #pragma acc parallel #pragma acc loop collapse (2) - for (i = 0; i < 5; i++) + for (i = 0; i < 5; i++) /* { dg-error "inner loops must be perfectly nested" } */ { - int k = foo (); /* { dg-error "not enough perfectly nested" } */ + int k = foo (); { { for (j = 0; j < 5; j++) @@ -56,12 +56,12 @@ f4 (void) { #pragma acc parallel #pragma acc loop collapse (2) - for (i = 0; i < 5; i++) + for (i = 0; i < 5; i++) /* { dg-error "inner loops must be perfectly nested" } */ { { for (j = 0; j < 5; j++) ; - foo (); /* { dg-error "collapsed loops not perfectly nested before" } */ + foo (); } } } @@ -71,13 +71,13 @@ f5 (void) { #pragma acc parallel #pragma acc loop collapse (2) - for (i = 0; i < 5; i++) + for (i = 0; i < 5; i++) /* { dg-error "inner loops must be perfectly nested" } */ { { for (j = 0; j < 5; j++) ; } - foo (); /* { dg-error "collapsed loops not perfectly nested before" } */ + foo (); } } diff --git a/gcc/testsuite/c-c++-common/goacc/default-3.c b/gcc/testsuite/c-c++-common/goacc/default-3.c index ac169a903e98..73dbc9084758 100644 --- a/gcc/testsuite/c-c++-common/goacc/default-3.c +++ b/gcc/testsuite/c-c++-common/goacc/default-3.c @@ -4,13 +4,66 @@ void f1 () { int f1_a = 2; float f1_b[2]; - -#pragma acc kernels default (none) /* { dg-message "enclosing OpenACC .kernels. construct" } */ + +#pragma acc kernels default (none) /* { dg-note "enclosing OpenACC 'kernels' construct with 'default\\\(none\\\)' clause" } */ { f1_b[0] /* { dg-error ".f1_b. not specified in enclosing OpenACC .kernels. construct" } */ = f1_a; /* { dg-error ".f1_a. not specified in enclosing OpenACC .kernels. construct" } */ } -#pragma acc parallel default (none) /* { dg-message "enclosing OpenACC .parallel. construct" } */ +#pragma acc parallel default (none) /* { dg-note "enclosing OpenACC 'parallel' construct with 'default\\\(none\\\)' clause" } */ + { + f1_b[0] /* { dg-error ".f1_b. not specified in enclosing OpenACC .parallel. construct" } */ + = f1_a; /* { dg-error ".f1_a. not specified in enclosing OpenACC .parallel. construct" } */ + } + +#pragma acc data default (none) /* { dg-note "enclosing OpenACC 'data' construct with 'default\\\(none\\\)' clause" } */ +#pragma acc kernels /* { dg-note "enclosing OpenACC 'kernels' construct and" } */ + { + f1_b[0] /* { dg-error ".f1_b. not specified in enclosing OpenACC .kernels. construct" } */ + = f1_a; /* { dg-error ".f1_a. not specified in enclosing OpenACC .kernels. construct" } */ + } +#pragma acc data default (none) /* { dg-note "enclosing OpenACC 'data' construct with 'default\\\(none\\\)' clause" } */ +#pragma acc parallel /* { dg-note "enclosing OpenACC 'parallel' construct and" } */ + { + f1_b[0] /* { dg-error ".f1_b. not specified in enclosing OpenACC .parallel. construct" } */ + = f1_a; /* { dg-error ".f1_a. not specified in enclosing OpenACC .parallel. construct" } */ + } + +#pragma acc data default (none) +#pragma acc parallel default (none) /* { dg-note "enclosing OpenACC 'parallel' construct with 'default\\\(none\\\)' clause" } */ + { + f1_b[0] /* { dg-error ".f1_b. not specified in enclosing OpenACC .parallel. construct" } */ + = f1_a; /* { dg-error ".f1_a. not specified in enclosing OpenACC .parallel. construct" } */ + } + +#pragma acc data default (none) /* { dg-note "enclosing OpenACC 'data' construct with 'default\\\(none\\\)' clause" } */ +#pragma acc data +#pragma acc data +#pragma acc parallel /* { dg-note "enclosing OpenACC 'parallel' construct and" } */ + { + f1_b[0] /* { dg-error ".f1_b. not specified in enclosing OpenACC .parallel. construct" } */ + = f1_a; /* { dg-error ".f1_a. not specified in enclosing OpenACC .parallel. construct" } */ + } +#pragma acc data +#pragma acc data default (none) /* { dg-note "enclosing OpenACC 'data' construct with 'default\\\(none\\\)' clause" } */ +#pragma acc data +#pragma acc parallel /* { dg-note "enclosing OpenACC 'parallel' construct and" } */ + { + f1_b[0] /* { dg-error ".f1_b. not specified in enclosing OpenACC .parallel. construct" } */ + = f1_a; /* { dg-error ".f1_a. not specified in enclosing OpenACC .parallel. construct" } */ + } +#pragma acc data +#pragma acc data +#pragma acc data default (none) /* { dg-note "enclosing OpenACC 'data' construct with 'default\\\(none\\\)' clause" } */ +#pragma acc parallel /* { dg-note "enclosing OpenACC 'parallel' construct and" } */ + { + f1_b[0] /* { dg-error ".f1_b. not specified in enclosing OpenACC .parallel. construct" } */ + = f1_a; /* { dg-error ".f1_a. not specified in enclosing OpenACC .parallel. construct" } */ + } +#pragma acc data +#pragma acc data default (none) +#pragma acc data default (none) /* { dg-note "enclosing OpenACC 'data' construct with 'default\\\(none\\\)' clause" } */ +#pragma acc parallel /* { dg-note "enclosing OpenACC 'parallel' construct and" } */ { f1_b[0] /* { dg-error ".f1_b. not specified in enclosing OpenACC .parallel. construct" } */ = f1_a; /* { dg-error ".f1_a. not specified in enclosing OpenACC .parallel. construct" } */ diff --git a/gcc/testsuite/c-c++-common/goacc/default-4.c b/gcc/testsuite/c-c++-common/goacc/default-4.c index 867175d48473..e12cb86d097b 100644 --- a/gcc/testsuite/c-c++-common/goacc/default-4.c +++ b/gcc/testsuite/c-c++-common/goacc/default-4.c @@ -44,6 +44,27 @@ void f2 () } } +void f2_ () +{ + int f2__a = 2; + float f2__b[2]; + +#pragma acc data default (none) copyin (f2__a) copyout (f2__b) + /* { dg-final { scan-tree-dump-times "omp target oacc_data map\\(from:f2__b \[^\\)\]+\\) map\\(to:f2__a \[^\\)\]+\\) default\\(none\\)" 1 "gimple" } } */ + { +#pragma acc kernels + /* { dg-final { scan-tree-dump-times "omp target oacc_kernels map\\(tofrom:f2__b \[^\\)\]+\\) map\\(tofrom:f2__a" 1 "gimple" } } */ + { + f2__b[0] = f2__a; + } +#pragma acc parallel + /* { dg-final { scan-tree-dump-times "omp target oacc_parallel map\\(tofrom:f2__b \[^\\)\]+\\) map\\(tofrom:f2__a" 1 "gimple" } } */ + { + f2__b[0] = f2__a; + } + } +} + void f3 () { int f3_a = 2; @@ -64,3 +85,24 @@ void f3 () } } } + +void f3_ () +{ + int f3__a = 2; + float f3__b[2]; + +#pragma acc data default (present) copyin (f3__a) copyout (f3__b) + /* { dg-final { scan-tree-dump-times "omp target oacc_data map\\(from:f3__b \[^\\)\]+\\) map\\(to:f3__a \[^\\)\]+\\) default\\(present\\)" 1 "gimple" } } */ + { +#pragma acc kernels + /* { dg-final { scan-tree-dump-times "omp target oacc_kernels map\\(tofrom:f3__b \[^\\)\]+\\) map\\(tofrom:f3__a" 1 "gimple" } } */ + { + f3__b[0] = f3__a; + } +#pragma acc parallel + /* { dg-final { scan-tree-dump-times "omp target oacc_parallel map\\(tofrom:f3__b \[^\\)\]+\\) map\\(tofrom:f3__a" 1 "gimple" } } */ + { + f3__b[0] = f3__a; + } + } +} diff --git a/gcc/testsuite/c-c++-common/goacc/default-5.c b/gcc/testsuite/c-c++-common/goacc/default-5.c index 37e3c3555cde..59ac1d79668a 100644 --- a/gcc/testsuite/c-c++-common/goacc/default-5.c +++ b/gcc/testsuite/c-c++-common/goacc/default-5.c @@ -4,8 +4,8 @@ void f1 () { - int f1_a = 2; - float f1_b[2]; + int f1_a = 2, f1_c = 3; + float f1_b[2], f1_d[2]; #pragma acc kernels default (present) /* { dg-final { scan-tree-dump-times "omp target oacc_kernels default\\(present\\) map\\(force_present:f1_b \[^\\)\]+\\) map\\(force_tofrom:f1_a" 1 "gimple" } } */ @@ -17,4 +17,19 @@ void f1 () { f1_b[0] = f1_a; } + + /* { dg-final { scan-tree-dump-times "omp target oacc_data default\\(present\\)" 2 "gimple" } } */ +#pragma acc data default (present) +#pragma acc kernels + /* { dg-final { scan-tree-dump-times "omp target oacc_kernels map\\(force_present:f1_d \[^\\)\]+\\) map\\(force_tofrom:f1_c" 1 "gimple" } } */ + { + f1_d[0] = f1_c; + } +#pragma acc data default (none) +#pragma acc data default (present) +#pragma acc parallel + /* { dg-final { scan-tree-dump-times "omp target oacc_parallel map\\(force_present:f1_d \[^\\)\]+\\) firstprivate\\(f1_c\\)" 1 "gimple" } } */ + { + f1_d[0] = f1_c; + } } diff --git a/gcc/testsuite/c-c++-common/goacc/tile-2.c b/gcc/testsuite/c-c++-common/goacc/tile-2.c index c8b240d225b9..dc3067032602 100644 --- a/gcc/testsuite/c-c++-common/goacc/tile-2.c +++ b/gcc/testsuite/c-c++-common/goacc/tile-2.c @@ -3,8 +3,8 @@ int main () #pragma acc parallel { #pragma acc loop tile (*,*) - for (int ix = 0; ix < 30; ix++) - ; /* { dg-error "not enough" } */ + for (int ix = 0; ix < 30; ix++) /* { dg-error "not enough" } */ + ; #pragma acc loop tile (*,*) for (int ix = 0; ix < 30; ix++) diff --git a/gcc/testsuite/c-c++-common/gomp/defaultmap-5.c b/gcc/testsuite/c-c++-common/gomp/defaultmap-5.c new file mode 100644 index 000000000000..cc1a77fadb34 --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/defaultmap-5.c @@ -0,0 +1,47 @@ +/* { dg-additional-options "-fdump-tree-original -fdump-tree-gimple" } */ + +void f() +{ + struct s { + int i; + }; + int scalar1 = 5; + int array1[5] = {1,2,3,4,5}; + int *ptr1 = &scalar1; + struct s mystruct1 = {.i = 5}; + + /* firstprivate + unspecified modifer. */ + #pragma omp target defaultmap(firstprivate) + { + scalar1 = 1; + array1[0] = 2; + if (ptr1 == 0L) + mystruct1.i = 3; + } + + /* equivalent: firstprivate + ALL modifer. */ + #pragma omp target defaultmap(firstprivate : all) + { + scalar1 = 1; + array1[0] = 2; + if (ptr1 == 0L) + mystruct1.i = 3; + } + + /* tofrom + ALL modifer. */ + #pragma omp target defaultmap(tofrom : all) + { + scalar1 = 1; + array1[0] = 2; + if (ptr1 == 0L) + mystruct1.i = 3; + } +} + +/* { dg-final { scan-tree-dump-times "#pragma omp target defaultmap\\(firstprivate\\)" 1 "original" } } */ +/* { dg-final { scan-tree-dump-times "#pragma omp target defaultmap\\(firstprivate:all\\)" 1 "original" } } */ +/* { dg-final { scan-tree-dump-times "#pragma omp target defaultmap\\(tofrom:all\\)" 1 "original" } } */ + +/* { dg-final { scan-tree-dump-times "#pragma omp target.* defaultmap\\(firstprivate\\) firstprivate\\(mystruct1\\) firstprivate\\(ptr1\\) firstprivate\\(array1\\) firstprivate\\(scalar1\\)" 1 "gimple" } } */ +/* { dg-final { scan-tree-dump-times "#pragma omp target.* defaultmap\\(firstprivate:all\\) firstprivate\\(mystruct1\\) firstprivate\\(ptr1\\) firstprivate\\(array1\\) firstprivate\\(scalar1\\)" 1 "gimple" } } */ +/* { dg-final { scan-tree-dump-times "#pragma omp target.* defaultmap\\(tofrom:all\\) map\\(tofrom:mystruct1 \\\[len: .\\\]\\\[implicit\\\]\\) map\\(tofrom:ptr1 \\\[len: .\\\]\\\[implicit\\\]\\) map\\(tofrom:array1 \\\[len: ..\\\]\\\[implicit\\\]\\) map\\(tofrom:scalar1 \\\[len: .\\\]\\\[implicit\\\]\\)" 1 "gimple" } } */ diff --git a/gcc/testsuite/c-c++-common/gomp/defaultmap-6.c b/gcc/testsuite/c-c++-common/gomp/defaultmap-6.c new file mode 100644 index 000000000000..45fce8b66e9d --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/defaultmap-6.c @@ -0,0 +1,48 @@ +void f() +{ + struct s { + int i; + }; + int scalar1 = 5; + int array1[5] = {1,2,3,4,5}; + int *ptr1 = &scalar1; + struct s mystruct1 = {.i = 5}; + + #pragma omp target defaultmap(firstprivate ) defaultmap(firstprivate : aggregate) /* { dg-error "too many 'defaultmap' clauses with 'aggregate' category" } */ + { + scalar1 = 1; array1[0] = 2; if (ptr1 == 0L) mystruct1.i = 3; + } + + #pragma omp target defaultmap(firstprivate : all ) defaultmap(alloc : pointer) /* { dg-error "too many 'defaultmap' clauses with 'pointer' category" } */ + { + scalar1 = 1; array1[0] = 2; if (ptr1 == 0L) mystruct1.i = 3; + } + + + #pragma omp target defaultmap(firstprivate : aggregate) defaultmap(firstprivate ) /* { dg-error "too many 'defaultmap' clauses with 'aggregate' category" } */ + { + scalar1 = 1; array1[0] = 2; if (ptr1 == 0L) mystruct1.i = 3; + } + + #pragma omp target defaultmap(alloc : pointer) defaultmap(firstprivate : all ) /* { dg-error "too many 'defaultmap' clauses with 'pointer' category" } */ + { + scalar1 = 1; array1[0] = 2; if (ptr1 == 0L) mystruct1.i = 3; + } + + #pragma omp target defaultmap(firstprivate :all ) defaultmap(firstprivate : all) /* { dg-error "too many 'defaultmap' clauses with 'all' category" } */ + { + scalar1 = 1; array1[0] = 2; if (ptr1 == 0L) mystruct1.i = 3; + } + #pragma omp target defaultmap(firstprivate ) defaultmap(firstprivate) /* { dg-error "too many 'defaultmap' clauses with unspecified category" } */ + { + scalar1 = 1; array1[0] = 2; if (ptr1 == 0L) mystruct1.i = 3; + } + #pragma omp target defaultmap(firstprivate ) defaultmap(firstprivate : all) /* { dg-error "too many 'defaultmap' clauses with 'all' category" } */ + { + scalar1 = 1; array1[0] = 2; if (ptr1 == 0L) mystruct1.i = 3; + } + #pragma omp target defaultmap(firstprivate : all) defaultmap(firstprivate) /* { dg-error "too many 'defaultmap' clauses with 'all' category" } */ + { + scalar1 = 1; array1[0] = 2; if (ptr1 == 0L) mystruct1.i = 3; + } +} diff --git a/gcc/testsuite/c-c++-common/gomp/imperfect-attributes.c b/gcc/testsuite/c-c++-common/gomp/imperfect-attributes.c new file mode 100644 index 000000000000..776295ce22a4 --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/imperfect-attributes.c @@ -0,0 +1,81 @@ +/* { dg-do compile { target { c || c++11 } } } */ + +/* Check that a nested FOR loop with standard c/c++ attributes on it + is treated as intervening code, since it doesn't match the grammar + for canonical loop nest form. */ + +extern void do_something (void); + +void imperfect1 (int x, int y) +{ +#pragma omp for collapse (2) + for (int i = 0; i < x; i++) /* { dg-error "not enough nested loops" } */ + { + [[]] for (int j = 0; j < y; j++) /* { dg-error "loop not permitted in intervening code" } */ + do_something (); + } +} + +void perfect1 (int x, int y) +{ +#pragma omp for ordered (2) + for (int i = 0; i < x; i++) /* { dg-error "not enough nested loops" } */ + /* { dg-error "inner loops must be perfectly nested" "" { target *-*-*} .-1 } */ + { + [[]] for (int j = 0; j < y; j++) /* { dg-error "loop not permitted in intervening code" } */ + do_something (); + } +} + +/* Similar, but put the attributes on a block wrapping the nested loop + instead. */ + +void imperfect2 (int x, int y) +{ +#pragma omp for collapse (2) + for (int i = 0; i < x; i++) /* { dg-error "not enough nested loops" } */ + { + [[]] + { + for (int j = 0; j < y; j++) /* { dg-error "loop not permitted in intervening code" } */ + do_something (); + } + } +} + +void perfect2 (int x, int y) +{ +#pragma omp for ordered (2) + for (int i = 0; i < x; i++) /* { dg-error "not enough nested loops" } */ + /* { dg-error "inner loops must be perfectly nested" "" { target *-*-*} .-1 } */ + { + [[]] + { + for (int j = 0; j < y; j++) /* { dg-error "loop not permitted in intervening code" } */ + do_something (); + } + } +} + +/* Make sure attributes are accepted in the innermost loop body, which has + no intervening code restrictions. */ + +void imperfect3 (int x, int y) +{ +#pragma omp for collapse (2) + for (int i = 0; i < x; i++) + for (int j = 0; j < y; j++) + { + [[]] do_something (); + } +} + +void perfect3 (int x, int y) +{ +#pragma omp for ordered (2) + for (int i = 0; i < x; i++) + for (int j = 0; j < y; j++) + { + [[]] do_something (); + } +} diff --git a/gcc/testsuite/c-c++-common/gomp/imperfect-badloops.c b/gcc/testsuite/c-c++-common/gomp/imperfect-badloops.c new file mode 100644 index 000000000000..dfd40b6cb2d7 --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/imperfect-badloops.c @@ -0,0 +1,50 @@ +/* { dg-do compile } */ + +/* This test case is expected to fail due to errors. */ + +int f1 (int depth, int iter); +int f2 (int depth, int iter); +void do_something (void); + +void s1 (int a1, int a2, int a3) +{ + int i, j, k; + +#pragma omp for collapse(3) + for (i = 0; i < a1; i++) + { + f1 (0, i); + if (a1 < a2) + { + int z = 0; + while (z < i) /* { dg-error "loop not permitted in intervening code " } */ + { + do_something (); + z++; + } + do /* { dg-error "loop not permitted in intervening code " } */ + { + do_something (); + z--; + } while (z >= 0); + } + for (j = 0; j < a2; j++) + { + for (k = 0; k < a3; k++) + { + f1 (2, k); + f2 (2, k); + } + f2 (1, j); + } + if (a1 < a3) + { + int z; + for (z = 0; z < i; z++) /* { dg-error "loop not permitted in intervening code " } */ + { + do_something (); + } + } + f2 (0, i); + } +} diff --git a/gcc/testsuite/c-c++-common/gomp/imperfect-blocks.c b/gcc/testsuite/c-c++-common/gomp/imperfect-blocks.c new file mode 100644 index 000000000000..0fea58faf789 --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/imperfect-blocks.c @@ -0,0 +1,75 @@ +/* { dg-do compile } */ + +/* Check that compound statements in intervening code are correctly + handled. */ + +extern void do_something (void); + +void imperfect1 (int x, int y) +{ +#pragma omp for collapse (2) + for (int i = 0; i < x; i++) + { + {} + for (int j = 0; j < y; j++) + do_something (); + } +} + +void perfect1 (int x, int y) +{ +#pragma omp for ordered (2) + for (int i = 0; i < x; i++) /* { dg-error "inner loops must be perfectly nested" } */ + { + {} + for (int j = 0; j < y; j++) + do_something (); + } +} + +void imperfect2 (int x, int y) +{ +#pragma omp for collapse (2) + for (int i = 0; i < x; i++) + { + for (int j = 0; j < y; j++) + do_something (); + {} + } +} + +void perfect2 (int x, int y) +{ +#pragma omp for ordered (2) + for (int i = 0; i < x; i++) /* { dg-error "inner loops must be perfectly nested" } */ + { + for (int j = 0; j < y; j++) + do_something (); + {} + } +} + +void imperfect3 (int x, int y) +{ +#pragma omp for collapse (2) + for (int i = 0; i < x; i++) + { + { do_something (); } + for (int j = 0; j < y; j++) + do_something (); + { do_something (); } + } +} + +void perfect3 (int x, int y) +{ +#pragma omp for ordered (2) + for (int i = 0; i < x; i++) /* { dg-error "inner loops must be perfectly nested" } */ + { + { do_something (); } + for (int j = 0; j < y; j++) + do_something (); + { do_something (); } + } +} + diff --git a/gcc/testsuite/c-c++-common/gomp/imperfect-extension.c b/gcc/testsuite/c-c++-common/gomp/imperfect-extension.c new file mode 100644 index 000000000000..a8a8f9ebe1df --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/imperfect-extension.c @@ -0,0 +1,55 @@ +/* { dg-do compile } */ + +/* Check that __extension__ introduces intervening code. */ + +extern void do_something (void); + +void imperfect1 (int x, int y) +{ +#pragma omp for collapse (2) + for (int i = 0; i < x; i++) /* { dg-error "not enough nested loops" } */ + { + __extension__ ({ + for (int j = 0; j < y; j++) /* { dg-error "loop not permitted in intervening code" } */ + do_something (); + }); + } +} + +void perfect1 (int x, int y) +{ +#pragma omp for ordered (2) + for (int i = 0; i < x; i++) /* { dg-error "not enough nested loops" } */ + /* { dg-error "inner loops must be perfectly nested" "" { target *-*-*} .-1 } */ + { + __extension__ ({ + for (int j = 0; j < y; j++) /* { dg-error "loop not permitted in intervening code" } */ + do_something (); + }); + } +} + +/* Check that we don't barf on __extension__ in the inner loop body. */ +void imperfect2 (int x, int y) +{ +#pragma omp for collapse (2) + for (int i = 0; i < x; i++) + for (int j = 0; j < y; j++) + { + __extension__ ({ + do_something (); + }); + } +} + +void perfect2 (int x, int y) +{ +#pragma omp for ordered (2) + for (int i = 0; i < x; i++) + for (int j = 0; j < y; j++) + { + __extension__ ({ + do_something (); + }); + } +} diff --git a/gcc/testsuite/c-c++-common/gomp/imperfect-gotos.c b/gcc/testsuite/c-c++-common/gomp/imperfect-gotos.c new file mode 100644 index 000000000000..897eed275ecb --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/imperfect-gotos.c @@ -0,0 +1,174 @@ +/* { dg-do compile } */ + +/* This file contains tests that are expected to fail. */ + + +/* These jumps are all OK since they are to/from the same structured block. */ + +void f1a (void) +{ +#pragma omp for collapse(2) + for (int i = 0; i < 64; ++i) + { + goto a; a:; + for (int j = 0; j < 64; ++j) + { + goto c; c:; + } + goto b; b:; + } +} + +/* Jump around loop body to/from different structured blocks of intervening + code. */ +void f2a (void) +{ +#pragma omp for collapse(2) + for (int i = 0; i < 64; ++i) + { + goto a; a:; + if (i > 16) goto b; /* { dg-error "invalid branch to/from OpenMP structured block" } */ + for (int j = 0; j < 64; ++j) + { + goto c; c:; + } + goto b; b:; + } +} + +/* Jump into loop body from intervening code. */ +void f3a (void) +{ +#pragma omp for collapse(2) + for (int i = 0; i < 64; ++i) + { + goto a; a:; + if (i > 16) goto c; /* { dg-error "invalid branch to/from OpenMP structured block" } */ + for (int j = 0; j < 64; ++j) + { + c: + ; + } + goto b; b:; + } +} + +/* Jump out of loop body to intervening code. */ +void f4a (void) +{ +#pragma omp for collapse(2) + for (int i = 0; i < 64; ++i) + { + goto a; a:; + for (int j = 0; j < 64; ++j) + if (i > 16) goto c; /* { dg-error "invalid branch to/from OpenMP structured block" } */ + c: + ; + goto b; b:; + } +} + +/* The next group of tests use the GNU extension for local labels. Expected + behavior is the same as the above group. */ + +/* These jumps are all OK since they are to/from the same structured block. */ + +void f1b (void) +{ +#pragma omp for collapse(2) + for (int i = 0; i < 64; ++i) + { + __label__ a, b, c; + goto a; a:; + for (int j = 0; j < 64; ++j) + { + goto c; c:; + } + goto b; b:; + } +} + +/* Jump around loop body to/from different structured blocks of intervening + code. */ +void f2b (void) +{ +#pragma omp for collapse(2) + for (int i = 0; i < 64; ++i) + { + __label__ a, b, c; + goto a; a:; + if (i > 16) goto b; /* { dg-error "invalid branch to/from OpenMP structured block" } */ + for (int j = 0; j < 64; ++j) + { + goto c; c:; + } + goto b; b:; + } +} + +/* Jump into loop body from intervening code. */ +void f3b (void) +{ +#pragma omp for collapse(2) + for (int i = 0; i < 64; ++i) + { + __label__ a, b, c; + goto a; a:; + if (i > 16) goto c; /* { dg-error "invalid branch to/from OpenMP structured block" } */ + for (int j = 0; j < 64; ++j) + { + c: + ; + } + goto b; b:; + } +} + +/* Jump out of loop body to intervening code. */ +void f4b (void) +{ +#pragma omp for collapse(2) + for (int i = 0; i < 64; ++i) + { + __label__ a, b, c; + goto a; a:; + for (int j = 0; j < 64; ++j) + if (i > 16) goto c; /* { dg-error "invalid branch to/from OpenMP structured block" } */ + c: + ; + goto b; b:; + } +} + +/* Test that the even the valid jumps are rejected when intervening code + is not allowed at all. */ + +void f1c (void) +{ +#pragma omp for ordered(2) + for (int i = 0; i < 64; ++i) /* { dg-error "inner loops must be perfectly nested" } */ + { + goto a; a:; + for (int j = 0; j < 64; ++j) + { + goto c; c:; + } + goto b; b:; + } +} + +void f1d (void) +{ +#pragma omp for ordered(2) + for (int i = 0; i < 64; ++i) /* { dg-error "inner loops must be perfectly nested" } */ + { + __label__ a, b, c; + goto a; a:; + for (int j = 0; j < 64; ++j) + { + goto c; c:; + } + goto b; b:; + } +} + diff --git a/gcc/testsuite/c-c++-common/gomp/imperfect-invalid-scope.c b/gcc/testsuite/c-c++-common/gomp/imperfect-invalid-scope.c new file mode 100644 index 000000000000..5c24aae07cca --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/imperfect-invalid-scope.c @@ -0,0 +1,77 @@ +/* { dg-do compile } */ + +/* Check that various cases of invalid references to variables bound + in an intervening code scope are diagnosed and do not ICE. This test + is expected to produce errors. */ + +extern void foo (int, int); + +void f1 (void) +{ +#pragma omp for collapse (2) + for (int i = 0; i < 64; i++) + { + int v = (i + 4) * 2; + for (int j = v; j < 64; j++) /* { dg-error "initializer is bound in intervening code" } */ + foo (i, j); + } +} + +void f2 (void) +{ +#pragma omp for collapse (2) + for (int i = 0; i < 64; i++) + { + int v = (i + 4) * 2; + for (int j = 0; j < v; j++) /* { dg-error "end test is bound in intervening code" } */ + foo (i, j); + } +} + +void f3 (void) +{ +#pragma omp for collapse (2) + for (int i = 0; i < 64; i++) + { + int v = (i + 4) * 2; + for (int j = 0; j < 64; j = j + v) /* { dg-error "increment expression is bound in intervening code" } */ + foo (i, j); + } +} + +void f4 (void) +{ +#pragma omp for collapse (2) + for (int i = 0; i < 64; i++) + { + int v = 8; + for (int j = v; j < 64; j++) /* { dg-error "initializer is bound in intervening code" } */ + foo (i, j); + } +} + +void f5 (void) +{ +#pragma omp for collapse (2) + for (int i = 0; i < 64; i++) + { + int j; + for (j = 0; j < 64; j++) /* { dg-error "loop variable is bound in intervening code" } */ + foo (i, j); + } +} + +void f6 (void) +{ +#pragma omp for collapse (2) + for (int i = 0; i < 64; i++) + { + int j; + { + int v = 8; + for (j = v; j < 64; j++) /* { dg-error "loop variable is bound in intervening code" } */ + /* { dg-error "initializer is bound in intervening code" "" { target *-*-* } .-1 } */ + foo (i, j); + } + } +} diff --git a/gcc/testsuite/c-c++-common/gomp/imperfect-labels.c b/gcc/testsuite/c-c++-common/gomp/imperfect-labels.c new file mode 100644 index 000000000000..b7a7a4c83586 --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/imperfect-labels.c @@ -0,0 +1,85 @@ +/* { dg-do compile } */ + +/* Check that a nested FOR loop with a label on it is treated as + intervening code, since it doesn't match the grammar for canonical + loop nest form. */ + +extern void do_something (void); + +void imperfect1 (int x, int y) +{ +#pragma omp for collapse (2) + for (int i = 0; i < x; i++) /* { dg-error "not enough nested loops" } */ + { + foo: + for (int j = 0; j < y; j++) /* { dg-error "loop not permitted in intervening code" } */ + do_something (); + } +} + +void perfect1 (int x, int y) +{ +#pragma omp for ordered (2) + for (int i = 0; i < x; i++) /* { dg-error "not enough nested loops" } */ + /* { dg-error "inner loops must be perfectly nested" "" { target *-*-*} .-1 } */ + { + foo: + for (int j = 0; j < y; j++) /* { dg-error "loop not permitted in intervening code" } */ + do_something (); + } +} + + +/* Similar, but put the label on a block wrapping the nested loop instead. */ + +void imperfect2 (int x, int y) +{ +#pragma omp for collapse (2) + for (int i = 0; i < x; i++) /* { dg-error "not enough nested loops" } */ + { + foo: + { + for (int j = 0; j < y; j++) /* { dg-error "loop not permitted in intervening code" } */ + do_something (); + } + } +} + +void perfect2 (int x, int y) +{ +#pragma omp for ordered (2) + for (int i = 0; i < x; i++) /* { dg-error "not enough nested loops" } */ + /* { dg-error "inner loops must be perfectly nested" "" { target *-*-*} .-1 } */ + { + foo: + { + for (int j = 0; j < y; j++) /* { dg-error "loop not permitted in intervening code" } */ + do_something (); + } + } +} + +/* Sanity check that labels are allowed in the innermost loop body. */ + +void imperfect3 (int x, int y) +{ +#pragma omp for collapse (2) + for (int i = 0; i < x; i++) + for (int j = 0; j < y; j++) + { + foo: + do_something (); + } +} + +void perfect3 (int x, int y) +{ +#pragma omp for ordered (2) + for (int i = 0; i < x; i++) + for (int j = 0; j < y; j++) + { + foo: + do_something (); + } +} + diff --git a/gcc/testsuite/c-c++-common/gomp/imperfect-legacy-syntax.c b/gcc/testsuite/c-c++-common/gomp/imperfect-legacy-syntax.c new file mode 100644 index 000000000000..571e067091b7 --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/imperfect-legacy-syntax.c @@ -0,0 +1,44 @@ +/* { dg-do compile } */ + +/* Braces may enclose a nested FOR even when intervening code is not + permitted. Before GCC implemented OpenMP 5.1 canonical loop syntax + and support for intervening code, it used to ignore empty statements + instead of treating them as intervening code; as an extension, those + are still accepted without complaint even in constructs where intervening + code is not supposed to be valid. */ + +void s1 (int a1, int a2, int a3) +{ + int i, j, k; + +#pragma omp for ordered(3) + for (i = 0; i < a1; i++) + { + for (j = 0; j < a2; j++) + { + for (k = 0; k < a3; k++) + { + } + } + } +} + +void s2 (int a1, int a2, int a3) +{ + int i, j, k; + +#pragma omp for ordered(3) + for (i = 0; i < a1; i++) + { + ; + for (j = 0; j < a2; j++) + { + ; + for (k = 0; k < a3; k++) + { + } + ; + } + ; + } +} diff --git a/gcc/testsuite/c-c++-common/gomp/imperfect-pragmas.c b/gcc/testsuite/c-c++-common/gomp/imperfect-pragmas.c new file mode 100644 index 000000000000..a9f552241580 --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/imperfect-pragmas.c @@ -0,0 +1,85 @@ +/* { dg-do compile } */ + +/* Check that non-statement pragmas are accepted in a canonical loop nest + even when perfect nesting is required. */ + +extern void do_something (void); + +void imperfect1 (int x, int y) +{ +#pragma omp for collapse (2) + for (int i = 0; i < x; i++) + { +#pragma GCC diagnostic push + for (int j = 0; j < y; j++) + do_something (); +#pragma GCC diagnostic pop + } +} + +void perfect1 (int x, int y) +{ +#pragma omp for ordered (2) + for (int i = 0; i < x; i++) + { +#pragma GCC diagnostic push + for (int j = 0; j < y; j++) + do_something (); +#pragma GCC diagnostic pop + } +} + + +/* "GCC unroll" is a statement pragma that consumes the following loop as + a substatement. Thus, the inner loop should be treated as intervening + code rather than part of the loop nest. */ + +void imperfect2 (int x, int y) +{ +#pragma omp for collapse (2) + for (int i = 0; i < x; i++) /* { dg-error "not enough nested loops" } */ + { +#pragma GCC unroll 4 + for (int j = 0; j < y; j++) /* { dg-error "loop not permitted in intervening code" } */ + do_something (); + } +} + +void perfect2 (int x, int y) +{ +#pragma omp for ordered (2) + for (int i = 0; i < x; i++) /* { dg-error "not enough nested loops" } */ + /* { dg-error "inner loops must be perfectly nested" "" { target *-*-*} .-1 } */ + { +#pragma GCC unroll 4 + for (int j = 0; j < y; j++) /* { dg-error "loop not permitted in intervening code" } */ + do_something (); + } +} + + +/* Check that statement pragmas are accepted in the innermost loop body. */ + +void imperfect3 (int x, int y) +{ +#pragma omp for collapse (2) + for (int i = 0; i < x; i++) + for (int j = 0; j < y; j++) + { +#pragma GCC unroll 4 + for (int k = 0; k < 4; k++) + do_something (); + } +} + +void perfect3 (int x, int y) +{ +#pragma omp for ordered (2) + for (int i = 0; i < x; i++) + for (int j = 0; j < y; j++) + { +#pragma GCC unroll 4 + for (int k = 0; k < 4; k++) + do_something (); + } +} diff --git a/gcc/testsuite/c-c++-common/gomp/imperfect1.c b/gcc/testsuite/c-c++-common/gomp/imperfect1.c new file mode 100644 index 000000000000..705626ad169e --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/imperfect1.c @@ -0,0 +1,38 @@ +/* { dg-do compile } */ + +/* This test case is expected to fail due to errors. */ + +int f1 (int depth, int iter); +int f2 (int depth, int iter); + +void s1 (int a1, int a2, int a3) +{ + int i, j, k; + +#pragma omp for collapse(3) + for (i = 0; i < a1; i++) + { + f1 (0, i); + for (j = 0; j < a2; j++) + { +#pragma omp barrier /* { dg-error "intervening code must not contain OpenMP directives" } */ + f1 (1, j); + if (i == 2) + continue; /* { dg-error "invalid exit" } */ + else + break; /* { dg-error "invalid exit" } */ + for (k = 0; k < a3; k++) + { + f1 (2, k); + f2 (2, k); + } + f2 (1, j); + } + for (k = 0; k < a3; k++) /* { dg-error "loop not permitted in intervening code " } */ + { + f1 (2, k); + f2 (2, k); + } + f2 (0, i); + } +} diff --git a/gcc/testsuite/c-c++-common/gomp/imperfect2.c b/gcc/testsuite/c-c++-common/gomp/imperfect2.c new file mode 100644 index 000000000000..dff17dd3ca52 --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/imperfect2.c @@ -0,0 +1,34 @@ +/* { dg-do compile } */ + +/* This test case is expected to fail due to errors. */ + +/* These functions that are part of the OpenMP runtime API would ordinarily + be declared in omp.h, but we don't have that here. */ +extern int omp_get_num_threads(void); +extern int omp_get_max_threads(void); + +int f1 (int depth, int iter); +int f2 (int depth, int iter); + +void s1 (int a1, int a2, int a3) +{ + int i, j, k; +#pragma omp for collapse(3) + for (i = 0; i < a1; i++) + { + f1 (0, i); + for (j = 0; j < omp_get_num_threads (); j++) /* This is OK */ + { + f1 (1, omp_get_num_threads ()); /* { dg-error "not permitted in intervening code" } */ + for (k = omp_get_num_threads (); k < a3; k++) /* This is OK */ + { + f1 (2, omp_get_num_threads ()); + f2 (2, omp_get_max_threads ()); + } + f2 (1, omp_get_max_threads ()); /* { dg-error "not permitted in intervening code" } */ + } + f2 (0, i); + } +} + + diff --git a/gcc/testsuite/c-c++-common/gomp/imperfect3.c b/gcc/testsuite/c-c++-common/gomp/imperfect3.c new file mode 100644 index 000000000000..b2b46c1993e2 --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/imperfect3.c @@ -0,0 +1,52 @@ +/* { dg-do compile } */ + +/* This test case is expected to fail due to errors. */ + +/* Test that the imperfectly-nested loops with the ordered clause gives + an error, and that there is only one error (and not one on every + intervening statement). */ + +int f1 (int depth, int iter); +int f2 (int depth, int iter); + +void s1 (int a1, int a2, int a3) +{ + int i, j, k; + + /* This loop without intervening code ought to be OK. */ +#pragma omp for ordered(3) + for (i = 0; i < a1; i++) + { + for (j = 0; j < a2; j++) + { + for (k = 0; k < a3; k++) + { + f1 (2, k); + f2 (2, k); +#pragma omp ordered doacross(source:omp_cur_iteration) +#pragma omp ordered doacross(sink: i - 2, j + 2, k - 1) + } + } + } + + /* Now add intervening code. */ +#pragma omp for ordered(3) + for (i = 0; i < a1; i++) /* { dg-error "inner loops must be perfectly nested" } */ + { + f1 (0, i); + for (j = 0; j < a2; j++) + { + f1 (1, j); + for (k = 0; k < a3; k++) + { + f1 (2, k); + f2 (2, k); +#pragma omp ordered doacross(source:omp_cur_iteration) +#pragma omp ordered doacross(sink: i - 2, j + 2, k - 1) + } + f2 (1, j); + } + f2 (0, i); + } +} + diff --git a/gcc/testsuite/c-c++-common/gomp/imperfect4.c b/gcc/testsuite/c-c++-common/gomp/imperfect4.c new file mode 100644 index 000000000000..1a0c07cd48e0 --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/imperfect4.c @@ -0,0 +1,33 @@ +/* { dg-do compile } */ + +/* This test case is expected to fail due to errors. */ + +int f1 (int depth, int iter); +int f2 (int depth, int iter); + +void s1 (int a1, int a2, int a3) +{ + int i, j, k; + +#pragma omp for collapse(4) + for (i = 0; i < a1; i++) /* { dg-error "not enough nested loops" } */ + { + f1 (0, i); + for (j = 0; j < a2; j++) + { + f1 (1, j); + for (k = 0; k < a3; k++) + { + /* According to the grammar, this is intervening code; we + don't know that we are also missing a nested for loop + until we have parsed this whole compound expression. */ +#pragma omp barrier /* { dg-error "intervening code must not contain OpenMP directives" } */ + f1 (2, k); + f2 (2, k); + } + f2 (1, j); + } + f2 (0, i); + } +} + diff --git a/gcc/testsuite/c-c++-common/gomp/imperfect5.c b/gcc/testsuite/c-c++-common/gomp/imperfect5.c new file mode 100644 index 000000000000..da92578ed252 --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/imperfect5.c @@ -0,0 +1,95 @@ +/* { dg-do compile } */ + +/* This test case is expected to fail due to errors. */ + +#define N 30 +#define M 3 + +int a[N][M], b[N][M], c[N][M]; + +extern void dostuff (int, int); + +/* good1 and good2 should compile without error. */ +void +good1 (void) +{ + int x, shift; + + x = 0; + #pragma omp parallel for simd collapse(2) reduction(inscan,+: x) private(shift) + for (int i = 0; i < N; i++) + { + for (int j = 0; j < M; j++) + { + x += a[i][j]; + x += b[i][j]; +#pragma omp scan inclusive(x) + shift = i + 29*j; + c[i][j] = x + shift; + } + } +} + +void +good2 (void) +{ + int x, shift; + x = 0; + + #pragma omp parallel for simd collapse(2) reduction(inscan,+: x) private(shift) + for (int i = 0; i < N; i++) + { + for (int j = 0; j < M; j++) + { + shift = i + 29*j; + c[i][j] = x + shift; +#pragma omp scan exclusive(x) + x += a[i][j]; + x += b[i][j]; + } + } +} + +/* Adding intervening code should trigger an error. */ + +void +bad1 (void) +{ + int x, shift; + + x = 0; + #pragma omp parallel for simd collapse(2) reduction(inscan,+: x) private(shift) + for (int i = 0; i < N; i++) /* { dg-error "inner loops must be perfectly nested" } */ + { + dostuff (i, 0); + for (int j = 0; j < M; j++) + { + x += a[i][j]; + x += b[i][j]; +#pragma omp scan inclusive(x) + shift = i + 29*j; + c[i][j] = x + shift; + } + } +} + +void +bad2 (void) +{ + int x, shift; + x = 0; + + #pragma omp parallel for simd collapse(2) reduction(inscan,+: x) private(shift) + for (int i = 0; i < N; i++) /* { dg-error "inner loops must be perfectly nested" } */ + { + for (int j = 0; j < M; j++) + { + shift = i + 29*j; + c[i][j] = x + shift; +#pragma omp scan exclusive(x) + x += a[i][j]; + x += b[i][j]; + } + dostuff (i, 1); + } +} diff --git a/gcc/testsuite/g++.dg/abi/macro0.C b/gcc/testsuite/g++.dg/abi/macro0.C index 4a0e9d06ca0f..183184e0f0a3 100644 --- a/gcc/testsuite/g++.dg/abi/macro0.C +++ b/gcc/testsuite/g++.dg/abi/macro0.C @@ -1,6 +1,6 @@ // This testcase will need to be kept in sync with c_common_post_options. // { dg-options "-fabi-version=0" } -#if __GXX_ABI_VERSION != 1018 +#if __GXX_ABI_VERSION != 1019 #error "Incorrect value of __GXX_ABI_VERSION" #endif diff --git a/gcc/testsuite/g++.dg/analyzer/analyzer.exp b/gcc/testsuite/g++.dg/analyzer/analyzer.exp index 9551d827c656..848bea616df1 100644 --- a/gcc/testsuite/g++.dg/analyzer/analyzer.exp +++ b/gcc/testsuite/g++.dg/analyzer/analyzer.exp @@ -39,6 +39,9 @@ set tests [lsort [glob -nocomplain $srcdir/$subdir/*.C]] g++-dg-runtest $tests "" $DEFAULT_CXXFLAGS +g++-dg-runtest [lsort [glob -nocomplain $srcdir/c-c++-common/analyzer/*.\[cS\]]] \ + "" $DEFAULT_CXXFLAGS + # All done. dg-finish diff --git a/gcc/testsuite/g++.dg/analyzer/fanalyzer-show-events-in-system-headers-default.C b/gcc/testsuite/g++.dg/analyzer/fanalyzer-show-events-in-system-headers-default.C new file mode 100644 index 000000000000..26f047d54715 --- /dev/null +++ b/gcc/testsuite/g++.dg/analyzer/fanalyzer-show-events-in-system-headers-default.C @@ -0,0 +1,18 @@ +/* { dg-skip-if "no shared_ptr in C++98" { c++98_only } } */ + +#include + +struct A {int x; int y;}; + +int main () { + std::shared_ptr a; /* { dg-line declare_a } */ + a->x = 4; /* { dg-line deref_a } */ + /* { dg-warning "dereference of NULL" "" { target *-*-* } deref_a } */ + + return 0; +} + +/* { dg-note "\\(1\\) 'a\\.std::.+::_M_ptr' is NULL" "" { target c++14_down } declare_a } */ +/* { dg-note "dereference of NULL 'a\\.std::.+::operator->\\(\\)'" "" { target *-*-* } deref_a } */ +/* { dg-note "calling 'std::.+::operator->' from 'main'" "" { target *-*-* } deref_a } */ +/* { dg-note "returning to 'main' from 'std::.+::operator->'" "" { target *-*-* } deref_a } */ diff --git a/gcc/testsuite/g++.dg/analyzer/fanalyzer-show-events-in-system-headers-no.C b/gcc/testsuite/g++.dg/analyzer/fanalyzer-show-events-in-system-headers-no.C new file mode 100644 index 000000000000..fd0df3180516 --- /dev/null +++ b/gcc/testsuite/g++.dg/analyzer/fanalyzer-show-events-in-system-headers-no.C @@ -0,0 +1,19 @@ +/* { dg-additional-options "-fno-analyzer-show-events-in-system-headers" } */ +/* { dg-skip-if "no shared_ptr in C++98" { c++98_only } } */ + +#include + +struct A {int x; int y;}; + +int main () { + std::shared_ptr a; /* { dg-line declare_a } */ + a->x = 4; /* { dg-line deref_a } */ + /* { dg-warning "dereference of NULL" "" { target *-*-* } deref_a } */ + + return 0; +} + +/* { dg-note "\\(1\\) 'a\\.std::.+::_M_ptr' is NULL" "" { target c++14_down } declare_a } */ +/* { dg-note "dereference of NULL 'a\\.std::.+::operator->\\(\\)'" "" { target *-*-* } deref_a } */ +/* { dg-note "calling 'std::.+::operator->' from 'main'" "" { target *-*-* } deref_a } */ +/* { dg-note "returning to 'main' from 'std::.+::operator->'" "" { target *-*-* } deref_a } */ diff --git a/gcc/testsuite/g++.dg/analyzer/fanalyzer-show-events-in-system-headers.C b/gcc/testsuite/g++.dg/analyzer/fanalyzer-show-events-in-system-headers.C new file mode 100644 index 000000000000..aa964f93563a --- /dev/null +++ b/gcc/testsuite/g++.dg/analyzer/fanalyzer-show-events-in-system-headers.C @@ -0,0 +1,14 @@ +/* { dg-additional-options "-fanalyzer-show-events-in-system-headers" } */ +/* { dg-skip-if "no shared_ptr in C++98" { c++98_only } } */ + +#include + +struct A {int x; int y;}; + +int main () { /* { dg-message "\\(1\\) entry to 'main'" "telltale event that we are going within a deeper frame than 'main'" } */ + std::shared_ptr a; + a->x = 4; /* { dg-line deref_a } */ + /* { dg-warning "dereference of NULL" "" { target *-*-* } deref_a } */ + + return 0; +} diff --git a/gcc/testsuite/g++.dg/analyzer/new-2.C b/gcc/testsuite/g++.dg/analyzer/new-2.C new file mode 100644 index 000000000000..391d159a53ae --- /dev/null +++ b/gcc/testsuite/g++.dg/analyzer/new-2.C @@ -0,0 +1,70 @@ +// { dg-additional-options "-O0 -fno-analyzer-suppress-followups -fexceptions" } +#include + +struct A +{ + int x; + int y; +}; + +void test_spurious_null_warning_throwing () +{ + int *x = new int; /* { dg-bogus "dereference of possibly-NULL" } */ + int *y = new int (); /* { dg-bogus "dereference of possibly-NULL" "non-throwing" } */ + int *arr = new int[3]; /* { dg-bogus "dereference of possibly-NULL" } */ + A *a = new A (); /* { dg-bogus "dereference of possibly-NULL" "throwing new cannot be null" } */ + + int z = *y + 2; + z = *x + 4; /* { dg-bogus "dereference of possibly-NULL 'x'" } */ + /* { dg-warning "use of uninitialized value '\\*x'" "" { target *-*-* } .-1 } */ + z = arr[0] + 4; /* { dg-bogus "dereference of possibly-NULL" } */ + /* { dg-warning "use of uninitialized value '\\*arr'" "" { target *-*-* } .-1 } */ + + delete a; + delete y; + delete x; + delete[] arr; +} + +void test_default_initialization () +{ + int *y = ::new int; + int *x = ::new int (); /* { dg-bogus "dereference of possibly-NULL 'operator new" } */ + + int b = *x + 3; /* { dg-bogus "dereference of possibly-NULL" } */ + /* { dg-bogus "use of uninitialized ‘*x’" "" { target *-*-* } .-1 } */ + int a = *y + 2; /* { dg-bogus "dereference of possibly-NULL 'y'" } */ + /* { dg-warning "use of uninitialized value '\\*y'" "no default init" { target *-*-* } .-1 } */ + + delete x; + delete y; +} + +/* From clang core.uninitialized.NewArraySize +new[] should not be called with an undefined size argument */ + +void test_garbage_new_array () +{ + int n; + int *arr = ::new int[n]; /* { dg-warning "use of uninitialized value 'n'" } */ + arr[0] = 7; + ::delete[] arr; /* no warnings emitted here either */ +} + +void test_nonthrowing () +{ + int* x = new(std::nothrow) int; + int* y = new(std::nothrow) int(); + int* arr = new(std::nothrow) int[10]; + + int z = *y + 2; /* { dg-warning "dereference of NULL 'y'" } */ + /* { dg-bogus "use of uninitialized value '\\*y'" "" { target *-*-* } .-1 } */ + z = *x + 4; /* { dg-warning "dereference of possibly-NULL 'x'" } */ + /* { dg-warning "use of uninitialized value '\\*x'" "" { target *-*-* } .-1 } */ + z = arr[0] + 4; /* { dg-warning "dereference of possibly-NULL 'arr'" } */ + /* { dg-warning "use of uninitialized value '\\*arr'" "" { target *-*-* } .-1 } */ + + delete y; + delete x; + delete[] arr; +} diff --git a/gcc/testsuite/g++.dg/analyzer/noexcept-new.C b/gcc/testsuite/g++.dg/analyzer/noexcept-new.C new file mode 100644 index 000000000000..f4bb4956d26d --- /dev/null +++ b/gcc/testsuite/g++.dg/analyzer/noexcept-new.C @@ -0,0 +1,48 @@ +/* { dg-additional-options "-O0 -fno-exceptions -fno-analyzer-suppress-followups" } */ +#include + +/* Test non-throwing variants of operator new */ + +struct A +{ + int x; + int y; +}; + +void test_throwing () +{ + int* x = new int; + int* y = new int(); /* { dg-warning "dereference of possibly-NULL" } */ + int* arr = new int[10]; + A *a = new A(); /* { dg-warning "dereference of possibly-NULL" } */ + + int z = *y + 2; + z = *x + 4; /* { dg-warning "dereference of possibly-NULL 'x'" } */ + /* { dg-warning "use of uninitialized value '\\*x'" "" { target *-*-* } .-1 } */ + z = arr[0] + 4; /* { dg-warning "dereference of possibly-NULL 'arr'" } */ + /* { dg-warning "use of uninitialized value '\\*arr'" "" { target *-*-* } .-1 } */ + a->y = a->x + 3; + + delete a; + delete y; + delete x; + delete[] arr; +} + +void test_nonthrowing () +{ + int* x = new(std::nothrow) int; + int* y = new(std::nothrow) int(); + int* arr = new(std::nothrow) int[10]; + + int z = *y + 2; /* { dg-warning "dereference of NULL 'y'" } */ + /* { dg-bogus "use of uninitialized value '\\*y'" "" { target *-*-* } .-1 } */ + z = *x + 4; /* { dg-warning "dereference of possibly-NULL 'x'" } */ + /* { dg-warning "use of uninitialized value '\\*x'" "" { target *-*-* } .-1 } */ + z = arr[0] + 4; /* { dg-warning "dereference of possibly-NULL 'arr'" } */ + /* { dg-warning "use of uninitialized value '\\*arr'" "" { target *-*-* } .-1 } */ + + delete y; + delete x; + delete[] arr; +} diff --git a/gcc/testsuite/g++.dg/analyzer/out-of-bounds-placement-new.C b/gcc/testsuite/g++.dg/analyzer/out-of-bounds-placement-new.C index d3076c3cf25b..33872e6ddab4 100644 --- a/gcc/testsuite/g++.dg/analyzer/out-of-bounds-placement-new.C +++ b/gcc/testsuite/g++.dg/analyzer/out-of-bounds-placement-new.C @@ -14,6 +14,6 @@ struct int_and_addr { int test (int_container ic) { - int_and_addr *iaddr = new (ic.addr ()) int_and_addr; + int_and_addr *iaddr = new (ic.addr ()) int_and_addr; /* { dg-warning "stack-based buffer overflow" } */ return iaddr->i; } diff --git a/gcc/testsuite/g++.dg/analyzer/placement-new-size.C b/gcc/testsuite/g++.dg/analyzer/placement-new-size.C new file mode 100644 index 000000000000..75a5a159282b --- /dev/null +++ b/gcc/testsuite/g++.dg/analyzer/placement-new-size.C @@ -0,0 +1,37 @@ +/* { dg-additional-options "-Wno-placement-new -Wno-analyzer-use-of-uninitialized-value" } */ + +#include +#include + +extern int get_buf_size (); + +void var_too_short () +{ + int8_t s; + int64_t *lp = new (&s) int64_t; /* { dg-warning "stack-based buffer overflow" } */ + /* { dg-warning "allocated buffer size is not a multiple of the pointee's size" "" { target *-*-* } .-1 } */ +} + +void static_buffer_too_short () +{ + int n = 16; + int buf[n]; + int *p = new (buf) int[n + 1]; /* { dg-warning "stack-based buffer overflow" } */ +} + +void symbolic_buffer_too_short () +{ + int n = get_buf_size (); + char buf[n]; + char *p = new (buf) char[n + 10]; /* { dg-warning "stack-based buffer overflow" } */ +} + +void test_binop () +{ + char *p = (char *) malloc (4); + if (!p) + return; + int32_t *i = ::new (p + 1) int32_t; /* { dg-warning "heap-based buffer overflow" } */ + *i = 42; /* { dg-warning "heap-based buffer overflow" } */ + free (p); +} \ No newline at end of file diff --git a/gcc/testsuite/g++.dg/analyzer/placement-new.C b/gcc/testsuite/g++.dg/analyzer/placement-new.C index 89055491a489..c10222bf2a94 100644 --- a/gcc/testsuite/g++.dg/analyzer/placement-new.C +++ b/gcc/testsuite/g++.dg/analyzer/placement-new.C @@ -14,15 +14,101 @@ void test_2 (void) { char buf[sizeof(int) * 10]; int *p = new(buf) int[10]; -} +} // { dg-prune-output "-Wfree-nonheap-object" } /* Delete of placement new. */ void test_3 (void) { char buf[sizeof(int)]; // { dg-message "region created on stack here" } - int *p = new(buf) int (42); + int *p = new (buf) int (42); delete p; // { dg-warning "memory on the stack" } } // { dg-prune-output "-Wfree-nonheap-object" } + +void test_4 (void) +{ + int buf[5]; // { dg-message "region created on stack here" } + int *p = new (&buf[2]) int (42); + delete p; // { dg-warning "memory on the stack" } +} + + +// { dg-prune-output "-Wfree-nonheap-object" } + +void test_write_placement_after_delete (void) +{ + short *s = ::new short; + short *lp = ::new (s) short; + ::delete s; + *lp = 12; /* { dg-warning "use after 'delete' of 'lp'" "write placement new after buffer deletion" } */ +} + +void test_read_placement_after_delete (void) +{ + short *s = ::new short; + short *lp = ::new (s) short; + ::delete s; + short m = *lp; // { dg-warning "use after 'delete' of 'lp'" "read placement new after buffer deletion" } +} + +struct A +{ + int x; + int y; +}; + +void test_use_placement_after_destruction (void) +{ + A a; + int *lp = ::new (&a.y) int; + *lp = 2; /* { dg-bogus "-Wanalyzer-use-of-uninitialized-value" } */ + a.~A(); + int m = *lp; /* { dg-warning "use of uninitialized value '\\*lp'" "use of placement after the underlying buffer was destructed." } */ +} + +void test_initialization_through_placement (void) +{ + int x; + int *p = ::new (&x) int; + *p = 10; + int z = x + 2; /* { dg-bogus "use of uninitialized value 'x'" "x has been initialized through placement pointer" } */ +} + +void test_partial_initialization_through_placement (void) +{ + char buf[4]; + char *p = ::new (&buf[2]) char; + *p = 10; + char *y = ::new (&buf[0]) char; + char z = buf[2] + 2; /* { dg-bogus "use of uninitialized value" } */ + z = *y + 2; /* { dg-warning "use of uninitialized value '\\*y'" "y has only been partially initialized" } */ +} + + +void test_delete_placement (void) +{ + A *a = ::new A; /* { dg-bogus "use of possibly-NULL 'operator new(8)' where non-null expected" "throwing new cannot be null" } */ + int *z = ::new (&a->y) int; + a->~A(); // deconstruct properly + ::operator delete (a); + ::operator delete (z); /* { dg-warning "use after 'delete' of 'z'" } */ +} + +void test_delete_placement_2 (void) +{ + A *a = ::new A; /* { dg-bogus "use of possibly-NULL 'operator new(8)' where non-null expected" "throwing new cannot be null" } */ + int *z = ::new (&a->y) int; + delete a; + ::operator delete (z); /* { dg-warning "use after 'delete' of 'z'" } */ +} + +void test_use_placement_after_deallocation (void) +{ + A *a = ::new A (); + int *lp = ::new (&a->y) int; + *lp = 2; /* { dg-bogus "use of uninitialized value" } */ + ::operator delete (a); + int m = *lp; /* { dg-warning "use after 'delete' of 'lp'" "use of placement after the underlying buffer was deallocated." } */ +} diff --git a/gcc/testsuite/g++.dg/cpp0x/decltype-100482.C b/gcc/testsuite/g++.dg/cpp0x/decltype-100482.C new file mode 100644 index 000000000000..1df8b1627437 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/decltype-100482.C @@ -0,0 +1,12 @@ +// PR c++/100482 +// { dg-do compile { target c++11 } } + +namespace N {} +decltype(N) x; // { dg-error "expected primary-expression" } + +struct S {}; +decltype(S) y; // { dg-error "argument to .decltype. must be an expression" } + +template +struct U {}; +decltype(U) z; // { dg-error "missing template arguments" } diff --git a/gcc/testsuite/g++.dg/cpp1y/var-templ84.C b/gcc/testsuite/g++.dg/cpp1y/var-templ84.C new file mode 100644 index 000000000000..39c2a0dc0cc9 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1y/var-templ84.C @@ -0,0 +1,12 @@ +// PR c++/71954 +// { dg-do compile { target c++14 } } + +struct A { + template static const int var = 0; + template static const int var = 1; + template static const int var = 2; +}; + +static_assert(A::var == 0, ""); +static_assert(A::var == 1, ""); +static_assert(A::var == 2, ""); diff --git a/gcc/testsuite/g++.dg/cpp1y/var-templ84a.C b/gcc/testsuite/g++.dg/cpp1y/var-templ84a.C new file mode 100644 index 000000000000..4aa3a2a7245e --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1y/var-templ84a.C @@ -0,0 +1,19 @@ +// PR c++/71954 +// A version of var-templ84.C where the partial specializations depend on +// outer template parameters. +// { dg-do compile { target c++14 } } + +template +struct A { + template static const int var = 0; + template static const int var = 1; + template static const int var = 2; +}; + +static_assert(A::var == 0, ""); +static_assert(A::var == 1, ""); +static_assert(A::var == 2, ""); + +static_assert(A::var == 0, ""); +static_assert(A::var == 0, ""); +static_assert(A::var == 0, ""); diff --git a/gcc/testsuite/g++.dg/cpp1z/class-deduction116.C b/gcc/testsuite/g++.dg/cpp1z/class-deduction116.C new file mode 100644 index 000000000000..00f6d5fef419 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1z/class-deduction116.C @@ -0,0 +1,8 @@ +// PR c++/106604 +// { dg-do compile { target c++17 } } +// { dg-additional-options "-Wunused-function" } + +namespace { + template struct A { A(...); }; + A(bool) -> A; // { dg-bogus "never defined" } +} diff --git a/gcc/testsuite/g++.dg/cpp1z/class-deduction74.C b/gcc/testsuite/g++.dg/cpp1z/class-deduction74.C index fe113819a956..7bab882da7d9 100644 --- a/gcc/testsuite/g++.dg/cpp1z/class-deduction74.C +++ b/gcc/testsuite/g++.dg/cpp1z/class-deduction74.C @@ -7,20 +7,20 @@ template struct S { }; template struct X { }; -S() -> S; // { dg-message "previously declared here|old declaration" } -S() -> S; // { dg-error "redeclared" } +S() -> S; // { dg-message "previously defined here|old declaration" } +S() -> S; // { dg-error "redefinition" } X() -> X; S() -> S; // { dg-error "ambiguating new declaration of" } -S(bool) -> S; // { dg-message "previously declared here" } -explicit S(bool) -> S; // { dg-error "redeclared" } +S(bool) -> S; // { dg-message "previously defined here" } +explicit S(bool) -> S; // { dg-error "redefinition" } -explicit S(char) -> S; // { dg-message "previously declared here" } -S(char) -> S; // { dg-error "redeclared" } +explicit S(char) -> S; // { dg-message "previously defined here" } +S(char) -> S; // { dg-error "redefinition" } template S(T, T) -> S; // { dg-message "previously declared here" } template X(T, T) -> X; -template S(T, T) -> S; // { dg-error "redeclared" } +template S(T, T) -> S; // { dg-error "redefinition" } // OK: Use SFINAE. template S(T) -> S; diff --git a/gcc/testsuite/g++.dg/cpp1z/decomp10.C b/gcc/testsuite/g++.dg/cpp1z/decomp10.C index f0723f8d85f2..af83a79e7812 100644 --- a/gcc/testsuite/g++.dg/cpp1z/decomp10.C +++ b/gcc/testsuite/g++.dg/cpp1z/decomp10.C @@ -7,7 +7,7 @@ namespace std { struct A1 { int i,j; } a1; template<> struct std::tuple_size { }; -void f1() { auto [ x ] = a1; } // { dg-error "is not an integral constant expression" } +void f1() { auto [ x ] = a1; } // { dg-error "only 1 name provided" } struct A2 { int i,j; } a2; template<> struct std::tuple_size { enum { value = 5 }; }; diff --git a/gcc/testsuite/g++.dg/cpp1z/pr110216.C b/gcc/testsuite/g++.dg/cpp1z/pr110216.C new file mode 100644 index 000000000000..be4fd5f7053f --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1z/pr110216.C @@ -0,0 +1,21 @@ +// DR 2386 +// PR c++/110216 +// { dg-do compile { target c++17 } } + + +namespace std{ + template struct tuple_size; +} + +struct A { + int x = 0; +}; + +template <> struct std::tuple_size <::A> {}; + +auto [x] = A{}; + +int +main () +{ +} diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-friend11.C b/gcc/testsuite/g++.dg/cpp2a/concepts-friend11.C index 0350ac3553e1..93cb1f05ad0f 100644 --- a/gcc/testsuite/g++.dg/cpp2a/concepts-friend11.C +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-friend11.C @@ -1,21 +1,29 @@ // CWG2596 // { dg-do compile { target c++20 } } +// { dg-additional-options -fno-implicit-constexpr } struct Base {}; -int foo(Base&) { return 0; } // #0 - template struct S : Base { friend int foo(Base&) requires (N == 1) { return 1; } // #1 - // friend int foo(Base&) requires (N == 2) { return 3; } // #2 + friend int foo(Base&) requires (N == 2) { return 3; } // #2 + + template + friend int bar(Base&) requires (N == 1) { return 1; } + template + friend int bar(Base&) requires (N == 2) { return 3; } }; S<1> s1; -S<2> s2; // OK, no conflict between #1 and #0 -int x = foo(s1); // { dg-error "ambiguous" } -int y = foo(s2); // OK, selects #0 +S<2> s2; // OK, no conflict between #1 and #2 -// ??? currently the foos all mangle the same, so comment out #2 -// and only test that #1 isn't multiply defined and overloads with #0. -// The 2596 example does not include #0 and expects both calls to work. +// { dg-final { scan-assembler "_ZN1SILi1EEF3fooER4Base" } } +int x = foo(s1); // OK, selects #1 +// { dg-final { scan-assembler "_ZN1SILi2EEF3fooER4Base" } } +int y = foo(s2); // OK, selects #2 + +// { dg-final { scan-assembler "_ZN1SILi1EEF3barIiEEiR4Base" } } +int x2 = bar(s1); // OK, selects #1 +// { dg-final { scan-assembler "_ZN1SILi2EEF3barIiEEiR4Base" } } +int y2 = bar(s2); // OK, selects #2 diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-friend11a.C b/gcc/testsuite/g++.dg/cpp2a/concepts-friend11a.C new file mode 100644 index 000000000000..f3481b6731e4 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-friend11a.C @@ -0,0 +1,15 @@ +// CWG2596 +// { dg-do compile { target c++20 } } + +struct Base {}; + +template +struct S : Base { + friend int foo(Base&) requires (N == 1); // { dg-error "must be a definition" } + friend int foo(Base&) requires (N == 2); // { dg-error "must be a definition" } + + template + friend int bar(Base&) requires (N == 1); // { dg-error "must be a definition" } + template + friend int bar(Base&) requires (N == 2); // { dg-error "must be a definition" } +}; diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-friend15.C b/gcc/testsuite/g++.dg/cpp2a/concepts-friend15.C new file mode 100644 index 000000000000..c37d547bbdfa --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-friend15.C @@ -0,0 +1,22 @@ +// PR c++/109751 +// { dg-do compile { target c++20 } } + +template concept cmpeq + = requires(_Tp __t, _Tp __u) { { __u != __t } ; }; + +template +struct iterator_interface +{ + friend constexpr bool operator>=(D lhs, D rhs) + requires cmpeq { return true; } +}; + +template +struct iterator : iterator_interface> +{ + bool operator==(iterator) const; + iterator &operator++(); + iterator &operator++(int); +}; + +static_assert(cmpeq>); diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-requires35.C b/gcc/testsuite/g++.dg/cpp2a/concepts-requires35.C new file mode 100644 index 000000000000..7023019ea418 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-requires35.C @@ -0,0 +1,27 @@ +// PR c++/110927 +// { dg-do compile { target c++20 } } + +template +struct A { + template struct B { using type = B; }; + template using type = U; +}; + +template<> struct A { }; + +template +concept C1 = requires { typename A::template B::type; }; + +template +concept C2 = requires { typename A::template B; }; + +template +concept C3 = requires { typename A::template type; }; + +static_assert(C1); +static_assert(C2); +static_assert(C3); + +static_assert(!C1); +static_assert(!C2); +static_assert(!C3); diff --git a/gcc/testsuite/g++.dg/cpp2a/constinit19.C b/gcc/testsuite/g++.dg/cpp2a/constinit19.C new file mode 100644 index 000000000000..5be610a18a26 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/constinit19.C @@ -0,0 +1,5 @@ +// PR c++/111173 +// { dg-do compile { target c++20 } } + +using Function = int(); +constinit Function f; // { dg-error ".constinit. specifier invalid for function" } diff --git a/gcc/testsuite/g++.dg/cpp2a/decomp8.C b/gcc/testsuite/g++.dg/cpp2a/decomp8.C new file mode 100644 index 000000000000..691913013f02 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/decomp8.C @@ -0,0 +1,74 @@ +// PR c++/111069 +// { dg-do compile { target c++11 } } +// { dg-options "" } + +extern int a[2]; +struct Y { int b, c, d; }; + +inline int +freddy () +{ + static auto [i, j] = a; // { dg-warning "structured bindings only available with" "" { target c++14_down } } + // { dg-warning "structured binding declaration can be 'static' only in" "" { target c++17_down } .-1 } + static auto [k, l] = a; // { dg-warning "structured bindings only available with" "" { target c++14_down } } + // { dg-warning "structured binding declaration can be 'static' only in" "" { target c++17_down } .-1 } + int ret = ++i + ++k; + { + static auto [i, j] = a; // { dg-warning "structured bindings only available with" "" { target c++14_down } } + // { dg-warning "structured binding declaration can be 'static' only in" "" { target c++17_down } .-1 } + static auto [k, l] = a; // { dg-warning "structured bindings only available with" "" { target c++14_down } } + // { dg-warning "structured binding declaration can be 'static' only in" "" { target c++17_down } .-1 } + ret += ++i + ++k; + } + { + static auto [i, j] = a; // { dg-warning "structured bindings only available with" "" { target c++14_down } } + // { dg-warning "structured binding declaration can be 'static' only in" "" { target c++17_down } .-1 } + static auto [k, l] = a; // { dg-warning "structured bindings only available with" "" { target c++14_down } } + // { dg-warning "structured binding declaration can be 'static' only in" "" { target c++17_down } .-1 } + ret += ++i + ++k; + } + return ret; +} + +namespace N +{ + namespace M + { + template + inline int + corge () + { + static auto [i, j] = a; // { dg-warning "structured bindings only available with" "" { target c++14_down } } + // { dg-warning "structured binding declaration can be 'static' only in" "" { target c++17_down } .-1 } + static auto && [u, v, w] = Y{}; // { dg-warning "structured bindings only available with" "" { target c++14_down } } + // { dg-warning "structured binding declaration can be 'static' only in" "" { target c++17_down } .-1 } + int ret = ++i + ++u; + { + static auto && [u, v, w] = Y{}; // { dg-warning "structured bindings only available with" "" { target c++14_down } } + // { dg-warning "structured binding declaration can be 'static' only in" "" { target c++17_down } .-1 } + ret += ++v; + } + return ret; + } + } +} + +int (*p) () = &freddy; +int (*q) () = N::M::corge<3>; + +// { dg-final { scan-assembler "_ZZ6freddyvEDC1i1jE" } } +// { dg-final { scan-assembler "_ZZ6freddyvEDC1i1jE_0" } } +// { dg-final { scan-assembler "_ZZ6freddyvEDC1i1jE_1" } } +// { dg-final { scan-assembler "_ZZ6freddyvEDC1k1lE" } } +// { dg-final { scan-assembler "_ZZ6freddyvEDC1k1lE_0" } } +// { dg-final { scan-assembler "_ZZ6freddyvEDC1k1lE_1" } } +// { dg-final { scan-assembler "_ZZN1N1M5corgeILi3EEEivEDC1i1jE" } } +// { dg-final { scan-assembler "_ZGVZ6freddyvEDC1i1jE" } } +// { dg-final { scan-assembler "_ZGVZ6freddyvEDC1i1jE_0" } } +// { dg-final { scan-assembler "_ZGVZ6freddyvEDC1i1jE_1" } } +// { dg-final { scan-assembler "_ZGVZ6freddyvEDC1k1lE" } } +// { dg-final { scan-assembler "_ZGVZ6freddyvEDC1k1lE_0" } } +// { dg-final { scan-assembler "_ZGVZ6freddyvEDC1k1lE_1" } } +// { dg-final { scan-assembler "_ZGVZN1N1M5corgeILi3EEEivEDC1i1jE" } } +// { dg-final { scan-assembler "_ZGRZN1N1M5corgeILi3EEEivEDC1u1v1wE_" } } +// { dg-final { scan-assembler "_ZGRZN1N1M5corgeILi3EEEivEDC1u1v1wE_0_" } } diff --git a/gcc/testsuite/g++.dg/cpp2a/decomp9.C b/gcc/testsuite/g++.dg/cpp2a/decomp9.C new file mode 100644 index 000000000000..e8ab0b798a08 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/decomp9.C @@ -0,0 +1,82 @@ +// PR c++/111069 +// { dg-do compile { target c++11 } } +// { dg-options "" } + +struct [[gnu::abi_tag ("foobar")]] S { int i; }; +extern S a[2]; +struct [[gnu::abi_tag ("qux")]] T { int i; S j; int k; }; +extern T b[2]; + +namespace N { + auto [i, j] = a; // { dg-warning "structured bindings only available with" "" { target c++14_down } } + auto [k, l] = b; // { dg-warning "structured bindings only available with" "" { target c++14_down } } +} + +inline int +foo () +{ + static auto [m, n] = a; // { dg-warning "structured bindings only available with" "" { target c++14_down } } + // { dg-warning "structured binding declaration can be 'static' only in" "" { target c++17_down } .-1 } + static auto [o, p] = b; // { dg-warning "structured bindings only available with" "" { target c++14_down } } + // { dg-warning "structured binding declaration can be 'static' only in" "" { target c++17_down } .-1 } + int ret = ++N::i.i + ++N::k.i; + { + static auto [m, n] = a; // { dg-warning "structured bindings only available with" "" { target c++14_down } } + // { dg-warning "structured binding declaration can be 'static' only in" "" { target c++17_down } .-1 } + + ret += ++n.i; + } + { + static auto [m, n] = a; // { dg-warning "structured bindings only available with" "" { target c++14_down } } + // { dg-warning "structured binding declaration can be 'static' only in" "" { target c++17_down } .-1 } + + ret += ++n.i; + } + ret += ++m.i + ++o.i; + return ret; +} + +template +inline int +bar () +{ + static auto [m, n] = a; // { dg-warning "structured bindings only available with" "" { target c++14_down } } + // { dg-warning "structured binding declaration can be 'static' only in" "" { target c++17_down } .-1 } + static auto [o, p] = b; // { dg-warning "structured bindings only available with" "" { target c++14_down } } + // { dg-warning "structured binding declaration can be 'static' only in" "" { target c++17_down } .-1 } + int ret = 0; + { + static auto [m, n] = a; // { dg-warning "structured bindings only available with" "" { target c++14_down } } + // { dg-warning "structured binding declaration can be 'static' only in" "" { target c++17_down } .-1 } + ret += ++n.i; + } + { + static auto [m, n] = a; // { dg-warning "structured bindings only available with" "" { target c++14_down } } + // { dg-warning "structured binding declaration can be 'static' only in" "" { target c++17_down } .-1 } + ret += ++n.i; + } + ret += ++m.i + ++o.i; + return ret; +} + +int (*p) () = &foo; +int (*q) () = &bar; + +// { dg-final { scan-assembler "_ZZ3foovEDC1m1nEB6foobar" } } +// { dg-final { scan-assembler "_ZZ3foovEDC1m1nEB6foobar_0" } } +// { dg-final { scan-assembler "_ZZ3foovEDC1m1nEB6foobar_1" } } +// { dg-final { scan-assembler "_ZZ3foovEDC1o1pEB3qux" } } +// { dg-final { scan-assembler "_ZZ3barI1TB3quxEivEDC1m1nEB6foobar" } } +// { dg-final { scan-assembler "_ZZ3barI1TB3quxEivEDC1m1nEB6foobar_0" } } +// { dg-final { scan-assembler "_ZZ3barI1TB3quxEivEDC1m1nEB6foobar_1" } } +// { dg-final { scan-assembler "_ZZ3barI1TB3quxEivEDC1o1pEB3qux" } } +// { dg-final { scan-assembler "_ZN1NDC1i1jEB6foobarE" } } +// { dg-final { scan-assembler "_ZN1NDC1k1lEB3quxE" } } +// { dg-final { scan-assembler "_ZGVZ3foovEDC1m1nEB6foobar" } } +// { dg-final { scan-assembler "_ZGVZ3foovEDC1m1nEB6foobar_0" } } +// { dg-final { scan-assembler "_ZGVZ3foovEDC1m1nEB6foobar_1" } } +// { dg-final { scan-assembler "_ZGVZ3foovEDC1o1pEB3qux" } } +// { dg-final { scan-assembler "_ZGVZ3barI1TB3quxEivEDC1m1nEB6foobar" } } +// { dg-final { scan-assembler "_ZGVZ3barI1TB3quxEivEDC1m1nEB6foobar_0" } } +// { dg-final { scan-assembler "_ZGVZ3barI1TB3quxEivEDC1m1nEB6foobar_1" } } +// { dg-final { scan-assembler "_ZGVZ3barI1TB3quxEivEDC1o1pEB3qux" } } diff --git a/gcc/testsuite/g++.dg/cpp2a/desig30.C b/gcc/testsuite/g++.dg/cpp2a/desig30.C new file mode 100644 index 000000000000..d9292df9de26 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/desig30.C @@ -0,0 +1,22 @@ +// PR c++/91319 +// { dg-do compile { target c++20 } } + +struct X { + explicit X() { } +}; + +struct Aggr { + X x; +}; + +Aggr +f () +{ + return Aggr{.x{}}; +} + +Aggr +f2 () +{ + return Aggr{.x = {}}; // { dg-error "explicit constructor" } +} diff --git a/gcc/testsuite/g++.dg/diagnostic/explicit.C b/gcc/testsuite/g++.dg/diagnostic/explicit.C new file mode 100644 index 000000000000..122accb86c15 --- /dev/null +++ b/gcc/testsuite/g++.dg/diagnostic/explicit.C @@ -0,0 +1,33 @@ +// { dg-do compile { target c++11 } } + +struct A { + long int l; +}; + +struct S { + explicit S(int) { } + explicit operator bool() const { return true; } // { dg-message "explicit conversion function was not considered" } + explicit operator int() const { return 42; } // { dg-message "explicit conversion function was not considered" } + explicit operator char() const { return 42; } // { dg-message "explicit conversion function was not considered" } + explicit operator double() const { return 42.; } // { dg-message "explicit conversion function was not considered" } + explicit operator float() const { return 42.; } // { dg-message "explicit conversion function was not considered" } + explicit operator long() const { return 42.; } // { dg-message "explicit conversion function was not considered" } +}; + +double +f (char) +{ + return S{2}; // { dg-error "cannot convert .S. to .double. in return" } +} + +void +g () +{ + S s = {1}; // { dg-error "would use explicit constructor" } + bool b = S{1}; // { dg-error "cannot convert .S. to .bool. in initialization" } + int i; + i = S{2}; // { dg-error "cannot convert .S. to .int. in assignment" } + f (S{3}); // { dg-error "cannot convert .S. to .char." } + A a{ S{4} }; // { dg-error "cannot convert .S. to .long int. in initialization" } + float arr[1] = { S{5} }; // { dg-error "cannot convert .S. to .float. in initialization" } +} diff --git a/gcc/testsuite/g++.dg/gomp/attrs-imperfect1.C b/gcc/testsuite/g++.dg/gomp/attrs-imperfect1.C new file mode 100644 index 000000000000..cf293b5081cf --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/attrs-imperfect1.C @@ -0,0 +1,38 @@ +/* { dg-do compile { target c++11 } } */ + +/* This test case is expected to fail due to errors. */ + +int f1 (int depth, int iter); +int f2 (int depth, int iter); + +void s1 (int a1, int a2, int a3) +{ + int i, j, k; + + [[ omp :: directive (for, collapse(3)) ]] + for (i = 0; i < a1; i++) + { + f1 (0, i); + for (j = 0; j < a2; j++) + { + [[ omp :: directive (barrier) ]] ; /* { dg-error "intervening code must not contain OpenMP directives" } */ + f1 (1, j); + if (i == 2) + continue; /* { dg-error "invalid exit" } */ + else + break; /* { dg-error "invalid exit" } */ + for (k = 0; k < a3; k++) + { + f1 (2, k); + f2 (2, k); + } + f2 (1, j); + } + for (k = 0; k < a3; k++) /* { dg-error "loop not permitted in intervening code " } */ + { + f1 (2, k); + f2 (2, k); + } + f2 (0, i); + } +} diff --git a/gcc/testsuite/g++.dg/gomp/attrs-imperfect2.C b/gcc/testsuite/g++.dg/gomp/attrs-imperfect2.C new file mode 100644 index 000000000000..0c9154dd10ca --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/attrs-imperfect2.C @@ -0,0 +1,34 @@ +/* { dg-do compile { target c++11 } } */ + +/* This test case is expected to fail due to errors. */ + +/* These functions that are part of the OpenMP runtime API would ordinarily + be declared in omp.h, but we don't have that here. */ +extern int omp_get_num_threads(void); +extern int omp_get_max_threads(void); + +int f1 (int depth, int iter); +int f2 (int depth, int iter); + +void s1 (int a1, int a2, int a3) +{ + int i, j, k; + [[ omp :: directive (for, collapse(3)) ]] + for (i = 0; i < a1; i++) + { + f1 (0, i); + for (j = 0; j < omp_get_num_threads (); j++) /* This is OK */ + { + f1 (1, omp_get_num_threads ()); /* { dg-error "not permitted in intervening code" } */ + for (k = omp_get_num_threads (); k < a3; k++) /* This is OK */ + { + f1 (2, omp_get_num_threads ()); + f2 (2, omp_get_max_threads ()); + } + f2 (1, omp_get_max_threads ()); /* { dg-error "not permitted in intervening code" } */ + } + f2 (0, i); + } +} + + diff --git a/gcc/testsuite/g++.dg/gomp/attrs-imperfect3.C b/gcc/testsuite/g++.dg/gomp/attrs-imperfect3.C new file mode 100644 index 000000000000..6b612afd355e --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/attrs-imperfect3.C @@ -0,0 +1,33 @@ +/* { dg-do compile { target c++11 } } */ + +/* This test case is expected to fail due to errors. */ + +/* Test that the imperfectly-nested loops with the ordered clause gives + an error, and that there is only one error (and not one on every + intervening statement). */ + +int f1 (int depth, int iter); +int f2 (int depth, int iter); + +void s1 (int a1, int a2, int a3) +{ + int i, j, k; + + [[ omp :: directive (for, ordered(3)) ]] + for (i = 0; i < a1; i++) /* { dg-error "inner loops must be perfectly nested" } */ + { + f1 (0, i); + for (j = 0; j < a2; j++) + { + f1 (1, j); + for (k = 0; k < a3; k++) + { + f1 (2, k); + f2 (2, k); + } + f2 (1, j); + } + f2 (0, i); + } +} + diff --git a/gcc/testsuite/g++.dg/gomp/attrs-imperfect4.C b/gcc/testsuite/g++.dg/gomp/attrs-imperfect4.C new file mode 100644 index 000000000000..16636ab3eb68 --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/attrs-imperfect4.C @@ -0,0 +1,33 @@ +/* { dg-do compile { target c++11 } } */ + +/* This test case is expected to fail due to errors. */ + +int f1 (int depth, int iter); +int f2 (int depth, int iter); + +void s1 (int a1, int a2, int a3) +{ + int i, j, k; + + [[ omp :: directive (for, collapse(4)) ]] + for (i = 0; i < a1; i++) /* { dg-error "not enough nested loops" } */ + { + f1 (0, i); + for (j = 0; j < a2; j++) + { + f1 (1, j); + for (k = 0; k < a3; k++) + { + /* According to the grammar, this is intervening code; we + don't know that we are also missing a nested for loop + until we have parsed this whole compound expression. */ + [[ omp :: directive (barrier) ]] ; /* { dg-error "intervening code must not contain OpenMP directives" } */ + f1 (2, k); + f2 (2, k); + } + f2 (1, j); + } + f2 (0, i); + } +} + diff --git a/gcc/testsuite/g++.dg/gomp/attrs-imperfect5.C b/gcc/testsuite/g++.dg/gomp/attrs-imperfect5.C new file mode 100644 index 000000000000..301307262a94 --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/attrs-imperfect5.C @@ -0,0 +1,57 @@ +/* { dg-do compile { target c++11 } } */ + +/* This test case is expected to fail due to errors. */ + +int f1 (int depth, int iter); +int f2 (int depth, int iter); +int ijk (int x, int y, int z); +void f3 (int sum); + +/* This function isn't particularly meaningful, but it should compile without + error. */ +int s1 (int a1, int a2, int a3) +{ + int i, j, k; + int r = 0; + + [[ omp :: directive (simd, collapse(3), reduction (inscan, +:r)) ]] + for (i = 0; i < a1; i++) + { + for (j = 0; j < a2; j++) + { + for (k = 0; k < a3; k++) + { + r = r + ijk (i, j, k); + [[ omp :: directive (scan, exclusive (r)) ]] ; + f3 (r); + } + } + } + return r; +} + +/* Adding intervening code should trigger an error. */ +int s2 (int a1, int a2, int a3) +{ + int i, j, k; + int r = 0; + + [[ omp :: directive (simd, collapse(3), reduction (inscan, +:r)) ]] + for (i = 0; i < a1; i++) /* { dg-error "inner loops must be perfectly nested" } */ + { + f1 (0, i); + for (j = 0; j < a2; j++) + { + f1 (1, j); + for (k = 0; k < a3; k++) + { + r = r + ijk (i, j, k); + [[ omp :: directive (scan, exclusive (r)) ]] ; + f3 (r); + } + f2 (1, j); + } + f2 (0, i); + } + return r; +} diff --git a/gcc/testsuite/g++.dg/gomp/pr41967.C b/gcc/testsuite/g++.dg/gomp/pr41967.C index 0eb489e8beef..7b59f831fe04 100644 --- a/gcc/testsuite/g++.dg/gomp/pr41967.C +++ b/gcc/testsuite/g++.dg/gomp/pr41967.C @@ -11,7 +11,7 @@ foo () { for (int j = 0; j < 5; ++j) ++sum; - ++sum; // { dg-error "collapsed loops not perfectly nested" } + ++sum; } return sum; } diff --git a/gcc/testsuite/g++.dg/gomp/pr58567.C b/gcc/testsuite/g++.dg/gomp/pr58567.C index 35a5bb027ffe..866d831c65e4 100644 --- a/gcc/testsuite/g++.dg/gomp/pr58567.C +++ b/gcc/testsuite/g++.dg/gomp/pr58567.C @@ -5,7 +5,7 @@ template void foo() { #pragma omp parallel for - for (typename T::X i = 0; i < 100; ++i) /* { dg-error "'int' is not a class, struct, or union type|expected iteration declaration or initialization" } */ + for (typename T::X i = 0; i < 100; ++i) /* { dg-error "'int' is not a class, struct, or union type|invalid type for iteration variable 'i'" } */ ; } diff --git a/gcc/testsuite/g++.dg/gomp/tpl-imperfect-gotos.C b/gcc/testsuite/g++.dg/gomp/tpl-imperfect-gotos.C new file mode 100644 index 000000000000..72206128fae6 --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/tpl-imperfect-gotos.C @@ -0,0 +1,161 @@ +/* { dg-do compile } */ + +/* This file contains tests that are expected to fail. */ + + +/* These jumps are all OK since they are to/from the same structured block. */ + +template +void f1a (void) +{ +#pragma omp for collapse(2) + for (T i = 0; i < 64; ++i) + { + goto a; a:; + for (T j = 0; j < 64; ++j) + { + goto c; c:; + } + goto b; b:; + } +} + +/* Jump around loop body to/from different structured blocks of intervening + code. */ +template +void f2a (void) +{ +#pragma omp for collapse(2) + for (T i = 0; i < 64; ++i) + { + goto a; a:; + if (i > 16) goto b; /* { dg-error "invalid branch to/from OpenMP structured block" } */ + for (T j = 0; j < 64; ++j) + { + goto c; c:; + } + goto b; b:; + } +} + +/* Jump into loop body from intervening code. */ +template +void f3a (void) +{ +#pragma omp for collapse(2) + for (T i = 0; i < 64; ++i) + { + goto a; a:; + if (i > 16) goto c; /* { dg-error "invalid branch to/from OpenMP structured block" } */ + for (T j = 0; j < 64; ++j) + { + c: /* { dg-error "jump to label .c." } */ + ; + } + goto b; b:; + } +} + +/* Jump out of loop body to intervening code. */ +template +void f4a (void) +{ +#pragma omp for collapse(2) + for (T i = 0; i < 64; ++i) + { + goto a; a:; + for (T j = 0; j < 64; ++j) + if (i > 16) goto c; /* { dg-error "invalid branch to/from OpenMP structured block" } */ + c: + ; + goto b; b:; + } +} + +/* The next group of tests use the GNU extension for local labels. Expected + behavior is the same as the above group. */ + +/* These jumps are all OK since they are to/from the same structured block. */ + +template +void f1b (void) +{ +#pragma omp for collapse(2) + for (T i = 0; i < 64; ++i) + { + __label__ a, b, c; + goto a; a:; + for (T j = 0; j < 64; ++j) + { + goto c; c:; + } + goto b; b:; + } +} + +/* Jump around loop body to/from different structured blocks of intervening + code. */ +template +void f2b (void) +{ +#pragma omp for collapse(2) + for (T i = 0; i < 64; ++i) + { + __label__ a, b, c; + goto a; a:; + if (i > 16) goto b; /* { dg-error "invalid branch to/from OpenMP structured block" } */ + for (T j = 0; j < 64; ++j) + { + goto c; c:; + } + goto b; b:; + } +} + +/* Jump into loop body from intervening code. */ +template +void f3b (void) +{ +#pragma omp for collapse(2) + for (T i = 0; i < 64; ++i) + { + __label__ a, b, c; + goto a; a:; + if (i > 16) goto c; /* { dg-error "invalid branch to/from OpenMP structured block" } */ + for (T j = 0; j < 64; ++j) + { + c: /* { dg-error "jump to label .c." } */ + ; + } + goto b; b:; + } +} + +/* Jump out of loop body to intervening code. */ +template +void f4b (void) +{ +#pragma omp for collapse(2) + for (T i = 0; i < 64; ++i) + { + __label__ a, b, c; + goto a; a:; + for (T j = 0; j < 64; ++j) + if (i > 16) goto c; /* { dg-error "invalid branch to/from OpenMP structured block" } */ + c: + ; + goto b; b:; + } +} + +int main (void) +{ + f1a (); + f2a (); + f3a (); + f4a (); + f1b (); + f2b (); + f3b (); + f4b (); +} diff --git a/gcc/testsuite/g++.dg/gomp/tpl-imperfect-invalid-scope.C b/gcc/testsuite/g++.dg/gomp/tpl-imperfect-invalid-scope.C new file mode 100644 index 000000000000..1e85e64b14ae --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/tpl-imperfect-invalid-scope.C @@ -0,0 +1,94 @@ +/* { dg-do compile } */ + +/* Check that various cases of invalid references to variables bound + in an intervening code scope are diagnosed and do not ICE. This test + is expected to produce errors. */ + +template +extern void foo (T, T); + +template +void f1 (void) +{ +#pragma omp for collapse (2) + for (T i = 0; i < 64; i++) + { + T v = (i + 4) * 2; + for (T j = v; j < 64; j++) /* { dg-error "initializer is bound in intervening code" } */ + foo (i, j); + } +} + +template +void f2 (void) +{ +#pragma omp for collapse (2) + for (T i = 0; i < 64; i++) + { + T v = (i + 4) * 2; + for (T j = 0; j < v; j++) /* { dg-error "end test is bound in intervening code" } */ + foo (i, j); + } +} + +template +void f3 (void) +{ +#pragma omp for collapse (2) + for (T i = 0; i < 64; i++) + { + T v = (i + 4) * 2; + for (T j = 0; j < 64; j = j + v) /* { dg-error "increment expression is bound in intervening code" } */ + foo (i, j); + } +} + +template +void f4 (void) +{ +#pragma omp for collapse (2) + for (T i = 0; i < 64; i++) + { + T v = 8; + for (T j = v; j < 64; j++) /* { dg-error "initializer is bound in intervening code" } */ + foo (i, j); + } +} + +template +void f5 (void) +{ +#pragma omp for collapse (2) + for (T i = 0; i < 64; i++) + { + T j; + for (j = 0; j < 64; j++) /* { dg-error "loop variable is bound in intervening code" } */ + foo (i, j); + } +} + +template +void f6 (void) +{ +#pragma omp for collapse (2) + for (T i = 0; i < 64; i++) + { + T j; + { + T v = 8; + for (j = v; j < 64; j++) /* { dg-error "loop variable is bound in intervening code" } */ + /* { dg-error "initializer is bound in intervening code" "" { target *-*-* } .-1 } */ + foo (i, j); + } + } +} + +int main() +{ + f1 (); + f2 (); + f3 (); + f4 (); + f5 (); + f6 (); +} diff --git a/gcc/testsuite/g++.dg/opt/pr110879.C b/gcc/testsuite/g++.dg/opt/pr110879.C new file mode 100644 index 000000000000..7f0a0a80b8af --- /dev/null +++ b/gcc/testsuite/g++.dg/opt/pr110879.C @@ -0,0 +1,16 @@ +// { dg-do compile } +// { dg-options "-O3 -fdump-tree-optimized" } + +#include + +std::vector f(std::size_t n) { + std::vector res; + for (std::size_t i = 0; i < n; ++i) { + res.push_back(i); + } + return res; +} + +// Reads of _M_finish should be optimized out. +// This regex matches all reads from res variable except for _M_end_of_storage field. +// { dg-final { scan-tree-dump-not "=\\s*\\S*res_(?!\\S*_M_end_of_storage;)" "optimized" } } diff --git a/gcc/testsuite/g++.dg/opt/vectcond-1.C b/gcc/testsuite/g++.dg/opt/vectcond-1.C new file mode 100644 index 000000000000..5be4e84fb801 --- /dev/null +++ b/gcc/testsuite/g++.dg/opt/vectcond-1.C @@ -0,0 +1,57 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-ccp1 -fdump-tree-optimized -Wno-psabi" } */ +/* This is the vector version of these optimizations. */ +/* PR tree-optimization/19832 */ + +#define vector __attribute__((vector_size(sizeof(unsigned)*2))) + +static inline vector int max_(vector int a, vector int b) +{ + return (a > b)? a : b; +} +static inline vector int min_(vector int a, vector int b) +{ + return (a < b) ? a : b; +} + +vector int f_minus(vector int a, vector int b) +{ + return (a != b) ? a - b : (a - a); +} +vector int f_xor(vector int a, vector int b) +{ + return (a != b) ? a ^ b : (a ^ a); +} + +vector int f_ior(vector int a, vector int b) +{ + return (a != b) ? a | b : (a | a); +} +vector int f_and(vector int a, vector int b) +{ + return (a != b) ? a & b : (a & a); +} +vector int f_max(vector int a, vector int b) +{ + return (a != b) ? max_(a, b) : max_(a, a); +} +vector int f_min(vector int a, vector int b) +{ + return (a != b) ? min_(a, b) : min_(a, a); +} +vector int f_mult(vector int a, vector int b) +{ + return (a != b) ? a * b : (a * a); +} +vector int f_plus(vector int a, vector int b) +{ + return (a != b) ? a + b : (a + a); +} +vector int f_plus_alt(vector int a, vector int b) +{ + return (a != b) ? a + b : (a * 2); +} + +/* All of the above function's VEC_COND_EXPR should have been optimized away. */ +/* { dg-final { scan-tree-dump-not "VEC_COND_EXPR " "ccp1" } } */ +/* { dg-final { scan-tree-dump-not "VEC_COND_EXPR " "optimized" } } */ diff --git a/gcc/testsuite/g++.dg/special/initpri3.C b/gcc/testsuite/g++.dg/special/initpri3.C index 3d745a42a6a4..63ed3208228d 100644 --- a/gcc/testsuite/g++.dg/special/initpri3.C +++ b/gcc/testsuite/g++.dg/special/initpri3.C @@ -7,4 +7,4 @@ #endif struct A { A(); } a __attribute__((init_priority(500))); -// { dg-warning "attribute directive ignored" "" { target { ! init_priority } } .-1 } +// { dg-warning "attribute ignored" "" { target { ! init_priority } } .-1 } diff --git a/gcc/testsuite/g++.dg/torture/pr111019.C b/gcc/testsuite/g++.dg/torture/pr111019.C new file mode 100644 index 000000000000..ce21a311c96e --- /dev/null +++ b/gcc/testsuite/g++.dg/torture/pr111019.C @@ -0,0 +1,65 @@ +// { dg-do run } +// { dg-additional-options "-fstrict-aliasing" } + +#include +#include +#include + +class Base +{ +public: + Base* previous = nullptr; + Base* next = nullptr; + Base* target = nullptr; +}; + +class Target : public Base +{ +public: + __attribute__((always_inline)) ~Target() + { + while (this->next) + { + Base* n = this->next; + + if (n->previous) + n->previous->next = n->next; + if (n->next) + n->next->previous = n->previous; + n->previous = nullptr; + n->next = nullptr; + n->target = nullptr; + } + } +}; + +template +class TargetWithData final : public Target +{ +public: + TargetWithData(T data) + : data(data) + {} + T data; +}; + +void test() +{ + printf("test\n"); + Base ptr; + { + auto data = std::make_unique>(std::string("asdf")); + ptr.target = &*data; + ptr.previous = &*data; + data->next = &ptr; + + assert(ptr.target != nullptr); + } + assert(ptr.target == nullptr); +} + +int main(int, char**) +{ + test(); + return 0; +} diff --git a/gcc/testsuite/g++.dg/vect/slp-pr87105.cc b/gcc/testsuite/g++.dg/vect/slp-pr87105.cc index d07b1cd46b77..17017686792b 100644 --- a/gcc/testsuite/g++.dg/vect/slp-pr87105.cc +++ b/gcc/testsuite/g++.dg/vect/slp-pr87105.cc @@ -99,7 +99,7 @@ void quadBoundingBoxA(const Point bez[3], Box& bBox) noexcept { // We should have if-converted everything down to straight-line code // { dg-final { scan-tree-dump-times "" 1 "slp2" } } -// { dg-final { scan-tree-dump-times "basic block part vectorized" 1 "slp2" { xfail { { ! vect_element_align } && { ! vect_hw_misalign } } } } } +// { dg-final { scan-tree-dump-times "Basic block will be vectorized using SLP" 1 "slp2" { xfail { { ! vect_element_align } && { ! vect_hw_misalign } } } } } // It's a bit awkward to detect that all stores were vectorized but the // following more or less does the trick // { dg-final { scan-tree-dump "vect_\[^\r\m\]* = MIN" "slp2" { xfail { { ! vect_element_align } && { ! vect_hw_misalign } } } } } diff --git a/gcc/testsuite/g++.dg/warn/Wuninitialized-pr111123-1.C b/gcc/testsuite/g++.dg/warn/Wuninitialized-pr111123-1.C new file mode 100644 index 000000000000..17a6f2b28d88 --- /dev/null +++ b/gcc/testsuite/g++.dg/warn/Wuninitialized-pr111123-1.C @@ -0,0 +1,20 @@ +// { dg-do compile } +// { dg-require-effective-target c++11 } +// { dg-options "-O -Wuninitialized" } + +#include + +struct Camera { + struct P2d { + float x, y; + }; + std::vector clip_area; + float border = 10.f; + [[gnu::noinline]] Camera() : clip_area({{border,border}}) { } // { dg-warning "uninitialized" } +}; + +Camera foo() +{ + Camera c; + return c; +} diff --git a/gcc/testsuite/g++.target/i386/pr94866.C b/gcc/testsuite/g++.target/i386/pr94866.C new file mode 100644 index 000000000000..eb0f5ef11c56 --- /dev/null +++ b/gcc/testsuite/g++.target/i386/pr94866.C @@ -0,0 +1,13 @@ +// PR target/94866 +// { dg-do compile } +// { dg-options "-O2 -msse4.1" } +// { dg-require-effective-target c++11 } + +typedef long long v2di __attribute__((vector_size(16))); + +v2di _mm_move_epi64(v2di a) +{ + return v2di{a[0], 0LL}; +} + +// { dg-final { scan-assembler-times "movq\[ \\t\]+\[^\n\]*%xmm" 1 } } diff --git a/gcc/testsuite/gcc.c-torture/compile/pr106537-1.c b/gcc/testsuite/gcc.c-torture/compile/pr106537-1.c new file mode 100644 index 000000000000..b67b6090dc38 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/compile/pr106537-1.c @@ -0,0 +1,36 @@ +/* { dg-do compile } + { dg-options "-O0" } + This testcase checks that warn_compare_distinct_pointer_types is enabled by + default. */ + +typedef int __u32; + +struct xdp_md +{ + char *data; + char *data_meta; +}; + +int xdp_context (struct xdp_md *xdp) +{ + void *data = (void *)(long)xdp->data; + __u32 *metadata = (void *)(long)xdp->data_meta; + __u32 ret; + + if (metadata + 1 > data) /* { dg-warning "comparison of distinct pointer types" } */ + return 1; + if (metadata + 1 >= data) /* { dg-warning "comparison of distinct pointer types" } */ + return 2; + if (metadata + 1 < data) /* { dg-warning "comparison of distinct pointer types" } */ + return 3; + if (metadata + 1 <= data) /* { dg-warning "comparison of distinct pointer types" } */ + return 4; + /* Note that it is ok to check for equality or inequality betewen void + pointers and any other non-function pointers. */ + if ((int*) (metadata + 1) == (long*) data) /* { dg-warning "comparison of distinct pointer types" } */ + return 5; + if ((int*) metadata + 1 != (long*) data) /* { dg-warning "comparison of distinct pointer types" } */ + return 5; + + return 1; +} diff --git a/gcc/testsuite/gcc.c-torture/compile/pr106537-2.c b/gcc/testsuite/gcc.c-torture/compile/pr106537-2.c new file mode 100644 index 000000000000..d4223c25c949 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/compile/pr106537-2.c @@ -0,0 +1,34 @@ +/* { dg-do compile } */ +/* { dg-options "-Wcompare-distinct-pointer-types" } */ + +typedef int __u32; + +struct xdp_md +{ + char *data; + char *data_meta; +}; + +int xdp_context (struct xdp_md *xdp) +{ + void *data = (void *)(long)xdp->data; + __u32 *metadata = (void *)(long)xdp->data_meta; + __u32 ret; + + if (metadata + 1 > data) /* { dg-warning "comparison of distinct pointer types" } */ + return 1; + if (metadata + 1 >= data) /* { dg-warning "comparison of distinct pointer types" } */ + return 2; + if (metadata + 1 < data) /* { dg-warning "comparison of distinct pointer types" } */ + return 3; + if (metadata + 1 <= data) /* { dg-warning "comparison of distinct pointer types" } */ + return 4; + /* Note that it is ok to check for equality or inequality betewen void + pointers and any other non-function pointers. */ + if ((int*) (metadata + 1) == (long*) data) /* { dg-warning "comparison of distinct pointer types" } */ + return 5; + if ((int*) metadata + 1 != (long*) data) /* { dg-warning "comparison of distinct pointer types" } */ + return 5; + + return 1; +} diff --git a/gcc/testsuite/gcc.c-torture/compile/pr106537-3.c b/gcc/testsuite/gcc.c-torture/compile/pr106537-3.c new file mode 100644 index 000000000000..73c9b251824d --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/compile/pr106537-3.c @@ -0,0 +1,32 @@ +/* { dg-do compile } */ +/* { dg-options "-O0 -Wno-compare-distinct-pointer-types" } */ + +typedef int __u32; + +struct xdp_md +{ + char *data; + char *data_meta; +}; + +int xdp_context (struct xdp_md *xdp) +{ + void *data = (void *)(long)xdp->data; + __u32 *metadata = (void *)(long)xdp->data_meta; + __u32 ret; + + if (metadata + 1 > data) /* There shouldn't be a warning here. */ + return 1; + if (metadata + 1 >= data) /* There shouldn't be a warning here. */ + return 2; + if (metadata + 1 < data) /* There shouldn't be a warning here. */ + return 3; + if (metadata + 1 <= data) /* There shouldn't be a warning here. */ + return 4; + if (metadata + 1 == data) /* There shouldn't be a warning here. */ + return 5; + if (metadata + 1 != data) /* There shouldn't be a warning here. */ + return 5; + + return 1; +} diff --git a/gcc/testsuite/gcc.c-torture/compile/pr110940.c b/gcc/testsuite/gcc.c-torture/compile/pr110940.c new file mode 100644 index 000000000000..c23c5ee81359 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/compile/pr110940.c @@ -0,0 +1,19 @@ +int a, b[1], c, *d = &a, e, f, g, h, i, j; +extern int l(); +int main() { + if (l()) + for (;;) + for (; g;) + for (; e;) + for (; a;) + for (; f;) + for (; h;) + for (; i;) + for (; c;) + for (; j;) + ; + l(); + for (; c; c++) + b[*d] = 0; + return 0; +} diff --git a/gcc/testsuite/gcc.c-torture/execute/ieee/fp-cmp-cond-1.c b/gcc/testsuite/gcc.c-torture/execute/ieee/fp-cmp-cond-1.c new file mode 100644 index 000000000000..4a3c4b0eee29 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/ieee/fp-cmp-cond-1.c @@ -0,0 +1,78 @@ +/* PR tree-optimization/111109 */ + +/* + f should return 0 if either fa and fb are a nan. + Rather than the value of a or b. +*/ +__attribute__((noipa)) +int f(int a, int b, float fa, float fb) { + const _Bool c = fa < fb; + const _Bool c1 = fa >= fb; + return (c * a) | (c1 * b); +} + +/* + f1 should return 0 if either fa and fb are a nan. + Rather than the value of a&1 or b&1. +*/ +__attribute__((noipa)) +int f1(int a, int b, float fa, float fb) { + const _Bool c = fa < fb; + const _Bool c1 = fa >= fb; + return (c & a) | (c1 & b); +} + +#if __SIZEOF_INT__ == __SIZEOF_FLOAT__ +typedef int v4si __attribute__ ((vector_size (1*sizeof(int)))); +typedef float v4sf __attribute__ ((vector_size (1*sizeof(float)))); +/* + fvf0 should return {0} if either fa and fb are a nan. + Rather than the value of a or b. +*/ +__attribute__((noipa)) +v4si vf0(v4si a, v4si b, v4sf fa, v4sf fb) { + const v4si c = fa < fb; + const v4si c1 = fa >= fb; + return (c & a) | (c1 & b); +} + + +#endif + +int main(void) +{ + float a = __builtin_nan(""); + + if (f(-1,-1, a, a) != 0) + __builtin_abort(); + if (f(-1,-1, a, 0) != 0) + __builtin_abort(); + if (f(-1,-1, 0, a) != 0) + __builtin_abort(); + if (f(-1,-1, 0, 0) != -1) + __builtin_abort(); + + + if (f1(1,1, a, a) != 0) + __builtin_abort(); + if (f1(1,1, a, 0) != 0) + __builtin_abort(); + if (f1(1,1, 0, a) != 0) + __builtin_abort(); + if (f1(1,1, 0, 0) != 1) + __builtin_abort(); + +#if __SIZEOF_INT__ == __SIZEOF_FLOAT__ + v4si b = {-1}; + v4sf c = {a}; + v4sf d = {0.0}; + if (vf0(b,b, c, c)[0] != 0) + __builtin_abort(); + if (vf0(b,b, c, d)[0] != 0) + __builtin_abort(); + if (vf0(b,b, d, c)[0] != 0) + __builtin_abort(); + if (vf0(b,b, d, d)[0] != b[0]) + __builtin_abort(); +#endif +} diff --git a/gcc/testsuite/gcc.c-torture/execute/pr109938.c b/gcc/testsuite/gcc.c-torture/execute/pr109938.c new file mode 100644 index 000000000000..a65d13b305dc --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/pr109938.c @@ -0,0 +1,33 @@ +/* PR tree-opt/109938 */ + +#include "../../gcc.dg/tree-ssa/pr109938.c" + +int +main () +{ + if (t1 (29789, 29477, 23942) != 30045) __builtin_abort (); + if (t2 (-20196, 18743, -32901) != -1729) __builtin_abort (); + if (t3 (2136614690L, 1136698390L, 2123767997L) != 2145003318UL) __builtin_abort (); + if (t4 (-4878, 9977, 23313) != 61171) __builtin_abort (); + if (t5 (127, 99, 43) != 127) __builtin_abort (); + if (t6 (9176690219839792930LL, 3176690219839721234LL, 5671738468274920831LL) + != 9177833729112616754LL) __builtin_abort (); + if (t7 (29789, 29477, 23942) != 30045) __builtin_abort (); + if (t8 (23489, 99477, 87942) != 90053) __builtin_abort (); + if (t9 (10489, 66477, -73313) != 10749) __builtin_abort (); + if (t10 (2136614690L, -1136614690L, 4136614690UL) != 4284131106UL) + __builtin_abort (); + if (t11 (29789, 29477, 12345) != 29821) __builtin_abort (); + if (t12 (-120, 98, -73) != 170) __builtin_abort (); + if (t13 (9176690219839792930ULL, -3176690219839721234LL, 5671738468274920831ULL) + != 9221726284835125102ULL) __builtin_abort (); + v4si a1 = {29789, -20196, 23489, 10489}; + v4si a2 = {29477, 18743, 99477, 66477}; + v4si a3 = {23942, -32901, 87942, -73313}; + v4si r1 = {30045, 63807, 90053, 10749}; + v4si b1 = t14 (a1, a2, a3); + v4si b2 = t15 (a1, a2, a3); + if (__builtin_memcmp (&b1, &r1, sizeof (b1) != 0)) __builtin_abort(); + if (__builtin_memcmp (&b2, &r1, sizeof (b2) != 0)) __builtin_abort(); + return 0; +} diff --git a/gcc/testsuite/gcc.c-torture/execute/pr110914.c b/gcc/testsuite/gcc.c-torture/execute/pr110914.c new file mode 100644 index 000000000000..ccc04e1bdd41 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/pr110914.c @@ -0,0 +1,22 @@ +/* PR tree-optimization/110914 */ + +__attribute__ ((noipa)) int +foo (const char *s, unsigned long l) +{ + unsigned char r = 0; + __builtin_memcpy (&r, s, l != 0); + return r; +} + +int +main () +{ + const char *p = "123456"; + int a = foo (p, __builtin_strlen (p) - 5); + int b = foo (p, __builtin_strlen (p) - 6); + if (a != '1') + __builtin_abort (); + if (b != 0) + __builtin_abort (); + return 0; +} diff --git a/gcc/testsuite/gcc.c-torture/execute/pr110954-1.c b/gcc/testsuite/gcc.c-torture/execute/pr110954-1.c new file mode 100644 index 000000000000..8aad758e10f8 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/pr110954-1.c @@ -0,0 +1,10 @@ + +#define comparison (f < 0) +int main() { + int f = 0; + int d = comparison | !comparison; + if (d != 1) + __builtin_abort(); + return 0; +} + diff --git a/gcc/testsuite/gcc.dg/Wfree-nonheap-object-7.c b/gcc/testsuite/gcc.dg/Wfree-nonheap-object-7.c new file mode 100644 index 000000000000..6116bfa4d8ea --- /dev/null +++ b/gcc/testsuite/gcc.dg/Wfree-nonheap-object-7.c @@ -0,0 +1,26 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -Wfree-nonheap-object" } */ + +struct local_caches *get_local_caches_lcs; +void *calloc(long, long); +void *realloc(); + +struct local_caches { + int *t_mem_caches; +}; + +struct local_caches *get_local_caches() { + if (get_local_caches_lcs) + return get_local_caches_lcs; + get_local_caches_lcs = calloc(1, 0); + return get_local_caches_lcs; +} + +void libtrace_ocache_free() { + struct local_caches lcs = *get_local_caches(), __trans_tmp_1 = lcs; + { + struct local_caches *lcs = &__trans_tmp_1; + lcs->t_mem_caches += 10; + __trans_tmp_1.t_mem_caches = realloc(__trans_tmp_1.t_mem_caches, sizeof(int)); // { dg-warning "called on pointer (?:(?!PHI).)*nonzero offset" } + } +} diff --git a/gcc/testsuite/gcc.dg/Wuseless-cast.c b/gcc/testsuite/gcc.dg/Wuseless-cast.c new file mode 100644 index 000000000000..86e87584b87d --- /dev/null +++ b/gcc/testsuite/gcc.dg/Wuseless-cast.c @@ -0,0 +1,26 @@ +/* { dg-do compile } */ +/* { dg-options "-Wuseless-cast" } */ + +void foo(void) +{ + // casts to the same type + int i = 0; + const int ic = 0; + struct foo { int x; } x = { 0 }; + int q[3]; + (int)ic; /* { dg-warning "useless cast" } */ + (int)i; /* { dg-warning "useless cast" } */ + (const int)ic; /* { dg-warning "useless cast" } */ + (const int)i; /* { dg-warning "useless cast" } */ + (struct foo)x; /* { dg-warning "useless cast" } */ + (int(*)[3])&q; /* { dg-warning "useless cast" } */ + (_Atomic(int))i; /* { dg-warning "useless cast" } */ + + // not the same + int n = 3; + (int(*)[n])&q; // no warning + int j = (int)0UL; + enum X { A = 1 } xx = { A }; + enum Y { B = 1 } yy = (enum Y)xx; +} + diff --git a/gcc/testsuite/gcc.dg/analyzer/allocation-size-1.c b/gcc/testsuite/gcc.dg/analyzer/allocation-size-1.c index dcffc1175cf8..003914ed96cd 100644 --- a/gcc/testsuite/gcc.dg/analyzer/allocation-size-1.c +++ b/gcc/testsuite/gcc.dg/analyzer/allocation-size-1.c @@ -16,7 +16,8 @@ void test_2 (void) free (ptr); /* { dg-warning "allocated buffer size is not a multiple of the pointee's size \\\[CWE-131\\\]" "warning" { target *-*-* } malloc2 } */ - /* { dg-message "allocated 42 bytes and assigned to 'int32_t \\*' (\\\{aka '(long )?int \\*'\\\})? here; 'sizeof \\(int32_t (\\\{aka (long )?int\\\})?\\)' is '4'" "note" { target *-*-* } malloc2 } */ + /* { dg-message "42 bytes" "note" { target *-*-* } malloc2 } */ + /* { dg-message "'int32_t \\*' (\\\{aka '(long )?int \\*'\\\})? here; 'sizeof \\(int32_t (\\\{aka (long )?int\\\})?\\)' is '4'" "note" { target *-*-* } malloc2 } */ } void test_3 (void) diff --git a/gcc/testsuite/gcc.dg/analyzer/allocation-size-2.c b/gcc/testsuite/gcc.dg/analyzer/allocation-size-2.c index d26c2672531b..eb770f73d4a4 100644 --- a/gcc/testsuite/gcc.dg/analyzer/allocation-size-2.c +++ b/gcc/testsuite/gcc.dg/analyzer/allocation-size-2.c @@ -19,7 +19,8 @@ void test_2 (int32_t n) free (ptr); /* { dg-warning "allocated buffer size is not a multiple of the pointee's size \\\[CWE-131\\\]" "warning" { target *-*-* } malloc2 } */ - /* { dg-message "allocated '\[a-z0-9\\*\\(\\)\\s\]*' bytes and assigned to 'int32_t \\*' (\\\{aka '(long )?int \\*'\\\})? here; 'sizeof \\(int32_t (\\\{aka (long )?int\\\})?\\)' is '4" "note" { target *-*-* } malloc2 } */ + /* { dg-message "'\[a-z0-9\\*\\(\\)\\s\]*' bytes" "note" { target *-*-* } malloc2 } */ + /* { dg-message "'int32_t \\*' (\\\{aka '(long )?int \\*'\\\})? here; 'sizeof \\(int32_t (\\\{aka (long )?int\\\})?\\)' is '4" "note" { target *-*-* } malloc2 } */ } void test_3 (int32_t n) diff --git a/gcc/testsuite/gcc.dg/analyzer/allocation-size-3.c b/gcc/testsuite/gcc.dg/analyzer/allocation-size-3.c index 6b753073008e..6751441dd18f 100644 --- a/gcc/testsuite/gcc.dg/analyzer/allocation-size-3.c +++ b/gcc/testsuite/gcc.dg/analyzer/allocation-size-3.c @@ -20,7 +20,8 @@ void test_1 (void) free (id_sequence); /* { dg-warning "allocated buffer size is not a multiple of the pointee's size \\\[CWE-131\\\]" "warning" { target *-*-* } malloc1 } */ - /* { dg-message "allocated 3 bytes and assigned to 'int32_t \\*' (\\\{aka '(long )?int \\*'\\\})? here; 'sizeof \\(int32_t (\\\{aka (long )?int\\\})?\\)' is '4'" "note" { target *-*-* } malloc1 } */ + /* { dg-message "3 bytes" "note" { target *-*-* } malloc1 } */ + /* { dg-message "'int32_t \\*' (\\\{aka '(long )?int \\*'\\\})? here; 'sizeof \\(int32_t (\\\{aka (long )?int\\\})?\\)' is '4'" "note" { target *-*-* } malloc1 } */ } void test_2 (void) @@ -29,7 +30,8 @@ void test_2 (void) free (ptr); /* { dg-warning "allocated buffer size is not a multiple of the pointee's size \\\[CWE-131\\\]" "warning" { target *-*-* } malloc2 } */ - /* { dg-message "allocated 14 bytes and assigned to 'int32_t \\*' (\\\{aka '(long )?int \\*'\\\})? here; 'sizeof \\(int32_t (\\\{aka (long )?int\\\})?\\)' is '4'" "note" { target *-*-* } malloc2 } */ + /* { dg-message "14 bytes" "note" { target *-*-* } malloc2 } */ + /* { dg-message "'int32_t \\*' (\\\{aka '(long )?int \\*'\\\})? here; 'sizeof \\(int32_t (\\\{aka (long )?int\\\})?\\)' is '4'" "note" { target *-*-* } malloc2 } */ } void test_3 (int32_t n) @@ -38,7 +40,8 @@ void test_3 (int32_t n) free (ptr); /* { dg-warning "allocated buffer size is not a multiple of the pointee's size \\\[CWE-131\\\]" "warning" { target *-*-* } malloc3 } */ - /* { dg-message "allocated '\[a-z0-9\\+\\(\\)\\s\]*' bytes and assigned to 'int32_t \\*' (\\\{aka '(long )?int \\*'\\\})? here; 'sizeof \\(int32_t (\\\{aka (long )?int\\\})?\\)' is '4'" "note" { target *-*-* } malloc3 } */ + /* { dg-message "'\[a-z0-9\\+\\(\\)\\s\]*' bytes" "note" { target *-*-* } malloc3 } */ + /* { dg-message "'int32_t \\*' (\\\{aka '(long )?int \\*'\\\})? here; 'sizeof \\(int32_t (\\\{aka (long )?int\\\})?\\)' is '4'" "note" { target *-*-* } malloc3 } */ } void test_4 (int32_t n, int32_t m) diff --git a/gcc/testsuite/gcc.dg/analyzer/allocation-size-4.c b/gcc/testsuite/gcc.dg/analyzer/allocation-size-4.c index 642e8f5f4967..a56b25b4374d 100644 --- a/gcc/testsuite/gcc.dg/analyzer/allocation-size-4.c +++ b/gcc/testsuite/gcc.dg/analyzer/allocation-size-4.c @@ -30,7 +30,8 @@ void test_2 (void) free (ptr); /* { dg-warning "allocated buffer size is not a multiple of the pointee's size \\\[CWE-131\\\]" "warning" { target *-*-* } malloc2 } */ - /* { dg-message "allocated \\d+ bytes and assigned to 'int32_t \\*' (\\\{aka '(long )?int \\*'\\\})? here; 'sizeof \\(int32_t (\\\{aka (long )?int\\\})?\\)' is '4'" "note" { target *-*-* } malloc2 } */ + /* { dg-message "\\d+ bytes" "note" { target *-*-* } malloc2 } */ + /* { dg-message "'int32_t \\*' (\\\{aka '(long )?int \\*'\\\})? here; 'sizeof \\(int32_t (\\\{aka (long )?int\\\})?\\)' is '4'" "note" { target *-*-* } malloc2 } */ } void test_3 (void) @@ -55,5 +56,6 @@ void test_5 (void) free (ptr); /* { dg-warning "allocated buffer size is not a multiple of the pointee's size \\\[CWE-131\\\]" "warning" { target *-*-* } malloc5 } */ - /* { dg-message "allocated 1 bytes and assigned to 'struct base \\*' here; 'sizeof \\(struct base\\)' is '\\d+'" "note" { target *-*-* } malloc5 } */ + /* { dg-message "allocated 1 byte here" "note" { target *-*-* } malloc5 } */ + /* { dg-message "'struct base \\*' here; 'sizeof \\(struct base\\)' is '\\d+'" "note" { target *-*-* } malloc5 } */ } diff --git a/gcc/testsuite/gcc.dg/analyzer/allocation-size-multiline-1.c b/gcc/testsuite/gcc.dg/analyzer/allocation-size-multiline-1.c deleted file mode 100644 index 9938ba237a08..000000000000 --- a/gcc/testsuite/gcc.dg/analyzer/allocation-size-multiline-1.c +++ /dev/null @@ -1,57 +0,0 @@ -/* { dg-additional-options "-fdiagnostics-path-format=inline-events -fdiagnostics-show-caret" } */ - -#include - -void test_constant_1 (void) -{ - int32_t *ptr = __builtin_malloc (1); /* { dg-warning "allocated buffer size is not a multiple of the pointee's size" } */ - __builtin_free (ptr); -} - -/* { dg-begin-multiline-output "" } - int32_t *ptr = __builtin_malloc (1); - ^~~~~~~~~~~~~~~~~~~~ - 'test_constant_1': event 1 - | - | int32_t *ptr = __builtin_malloc (1); - | ^~~~~~~~~~~~~~~~~~~~ - | | - | (1) allocated 1 bytes and assigned to 'int32_t *' {aka 'int *'} here; 'sizeof (int32_t {aka int})' is '4' - | - { dg-end-multiline-output "" } */ - -void test_constant_2 (void) -{ - int32_t *ptr = __builtin_malloc (2); /* { dg-warning "allocated buffer size is not a multiple of the pointee's size" } */ - __builtin_free (ptr); -} - -/* { dg-begin-multiline-output "" } - int32_t *ptr = __builtin_malloc (2); - ^~~~~~~~~~~~~~~~~~~~ - 'test_constant_2': event 1 - | - | int32_t *ptr = __builtin_malloc (2); - | ^~~~~~~~~~~~~~~~~~~~ - | | - | (1) allocated 2 bytes and assigned to 'int32_t *' {aka 'int *'} here; 'sizeof (int32_t {aka int})' is '4' - | - { dg-end-multiline-output "" } */ - -void test_symbolic (int n) -{ - int32_t *ptr = __builtin_malloc (n * 2); /* { dg-warning "allocated buffer size is not a multiple of the pointee's size" } */ - __builtin_free (ptr); -} - -/* { dg-begin-multiline-output "" } - int32_t *ptr = __builtin_malloc (n * 2); - ^~~~~~~~~~~~~~~~~~~~~~~~ - 'test_symbolic': event 1 - | - | int32_t *ptr = __builtin_malloc (n * 2); - | ^~~~~~~~~~~~~~~~~~~~~~~~ - | | - | (1) allocated 'n * 2' bytes and assigned to 'int32_t *' {aka 'int *'} here; 'sizeof (int32_t {aka int})' is '4' - | - { dg-end-multiline-output "" } */ diff --git a/gcc/testsuite/gcc.dg/analyzer/allocation-size-multiline-2.c b/gcc/testsuite/gcc.dg/analyzer/allocation-size-multiline-2.c deleted file mode 100644 index 9e1269cbb7a5..000000000000 --- a/gcc/testsuite/gcc.dg/analyzer/allocation-size-multiline-2.c +++ /dev/null @@ -1,59 +0,0 @@ -/* { dg-additional-options "-fdiagnostics-path-format=inline-events -fdiagnostics-show-caret -fanalyzer-fine-grained" } */ -/* { dg-require-effective-target alloca } */ - -#include - -void test_constant_1 (void) -{ - int32_t *ptr = __builtin_alloca (1); /* { dg-warning "allocated buffer size is not a multiple of the pointee's size" } */ -} - -/* { dg-begin-multiline-output "" } - int32_t *ptr = __builtin_alloca (1); - ^~~~~~~~~~~~~~~~~~~~ - 'test_constant_1': event 1 - | - | int32_t *ptr = __builtin_alloca (1); - | ^~~~~~~~~~~~~~~~~~~~ - | | - | (1) allocated 1 bytes and assigned to 'int32_t *' {aka 'int *'} here; 'sizeof (int32_t {aka int})' is '4' - | - { dg-end-multiline-output "" } */ - -void test_constant_2 (void) -{ - int32_t *ptr = __builtin_alloca (2); /* { dg-warning "allocated buffer size is not a multiple of the pointee's size" } */ -} - -/* { dg-begin-multiline-output "" } - int32_t *ptr = __builtin_alloca (2); - ^~~~~~~~~~~~~~~~~~~~ - 'test_constant_2': event 1 - | - | int32_t *ptr = __builtin_alloca (2); - | ^~~~~~~~~~~~~~~~~~~~ - | | - | (1) allocated 2 bytes and assigned to 'int32_t *' {aka 'int *'} here; 'sizeof (int32_t {aka int})' is '4' - | - { dg-end-multiline-output "" } */ - -void test_symbolic (int n) -{ - int32_t *ptr = __builtin_alloca (n * 2); /* { dg-warning "allocated buffer size is not a multiple of the pointee's size" } */ -} - -/* { dg-begin-multiline-output "" } - int32_t *ptr = __builtin_alloca (n * 2); - ^~~~~~~~~~~~~~~~~~~~~~~~ - 'test_symbolic': event 1 - | - | int32_t *ptr = __builtin_alloca (n * 2); - | ^~~~~~~~~~~~~~~~~~~~~~~~ - | | - | (1) allocated 'n * 2' bytes and assigned to 'int32_t *' {aka 'int *'} here; 'sizeof (int32_t {aka int})' is '4' - | - { dg-end-multiline-output "" } */ - -/* FIXME: am getting a duplicate warning here for some reason - without -fanalyzer-fine-grained (PR PR analyzer/107851). */ - diff --git a/gcc/testsuite/gcc.dg/analyzer/allocation-size-multiline-3.c b/gcc/testsuite/gcc.dg/analyzer/allocation-size-multiline-3.c deleted file mode 100644 index 71790d91753b..000000000000 --- a/gcc/testsuite/gcc.dg/analyzer/allocation-size-multiline-3.c +++ /dev/null @@ -1,42 +0,0 @@ -/* Verify that we warn for incorrect uses of "alloca" (which may be in a - macro in a system header), and that the output looks correct. */ - -/* { dg-additional-options "-fdiagnostics-path-format=inline-events -fdiagnostics-show-caret -fanalyzer-fine-grained" } */ -/* { dg-require-effective-target alloca } */ - -#include -#include "test-alloca.h" - -void test_constant_99 (void) -{ - int32_t *ptr = alloca (99); /* { dg-warning "allocated buffer size is not a multiple of the pointee's size" } */ -} - -/* { dg-begin-multiline-output "" } - int32_t *ptr = alloca (99); - ^~~~~~ - 'test_constant_99': event 1 - | - | int32_t *ptr = alloca (99); - | ^~~~~~ - | | - | (1) allocated 99 bytes and assigned to 'int32_t *' {aka 'int *'} here; 'sizeof (int32_t {aka int})' is '4' - | - { dg-end-multiline-output "" } */ - -void test_symbolic (int n) -{ - int32_t *ptr = alloca (n * 2); /* { dg-warning "allocated buffer size is not a multiple of the pointee's size" } */ -} - -/* { dg-begin-multiline-output "" } - int32_t *ptr = alloca (n * 2); - ^~~~~~ - 'test_symbolic': event 1 - | - | int32_t *ptr = alloca (n * 2); - | ^~~~~~ - | | - | (1) allocated 'n * 2' bytes and assigned to 'int32_t *' {aka 'int *'} here; 'sizeof (int32_t {aka int})' is '4' - | - { dg-end-multiline-output "" } */ diff --git a/gcc/testsuite/gcc.dg/analyzer/analyzer-decls.h b/gcc/testsuite/gcc.dg/analyzer/analyzer-decls.h index d9a32ed93706..372a13608d09 100644 --- a/gcc/testsuite/gcc.dg/analyzer/analyzer-decls.h +++ b/gcc/testsuite/gcc.dg/analyzer/analyzer-decls.h @@ -1,6 +1,18 @@ #ifndef ANALYZER_DECLS_H #define ANALYZER_DECLS_H +#ifndef NULL +#ifdef __cplusplus +#if __cplusplus >= 201103L +#define NULL nullptr +#else +#define NULL 0 +#endif +#else +#define NULL ((void *)0) +#endif +#endif + /* Function decls with special meaning to the analyzer. None of these are actually implemented. */ @@ -53,4 +65,9 @@ extern void __analyzer_eval (int); /* Obtain an "unknown" void *. */ extern void *__analyzer_get_unknown_ptr (void); +/* Complain if PTR doesn't point to a null-terminated string. + TODO: eventually get the strlen of the buffer (without the + optimizer touching it). */ +extern __SIZE_TYPE__ __analyzer_get_strlen (const char *ptr); + #endif /* #ifndef ANALYZER_DECLS_H. */ diff --git a/gcc/testsuite/gcc.dg/analyzer/analyzer.exp b/gcc/testsuite/gcc.dg/analyzer/analyzer.exp index 76569267af0d..cedf3c0466fd 100644 --- a/gcc/testsuite/gcc.dg/analyzer/analyzer.exp +++ b/gcc/testsuite/gcc.dg/analyzer/analyzer.exp @@ -32,6 +32,14 @@ if [info exists DEFAULT_CFLAGS] then { # If a testcase doesn't have special options, use these. set DEFAULT_CFLAGS "-fanalyzer -Wanalyzer-too-complex -fanalyzer-call-summaries" +if { [istarget "*-*-darwin*" ] } { + # On macOS, system headers redefine by default some macros (memcpy, + # memmove, etc) to checked versions, which defeats the analyzer. We + # want to turn this off. + # See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=104042 + set DEFAULT_CFLAGS "$DEFAULT_CFLAGS -D_FORTIFY_SOURCE=0" +} + # Initialize `dg'. dg-init @@ -39,6 +47,9 @@ dg-init dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.\[cS\]]] \ "" $DEFAULT_CFLAGS +dg-runtest [lsort [glob -nocomplain $srcdir/c-c++-common/analyzer/*.\[cS\]]] \ + "" $DEFAULT_CFLAGS + # All done. dg-finish diff --git a/gcc/testsuite/gcc.dg/analyzer/attr-format-1.c b/gcc/testsuite/gcc.dg/analyzer/attr-format-1.c new file mode 100644 index 000000000000..c7fa705585d7 --- /dev/null +++ b/gcc/testsuite/gcc.dg/analyzer/attr-format-1.c @@ -0,0 +1,31 @@ +extern int +my_printf (void *my_object, const char *my_format, ...) + __attribute__ ((format (printf, 2, 3))); +/* { dg-message "parameter 2 of 'my_printf' marked as a format string via 'format' attribute" "attr note" { target *-*-* } .-2 } */ +/* { dg-message "argument 2 of 'my_printf' must be a pointer to a null-terminated string" "arg note" { target *-*-* } .-3 } */ + +int test_empty (void *my_object, const char *msg) +{ + return my_printf (my_object, ""); +} + +int test_percent_s (void *my_object, const char *msg) +{ + return my_printf (my_object, "%s\n", msg); +} + +int +test_unterminated_format (void *my_object) +{ + char fmt[3] = "abc"; + return my_printf (my_object, fmt); /* { dg-warning "stack-based buffer over-read" } */ + /* { dg-message "while looking for null terminator for argument 2 \\('&fmt'\\) of 'my_printf'..." "event" { target *-*-* } .-1 } */ +} + +int +test_uninitialized_format (void *my_object) +{ + char fmt[10]; + return my_printf (my_object, fmt); /* { dg-warning "use of uninitialized value 'fmt\\\[0\\\]'" } */ + /* { dg-message "while looking for null terminator for argument 2 \\('&fmt'\\) of 'my_printf'..." "event" { target *-*-* } .-1 } */ +} diff --git a/gcc/testsuite/gcc.dg/analyzer/data-model-11.c b/gcc/testsuite/gcc.dg/analyzer/data-model-11.c deleted file mode 100644 index 27663247c327..000000000000 --- a/gcc/testsuite/gcc.dg/analyzer/data-model-11.c +++ /dev/null @@ -1,6 +0,0 @@ -int test (void) -{ - unsigned char *s = "abc"; - char *t = "xyz"; - return s[1] + t[1]; -} diff --git a/gcc/testsuite/gcc.dg/analyzer/error-1.c b/gcc/testsuite/gcc.dg/analyzer/error-1.c index f82a4cdd3c09..794a9ae7b42d 100644 --- a/gcc/testsuite/gcc.dg/analyzer/error-1.c +++ b/gcc/testsuite/gcc.dg/analyzer/error-1.c @@ -64,3 +64,31 @@ void test_6 (int st, const char *str) error (st, errno, "test: %s", str); __analyzer_eval (st == 0); /* { dg-warning "TRUE" } */ } + +char *test_error_unterminated (int st) +{ + char fmt[3] = "abc"; + error (st, errno, fmt); /* { dg-warning "stack-based buffer over-read" } */ + /* { dg-message "while looking for null terminator for argument 3 \\('&fmt'\\) of 'error'..." "event" { target *-*-* } .-1 } */ +} + +char *test_error_at_line_unterminated (int st, int errno) +{ + char fmt[3] = "abc"; + error_at_line (st, errno, __FILE__, __LINE__, fmt); /* { dg-warning "stack-based buffer over-read" } */ + /* { dg-message "while looking for null terminator for argument 5 \\('&fmt'\\) of 'error_at_line'..." "event" { target *-*-* } .-1 } */ +} + +char *test_error_uninitialized (int st, int errno) +{ + char fmt[16]; + error (st, errno, fmt); /* { dg-warning "use of uninitialized value 'fmt\\\[0\\\]'" } */ + /* { dg-message "while looking for null terminator for argument 3 \\('&fmt'\\) of 'error'..." "event" { target *-*-* } .-1 } */ +} + +char *test_error_at_line_uninitialized (int st, int errno) +{ + char fmt[16]; + error_at_line (st, errno, __FILE__, __LINE__, fmt); /* { dg-warning "use of uninitialized value 'fmt\\\[0\\\]'" } */ + /* { dg-message "while looking for null terminator for argument 5 \\('&fmt'\\) of 'error_at_line'..." "event" { target *-*-* } .-1 } */ +} diff --git a/gcc/testsuite/gcc.dg/analyzer/fd-bind.c b/gcc/testsuite/gcc.dg/analyzer/fd-bind.c index 184a471f0b23..2a5cee582301 100644 --- a/gcc/testsuite/gcc.dg/analyzer/fd-bind.c +++ b/gcc/testsuite/gcc.dg/analyzer/fd-bind.c @@ -1,6 +1,7 @@ /* { dg-require-effective-target sockets } */ /* { dg-skip-if "" { powerpc*-*-aix* } } */ +#include #include #include #include diff --git a/gcc/testsuite/gcc.dg/analyzer/fd-datagram-socket.c b/gcc/testsuite/gcc.dg/analyzer/fd-datagram-socket.c index 6546df1962ca..59e80c831e3e 100644 --- a/gcc/testsuite/gcc.dg/analyzer/fd-datagram-socket.c +++ b/gcc/testsuite/gcc.dg/analyzer/fd-datagram-socket.c @@ -1,6 +1,7 @@ /* { dg-require-effective-target sockets } */ /* { dg-skip-if "" { powerpc*-*-aix* } } */ +#include #include #include #include diff --git a/gcc/testsuite/gcc.dg/analyzer/fd-listen.c b/gcc/testsuite/gcc.dg/analyzer/fd-listen.c index e47c3f628d1d..3ac7a990042c 100644 --- a/gcc/testsuite/gcc.dg/analyzer/fd-listen.c +++ b/gcc/testsuite/gcc.dg/analyzer/fd-listen.c @@ -1,6 +1,7 @@ /* { dg-require-effective-target sockets } */ /* { dg-skip-if "" { powerpc*-*-aix* } } */ +#include #include #include #include diff --git a/gcc/testsuite/gcc.dg/analyzer/fd-socket-misuse.c b/gcc/testsuite/gcc.dg/analyzer/fd-socket-misuse.c index 4b427d69a784..87e8967ff21b 100644 --- a/gcc/testsuite/gcc.dg/analyzer/fd-socket-misuse.c +++ b/gcc/testsuite/gcc.dg/analyzer/fd-socket-misuse.c @@ -3,6 +3,7 @@ /* { dg-require-effective-target sockets } */ /* { dg-skip-if "" { powerpc*-*-aix* } } */ +#include #include #include #include diff --git a/gcc/testsuite/gcc.dg/analyzer/fd-stream-socket-active-open.c b/gcc/testsuite/gcc.dg/analyzer/fd-stream-socket-active-open.c index 4ec582173608..b39dbf85c3de 100644 --- a/gcc/testsuite/gcc.dg/analyzer/fd-stream-socket-active-open.c +++ b/gcc/testsuite/gcc.dg/analyzer/fd-stream-socket-active-open.c @@ -1,6 +1,7 @@ /* { dg-require-effective-target sockets } */ /* { dg-skip-if "" { powerpc*-*-aix* } } */ +#include #include #include #include diff --git a/gcc/testsuite/gcc.dg/analyzer/fd-stream-socket-passive-open.c b/gcc/testsuite/gcc.dg/analyzer/fd-stream-socket-passive-open.c index 102e4350f457..e161098b96b0 100644 --- a/gcc/testsuite/gcc.dg/analyzer/fd-stream-socket-passive-open.c +++ b/gcc/testsuite/gcc.dg/analyzer/fd-stream-socket-passive-open.c @@ -5,6 +5,7 @@ /* { dg-require-effective-target sockets } */ /* { dg-skip-if "" { powerpc*-*-aix* } } */ +#include #include #include #include diff --git a/gcc/testsuite/gcc.dg/analyzer/fd-stream-socket.c b/gcc/testsuite/gcc.dg/analyzer/fd-stream-socket.c index d458708aea01..7e0e26ab40b5 100644 --- a/gcc/testsuite/gcc.dg/analyzer/fd-stream-socket.c +++ b/gcc/testsuite/gcc.dg/analyzer/fd-stream-socket.c @@ -1,6 +1,7 @@ /* { dg-require-effective-target sockets } */ /* { dg-skip-if "" { powerpc*-*-aix* } } */ +#include #include #include #include diff --git a/gcc/testsuite/gcc.dg/analyzer/fd-symbolic-socket.c b/gcc/testsuite/gcc.dg/analyzer/fd-symbolic-socket.c index 4479cc965abd..d7dc46a2d47c 100644 --- a/gcc/testsuite/gcc.dg/analyzer/fd-symbolic-socket.c +++ b/gcc/testsuite/gcc.dg/analyzer/fd-symbolic-socket.c @@ -1,6 +1,7 @@ /* { dg-require-effective-target sockets } */ /* { dg-skip-if "" { powerpc*-*-aix* } } */ +#include #include #include #include diff --git a/gcc/testsuite/gcc.dg/analyzer/fopen-1.c b/gcc/testsuite/gcc.dg/analyzer/fopen-1.c new file mode 100644 index 000000000000..e5b00e93b6da --- /dev/null +++ b/gcc/testsuite/gcc.dg/analyzer/fopen-1.c @@ -0,0 +1,66 @@ +typedef struct FILE FILE; +FILE *fopen (const char *pathname, const char *mode); +#define NULL ((void *)0) + +FILE * +test_passthrough (const char *pathname, const char *mode) +{ + return fopen (pathname, mode); +} + +FILE * +test_null_pathname (const char *pathname, const char *mode) +{ + return fopen (NULL, mode); +} + +FILE * +test_null_mode (const char *pathname) +{ + return fopen (pathname, NULL); +} + +FILE * +test_simple_r (void) +{ + return fopen ("foo.txt", "r"); +} + +FILE * +test_swapped_args (void) +{ + return fopen ("r", "foo.txt"); /* TODO: would be nice to detect this. */ +} + +FILE * +test_unterminated_pathname (const char *mode) +{ + char buf[3] = "abc"; + return fopen (buf, mode); /* { dg-warning "stack-based buffer over-read" } */ + /* { dg-message "while looking for null terminator for argument 1 \\('&buf'\\) of 'fopen'..." "event" { target *-*-* } .-1 } */ +} + +FILE * +test_unterminated_mode (const char *filename) +{ + char buf[3] = "abc"; + return fopen (filename, buf); /* { dg-warning "stack-based buffer over-read" } */ + /* { dg-message "while looking for null terminator for argument 2 \\('&buf'\\) of 'fopen'..." "event" { target *-*-* } .-1 } */ +} + +FILE * +test_uninitialized_pathname (const char *mode) +{ + char buf[10]; + return fopen (buf, mode); /* { dg-warning "use of uninitialized value 'buf\\\[0\\\]'" } */ + /* { dg-message "while looking for null terminator for argument 1 \\('&buf'\\) of 'fopen'..." "event" { target *-*-* } .-1 } */ +} + +FILE * +test_uninitialized_mode (const char *filename) +{ + char buf[10]; + return fopen (filename, buf); /* { dg-warning "use of uninitialized value 'buf\\\[0\\\]'" } */ + /* { dg-message "while looking for null terminator for argument 2 \\('&buf'\\) of 'fopen'..." "event" { target *-*-* } .-1 } */ +} + diff --git a/gcc/testsuite/gcc.dg/analyzer/memset-1.c b/gcc/testsuite/gcc.dg/analyzer/memset-1.c index 94c5a1b7c920..75aef53d3487 100644 --- a/gcc/testsuite/gcc.dg/analyzer/memset-1.c +++ b/gcc/testsuite/gcc.dg/analyzer/memset-1.c @@ -6,8 +6,9 @@ void test_1 (void) { char buf[256]; - memset (buf, 0, 256); + void *p = memset (buf, 0, 256); __analyzer_eval (buf[42] == 0); /* { dg-warning "TRUE" } */ + __analyzer_eval (p == buf); /* { dg-warning "TRUE" } */ } /* As above, but with __builtin_memset. */ diff --git a/gcc/testsuite/gcc.dg/analyzer/null-terminated-strings-1.c b/gcc/testsuite/gcc.dg/analyzer/null-terminated-strings-1.c new file mode 100644 index 000000000000..ecd794a2337a --- /dev/null +++ b/gcc/testsuite/gcc.dg/analyzer/null-terminated-strings-1.c @@ -0,0 +1,146 @@ +#include "analyzer-decls.h" + +#define NULL ((void *)0) +typedef __SIZE_TYPE__ size_t; + +void test_terminated (void) +{ + __analyzer_eval (__analyzer_get_strlen ("abc") == 3); /* { dg-warning "TRUE" } */ +} + +void test_unterminated (void) +{ + char buf[3] = "abc"; + __analyzer_get_strlen (buf); /* { dg-warning "stack-based buffer over-read" } */ + /* { dg-message "out-of-bounds read at byte 3 but 'buf' ends at byte 3" "bad read event" { target *-*-* } .-1 } */ + /* { dg-message "while looking for null terminator for argument 1 \\('&buf'\\) of '__analyzer_get_strlen'..." "null terminator event" { target *-*-* } .-2 } */ +} + +void test_embedded_nuls (void) +{ + /* 0123 456 78. */ + char buf[9] = "abc\0pq\0xy"; /* unterminated. */ + __analyzer_eval (__analyzer_get_strlen (buf) == 3); /* { dg-warning "TRUE" } */ + __analyzer_eval (__analyzer_get_strlen (buf + 1) == 2); /* { dg-warning "TRUE" } */ + __analyzer_eval (__analyzer_get_strlen (buf + 2) == 1); /* { dg-warning "TRUE" } */ + __analyzer_eval (__analyzer_get_strlen (buf + 3) == 0); /* { dg-warning "TRUE" } */ + __analyzer_eval (__analyzer_get_strlen (buf + 4) == 2); /* { dg-warning "TRUE" } */ + __analyzer_eval (__analyzer_get_strlen (buf + 5) == 1); /* { dg-warning "TRUE" } */ + __analyzer_eval (__analyzer_get_strlen (buf + 6) == 0); /* { dg-warning "TRUE" } */ + __analyzer_get_strlen (buf + 7); /* { dg-warning "stack-based buffer over-read" } */ + /* { dg-message "while looking for null terminator for argument 1 \\(''\\) of '__analyzer_get_strlen'..." "event" { target *-*-* } .-1 } */ + // TODO: fix the "" here? +} + +void test_before_start_of_buffer (void) +{ + const char *buf = "abc"; + __analyzer_get_strlen (buf - 1); /* { dg-warning "buffer under-read" } */ + /* { dg-message "while looking for null terminator for argument 1 \\(''\\) of '__analyzer_get_strlen'..." "event" { target *-*-* } .-1 } */ + // TODO: fix the "" here? +} + +void test_after_end_of_buffer (void) +{ + const char *buf = "abc"; + __analyzer_get_strlen (buf + 4); /* { dg-warning "buffer over-read" } */ + /* { dg-message "while looking for null terminator for argument 1 \\(''\\) of '__analyzer_get_strlen'..." "event" { target *-*-* } .-1 } */ + // TODO: fix the "" here? +} + +void test_fully_initialized_but_unterminated (void) +{ + char buf[3]; + buf[0] = 'a'; + buf[1] = 'b'; + buf[2] = 'c'; + __analyzer_get_strlen (buf); /* { dg-warning "stack-based buffer over-read" } */ + /* { dg-message "while looking for null terminator for argument 1 \\('&buf'\\) of '__analyzer_get_strlen'..." "event" { target *-*-* } .-1 } */ +} + +void test_uninitialized (void) +{ + char buf[16]; + __analyzer_get_strlen (buf); /* { dg-warning "use of uninitialized value 'buf\\\[0\\\]'" } */ + /* { dg-message "while looking for null terminator for argument 1 \\('&buf'\\) of '__analyzer_get_strlen'..." "event" { target *-*-* } .-1 } */ +} + +void test_partially_initialized (void) +{ + char buf[16]; + buf[0] = 'a'; + __analyzer_get_strlen (buf); /* { dg-warning "use of uninitialized value 'buf\\\[1\\\]'" } */ + /* { dg-message "while looking for null terminator for argument 1 \\('&buf'\\) of '__analyzer_get_strlen'..." "event" { target *-*-* } .-1 } */ +} + +char *test_dynamic_1 (void) +{ + const char *kvstr = "NAME=value"; + size_t len = __builtin_strlen (kvstr); + char *ptr = __builtin_malloc (len + 1); + if (!ptr) + return NULL; + __builtin_memcpy (ptr, kvstr, len); + ptr[len] = '\0'; + __analyzer_eval (__analyzer_get_strlen (ptr) == 10); /* { dg-warning "UNKNOWN" } */ + // TODO: should be TRUE + return ptr; +} + +char *test_dynamic_2 (void) +{ + const char *kvstr = "NAME=value"; + size_t len = __builtin_strlen (kvstr); + char *ptr = __builtin_malloc (len + 1); + if (!ptr) + return NULL; + __builtin_memcpy (ptr, kvstr, len); + /* Missing termination. */ + __analyzer_get_strlen (ptr); /* { dg-warning "use of uninitialized value '&buf'" "" { xfail *-*-* } } */ + // TODO (xfail) + return ptr; +} + +char *test_dynamic_3 (const char *src) +{ + size_t len = __builtin_strlen (src); + char *ptr = __builtin_malloc (len + 1); + if (!ptr) + return NULL; + __builtin_memcpy (ptr, src, len); + ptr[len] = '\0'; + __analyzer_eval (__analyzer_get_strlen (ptr) == len); /* { dg-warning "UNKNOWN" } */ + // TODO: should get TRUE for this + return ptr; +} + +char *test_dynamic_4 (const char *src) +{ + size_t len = __builtin_strlen (src); + char *ptr = __builtin_malloc (len + 1); + if (!ptr) + return NULL; + __builtin_memcpy (ptr, src, len); + /* Missing termination. */ + __analyzer_get_strlen (ptr); /* { dg-warning "use of uninitialized value 'buf\\\[len\\\]'" "" { xfail *-*-* } } */ + // TODO (xfail) + return ptr; +} + +void test_symbolic_ptr (const char *ptr) +{ + __analyzer_describe (0, __analyzer_get_strlen (ptr)); /* { dg-warning "CONJURED" } */ +} + +void test_symbolic_offset (size_t idx) +{ + __analyzer_describe (0, __analyzer_get_strlen ("abc" + idx)); /* { dg-warning "CONJURED" } */ +} + +void test_casts (void) +{ + int i = 42; + const char *p = (const char *)&i; + __analyzer_eval (__analyzer_get_strlen (p) == 0); /* { dg-warning "UNKNOWN" } */ + __analyzer_eval (__analyzer_get_strlen (p + 1) == 0); /* { dg-warning "UNKNOWN" } */ +} diff --git a/gcc/testsuite/gcc.dg/analyzer/out-of-bounds-diagram-16.c b/gcc/testsuite/gcc.dg/analyzer/out-of-bounds-diagram-16.c new file mode 100644 index 000000000000..b0fb409267ea --- /dev/null +++ b/gcc/testsuite/gcc.dg/analyzer/out-of-bounds-diagram-16.c @@ -0,0 +1,31 @@ +/* { dg-additional-options "-fdiagnostics-text-art-charset=unicode" } */ + +#include +#include "analyzer-decls.h" + +char *test_fixed_size_heap_2_invalid (void) +{ + char str[] = "abc"; + char *p = __builtin_malloc (strlen (str)); /* { dg-message "\\(1\\) capacity: 3 bytes" } */ + if (!p) + return NULL; + strcpy (p, str); /* { dg-warning "heap-based buffer overflow" } */ + return p; +} + +/* { dg-begin-multiline-output "" } + ┌──────────────────────────────────────────────────────────────────────┐ + │ write of 4 bytes │ + └──────────────────────────────────────────────────────────────────────┘ + │ │ + │ │ + v v + ┌───────────────────────────────────────────────────┐┌─────────────────┐ + │ buffer allocated on heap at (1) ││after valid range│ + └───────────────────────────────────────────────────┘└─────────────────┘ + ├─────────────────────────┬─────────────────────────┤├────────┬────────┤ + │ │ + ╭────────┴────────╮ ╭─────────┴────────╮ + │capacity: 3 bytes│ │overflow of 1 byte│ + ╰─────────────────╯ ╰──────────────────╯ + { dg-end-multiline-output "" } */ diff --git a/gcc/testsuite/gcc.dg/analyzer/out-of-bounds-diagram-17.c b/gcc/testsuite/gcc.dg/analyzer/out-of-bounds-diagram-17.c new file mode 100644 index 000000000000..6920e8c776fc --- /dev/null +++ b/gcc/testsuite/gcc.dg/analyzer/out-of-bounds-diagram-17.c @@ -0,0 +1,34 @@ +/* { dg-additional-options "-fdiagnostics-text-art-charset=unicode" } */ + +#include + +void test (void) +{ + char buf[10]; + strcpy (buf, "hello"); + strcat (buf, " world!"); /* { dg-warning "stack-based buffer overflow" } */ + /* { dg-message "write of 3 bytes to beyond the end of 'buf'" "" { target *-*-* } .-1 } */ +} + +/* { dg-begin-multiline-output "" } + ┌─────┬─────┬────┬────┬────┐┌─────┬─────┬─────┐ + │ [0] │ [1] │[2] │[3] │[4] ││ [5] │ [6] │ [7] │ + ├─────┼─────┼────┼────┼────┤├─────┼─────┼─────┤ + │ ' ' │ 'w' │'o' │'r' │'l' ││ 'd' │ '!' │ NUL │ + ├─────┴─────┴────┴────┴────┴┴─────┴─────┴─────┤ + │ string literal (type: 'char[8]') │ + └─────────────────────────────────────────────┘ + │ │ │ │ │ │ │ │ + │ │ │ │ │ │ │ │ + v v v v v v v v + ┌─────┬────────────────────────────────────────┬────┐┌─────────────────┐ + │ [0] │ ... │[9] ││ │ + ├─────┴────────────────────────────────────────┴────┤│after valid range│ + │ 'buf' (type: 'char[10]') ││ │ + └───────────────────────────────────────────────────┘└─────────────────┘ + ├─────────────────────────┬─────────────────────────┤├────────┬────────┤ + │ │ + ╭─────────┴────────╮ ╭─────────┴─────────╮ + │capacity: 10 bytes│ │overflow of 3 bytes│ + ╰──────────────────╯ ╰───────────────────╯ + { dg-end-multiline-output "" } */ diff --git a/gcc/testsuite/gcc.dg/analyzer/out-of-bounds-diagram-18.c b/gcc/testsuite/gcc.dg/analyzer/out-of-bounds-diagram-18.c new file mode 100644 index 000000000000..ea0b88019cd9 --- /dev/null +++ b/gcc/testsuite/gcc.dg/analyzer/out-of-bounds-diagram-18.c @@ -0,0 +1,38 @@ +/* { dg-additional-options "-fdiagnostics-text-art-charset=unicode" } */ + +#include + +void test (void) +{ + char buf[11]; + strcpy (buf, "サツキ"); + strcat (buf, "メイ"); /* { dg-warning "stack-based buffer overflow" } */ + /* { dg-message "write of 5 bytes to beyond the end of 'buf'" "" { target *-*-* } .-1 } */ +} + +/* { dg-begin-multiline-output "" } + ┌─────┬─────────┐┌────┬────┬────┬────┬──────┐ + │ [0] │ [1] ││[2] │[3] │[4] │[5] │ [6] │ + ├─────┼─────────┤├────┼────┼────┼────┼──────┤ + │0xe3 │ 0x83 ││0xa1│0xe3│0x82│0xa4│ 0x00 │ + ├─────┴─────────┴┴────┼────┴────┴────┼──────┤ + │ U+30e1 │ U+30a4 │U+0000│ + ├─────────────────────┼──────────────┼──────┤ + │ メ │ イ │ NUL │ + ├─────────────────────┴──────────────┴──────┤ + │ string literal (type: 'char[7]') │ + └───────────────────────────────────────────┘ + │ │ │ │ │ │ │ + │ │ │ │ │ │ │ + v v v v v v v + ┌────┬───────────────────────────┬─────────┐┌──────────────────────────┐ + │[0] │ ... │ [10] ││ │ + ├────┴───────────────────────────┴─────────┤│ after valid range │ + │ 'buf' (type: 'char[11]') ││ │ + └──────────────────────────────────────────┘└──────────────────────────┘ + ├────────────────────┬─────────────────────┤├────────────┬─────────────┤ + │ │ + ╭─────────┴────────╮ ╭─────────┴─────────╮ + │capacity: 11 bytes│ │overflow of 5 bytes│ + ╰──────────────────╯ ╰───────────────────╯ + { dg-end-multiline-output "" } */ diff --git a/gcc/testsuite/gcc.dg/analyzer/out-of-bounds-diagram-19.c b/gcc/testsuite/gcc.dg/analyzer/out-of-bounds-diagram-19.c new file mode 100644 index 000000000000..35ab72b6efc2 --- /dev/null +++ b/gcc/testsuite/gcc.dg/analyzer/out-of-bounds-diagram-19.c @@ -0,0 +1,45 @@ +/* { dg-additional-options "-fdiagnostics-text-art-charset=unicode -Wno-stringop-overflow" } */ +/* { dg-skip-if "" { powerpc-ibm-aix* } } */ + +#include + +#define LOREM_IPSUM \ + "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod" \ + " tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim" \ + " veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea" \ + " commodo consequat. Duis aute irure dolor in reprehenderit in voluptate" \ + " velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint" \ + " occaecat cupidatat non proident, sunt in culpa qui officia deserunt" \ + " mollit anim id est laborum." + +void +test_long_string () +{ + char buf[100]; + strcpy (buf, "abc "); + strcat (buf, LOREM_IPSUM); /* { dg-warning "stack-based buffer overflow" } */ + /* { dg-message "write of 350 bytes to beyond the end of 'buf'" "" { target *-*-* } .-1 } */ +} + +/* { dg-begin-multiline-output "" } + ┌───┬───┬───┬───┬───┬───┬───────┬─────┬─────┬─────┬─────┬─────┬─────┐ + │[0]│[1]│[2]│[3]│[4]│[5]│ │[440]│[441]│[442]│[443]│[444]│[445]│ + ├───┼───┼───┼───┼───┼───┤ ... ├─────┼─────┼─────┼─────┼─────┼─────┤ + │'L'│'o'│'r'│'e'│'m'│' '│ │ 'o' │ 'r' │ 'u' │ 'm' │ '.' │ NUL │ + ├───┴───┴───┴───┴───┴───┴───────┴─────┴─────┴─────┴─────┴─────┴─────┤ + │ string literal (type: 'char[446]') │ + └───────────────────────────────────────────────────────────────────┘ + │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ + │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ + v v v v v v v v v v v v v v v + ┌───┬──────────────────────────┬────┐┌────────────────────────────────────┐ + │[0]│ ... │[99]││ │ + ├───┴──────────────────────────┴────┤│ after valid range │ + │ 'buf' (type: 'char[100]') ││ │ + └───────────────────────────────────┘└────────────────────────────────────┘ + ├─────────────────┬─────────────────┤├─────────────────┬──────────────────┤ + │ │ + ╭─────────┴─────────╮ ╭──────────┴──────────╮ + │capacity: 100 bytes│ │overflow of 350 bytes│ + ╰───────────────────╯ ╰─────────────────────╯ + { dg-end-multiline-output "" } */ diff --git a/gcc/testsuite/gcc.dg/analyzer/pr104369-1.c b/gcc/testsuite/gcc.dg/analyzer/pr104369-1.c index c05137bb219b..4a01b8c656c3 100644 --- a/gcc/testsuite/gcc.dg/analyzer/pr104369-1.c +++ b/gcc/testsuite/gcc.dg/analyzer/pr104369-1.c @@ -1,5 +1,7 @@ /* { dg-additional-options "-Wno-analyzer-too-complex -Wno-analyzer-fd-leak" } */ // TODO: remove need for these options +/* C only: C++ does not support transparent_union. */ + typedef __SIZE_TYPE__ size_t; #define NULL ((void *)0) @@ -61,7 +63,7 @@ int main() { struct sockaddr_un remote; socklen_t len = sizeof(remote); - pollfds = calloc(1, sizeof(struct pollfd)); + pollfds = (struct pollfd *) calloc(1, sizeof(struct pollfd)); if (!pollfds) { exit(1); } @@ -74,12 +76,13 @@ int main() { if (pollfds[0].revents & POLLIN) { nsockets++; - newpollfds = realloc(pollfds, nsockets * sizeof(*pollfds)); + newpollfds = (struct pollfd *) realloc(pollfds, nsockets * sizeof(*pollfds)); if (!newpollfds) { exit(1); } pollfds = newpollfds; pollfds[nsockets - 1].fd = accept(pollfds[0].fd, &remote, &len); + /* { dg-error "could not convert '& remote' from 'sockaddr_un*' to '__SOCKADDR_ARG'" "G++ doesn't support transparent_union" { target c++ } .-1 } */ } } return 0; diff --git a/gcc/testsuite/gcc.dg/analyzer/pr104369-2.c b/gcc/testsuite/gcc.dg/analyzer/pr104369-2.c index 93d9987d0ba0..0121d1fb29ea 100644 --- a/gcc/testsuite/gcc.dg/analyzer/pr104369-2.c +++ b/gcc/testsuite/gcc.dg/analyzer/pr104369-2.c @@ -1,5 +1,6 @@ /* { dg-additional-options "-Wno-analyzer-fd-leak" } */ // TODO: remove need for this option +/* C only: C++ does not support transparent_union. */ typedef __SIZE_TYPE__ size_t; #define NULL ((void *)0) @@ -61,7 +62,7 @@ int main() { struct sockaddr_un remote; socklen_t len = sizeof(remote); - pollfds = calloc(1, sizeof(struct pollfd)); + pollfds = (struct pollfd *) calloc(1, sizeof(struct pollfd)); if (!pollfds) { exit(1); } @@ -72,11 +73,13 @@ int main() { } nsockets++; - newpollfds = realloc(pollfds, nsockets * sizeof(*pollfds)); + newpollfds = (struct pollfd *) realloc(pollfds, nsockets * sizeof(*pollfds)); if (!newpollfds) { exit(3); } pollfds = newpollfds; pollfds[nsockets - 1].fd = accept(pollfds[0].fd, &remote, &len); + /* { dg-error "could not convert '& remote' from 'sockaddr_un*' to '__SOCKADDR_ARG'" "G++ doesn't support transparent_union" { target c++ } .-1 } */ + exit(4); } diff --git a/gcc/testsuite/gcc.dg/analyzer/pr61861.c b/gcc/testsuite/gcc.dg/analyzer/pr61861.c index a85e74389052..b03f510115db 100644 --- a/gcc/testsuite/gcc.dg/analyzer/pr61861.c +++ b/gcc/testsuite/gcc.dg/analyzer/pr61861.c @@ -1,2 +1,3 @@ /* { dg-additional-options "-Wno-int-conversion" } */ -#include "../pr61861.c" +/* { C only: Wno-int-conversion is not valid for C++. */ +#include "../../gcc.dg/pr61861.c" diff --git a/gcc/testsuite/gcc.dg/analyzer/pr93355-localealias-feasibility-2.c b/gcc/testsuite/gcc.dg/analyzer/pr93355-localealias-feasibility-2.c index 148429768cd6..df14bea7155d 100644 --- a/gcc/testsuite/gcc.dg/analyzer/pr93355-localealias-feasibility-2.c +++ b/gcc/testsuite/gcc.dg/analyzer/pr93355-localealias-feasibility-2.c @@ -6,7 +6,6 @@ #include "analyzer-decls.h" -#define NULL ((void *) 0) #define PATH_SEPARATOR ':' #define LOCALE_ALIAS_PATH "value for LOCALE_ALIAS_PATH" diff --git a/gcc/testsuite/gcc.dg/analyzer/pr93457.c b/gcc/testsuite/gcc.dg/analyzer/pr93457.c deleted file mode 100644 index b77911ba7895..000000000000 --- a/gcc/testsuite/gcc.dg/analyzer/pr93457.c +++ /dev/null @@ -1,10 +0,0 @@ -/* { dg-do compile } */ - -void -p5 (const void *); - -void -s5 (const void *cl) -{ - p5 (&cl[1]); /* { dg-warning "dereferencing 'void \\*' pointer" } */ -} diff --git a/gcc/testsuite/gcc.dg/analyzer/pr95152-4.c b/gcc/testsuite/gcc.dg/analyzer/pr95152-4.c index f2a72cad01c0..579e360a0a37 100644 --- a/gcc/testsuite/gcc.dg/analyzer/pr95152-4.c +++ b/gcc/testsuite/gcc.dg/analyzer/pr95152-4.c @@ -1,4 +1,6 @@ /* { dg-additional-options "-Wno-pointer-to-int-cast" } */ +/* { C only: Wno-pointer-to-int-cast is not valid for C++. */ + extern void my_func (int); typedef struct { int var; @@ -6,6 +8,6 @@ typedef struct { extern void *_data_offs; void test() { - info_t *info = ((void *)((void *)1) + ((unsigned int)&_data_offs)); + info_t *info = (info_t *) ((void *)((void *)1) + ((unsigned int)&_data_offs)); my_func(info->var == 0); } diff --git a/gcc/testsuite/gcc.dg/analyzer/pr95152-5.c b/gcc/testsuite/gcc.dg/analyzer/pr95152-5.c index 604b78458c7e..f40d9eb21677 100644 --- a/gcc/testsuite/gcc.dg/analyzer/pr95152-5.c +++ b/gcc/testsuite/gcc.dg/analyzer/pr95152-5.c @@ -1,4 +1,5 @@ /* { dg-additional-options "-Wno-incompatible-pointer-types" } */ +/* { C only: Wno-incompatible-pointer-types' is not valid for C++. */ void foo(void) { void (*a[1]) (); diff --git a/gcc/testsuite/gcc.dg/analyzer/pr97568.c b/gcc/testsuite/gcc.dg/analyzer/pr97568.c deleted file mode 100644 index 22d574b5fbd3..000000000000 --- a/gcc/testsuite/gcc.dg/analyzer/pr97568.c +++ /dev/null @@ -1,29 +0,0 @@ -#include "analyzer-decls.h" - -#define NULL ((void *)0) - -extern int *const p1; - -int *const p2; - -int v3; -extern int *const p3 = &v3; /* { dg-warning "'p3' initialized and declared 'extern'" } */ - -int v4; -int *const p4 = &v4; - -int main (void) -{ - __analyzer_describe (0, p1); /* { dg-message "INIT_VAL\\(p1\\)" } */ - __analyzer_eval (p1 == NULL); /* { dg-message "UNKNOWN" } */ - - __analyzer_eval (p2 == NULL); /* { dg-message "TRUE" } */ - - __analyzer_describe (0, p3); /* { dg-message "&v3" } */ - __analyzer_eval (p3 == NULL); /* { dg-message "FALSE" } */ - - __analyzer_describe (0, p4); /* { dg-message "&v4" } */ - __analyzer_eval (p4 == NULL); /* { dg-message "FALSE" } */ - - return p1[0]; -} diff --git a/gcc/testsuite/gcc.dg/analyzer/putenv-1.c b/gcc/testsuite/gcc.dg/analyzer/putenv-1.c index 543121258c8f..5c4e08c68dff 100644 --- a/gcc/testsuite/gcc.dg/analyzer/putenv-1.c +++ b/gcc/testsuite/gcc.dg/analyzer/putenv-1.c @@ -108,3 +108,19 @@ void test_outer (void) char arr_outer[] = "NAME=VALUE"; /* { dg-message "'arr_outer' declared on stack here" } */ __analyzer_test_inner (arr_outer); } + +void test_unterminated (void) +{ + char buf[3] = "abc"; + putenv (buf); /* { dg-warning "stack-based buffer over-read" } */ + /* { dg-message "while looking for null terminator for argument 1 \\('&buf'\\) of 'putenv'..." "event" { target *-*-* } .-1 } */ + /* { dg-warning "'putenv' on a pointer to automatic variable 'buf'" "POS34-C" { target *-*-* } .-2 } */ +} + +void test_uninitialized (void) +{ + char buf[16]; + putenv (buf); /* { dg-warning "use of uninitialized value 'buf\\\[0\\\]'" } */ + /* { dg-message "while looking for null terminator for argument 1 \\('&buf'\\) of 'putenv'..." "event" { target *-*-* } .-1 } */ + /* { dg-warning "'putenv' on a pointer to automatic variable 'buf'" "POS34-C" { target *-*-* } .-2 } */ +} diff --git a/gcc/testsuite/gcc.dg/analyzer/sprintf-1.c b/gcc/testsuite/gcc.dg/analyzer/sprintf-1.c index c79525d912f1..28914d224f50 100644 --- a/gcc/testsuite/gcc.dg/analyzer/sprintf-1.c +++ b/gcc/testsuite/gcc.dg/analyzer/sprintf-1.c @@ -1,64 +1,28 @@ /* See e.g. https://en.cppreference.com/w/c/io/fprintf and https://www.man7.org/linux/man-pages/man3/sprintf.3.html */ +/* C only: C++ fpermissive already emits errors. */ +#include "analyzer-decls.h" + extern int sprintf(char* dst, const char* fmt, ...) __attribute__((__nothrow__)); + #define NULL ((void *)0) -int -test_passthrough (char* dst, const char* fmt) -{ - /* This assumes that fmt doesn't have any arguments. */ - return sprintf (dst, fmt); -} - -void -test_known (void) -{ - char buf[10]; - int res = sprintf (buf, "foo"); - /* TODO: ideally we would know the value of "res" is 3, - and known the content and strlen of "buf" after the call */ -} - -int -test_null_dst (void) -{ - return sprintf (NULL, "hello world"); /* { dg-warning "use of NULL where non-null expected" } */ -} - -int -test_null_fmt (char *dst) -{ - return sprintf (dst, NULL); /* { dg-warning "use of NULL where non-null expected" } */ -} - -int -test_uninit_dst (void) -{ - char *dst; - return sprintf (dst, "hello world"); /* { dg-warning "use of uninitialized value 'dst'" } */ -} - -int -test_uninit_fmt_ptr (char *dst) -{ - const char *fmt; - return sprintf (dst, fmt); /* { dg-warning "use of uninitialized value 'fmt'" } */ -} - int test_uninit_fmt_buf (char *dst) { const char fmt[10]; - return sprintf (dst, fmt); // TODO (PR analyzer/105899): complain about "fmt" not being initialized + return sprintf (dst, fmt); /* { dg-warning "use of uninitialized value 'fmt\\\[0\\\]'" } */ + /* { dg-message "while looking for null terminator for argument 2 \\('&fmt'\\) of 'sprintf'..." "event" { target *-*-* } .-1 } */ } int test_fmt_not_terminated (char *dst) { const char fmt[3] = "foo"; - return sprintf (dst, fmt); // TODO (PR analyzer/105899): complain about "fmt" not being terminated + return sprintf (dst, fmt); /* { dg-warning "stack-based buffer over-read" } */ + /* { dg-message "while looking for null terminator for argument 2 \\('&fmt'\\) of 'sprintf'..." "event" { target *-*-* } .-1 } */ } diff --git a/gcc/testsuite/gcc.dg/analyzer/strcat-1.c b/gcc/testsuite/gcc.dg/analyzer/strcat-1.c new file mode 100644 index 000000000000..e3b698ae73d3 --- /dev/null +++ b/gcc/testsuite/gcc.dg/analyzer/strcat-1.c @@ -0,0 +1,136 @@ +/* See e.g. https://en.cppreference.com/w/c/string/byte/strcat */ + +#include "analyzer-decls.h" + +char *strcat (char *dest, const char *src); +#define NULL ((void *)0) + +char * +test_passthrough (char *dest, const char *src) +{ + return strcat (dest, src); +} + +char * +test_null_dest (const char *src) +{ + return strcat (NULL, src); /* { dg-warning "use of NULL where non-null expected" } */ +} + +char * +test_null_src (char *dest) +{ + return strcat (dest, NULL); /* { dg-warning "use of NULL where non-null expected" } */ +} + +char * +test_uninit_dest (const char *src) +{ + char dest[10]; + return strcat (dest, src); /* { dg-warning "use of uninitialized value 'dest\\\[0\\\]'" } */ +} + +char * +test_uninit_src (char *dest) +{ + const char src[10]; + return strcat (dest, src); /* { dg-warning "use of uninitialized value 'src\\\[0\\\]'" } */ +} + +char * +test_dest_not_terminated (char *src) +{ + char dest[3] = "foo"; + return strcat (dest, src); /* { dg-warning "stack-based buffer over-read" } */ + /* { dg-message "while looking for null terminator for argument 1 \\('&dest'\\) of 'strcat'" "" { target *-*-* } .-1 } */ +} + +char * +test_src_not_terminated (char *dest) +{ + const char src[3] = "foo"; + return strcat (dest, src); /* { dg-warning "stack-based buffer over-read" } */ + /* { dg-message "while looking for null terminator for argument 2 \\('&src'\\) of 'strcat'" "" { target *-*-* } .-1 } */ +} + +char * __attribute__((noinline)) +call_strcat (char *dest, const char *src) +{ + return strcat (dest, src); +} + +void +test_concrete_valid_static_size (void) +{ + char buf[16]; + char *p1 = __builtin_strcpy (buf, "abc"); + char *p2 = call_strcat (buf, "def"); + __analyzer_eval (p1 == buf); /* { dg-warning "TRUE" } */ + __analyzer_eval (p2 == buf); /* { dg-warning "TRUE" } */ + __analyzer_eval (buf[0] == 'a'); /* { dg-warning "TRUE" } */ + __analyzer_eval (buf[1] == 'b'); /* { dg-warning "TRUE" } */ + __analyzer_eval (buf[2] == 'c'); /* { dg-warning "TRUE" } */ + __analyzer_eval (buf[3] == 'd'); /* { dg-warning "TRUE" } */ + __analyzer_eval (buf[4] == 'e'); /* { dg-warning "TRUE" } */ + __analyzer_eval (buf[5] == 'f'); /* { dg-warning "TRUE" } */ + __analyzer_eval (buf[6] == '\0'); /* { dg-warning "TRUE" } */ + __analyzer_eval (__builtin_strlen (buf) == 6); /* { dg-warning "TRUE" } */ +} + +void +test_concrete_valid_static_size_2 (void) +{ + char buf[16]; + char *p1 = __builtin_strcpy (buf, "abc"); + char *p2 = call_strcat (buf, "def"); + char *p3 = call_strcat (buf, "ghi"); + __analyzer_eval (p1 == buf); /* { dg-warning "TRUE" } */ + __analyzer_eval (p2 == buf); /* { dg-warning "TRUE" } */ + __analyzer_eval (p3 == buf); /* { dg-warning "TRUE" } */ + __analyzer_eval (buf[0] == 'a'); /* { dg-warning "TRUE" } */ + __analyzer_eval (buf[1] == 'b'); /* { dg-warning "TRUE" } */ + __analyzer_eval (buf[2] == 'c'); /* { dg-warning "TRUE" } */ + __analyzer_eval (buf[3] == 'd'); /* { dg-warning "TRUE" } */ + __analyzer_eval (buf[4] == 'e'); /* { dg-warning "TRUE" } */ + __analyzer_eval (buf[5] == 'f'); /* { dg-warning "TRUE" } */ + __analyzer_eval (buf[6] == 'g'); /* { dg-warning "TRUE" } */ + __analyzer_eval (buf[7] == 'h'); /* { dg-warning "TRUE" } */ + __analyzer_eval (buf[8] == 'i'); /* { dg-warning "TRUE" } */ + __analyzer_eval (buf[9] == '\0'); /* { dg-warning "TRUE" } */ + __analyzer_eval (__builtin_strlen (buf) == 9); /* { dg-warning "TRUE" } */ + __analyzer_eval (__builtin_strlen (buf + 1) == 8); /* { dg-warning "TRUE" } */ + __analyzer_eval (__builtin_strlen (buf + 2) == 7); /* { dg-warning "TRUE" } */ + __analyzer_eval (__builtin_strlen (buf + 3) == 6); /* { dg-warning "TRUE" } */ + __analyzer_eval (__builtin_strlen (buf + 4) == 5); /* { dg-warning "TRUE" } */ + __analyzer_eval (__builtin_strlen (buf + 5) == 4); /* { dg-warning "TRUE" } */ + __analyzer_eval (__builtin_strlen (buf + 6) == 3); /* { dg-warning "TRUE" } */ + __analyzer_eval (__builtin_strlen (buf + 7) == 2); /* { dg-warning "TRUE" } */ + __analyzer_eval (__builtin_strlen (buf + 8) == 1); /* { dg-warning "TRUE" } */ + __analyzer_eval (__builtin_strlen (buf + 9) == 0); /* { dg-warning "TRUE" } */ +} + +char * __attribute__((noinline)) +call_strcat_invalid (char *dest, const char *src) +{ + return strcat (dest, src); /* { dg-warning "stack-based buffer overflow" } */ +} + +void +test_concrete_invalid_static_size (void) +{ + char buf[3]; + buf[0] = '\0'; + call_strcat_invalid (buf, "abc"); +} + +void +test_concrete_symbolic (const char *suffix) +{ + char buf[10]; + buf[0] = '\0'; + call_strcat (buf, suffix); +} + +/* TODO: + - "The behavior is undefined if the strings overlap." +*/ diff --git a/gcc/testsuite/gcc.dg/analyzer/strchr-1.c b/gcc/testsuite/gcc.dg/analyzer/strchr-1.c index bfa48916ca25..08c429d8f909 100644 --- a/gcc/testsuite/gcc.dg/analyzer/strchr-1.c +++ b/gcc/testsuite/gcc.dg/analyzer/strchr-1.c @@ -25,3 +25,17 @@ void test_3 (const char *s, int c) char *p = strchr (s, c); /* { dg-message "when 'strchr' returns NULL"} */ *p = 'A'; /* { dg-warning "dereference of NULL 'p'" "null deref" } */ } + +void test_unterminated (int c) +{ + char buf[3] = "abc"; + strchr (buf, c); /* { dg-warning "stack-based buffer over-read" } */ + /* { dg-message "while looking for null terminator for argument 1 \\('&buf'\\) of 'strchr'..." "event" { target *-*-* } .-1 } */ +} + +void test_uninitialized (int c) +{ + char buf[16]; + strchr (buf, c); /* { dg-warning "use of uninitialized value 'buf\\\[0\\\]'" } */ + /* { dg-message "while looking for null terminator for argument 1 \\('&buf'\\) of 'strchr'..." "event" { target *-*-* } .-1 } */ +} diff --git a/gcc/testsuite/gcc.dg/analyzer/strcpy-1.c b/gcc/testsuite/gcc.dg/analyzer/strcpy-1.c index ed5bab98e4be..30341061f4cc 100644 --- a/gcc/testsuite/gcc.dg/analyzer/strcpy-1.c +++ b/gcc/testsuite/gcc.dg/analyzer/strcpy-1.c @@ -16,3 +16,39 @@ test_1a (char *dst, char *src) __analyzer_eval (result == dst); /* { dg-warning "TRUE" } */ return result; } + +char *test_unterminated (char *dst) +{ + char buf[3] = "abc"; + return strcpy (dst, buf); /* { dg-warning "stack-based buffer over-read" } */ + /* { dg-message "while looking for null terminator for argument 2 \\('&buf'\\) of 'strcpy'..." "event" { target *-*-* } .-1 } */ +} + +char *test_uninitialized (char *dst) +{ + char buf[16]; + return strcpy (dst, buf); /* { dg-warning "use of uninitialized value 'buf\\\[0\\\]'" } */ + /* { dg-message "while looking for null terminator for argument 2 \\('&buf'\\) of 'strcpy'..." "event" { target *-*-* } .-1 } */ +} + +extern void external_fn (void *ptr); + +char *test_external_fn (void) +{ + char src[10]; + char dst[10]; + external_fn (src); + strcpy (dst, src); + __analyzer_eval (strlen (dst) == strlen (src)); /* { dg-warning "UNKNOWN" } */ + // TODO: ideally would be TRUE +} + +void test_sprintf_strcpy (const char *a, const char *b) +{ + char buf_1[10]; + char buf_2[10]; + __builtin_sprintf (buf_1, "%s/%s", a, b); + strcpy (buf_2, buf_1); + __analyzer_eval (strlen (buf_1) == strlen (buf_2)); /* { dg-warning "UNKNOWN" } */ + // TODO: ideally would be TRUE +} diff --git a/gcc/testsuite/gcc.dg/analyzer/strcpy-3.c b/gcc/testsuite/gcc.dg/analyzer/strcpy-3.c index a38f9a7641fe..a7b324fc445e 100644 --- a/gcc/testsuite/gcc.dg/analyzer/strcpy-3.c +++ b/gcc/testsuite/gcc.dg/analyzer/strcpy-3.c @@ -20,4 +20,12 @@ void test_1 (void) __analyzer_eval (result[3] == 'l'); /* { dg-warning "TRUE" } */ __analyzer_eval (result[4] == 'o'); /* { dg-warning "TRUE" } */ __analyzer_eval (result[5] == 0); /* { dg-warning "TRUE" } */ + __analyzer_eval (strlen (result) == 5); /* { dg-warning "TRUE" } */ +} + +void test_2 (void) +{ + char buf[16]; + __builtin_strcpy (buf, "abc"); + __analyzer_eval (strlen (buf) == 3); /* { dg-warning "TRUE" } */ } diff --git a/gcc/testsuite/gcc.dg/analyzer/strcpy-4.c b/gcc/testsuite/gcc.dg/analyzer/strcpy-4.c new file mode 100644 index 000000000000..435a4cadee9d --- /dev/null +++ b/gcc/testsuite/gcc.dg/analyzer/strcpy-4.c @@ -0,0 +1,51 @@ +/* { dg-additional-options "-Wno-stringop-overflow" } */ + +#include +#include "analyzer-decls.h" + +void +test_fixed_size_stack_1 (void) +{ + char buf[3]; + strcpy (buf, "abc"); /* { dg-warning "stack-based buffer overflow" } */ +} + +char *test_fixed_size_heap_1 (void) +{ + char str[] = "abc"; + char *p = __builtin_malloc (3); + if (!p) + return NULL; + strcpy (p, str); /* { dg-warning "heap-based buffer overflow" } */ + return p; +} + +char *test_fixed_size_heap_2_invalid (void) +{ + char str[] = "abc"; + char *p = __builtin_malloc (strlen (str)); + if (!p) + return NULL; + strcpy (p, str); /* { dg-warning "heap-based buffer overflow" } */ + return p; +} + +char *test_fixed_size_heap_2_valid (void) +{ + char str[] = "abc"; + char *p = __builtin_malloc (strlen (str) + 1); + if (!p) + return NULL; + strcpy (p, str); /* { dg-bogus "" } */ + __analyzer_eval (strlen (p) == 3); /* { dg-warning "TRUE" } */ + return p; +} + +char *test_dynamic_size_heap_1 (const char *src) +{ + char *p = __builtin_malloc (strlen (src)); + if (!p) + return NULL; + strcpy (p, src); // TODO: write of null terminator is oob + return p; +} diff --git a/gcc/testsuite/gcc.dg/analyzer/strdup-1.c b/gcc/testsuite/gcc.dg/analyzer/strdup-1.c index 9ac3921af212..11bc964922b5 100644 --- a/gcc/testsuite/gcc.dg/analyzer/strdup-1.c +++ b/gcc/testsuite/gcc.dg/analyzer/strdup-1.c @@ -1,6 +1,8 @@ #include #include +#include "analyzer-decls.h" + extern void requires_nonnull (void *ptr) __attribute__((nonnull)); @@ -38,3 +40,42 @@ void test_6 (const char *s) char *p = __builtin_strdup (s); /* { dg-message "this call could return NULL" } */ requires_nonnull (p); /* { dg-warning "use of possibly-NULL 'p'" } */ } + +char *test_unterminated (void) +{ + char buf[3] = "abc"; + return strdup (buf); /* { dg-warning "stack-based buffer over-read" } */ + /* { dg-message "while looking for null terminator for argument 1 \\('&buf'\\) of 'strdup'..." "event" { target *-*-* } .-1 } */ +} + +char *test_uninitialized (void) +{ + char buf[16]; + return strdup (buf); /* { dg-warning "use of uninitialized value 'buf\\\[0\\\]'" } */ + /* { dg-message "while looking for null terminator for argument 1 \\('&buf'\\) of 'strdup'..." "event" { target *-*-* } .-1 } */ +} + +char *test_concrete_strlen (void) +{ + char *p = strdup ("abc"); + if (!p) + return p; + __analyzer_eval (__analyzer_get_strlen (p) == 3); /* { dg-warning "TRUE" } */ + __analyzer_eval (p[0] == 'a'); /* { dg-warning "TRUE" } */ + __analyzer_eval (p[1] == 'b'); /* { dg-warning "TRUE" } */ + __analyzer_eval (p[2] == 'c'); /* { dg-warning "TRUE" } */ + __analyzer_eval (p[3] == '\0'); /* { dg-warning "TRUE" } */ + return p; +} + +char *test_symbolic_strlen (const char *p) +{ + char *q = strdup (p); + if (!q) + return q; + __analyzer_eval (__analyzer_get_strlen (p) == __analyzer_get_strlen (q)); /* { dg-warning "UNKNOWN" } */ + // TODO: should be TRUE + __analyzer_eval (p[0] == q[0]); /* { dg-warning "UNKNOWN" } */ + // TODO: should be TRUE + return q; +} diff --git a/gcc/testsuite/gcc.dg/analyzer/strlen-1.c b/gcc/testsuite/gcc.dg/analyzer/strlen-1.c new file mode 100644 index 000000000000..99ce3aa297b5 --- /dev/null +++ b/gcc/testsuite/gcc.dg/analyzer/strlen-1.c @@ -0,0 +1,54 @@ +/* See e.g. https://en.cppreference.com/w/c/string/byte/strlen */ + +#include "analyzer-decls.h" + +typedef __SIZE_TYPE__ size_t; + +static size_t __attribute__((noinline)) +call_strlen_1 (const char *p) +{ + return __builtin_strlen (p); +} + +void test_string (void) +{ + __analyzer_eval (call_strlen_1 ("abc") == 3); /* { dg-warning "TRUE" } */ +} + +static size_t __attribute__((noinline)) +call_strlen_2 (const char *p) +{ + return __builtin_strlen (p); /* { dg-warning "stack-based buffer over-read" } */ +} + +void test_unterminated (void) +{ + const char buf[3] = "abc"; + __analyzer_eval (call_strlen_2 (buf) == 3); /* { dg-warning "UNKNOWN" } */ +} + +void test_uninitialized (void) +{ + char buf[16]; + __builtin_strlen (buf); /* { dg-warning "use of uninitialized value 'buf\\\[0\\\]'" } */ +} + +void test_partially_initialized (void) +{ + char buf[16]; + buf[0] = 'a'; + __builtin_strlen (buf); /* { dg-warning "use of uninitialized value 'buf\\\[1\\\]'" } */ +} + +extern size_t strlen (const char *str); + +size_t +test_passthrough (const char *str) +{ + return strlen (str); +} + +/* TODO + - complain if NULL str + - should it be tainted if str's bytes are tainted? +*/ diff --git a/gcc/testsuite/gcc.dg/analyzer/write-to-function-1.c b/gcc/testsuite/gcc.dg/analyzer/write-to-function-1.c index c1bece632ce4..a5ee4cabcc0b 100644 --- a/gcc/testsuite/gcc.dg/analyzer/write-to-function-1.c +++ b/gcc/testsuite/gcc.dg/analyzer/write-to-function-1.c @@ -1,3 +1,5 @@ +/* { C only: C++ does not allow for conversion from function pointer to 'void *' */ + typedef __SIZE_TYPE__ size_t; int getrandom (void *__buffer, size_t __length, /* { dg-message "parameter 1 of 'getrandom' marked with attribute 'access \\(write_only, 1, 2\\)'" } */ diff --git a/gcc/testsuite/gcc.dg/analyzer/write-to-string-literal-4.c b/gcc/testsuite/gcc.dg/analyzer/write-to-string-literal-4.c deleted file mode 100644 index a8f600f81a38..000000000000 --- a/gcc/testsuite/gcc.dg/analyzer/write-to-string-literal-4.c +++ /dev/null @@ -1,23 +0,0 @@ -typedef __SIZE_TYPE__ size_t; - -int getrandom (void *__buffer, size_t __length, /* { dg-message "parameter 1 of 'getrandom' marked with attribute 'access \\(write_only, 1, 2\\)'" } */ - unsigned int __flags) - __attribute__ ((access (__write_only__, 1, 2))); - -#define GRND_RANDOM 0x02 - -void test (int flag) -{ - char *buf; - - if (flag) - buf = __builtin_malloc (1024); - else - buf = (char *)""; /* { dg-message "here" } */ - - if (getrandom(buf, 16, GRND_RANDOM)) /* { dg-warning "write to string literal" } */ - __builtin_printf("%s\n", buf); - - if (flag) - __builtin_free (buf); -} diff --git a/gcc/testsuite/gcc.dg/c11-typeof-2.c b/gcc/testsuite/gcc.dg/c11-typeof-2.c new file mode 100644 index 000000000000..3d49ada5fce6 --- /dev/null +++ b/gcc/testsuite/gcc.dg/c11-typeof-2.c @@ -0,0 +1,177 @@ +/* Test GNU extensions __typeof__ and __typeof_unqual__. Valid code. */ +/* { dg-do run } */ +/* { dg-options "-std=c11 -pedantic-errors" } */ + +int i; +extern __typeof__ (i) i; +extern __typeof (int) i; +extern __typeof_unqual__ (i) i; +extern __typeof_unqual (int) i; + +volatile int vi; +extern __typeof__ (volatile int) vi; +extern __typeof (vi) vi; + +extern __typeof_unqual__ (volatile int) i; +extern __typeof_unqual__ (vi) i; +extern __typeof__ ((const int) vi) i; +extern __typeof ((volatile int) vi) i; + +const int ci; +extern __typeof (const int) ci; +extern __typeof (ci) ci; + +extern __typeof_unqual (const int) i; +extern __typeof_unqual (ci) i; +extern __typeof__ ((const int) ci) i; +extern __typeof__ (+ci) i; +extern __typeof (0, ci) i; +extern __typeof__ (1 ? ci : ci) i; +extern __typeof (0) i; + +const int fci (void); +extern __typeof__ (fci ()) i; + +_Atomic int ai; +extern __typeof (_Atomic int) ai; +extern __typeof__ (_Atomic (int)) ai; +extern __typeof (ai) ai; + +extern __typeof_unqual__ (_Atomic int) i; +extern __typeof_unqual (_Atomic (int)) i; +extern __typeof_unqual__ (ai) i; +extern __typeof (+ai) i; +extern __typeof__ ((_Atomic int) ai) i; +extern __typeof__ (0, ai) i; +extern __typeof (1 ? ai : ai) i; + +_Atomic int fai (void); +extern __typeof__ (fai ()) i; + +_Atomic const volatile int acvi; +extern __typeof (int volatile const _Atomic) acvi; +extern __typeof (acvi) acvi; +extern const _Atomic volatile __typeof (acvi) acvi; +extern _Atomic volatile __typeof__ (ci) acvi; +extern _Atomic const __typeof (vi) acvi; +extern const __typeof__ (ai) volatile acvi; + +extern __typeof_unqual (acvi) i; +extern __typeof_unqual__ (__typeof (acvi)) i; +extern __typeof_unqual (_Atomic __typeof_unqual__ (acvi)) i; + +extern _Atomic __typeof_unqual (acvi) ai; + +char c; +volatile char vc; +volatile char *pvc; +volatile char *const cpvc; +const char *pcc; +const char *volatile vpcc; +__typeof (*vpcc) cc; + +extern __typeof__ (*cpvc) vc; +extern __typeof_unqual (*cpvc) c; +extern __typeof_unqual__ (cpvc) pvc; +extern __typeof_unqual__ (vpcc) pcc; +extern const char cc; + +extern __typeof (++vi) i; +extern __typeof (++ai) i; +extern __typeof__ (--vi) i; +extern __typeof (--ai) i; +extern __typeof__ (vi++) i; +extern __typeof__ (ai++) i; +extern __typeof (vi--) i; +extern __typeof__ (ai--) i; + +_Bool b; +volatile _Bool vb; +_Atomic _Bool ab; +extern __typeof__ (++vb) b; +extern __typeof__ (++ab) b; +extern __typeof (--vb) b; +extern __typeof__ (--ab) b; +extern __typeof (vb++) b; +extern __typeof (ab++) b; +extern __typeof__ (vb--) b; +extern __typeof (ab--) b; + +extern __typeof__ (vc = 1) c; +extern __typeof__ (vpcc = 0) pcc; +extern __typeof (ai *= 2) i; + +int s = sizeof (__typeof__ (int (*)[++i])); + +void *vp; + +extern void abort (void); +extern void exit (int); + +extern int only_used_in_typeof; + +static int not_defined (void); + +__typeof (i) +main (__typeof (*vp)) +{ + volatile __typeof__ (only_used_in_typeof) ii = 2; + if (ii != 2) + abort (); + const __typeof__ (not_defined ()) jj = 3; + if (jj != 3) + abort (); + unsigned int u = 1; + __typeof__ (u) u2 = 0; + __typeof (int (*)[++u2]) p = 0; + if (u2 != 1) + abort (); + if (sizeof (*p) != sizeof (int)) + abort (); + __typeof_unqual (int (*)[++u2]) q = 0; + if (u2 != 2) + abort (); + if (sizeof (*q) != 2 * sizeof (int)) + abort (); + if (sizeof (*p) != sizeof (int)) + abort (); + __typeof (++u2) u3 = 1; + if (u2 != u + u3) + abort (); + __typeof_unqual__ (++u2) u4 = 2; + if (u2 != u4) + abort (); + u = sizeof (__typeof__ (int (*)[++u2])); + if (u2 != 2) + abort (); + u = sizeof (__typeof_unqual (int (*)[++u2])); + if (u2 != 2) + abort (); + __typeof ((int (*)[++u2]) 0) q2; + if (u2 != 3) + abort (); + __typeof ((void) 0, (int (*)[++u2]) 0) q3; + if (u2 != 4) + abort (); + __typeof__ ((int (*)[++u2]) 0, 0) q4; + if (u2 != 4) + abort (); + __typeof_unqual ((int (*)[++u2]) 0) q5; + if (u2 != 5) + abort (); + __typeof_unqual__ ((void) 0, (int (*)[++u2]) 0) q6; + if (u2 != 6) + abort (); + __typeof_unqual__ ((int (*)[++u2]) 0, 0) q7; + if (u2 != 6) + abort (); + int a1[6], a2[6]; + int (*pa)[u2] = &a1; + __typeof (pa = &a2) pp; + if (pa != &a2) + abort (); + __typeof_unqual (pa = &a1) pp2; + if (pa != &a1) + abort (); + exit (0); +} diff --git a/gcc/testsuite/gcc.dg/c11-typeof-3.c b/gcc/testsuite/gcc.dg/c11-typeof-3.c new file mode 100644 index 000000000000..026a57f65b83 --- /dev/null +++ b/gcc/testsuite/gcc.dg/c11-typeof-3.c @@ -0,0 +1,58 @@ +/* Test GNU extensions __typeof__ and __typeof_unqual__. Invalid code. */ +/* { dg-do compile } */ +/* { dg-options "-std=c11 -pedantic-errors" } */ + +struct s { int i : 2; } x; +union u { unsigned int j : 1; } y; + +__typeof__ (x.i) j; /* { dg-error "applied to a bit-field" } */ +__typeof_unqual__ (x.i) j2; /* { dg-error "applied to a bit-field" } */ +__typeof (y.j) j3; /* { dg-error "applied to a bit-field" } */ +__typeof_unqual (y.j) j4; /* { dg-error "applied to a bit-field" } */ + +static int ok (void); +static int also_ok (void); +static int not_defined (void); /* { dg-error "used but never defined" } */ +static int also_not_defined (void); /* { dg-error "used but never defined" } */ + +_Noreturn void nf1 (void); +__attribute__((noreturn)) void nf2 (void); +void fg (void) {} +__typeof__ (&nf1) pnf1 = fg; /* { dg-error "qualified function pointer from unqualified" } */ +__typeof (&nf2) pnf2 = fg; /* { dg-error "qualified function pointer from unqualified" } */ +extern void (*pnf1) (void); /* { dg-error "conflicting types for" } */ +extern void (*pnf2) (void); /* { dg-error "conflicting types for" } */ +extern __typeof (nf1) *pnf1; /* { dg-error "conflicting types for" } */ +extern __typeof (nf1) *pnf2; /* { dg-error "conflicting types for" } */ +extern __typeof__ (nf2) *pnf1; /* { dg-error "conflicting types for" } */ +extern __typeof__ (nf2) *pnf2; /* { dg-error "conflicting types for" } */ +__typeof (*&nf1) fg2, fg2a, fg2b; /* { dg-error "ISO C forbids qualified function types" } */ +__typeof__ (*&nf2) fg3, fg3a, fg3b; /* { dg-error "ISO C forbids qualified function types" } */ +__typeof (nf1) fg4, fg4a, fg4b; +__typeof__ (nf2) fg5, fg5a, fg5b; + +extern void abort (void); + +void fg2 (void) {} /* { dg-error "conflicting type qualifiers for" } */ +_Noreturn void fg2a (void) { abort (); } /* { dg-error "conflicting type qualifiers for" } */ +__attribute__((noreturn)) void fg2b (void) { abort (); } /* { dg-error "conflicting type qualifiers for" } */ +void fg3 (void) {} /* { dg-error "conflicting type qualifiers for" } */ +_Noreturn void fg3a (void) { abort (); } /* { dg-error "conflicting type qualifiers for" } */ +__attribute__((noreturn)) void fg3b (void) { abort (); } /* { dg-error "conflicting type qualifiers for" } */ +void fg4 (void) {} +_Noreturn void fg4a (void) { abort (); } +__attribute__((noreturn)) void fg4b (void) { abort (); } +void fg5 (void) {} +_Noreturn void fg5a (void) { abort (); } +__attribute__((noreturn)) void fg5b (void) { abort (); } + +void +f (void) +{ + __typeof__ (ok ()) x = 2; + __typeof_unqual (also_ok ()) y = 2; + int a[2]; + int (*p)[x] = &a; + __typeof (p + not_defined ()) q; + __typeof_unqual__ (p + also_not_defined ()) q2; +} diff --git a/gcc/testsuite/gcc.dg/c2x-attr-syntax-6.c b/gcc/testsuite/gcc.dg/c2x-attr-syntax-6.c new file mode 100644 index 000000000000..9e5f65ce469b --- /dev/null +++ b/gcc/testsuite/gcc.dg/c2x-attr-syntax-6.c @@ -0,0 +1,62 @@ +/* Test C2x attribute syntax: use of __extension__ in C11 mode. */ +/* { dg-do compile } */ +/* { dg-options "-std=c11 -pedantic-errors" } */ + +#define FOO :: +#define BAR : +#define JOIN(A, B) A/**/B +#define JOIN2(A, B) A##B + +typedef int [[__extension__ gnu::vector_size (4)]] g1; +typedef int [[__extension__ gnu :: vector_size (4)]] g2; +typedef int [[__extension__ gnu : : vector_size (4)]] g3; +typedef int [[__extension__ gnu: :vector_size (4)]] g4; +typedef int [[__extension__ gnu FOO vector_size (4)]] g5; +typedef int [[__extension__ gnu BAR BAR vector_size (4)]] g6; +typedef int [[__extension__ gnu :/**/: vector_size (4)]] g7; +typedef int [[__extension__ gnu JOIN(:,:) vector_size (4)]] g8; +typedef int [[__extension__ gnu :: vector_size (sizeof (void (*)(...)))]] g10; +typedef int [[__extension__]] g11; +typedef int [[__extension__,]] g12; +typedef int [[__extension__, ,,,, ,, ,]] g13; +[[__extension__ deprecated]] int g14 (); +[[__extension__ nodiscard]] int g15 (); +[[__extension__ noreturn]] void g16 (); + +int +cases (int x) +{ + switch (x) + { + case 1: + case 2: + case 4: + x += 1; + [[__extension__ fallthrough]]; + case 19: + case 33: + x *= 2; + [[fallthrough]]; /* { dg-error {attributes before C2X} } */ + case 99: + return x; + + default: + return 0; + } +} + +typedef int [[__extension__ vector_size (4)]] b1; /* { dg-error {'vector_size' attribute ignored} } */ +typedef int [[__extension__ __extension__]] b2; /* { dg-error {'extension' attribute ignored} } */ +typedef int [[__extension__ unknown_attribute]] b3; /* { dg-error {'unknown_attribute' attribute ignored} } */ +typedef int [[__extension__ gnu:vector_size(4)]] b4; /* { dg-error {expected '\]' before ':'} } */ +/* { dg-error {'gnu' attribute ignored} "" { target *-*-* } .-1 } */ +typedef int [[__extension__ gnu JOIN2(:,:) vector_size (4)]] b5; /* { dg-error {pasting ":" and ":" does not give a valid preprocessing token} } */ +typedef int [[gnu::vector_size(4)]] b6; /* { dg-error {expected '\]' before ':'} } */ +/* { dg-error {'gnu' attribute ignored} "" { target *-*-* } .-1 } */ +/* { dg-error {attributes before C2X} "" { target *-*-* } .-2 } */ +typedef int [[gnu : : vector_size(4)]] b7; /* { dg-error {expected '\]' before ':'} } */ +/* { dg-error {'gnu' attribute ignored} "" { target *-*-* } .-1 } */ +/* { dg-error {attributes before C2X} "" { target *-*-* } .-2 } */ +typedef int [[gnu : vector_size(4)]] b8; /* { dg-error {expected '\]' before ':'} } */ +/* { dg-error {'gnu' attribute ignored} "" { target *-*-* } .-1 } */ +/* { dg-error {attributes before C2X} "" { target *-*-* } .-2 } */ diff --git a/gcc/testsuite/gcc.dg/c2x-attr-syntax-7.c b/gcc/testsuite/gcc.dg/c2x-attr-syntax-7.c new file mode 100644 index 000000000000..702f733b171b --- /dev/null +++ b/gcc/testsuite/gcc.dg/c2x-attr-syntax-7.c @@ -0,0 +1,60 @@ +/* Test C2x attribute syntax: use of __extension__ in C11 mode. */ +/* { dg-do compile } */ +/* { dg-options "-std=c2x -pedantic-errors -Wc11-c2x-compat" } */ + +#define FOO :: +#define BAR : +#define JOIN(A, B) A/**/B +#define JOIN2(A, B) A##B + +typedef int [[__extension__ gnu::vector_size (4)]] g1; +typedef int [[__extension__ gnu :: vector_size (4)]] g2; +typedef int [[__extension__ gnu : : vector_size (4)]] g3; +typedef int [[__extension__ gnu: :vector_size (4)]] g4; +typedef int [[__extension__ gnu FOO vector_size (4)]] g5; +typedef int [[__extension__ gnu BAR BAR vector_size (4)]] g6; +typedef int [[__extension__ gnu :/**/: vector_size (4)]] g7; +typedef int [[__extension__ gnu JOIN(:,:) vector_size (4)]] g8; +typedef int [[__extension__ gnu :: vector_size (sizeof (void (*)(...)))]] g10; +typedef int [[__extension__]] g11; +typedef int [[__extension__,]] g12; +typedef int [[__extension__, ,,,, ,, ,]] g13; +[[__extension__ deprecated]] int g14 (); +[[__extension__ nodiscard]] int g15 (); +[[__extension__ noreturn]] void g16 (); + +int +cases (int x) +{ + switch (x) + { + case 1: + case 2: + case 4: + x += 1; + [[__extension__ fallthrough]]; + case 19: + case 33: + x *= 2; + [[fallthrough]]; /* { dg-warning {attributes before C2X} } */ + case 99: + return x; + + default: + return 0; + } +} + +typedef int [[__extension__ vector_size (4)]] b1; /* { dg-error {'vector_size' attribute ignored} } */ +typedef int [[__extension__ __extension__]] b2; /* { dg-error {'extension' attribute ignored} } */ +typedef int [[__extension__ unknown_attribute]] b3; /* { dg-error {'unknown_attribute' attribute ignored} } */ +typedef int [[__extension__ gnu:vector_size(4)]] b4; /* { dg-error {expected '\]' before ':'} } */ +/* { dg-error {'gnu' attribute ignored} "" { target *-*-* } .-1 } */ +typedef int [[__extension__ gnu JOIN2(:,:) vector_size (4)]] b5; +typedef int [[gnu::vector_size(4)]] b6; /* { dg-warning {attributes before C2X} } */ +typedef int [[gnu : : vector_size(4)]] b7; /* { dg-error {expected '\]' before ':'} } */ +/* { dg-error {'gnu' attribute ignored} "" { target *-*-* } .-1 } */ +/* { dg-warning {attributes before C2X} "" { target *-*-* } .-2 } */ +typedef int [[gnu : vector_size(4)]] b8; /* { dg-error {expected '\]' before ':'} } */ +/* { dg-error {'gnu' attribute ignored} "" { target *-*-* } .-1 } */ +/* { dg-warning {attributes before C2X} "" { target *-*-* } .-2 } */ diff --git a/gcc/testsuite/gcc.dg/cmp-mem-const-1.c b/gcc/testsuite/gcc.dg/cmp-mem-const-1.c index 4f21a1ade4a3..0b0e7331354a 100644 --- a/gcc/testsuite/gcc.dg/cmp-mem-const-1.c +++ b/gcc/testsuite/gcc.dg/cmp-mem-const-1.c @@ -1,5 +1,5 @@ /* { dg-do compile { target { lp64 } } } */ -/* { dg-options "-O1 -fdump-rtl-combine-details" } */ +/* { dg-options "-O2 -fdump-rtl-combine-details" } */ /* { dg-final { scan-rtl-dump "narrow comparison from mode .I to QI" "combine" } } */ typedef __UINT64_TYPE__ uint64_t; diff --git a/gcc/testsuite/gcc.dg/cmp-mem-const-2.c b/gcc/testsuite/gcc.dg/cmp-mem-const-2.c index 7b722951594c..8022137a8eca 100644 --- a/gcc/testsuite/gcc.dg/cmp-mem-const-2.c +++ b/gcc/testsuite/gcc.dg/cmp-mem-const-2.c @@ -1,5 +1,5 @@ /* { dg-do compile { target { lp64 } } } */ -/* { dg-options "-O1 -fdump-rtl-combine-details" } */ +/* { dg-options "-O2 -fdump-rtl-combine-details" } */ /* { dg-final { scan-rtl-dump "narrow comparison from mode .I to QI" "combine" } } */ typedef __UINT64_TYPE__ uint64_t; diff --git a/gcc/testsuite/gcc.dg/cmp-mem-const-3.c b/gcc/testsuite/gcc.dg/cmp-mem-const-3.c index ed5059d38074..c60ecdb4026c 100644 --- a/gcc/testsuite/gcc.dg/cmp-mem-const-3.c +++ b/gcc/testsuite/gcc.dg/cmp-mem-const-3.c @@ -1,5 +1,7 @@ -/* { dg-do compile { target { lp64 } } } */ -/* { dg-options "-O1 -fdump-rtl-combine-details" } */ +/* { dg-do compile { target { lp64 && { ! sparc*-*-* } } } } */ +/* Excluding sparc since there we do not end up with a comparison of memory and + a constant which means that the optimization is not applicable. */ +/* { dg-options "-O2 -fdump-rtl-combine-details" } */ /* { dg-final { scan-rtl-dump "narrow comparison from mode .I to HI" "combine" } } */ typedef __UINT64_TYPE__ uint64_t; diff --git a/gcc/testsuite/gcc.dg/cmp-mem-const-4.c b/gcc/testsuite/gcc.dg/cmp-mem-const-4.c index 23e83372beed..7aa403d76d97 100644 --- a/gcc/testsuite/gcc.dg/cmp-mem-const-4.c +++ b/gcc/testsuite/gcc.dg/cmp-mem-const-4.c @@ -1,5 +1,7 @@ -/* { dg-do compile { target { lp64 } } } */ -/* { dg-options "-O1 -fdump-rtl-combine-details" } */ +/* { dg-do compile { target { lp64 && { ! sparc*-*-* } } } } */ +/* Excluding sparc since there we do not end up with a comparison of memory and + a constant which means that the optimization is not applicable. */ +/* { dg-options "-O2 -fdump-rtl-combine-details" } */ /* { dg-final { scan-rtl-dump "narrow comparison from mode .I to HI" "combine" } } */ typedef __UINT64_TYPE__ uint64_t; diff --git a/gcc/testsuite/gcc.dg/cmp-mem-const-5.c b/gcc/testsuite/gcc.dg/cmp-mem-const-5.c index d266896a25e0..4316dcb56050 100644 --- a/gcc/testsuite/gcc.dg/cmp-mem-const-5.c +++ b/gcc/testsuite/gcc.dg/cmp-mem-const-5.c @@ -1,5 +1,7 @@ -/* { dg-do compile { target { lp64 } && ! target { sparc*-*-* } } } */ -/* { dg-options "-O1 -fdump-rtl-combine-details" } */ +/* { dg-do compile { target { lp64 && { ! sparc*-*-* } } } } */ +/* Excluding sparc since there a prior optimization already reduced the + constant, i.e., nothing left for us. */ +/* { dg-options "-O2 -fdump-rtl-combine-details" } */ /* { dg-final { scan-rtl-dump "narrow comparison from mode .I to SI" "combine" } } */ typedef __UINT64_TYPE__ uint64_t; diff --git a/gcc/testsuite/gcc.dg/cmp-mem-const-6.c b/gcc/testsuite/gcc.dg/cmp-mem-const-6.c index 68d7a9d02658..d9046af79eb6 100644 --- a/gcc/testsuite/gcc.dg/cmp-mem-const-6.c +++ b/gcc/testsuite/gcc.dg/cmp-mem-const-6.c @@ -1,5 +1,7 @@ -/* { dg-do compile { target { lp64 } && ! target { sparc*-*-* } } } */ -/* { dg-options "-O1 -fdump-rtl-combine-details" } */ +/* { dg-do compile { target { lp64 && { ! sparc*-*-* } } } } */ +/* Excluding sparc since there a prior optimization already reduced the + constant, i.e., nothing left for us. */ +/* { dg-options "-O2 -fdump-rtl-combine-details" } */ /* { dg-final { scan-rtl-dump "narrow comparison from mode .I to SI" "combine" } } */ typedef __UINT64_TYPE__ uint64_t; diff --git a/gcc/testsuite/gcc.dg/darwin-minversion-link.c b/gcc/testsuite/gcc.dg/darwin-minversion-link.c index b6ede31c985e..a835e9d4648a 100644 --- a/gcc/testsuite/gcc.dg/darwin-minversion-link.c +++ b/gcc/testsuite/gcc.dg/darwin-minversion-link.c @@ -17,6 +17,8 @@ /* { dg-additional-options "-mmacosx-version-min=010.015.06 -DCHECK=101506" { target *-*-darwin19* } } */ /* { dg-additional-options "-mmacosx-version-min=011.000.00 -DCHECK=110000" { target *-*-darwin20* } } */ /* { dg-additional-options "-mmacosx-version-min=012.000.00 -DCHECK=120000" { target *-*-darwin21* } } */ +/* { dg-additional-options "-mmacosx-version-min=013.000.00 -DCHECK=130000" { target *-*-darwin22* } } */ +/* { dg-additional-options "-mmacosx-version-min=014.000.00 -DCHECK=140000" { target *-*-darwin23* } } */ int main () diff --git a/gcc/testsuite/gcc.dg/debug/dwarf2/pr111080.c b/gcc/testsuite/gcc.dg/debug/dwarf2/pr111080.c new file mode 100644 index 000000000000..3949d7e7c643 --- /dev/null +++ b/gcc/testsuite/gcc.dg/debug/dwarf2/pr111080.c @@ -0,0 +1,18 @@ +/* { dg-do compile } */ +/* { dg-options "-save-temps -gdwarf-3 -dA" } */ + +struct foo { + int field_number_1; + int field_number_2; + int field_number_3; + int field_number_4; + int field_number_5; +}; + +typedef int fun_t(struct foo *restrict); + +int main() { + return 0; +} + +/* { dg-final { scan-assembler-not "DW_TAG_structure_type" } } */ diff --git a/gcc/testsuite/gcc.dg/gnu11-typeof-3.c b/gcc/testsuite/gcc.dg/gnu11-typeof-3.c new file mode 100644 index 000000000000..0ae5e5bb8a8d --- /dev/null +++ b/gcc/testsuite/gcc.dg/gnu11-typeof-3.c @@ -0,0 +1,177 @@ +/* Test GNU extensions __typeof__ and __typeof_unqual__. Valid code. */ +/* { dg-do run } */ +/* { dg-options "-std=gnu11" } */ + +int i; +extern __typeof__ (i) i; +extern __typeof (int) i; +extern __typeof_unqual__ (i) i; +extern __typeof_unqual (int) i; + +volatile int vi; +extern __typeof__ (volatile int) vi; +extern __typeof (vi) vi; + +extern __typeof_unqual__ (volatile int) i; +extern __typeof_unqual__ (vi) i; +extern __typeof__ ((const int) vi) i; +extern __typeof ((volatile int) vi) i; + +const int ci; +extern __typeof (const int) ci; +extern __typeof (ci) ci; + +extern __typeof_unqual (const int) i; +extern __typeof_unqual (ci) i; +extern __typeof__ ((const int) ci) i; +extern __typeof__ (+ci) i; +extern __typeof (0, ci) i; +extern __typeof__ (1 ? ci : ci) i; +extern __typeof (0) i; + +const int fci (void); +extern __typeof__ (fci ()) i; + +_Atomic int ai; +extern __typeof (_Atomic int) ai; +extern __typeof__ (_Atomic (int)) ai; +extern __typeof (ai) ai; + +extern __typeof_unqual__ (_Atomic int) i; +extern __typeof_unqual (_Atomic (int)) i; +extern __typeof_unqual__ (ai) i; +extern __typeof (+ai) i; +extern __typeof__ ((_Atomic int) ai) i; +extern __typeof__ (0, ai) i; +extern __typeof (1 ? ai : ai) i; + +_Atomic int fai (void); +extern __typeof__ (fai ()) i; + +_Atomic const volatile int acvi; +extern __typeof (int volatile const _Atomic) acvi; +extern __typeof (acvi) acvi; +extern const _Atomic volatile __typeof (acvi) acvi; +extern _Atomic volatile __typeof__ (ci) acvi; +extern _Atomic const __typeof (vi) acvi; +extern const __typeof__ (ai) volatile acvi; + +extern __typeof_unqual (acvi) i; +extern __typeof_unqual__ (__typeof (acvi)) i; +extern __typeof_unqual (_Atomic __typeof_unqual__ (acvi)) i; + +extern _Atomic __typeof_unqual (acvi) ai; + +char c; +volatile char vc; +volatile char *pvc; +volatile char *const cpvc; +const char *pcc; +const char *volatile vpcc; +__typeof (*vpcc) cc; + +extern __typeof__ (*cpvc) vc; +extern __typeof_unqual (*cpvc) c; +extern __typeof_unqual__ (cpvc) pvc; +extern __typeof_unqual__ (vpcc) pcc; +extern const char cc; + +extern __typeof (++vi) i; +extern __typeof (++ai) i; +extern __typeof__ (--vi) i; +extern __typeof (--ai) i; +extern __typeof__ (vi++) i; +extern __typeof__ (ai++) i; +extern __typeof (vi--) i; +extern __typeof__ (ai--) i; + +_Bool b; +volatile _Bool vb; +_Atomic _Bool ab; +extern __typeof__ (++vb) b; +extern __typeof__ (++ab) b; +extern __typeof (--vb) b; +extern __typeof__ (--ab) b; +extern __typeof (vb++) b; +extern __typeof (ab++) b; +extern __typeof__ (vb--) b; +extern __typeof (ab--) b; + +extern __typeof__ (vc = 1) c; +extern __typeof__ (vpcc = 0) pcc; +extern __typeof (ai *= 2) i; + +int s = sizeof (__typeof__ (int (*)[++i])); + +void *vp; + +extern void abort (void); +extern void exit (int); + +extern int only_used_in_typeof; + +static int not_defined (void); + +__typeof (i) +main (__typeof (*vp)) +{ + volatile __typeof__ (only_used_in_typeof) ii = 2; + if (ii != 2) + abort (); + const __typeof__ (not_defined ()) jj = 3; + if (jj != 3) + abort (); + unsigned int u = 1; + __typeof__ (u) u2 = 0; + __typeof (int (*)[++u2]) p = 0; + if (u2 != 1) + abort (); + if (sizeof (*p) != sizeof (int)) + abort (); + __typeof_unqual (int (*)[++u2]) q = 0; + if (u2 != 2) + abort (); + if (sizeof (*q) != 2 * sizeof (int)) + abort (); + if (sizeof (*p) != sizeof (int)) + abort (); + __typeof (++u2) u3 = 1; + if (u2 != u + u3) + abort (); + __typeof_unqual__ (++u2) u4 = 2; + if (u2 != u4) + abort (); + u = sizeof (__typeof__ (int (*)[++u2])); + if (u2 != 2) + abort (); + u = sizeof (__typeof_unqual (int (*)[++u2])); + if (u2 != 2) + abort (); + __typeof ((int (*)[++u2]) 0) q2; + if (u2 != 3) + abort (); + __typeof ((void) 0, (int (*)[++u2]) 0) q3; + if (u2 != 4) + abort (); + __typeof__ ((int (*)[++u2]) 0, 0) q4; + if (u2 != 4) + abort (); + __typeof_unqual ((int (*)[++u2]) 0) q5; + if (u2 != 5) + abort (); + __typeof_unqual__ ((void) 0, (int (*)[++u2]) 0) q6; + if (u2 != 6) + abort (); + __typeof_unqual__ ((int (*)[++u2]) 0, 0) q7; + if (u2 != 6) + abort (); + int a1[6], a2[6]; + int (*pa)[u2] = &a1; + __typeof (pa = &a2) pp; + if (pa != &a2) + abort (); + __typeof_unqual (pa = &a1) pp2; + if (pa != &a1) + abort (); + exit (0); +} diff --git a/gcc/testsuite/gcc.dg/gnu11-typeof-4.c b/gcc/testsuite/gcc.dg/gnu11-typeof-4.c new file mode 100644 index 000000000000..313ee97875ca --- /dev/null +++ b/gcc/testsuite/gcc.dg/gnu11-typeof-4.c @@ -0,0 +1,58 @@ +/* Test GNU extensions __typeof__ and __typeof_unqual__. Invalid code. */ +/* { dg-do compile } */ +/* { dg-options "-std=gnu11" } */ + +struct s { int i : 2; } x; +union u { unsigned int j : 1; } y; + +__typeof__ (x.i) j; /* { dg-error "applied to a bit-field" } */ +__typeof_unqual__ (x.i) j2; /* { dg-error "applied to a bit-field" } */ +__typeof (y.j) j3; /* { dg-error "applied to a bit-field" } */ +__typeof_unqual (y.j) j4; /* { dg-error "applied to a bit-field" } */ + +static int ok (void); +static int also_ok (void); +static int not_defined (void); /* { dg-warning "used but never defined" } */ +static int also_not_defined (void); /* { dg-warning "used but never defined" } */ + +_Noreturn void nf1 (void); +__attribute__((noreturn)) void nf2 (void); +void fg (void) {} +__typeof__ (&nf1) pnf1 = fg; /* { dg-warning "qualified function pointer from unqualified" } */ +__typeof (&nf2) pnf2 = fg; /* { dg-warning "qualified function pointer from unqualified" } */ +extern void (*pnf1) (void); /* { dg-error "conflicting types for" } */ +extern void (*pnf2) (void); /* { dg-error "conflicting types for" } */ +extern __typeof (nf1) *pnf1; /* { dg-error "conflicting types for" } */ +extern __typeof (nf1) *pnf2; /* { dg-error "conflicting types for" } */ +extern __typeof__ (nf2) *pnf1; /* { dg-error "conflicting types for" } */ +extern __typeof__ (nf2) *pnf2; /* { dg-error "conflicting types for" } */ +__typeof (*&nf1) fg2, fg2a, fg2b; +__typeof__ (*&nf2) fg3, fg3a, fg3b; +__typeof (nf1) fg4, fg4a, fg4b; +__typeof__ (nf2) fg5, fg5a, fg5b; + +extern void abort (void); + +void fg2 (void) {} /* { dg-error "conflicting type qualifiers for" } */ +_Noreturn void fg2a (void) { abort (); } /* { dg-error "conflicting type qualifiers for" } */ +__attribute__((noreturn)) void fg2b (void) { abort (); } /* { dg-error "conflicting type qualifiers for" } */ +void fg3 (void) {} /* { dg-error "conflicting type qualifiers for" } */ +_Noreturn void fg3a (void) { abort (); } /* { dg-error "conflicting type qualifiers for" } */ +__attribute__((noreturn)) void fg3b (void) { abort (); } /* { dg-error "conflicting type qualifiers for" } */ +void fg4 (void) {} +_Noreturn void fg4a (void) { abort (); } +__attribute__((noreturn)) void fg4b (void) { abort (); } +void fg5 (void) {} +_Noreturn void fg5a (void) { abort (); } +__attribute__((noreturn)) void fg5b (void) { abort (); } + +void +f (void) +{ + __typeof__ (ok ()) x = 2; + __typeof_unqual (also_ok ()) y = 2; + int a[2]; + int (*p)[x] = &a; + __typeof (p + not_defined ()) q; + __typeof_unqual__ (p + also_not_defined ()) q2; +} diff --git a/gcc/testsuite/gcc.dg/gomp/collapse-1.c b/gcc/testsuite/gcc.dg/gomp/collapse-1.c index 89b76bb669cb..16a102ff3fd0 100644 --- a/gcc/testsuite/gcc.dg/gomp/collapse-1.c +++ b/gcc/testsuite/gcc.dg/gomp/collapse-1.c @@ -8,8 +8,8 @@ void f1 (void) { #pragma omp for collapse (2) - for (i = 0; i < 5; i++) - ; /* { dg-error "not enough perfectly nested" } */ + for (i = 0; i < 5; i++) /* { dg-error "not enough nested loops" } */ + ; { for (j = 0; j < 5; j++) ; @@ -38,7 +38,7 @@ f3 (void) #pragma omp for collapse (2) for (i = 0; i < 5; i++) { - int k = foo (); /* { dg-error "not enough perfectly nested" } */ + int k = foo (); { { for (j = 0; j < 5; j++) @@ -58,7 +58,7 @@ f4 (void) { for (j = 0; j < 5; j++) ; - foo (); /* { dg-error "collapsed loops not perfectly nested before" } */ + foo (); } } } @@ -73,7 +73,7 @@ f5 (void) for (j = 0; j < 5; j++) ; } - foo (); /* { dg-error "collapsed loops not perfectly nested before" } */ + foo (); } } diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-icf-38.c b/gcc/testsuite/gcc.dg/ipa/ipa-icf-38.c index 452e1b885145..57c5262dd4a8 100644 --- a/gcc/testsuite/gcc.dg/ipa/ipa-icf-38.c +++ b/gcc/testsuite/gcc.dg/ipa/ipa-icf-38.c @@ -1,4 +1,5 @@ /* { dg-do link } */ +/* { dg-require-alias "" } */ /* { dg-options "-O2 -fdump-ipa-icf-optimized -flto -fdump-tree-optimized" } */ /* { dg-require-effective-target lto } */ /* { dg-additional-sources "ipa-icf-38a.c" }*/ diff --git a/gcc/testsuite/gcc.dg/ipa/pr92497-1.c b/gcc/testsuite/gcc.dg/ipa/pr92497-1.c new file mode 100644 index 000000000000..dcece15963ce --- /dev/null +++ b/gcc/testsuite/gcc.dg/ipa/pr92497-1.c @@ -0,0 +1,26 @@ +/* { dg-do run } */ +/* { dg-options "-O2 -fno-early-inlining" } */ + +struct a {int a;}; +static int +foo (struct a a) +{ + if (!__builtin_constant_p (a.a)) + __builtin_abort (); + return a.a; +} + +static int __attribute__ ((noinline)) +bar (struct a a) +{ + return foo(a); +} + +volatile int r; + +int main() +{ + struct a a={1}; + r = bar (a); + return 0; +} diff --git a/gcc/testsuite/gcc.dg/ipa/pr92497-2.c b/gcc/testsuite/gcc.dg/ipa/pr92497-2.c new file mode 100644 index 000000000000..c64090d1a7ab --- /dev/null +++ b/gcc/testsuite/gcc.dg/ipa/pr92497-2.c @@ -0,0 +1,26 @@ +/* { dg-do run } */ +/* { dg-options "-O2 -fno-early-inlining -fno-ipa-sra" } */ + +struct a {int a;}; +static int +foo (struct a *a) +{ + if (!__builtin_constant_p (a->a)) + __builtin_abort (); + return a->a; +} + +static int __attribute__ ((noinline)) +bar (struct a *a) +{ + return foo(a); +} + +volatile int r; + +int main() +{ + struct a a={1}; + r = bar (&a); + return 0; +} diff --git a/gcc/testsuite/gcc.dg/lto/20091013-1_2.c b/gcc/testsuite/gcc.dg/lto/20091013-1_2.c index 1af49aa97b6e..89caea868e6e 100644 --- a/gcc/testsuite/gcc.dg/lto/20091013-1_2.c +++ b/gcc/testsuite/gcc.dg/lto/20091013-1_2.c @@ -1,3 +1,5 @@ +/* { dg-options "-Wno-stringop-overread" } */ + typedef struct HDC__ { int unused; } *HDC; typedef struct HFONT__ { int unused; } *HFONT; diff --git a/gcc/testsuite/gcc.dg/plugin/analyzer_cpython_plugin.c b/gcc/testsuite/gcc.dg/plugin/analyzer_cpython_plugin.c index 9ecc42d44654..bf1982e79c37 100644 --- a/gcc/testsuite/gcc.dg/plugin/analyzer_cpython_plugin.c +++ b/gcc/testsuite/gcc.dg/plugin/analyzer_cpython_plugin.c @@ -44,6 +44,7 @@ #include "analyzer/region-model.h" #include "analyzer/call-details.h" #include "analyzer/call-info.h" +#include "analyzer/exploded-graph.h" #include "make-unique.h" int plugin_is_GPL_compatible; @@ -55,6 +56,8 @@ static GTY (()) hash_map *analyzer_stashed_globals; namespace ana { static tree pyobj_record = NULL_TREE; +static tree pyobj_ptr_tree = NULL_TREE; +static tree pyobj_ptr_ptr = NULL_TREE; static tree varobj_record = NULL_TREE; static tree pylistobj_record = NULL_TREE; static tree pylongobj_record = NULL_TREE; @@ -76,6 +79,1089 @@ get_field_by_name (tree type, const char *name) return NULL_TREE; } +static const svalue * +get_sizeof_pyobjptr (region_model_manager *mgr) +{ + tree size_tree = TYPE_SIZE_UNIT (pyobj_ptr_tree); + const svalue *sizeof_sval = mgr->get_or_create_constant_svalue (size_tree); + return sizeof_sval; +} + +/* Update MODEL to set OB_BASE_REGION's ob_refcnt to 1. */ +static void +init_ob_refcnt_field (region_model_manager *mgr, region_model *model, + const region *ob_base_region, tree pyobj_record, + const call_details &cd) +{ + tree ob_refcnt_tree = get_field_by_name (pyobj_record, "ob_refcnt"); + const region *ob_refcnt_region + = mgr->get_field_region (ob_base_region, ob_refcnt_tree); + const svalue *refcnt_one_sval + = mgr->get_or_create_int_cst (size_type_node, 1); + model->set_value (ob_refcnt_region, refcnt_one_sval, cd.get_ctxt ()); +} + +/* Update MODEL to set OB_BASE_REGION's ob_type to point to + PYTYPE_VAR_DECL_PTR. */ +static void +set_ob_type_field (region_model_manager *mgr, region_model *model, + const region *ob_base_region, tree pyobj_record, + tree pytype_var_decl_ptr, const call_details &cd) +{ + const region *pylist_type_region + = mgr->get_region_for_global (pytype_var_decl_ptr); + tree pytype_var_decl_ptr_type + = build_pointer_type (TREE_TYPE (pytype_var_decl_ptr)); + const svalue *pylist_type_ptr_sval + = mgr->get_ptr_svalue (pytype_var_decl_ptr_type, pylist_type_region); + tree ob_type_field = get_field_by_name (pyobj_record, "ob_type"); + const region *ob_type_region + = mgr->get_field_region (ob_base_region, ob_type_field); + model->set_value (ob_type_region, pylist_type_ptr_sval, cd.get_ctxt ()); +} + +/* Retrieve the "ob_base" field's region from OBJECT_RECORD within + NEW_OBJECT_REGION and set its value in the MODEL to PYOBJ_SVALUE. */ +static const region * +get_ob_base_region (region_model_manager *mgr, region_model *model, + const region *new_object_region, tree object_record, + const svalue *pyobj_svalue, const call_details &cd) +{ + tree ob_base_tree = get_field_by_name (object_record, "ob_base"); + const region *ob_base_region + = mgr->get_field_region (new_object_region, ob_base_tree); + model->set_value (ob_base_region, pyobj_svalue, cd.get_ctxt ()); + return ob_base_region; +} + +/* Initialize and retrieve a region within the MODEL for a PyObject + and set its value to OBJECT_SVALUE. */ +static const region * +init_pyobject_region (region_model_manager *mgr, region_model *model, + const svalue *object_svalue, const call_details &cd) +{ + const region *pyobject_region = model->get_or_create_region_for_heap_alloc ( + NULL, cd.get_ctxt (), true, &cd); + model->set_value (pyobject_region, object_svalue, cd.get_ctxt ()); + return pyobject_region; +} + +/* Increment the value of FIELD_REGION in the MODEL by 1. Optionally + capture the old and new svalues if OLD_SVAL and NEW_SVAL pointers are + provided. */ +static void +inc_field_val (region_model_manager *mgr, region_model *model, + const region *field_region, const tree type_node, + const call_details &cd, const svalue **old_sval = nullptr, + const svalue **new_sval = nullptr) +{ + const svalue *tmp_old_sval + = model->get_store_value (field_region, cd.get_ctxt ()); + const svalue *one_sval = mgr->get_or_create_int_cst (type_node, 1); + const svalue *tmp_new_sval = mgr->get_or_create_binop ( + type_node, PLUS_EXPR, tmp_old_sval, one_sval); + + model->set_value (field_region, tmp_new_sval, cd.get_ctxt ()); + + if (old_sval) + *old_sval = tmp_old_sval; + + if (new_sval) + *new_sval = tmp_new_sval; +} + +class pyobj_init_fail : public failed_call_info +{ +public: + pyobj_init_fail (const call_details &cd) : failed_call_info (cd) {} + + bool + update_model (region_model *model, const exploded_edge *, + region_model_context *ctxt) const final override + { + /* Return NULL; everything else is unchanged. */ + const call_details cd (get_call_details (model, ctxt)); + region_model_manager *mgr = cd.get_manager (); + if (cd.get_lhs_type ()) + { + const svalue *zero + = mgr->get_or_create_int_cst (cd.get_lhs_type (), 0); + model->set_value (cd.get_lhs_region (), zero, cd.get_ctxt ()); + } + return true; + } +}; + +/* This is just a copy of leak_stmt_finder for now (subject to change if + * necssary) */ + +class refcnt_stmt_finder : public stmt_finder +{ +public: + refcnt_stmt_finder (const exploded_graph &eg, tree var) + : m_eg (eg), m_var (var) + { + } + + std::unique_ptr + clone () const final override + { + return make_unique (m_eg, m_var); + } + + const gimple * + find_stmt (const exploded_path &epath) final override + { + logger *const logger = m_eg.get_logger (); + LOG_FUNC (logger); + + if (m_var && TREE_CODE (m_var) == SSA_NAME) + { + /* Locate the final write to this SSA name in the path. */ + const gimple *def_stmt = SSA_NAME_DEF_STMT (m_var); + + int idx_of_def_stmt; + bool found = epath.find_stmt_backwards (def_stmt, &idx_of_def_stmt); + if (!found) + goto not_found; + + /* What was the next write to the underlying var + after the SSA name was set? (if any). */ + + for (unsigned idx = idx_of_def_stmt + 1; idx < epath.m_edges.length (); + ++idx) + { + const exploded_edge *eedge = epath.m_edges[idx]; + if (logger) + logger->log ("eedge[%i]: EN %i -> EN %i", idx, + eedge->m_src->m_index, + eedge->m_dest->m_index); + const exploded_node *dst_node = eedge->m_dest; + const program_point &dst_point = dst_node->get_point (); + const gimple *stmt = dst_point.get_stmt (); + if (!stmt) + continue; + if (const gassign *assign = dyn_cast (stmt)) + { + tree lhs = gimple_assign_lhs (assign); + if (TREE_CODE (lhs) == SSA_NAME + && SSA_NAME_VAR (lhs) == SSA_NAME_VAR (m_var)) + return assign; + } + } + } + + not_found: + + /* Look backwards for the first statement with a location. */ + int i; + const exploded_edge *eedge; + FOR_EACH_VEC_ELT_REVERSE (epath.m_edges, i, eedge) + { + if (logger) + logger->log ("eedge[%i]: EN %i -> EN %i", i, eedge->m_src->m_index, + eedge->m_dest->m_index); + const exploded_node *dst_node = eedge->m_dest; + const program_point &dst_point = dst_node->get_point (); + const gimple *stmt = dst_point.get_stmt (); + if (stmt) + if (get_pure_location (stmt->location) != UNKNOWN_LOCATION) + return stmt; + } + + gcc_unreachable (); + return NULL; + } + +private: + const exploded_graph &m_eg; + tree m_var; +}; + +class refcnt_mismatch : public pending_diagnostic_subclass +{ +public: + refcnt_mismatch (const region *base_region, + const svalue *ob_refcnt, + const svalue *actual_refcnt, + tree reg_tree) + : m_base_region (base_region), m_ob_refcnt (ob_refcnt), + m_actual_refcnt (actual_refcnt), m_reg_tree(reg_tree) + { + } + + const char * + get_kind () const final override + { + return "refcnt_mismatch"; + } + + bool + operator== (const refcnt_mismatch &other) const + { + return (m_base_region == other.m_base_region + && m_ob_refcnt == other.m_ob_refcnt + && m_actual_refcnt == other.m_actual_refcnt); + } + + int get_controlling_option () const final override + { + return 0; + } + + bool + emit (rich_location *rich_loc, logger *) final override + { + diagnostic_metadata m; + bool warned; + // just assuming constants for now + auto actual_refcnt + = m_actual_refcnt->dyn_cast_constant_svalue ()->get_constant (); + auto ob_refcnt = m_ob_refcnt->dyn_cast_constant_svalue ()->get_constant (); + warned = warning_meta (rich_loc, m, get_controlling_option (), + "expected %qE to have " + "reference count: %qE but ob_refcnt field is: %qE", + m_reg_tree, actual_refcnt, ob_refcnt); + + // location_t loc = rich_loc->get_loc (); + // foo (loc); + return warned; + } + + void mark_interesting_stuff (interesting_t *interest) final override + { + if (m_base_region) + interest->add_region_creation (m_base_region); + } + +private: + + void foo(location_t loc) const + { + inform(loc, "something is up right here"); + } + const region *m_base_region; + const svalue *m_ob_refcnt; + const svalue *m_actual_refcnt; + tree m_reg_tree; +}; + +/* Retrieves the svalue associated with the ob_refcnt field of the base region. + */ +static const svalue * +retrieve_ob_refcnt_sval (const region *base_reg, const region_model *model, + region_model_context *ctxt) +{ + region_model_manager *mgr = model->get_manager (); + tree ob_refcnt_tree = get_field_by_name (pyobj_record, "ob_refcnt"); + const region *ob_refcnt_region + = mgr->get_field_region (base_reg, ob_refcnt_tree); + const svalue *ob_refcnt_sval + = model->get_store_value (ob_refcnt_region, ctxt); + return ob_refcnt_sval; +} + +static void +increment_region_refcnt (hash_map &map, const region *key) +{ + bool existed; + auto &refcnt = map.get_or_insert (key, &existed); + refcnt = existed ? refcnt + 1 : 1; +} + + +/* Recursively fills in region_to_refcnt with the references owned by + pyobj_ptr_sval. */ +static void +count_pyobj_references (const region_model *model, + hash_map ®ion_to_refcnt, + const svalue *pyobj_ptr_sval, + hash_set &seen) +{ + if (!pyobj_ptr_sval) + return; + + const auto *pyobj_region_sval = pyobj_ptr_sval->dyn_cast_region_svalue (); + const auto *pyobj_initial_sval = pyobj_ptr_sval->dyn_cast_initial_svalue (); + if (!pyobj_region_sval && !pyobj_initial_sval) + return; + + // todo: support initial sval (e.g passed in as parameter) + if (pyobj_initial_sval) + { + // increment_region_refcnt (region_to_refcnt, + // pyobj_initial_sval->get_region ()); + return; + } + + const region *pyobj_region = pyobj_region_sval->get_pointee (); + if (!pyobj_region || seen.contains (pyobj_region)) + return; + + seen.add (pyobj_region); + + if (pyobj_ptr_sval->get_type () == pyobj_ptr_tree) + increment_region_refcnt (region_to_refcnt, pyobj_region); + + const auto *curr_store = model->get_store (); + const auto *retval_cluster = curr_store->get_cluster (pyobj_region); + if (!retval_cluster) + return; + + const auto &retval_binding_map = retval_cluster->get_map (); + + for (const auto &binding : retval_binding_map) + { + const svalue *binding_sval = binding.second; + const svalue *unwrapped_sval = binding_sval->unwrap_any_unmergeable (); + const region *pointee = unwrapped_sval->maybe_get_region (); + + if (pointee && pointee->get_kind () == RK_HEAP_ALLOCATED) + count_pyobj_references (model, region_to_refcnt, binding_sval, seen); + } +} + +/* Compare ob_refcnt field vs the actual reference count of a region */ +static void +check_refcnt (const region_model *model, + const region_model *old_model, + region_model_context *ctxt, + const hash_map::iterator::reference_pair region_refcnt) +{ + region_model_manager *mgr = model->get_manager (); + const auto &curr_region = region_refcnt.first; + const auto &actual_refcnt = region_refcnt.second; + const svalue *ob_refcnt_sval + = retrieve_ob_refcnt_sval (curr_region, model, ctxt); + const svalue *actual_refcnt_sval = mgr->get_or_create_int_cst ( + ob_refcnt_sval->get_type (), actual_refcnt); + + if (ob_refcnt_sval != actual_refcnt_sval) + { + const svalue *curr_reg_sval + = mgr->get_ptr_svalue (pyobj_ptr_tree, curr_region); + tree reg_tree = old_model->get_representative_tree (curr_reg_sval); + if (!reg_tree) + return; + + const auto &eg = ctxt->get_eg (); + refcnt_stmt_finder finder (*eg, reg_tree); + auto pd = make_unique (curr_region, ob_refcnt_sval, + actual_refcnt_sval, reg_tree); + if (pd && eg) + ctxt->warn (std::move (pd), &finder); + } +} + +static void +check_refcnts (const region_model *model, + const region_model *old_model, + const svalue *retval, + region_model_context *ctxt, + hash_map ®ion_to_refcnt) +{ + for (const auto ®ion_refcnt : region_to_refcnt) + { + check_refcnt (model, old_model, ctxt, region_refcnt); + } +} + +/* Validates the reference count of all Python objects. */ +void +pyobj_refcnt_checker (const region_model *model, + const region_model *old_model, + const svalue *retval, + region_model_context *ctxt) +{ + if (!ctxt) + return; + + hash_map region_to_refcnt; + hash_set seen_regions; + + count_pyobj_references (model, region_to_refcnt, retval, seen_regions); + check_refcnts (model, old_model, retval, ctxt, region_to_refcnt); +} + +/* Counts the actual pyobject references from all clusters in the model's + * store. */ +static void +count_all_references (const region_model *model, + hash_map ®ion_to_refcnt) +{ + for (const auto &cluster : *model->get_store ()) + { + auto curr_region = cluster.first; + if (curr_region->get_kind () != RK_HEAP_ALLOCATED) + continue; + + increment_region_refcnt (region_to_refcnt, curr_region); + + auto binding_cluster = cluster.second; + for (const auto &binding : binding_cluster->get_map ()) + { + const svalue *binding_sval = binding.second; + + const svalue *unwrapped_sval + = binding_sval->unwrap_any_unmergeable (); + // if (unwrapped_sval->get_type () != pyobj_ptr_tree) + // continue; + + const region *pointee = unwrapped_sval->maybe_get_region (); + if (!pointee || pointee->get_kind () != RK_HEAP_ALLOCATED) + continue; + + increment_region_refcnt (region_to_refcnt, pointee); + } + } +} + +static void +dump_refcnt_info (const hash_map ®ion_to_refcnt, + const region_model *model, + region_model_context *ctxt) +{ + region_model_manager *mgr = model->get_manager (); + pretty_printer pp; + pp_format_decoder (&pp) = default_tree_printer; + pp_show_color (&pp) = pp_show_color (global_dc->printer); + pp.buffer->stream = stderr; + + for (const auto ®ion_refcnt : region_to_refcnt) + { + auto region = region_refcnt.first; + auto actual_refcnt = region_refcnt.second; + const svalue *ob_refcnt_sval + = retrieve_ob_refcnt_sval (region, model, ctxt); + const svalue *actual_refcnt_sval = mgr->get_or_create_int_cst ( + ob_refcnt_sval->get_type (), actual_refcnt); + + region->dump_to_pp (&pp, true); + pp_string (&pp, " — ob_refcnt: "); + ob_refcnt_sval->dump_to_pp (&pp, true); + pp_string (&pp, " actual refcnt: "); + actual_refcnt_sval->dump_to_pp (&pp, true); + pp_newline (&pp); + } + pp_string (&pp, "~~~~~~~~\n"); + pp_flush (&pp); +} + +class kf_analyzer_cpython_dump_refcounts : public known_function +{ +public: + bool matches_call_types_p (const call_details &cd) const final override + { + return cd.num_args () == 0; + } + void impl_call_pre (const call_details &cd) const final override + { + region_model_context *ctxt = cd.get_ctxt (); + if (!ctxt) + return; + region_model *model = cd.get_model (); + hash_map region_to_refcnt; + count_all_references(model, region_to_refcnt); + dump_refcnt_info(region_to_refcnt, model, ctxt); + } +}; + +/* Some concessions were made to +simplify the analysis process when comparing kf_PyList_Append with the +real implementation. In particular, PyList_Append performs some +optimization internally to try and avoid calls to realloc if +possible. For simplicity, we assume that realloc is called every time. +Also, we grow the size by just 1 (to ensure enough space for adding a +new element) rather than abide by the heuristics that the actual implementation +follows. */ +class kf_PyList_Append : public known_function +{ +public: + bool + matches_call_types_p (const call_details &cd) const final override + { + return (cd.num_args () == 2 && cd.arg_is_pointer_p (0) + && cd.arg_is_pointer_p (1)); + } + void impl_call_pre (const call_details &cd) const final override; + void impl_call_post (const call_details &cd) const final override; +}; + +void +kf_PyList_Append::impl_call_pre (const call_details &cd) const +{ + region_model_manager *mgr = cd.get_manager (); + region_model *model = cd.get_model (); + + const svalue *pylist_sval = cd.get_arg_svalue (0); + const region *pylist_reg + = model->deref_rvalue (pylist_sval, cd.get_arg_tree (0), cd.get_ctxt ()); + + const svalue *newitem_sval = cd.get_arg_svalue (1); + const region *newitem_reg + = model->deref_rvalue (pylist_sval, cd.get_arg_tree (0), cd.get_ctxt ()); + + // Skip checks if unknown etc + if (pylist_sval->get_kind () != SK_REGION + && pylist_sval->get_kind () != SK_CONSTANT) + return; + + // PyList_Check + tree ob_type_field = get_field_by_name (pyobj_record, "ob_type"); + const region *ob_type_region + = mgr->get_field_region (pylist_reg, ob_type_field); + const svalue *stored_sval + = model->get_store_value (ob_type_region, cd.get_ctxt ()); + const region *pylist_type_region + = mgr->get_region_for_global (pylisttype_vardecl); + tree pylisttype_vardecl_ptr + = build_pointer_type (TREE_TYPE (pylisttype_vardecl)); + const svalue *pylist_type_ptr + = mgr->get_ptr_svalue (pylisttype_vardecl_ptr, pylist_type_region); + + if (stored_sval != pylist_type_ptr) + { + // TODO: emit diagnostic -Wanalyzer-type-error + cd.get_ctxt ()->terminate_path (); + return; + } + + // Check that new_item is not null. + { + const svalue *null_ptr + = mgr->get_or_create_int_cst (newitem_sval->get_type (), 0); + if (!model->add_constraint (newitem_sval, NE_EXPR, null_ptr, + cd.get_ctxt ())) + { + // TODO: emit diagnostic here + cd.get_ctxt ()->terminate_path (); + return; + } + } +} + +void +kf_PyList_Append::impl_call_post (const call_details &cd) const +{ + /* Three custom subclasses of custom_edge_info, for handling the various + outcomes of "realloc". */ + + /* Concrete custom_edge_info: a realloc call that fails, returning NULL. + */ + class realloc_failure : public failed_call_info + { + public: + realloc_failure (const call_details &cd) : failed_call_info (cd) {} + + bool + update_model (region_model *model, const exploded_edge *, + region_model_context *ctxt) const final override + { + const call_details cd (get_call_details (model, ctxt)); + region_model_manager *mgr = cd.get_manager (); + + const svalue *pylist_sval = cd.get_arg_svalue (0); + const region *pylist_reg = model->deref_rvalue ( + pylist_sval, cd.get_arg_tree (0), cd.get_ctxt ()); + + /* Identify ob_item field and set it to NULL. */ + tree ob_item_field = get_field_by_name (pylistobj_record, "ob_item"); + const region *ob_item_reg + = mgr->get_field_region (pylist_reg, ob_item_field); + const svalue *old_ptr_sval + = model->get_store_value (ob_item_reg, cd.get_ctxt ()); + + if (const region_svalue *old_reg + = old_ptr_sval->dyn_cast_region_svalue ()) + { + const region *freed_reg = old_reg->get_pointee (); + model->unbind_region_and_descendents (freed_reg, POISON_KIND_FREED); + model->unset_dynamic_extents (freed_reg); + } + + const svalue *null_sval = mgr->get_or_create_null_ptr (pyobj_ptr_ptr); + model->set_value (ob_item_reg, null_sval, cd.get_ctxt ()); + + if (cd.get_lhs_type ()) + { + const svalue *neg_one + = mgr->get_or_create_int_cst (cd.get_lhs_type (), -1); + cd.maybe_set_lhs(neg_one); + } + return true; + } + }; + + class realloc_success_no_move : public call_info + { + public: + realloc_success_no_move (const call_details &cd) : call_info (cd) {} + + label_text + get_desc (bool can_colorize) const final override + { + return make_label_text ( + can_colorize, "when %qE succeeds, without moving underlying buffer", + get_fndecl ()); + } + + bool + update_model (region_model *model, const exploded_edge *, + region_model_context *ctxt) const final override + { + const call_details cd (get_call_details (model, ctxt)); + region_model_manager *mgr = cd.get_manager (); + + const svalue *pylist_sval = cd.get_arg_svalue (0); + const region *pylist_reg = model->deref_rvalue ( + pylist_sval, cd.get_arg_tree (0), cd.get_ctxt ()); + + const svalue *newitem_sval = cd.get_arg_svalue (1); + const region *newitem_reg = model->deref_rvalue ( + newitem_sval, cd.get_arg_tree (1), cd.get_ctxt ()); + + tree ob_size_field = get_field_by_name (varobj_record, "ob_size"); + const region *ob_size_region + = mgr->get_field_region (pylist_reg, ob_size_field); + const svalue *ob_size_sval = nullptr; + const svalue *new_size_sval = nullptr; + inc_field_val (mgr, model, ob_size_region, integer_type_node, cd, + &ob_size_sval, &new_size_sval); + + const svalue *sizeof_sval = mgr->get_or_create_cast ( + ob_size_sval->get_type (), get_sizeof_pyobjptr (mgr)); + const svalue *num_allocated_bytes = mgr->get_or_create_binop ( + size_type_node, MULT_EXPR, sizeof_sval, new_size_sval); + + tree ob_item_field = get_field_by_name (pylistobj_record, "ob_item"); + const region *ob_item_region + = mgr->get_field_region (pylist_reg, ob_item_field); + const svalue *ob_item_ptr_sval + = model->get_store_value (ob_item_region, cd.get_ctxt ()); + + /* We can only grow in place with a non-NULL pointer and no unknown + */ + { + const svalue *null_ptr = mgr->get_or_create_null_ptr (pyobj_ptr_ptr); + if (!model->add_constraint (ob_item_ptr_sval, NE_EXPR, null_ptr, + cd.get_ctxt ())) + { + return false; + } + } + + const unmergeable_svalue *underlying_svalue + = ob_item_ptr_sval->dyn_cast_unmergeable_svalue (); + const svalue *target_svalue = nullptr; + const region_svalue *target_region_svalue = nullptr; + + if (underlying_svalue) + { + target_svalue = underlying_svalue->get_arg (); + if (target_svalue->get_kind () != SK_REGION) + { + return false; + } + } + else + { + if (ob_item_ptr_sval->get_kind () != SK_REGION) + { + return false; + } + target_svalue = ob_item_ptr_sval; + } + + target_region_svalue = target_svalue->dyn_cast_region_svalue (); + const region *curr_reg = target_region_svalue->get_pointee (); + + if (compat_types_p (num_allocated_bytes->get_type (), size_type_node)) + model->set_dynamic_extents (curr_reg, num_allocated_bytes, ctxt); + + model->set_value (ob_size_region, new_size_sval, ctxt); + + const svalue *offset_sval = mgr->get_or_create_binop ( + size_type_node, MULT_EXPR, sizeof_sval, ob_size_sval); + const region *element_region + = mgr->get_offset_region (curr_reg, pyobj_ptr_ptr, offset_sval); + model->set_value (element_region, newitem_sval, cd.get_ctxt ()); + + // Increment ob_refcnt of appended item. + tree ob_refcnt_tree = get_field_by_name (pyobj_record, "ob_refcnt"); + const region *ob_refcnt_region + = mgr->get_field_region (newitem_reg, ob_refcnt_tree); + inc_field_val (mgr, model, ob_refcnt_region, size_type_node, cd); + + if (cd.get_lhs_type ()) + { + const svalue *zero + = mgr->get_or_create_int_cst (cd.get_lhs_type (), 0); + cd.maybe_set_lhs(zero); + } + return true; + } + }; + + class realloc_success_move : public call_info + { + public: + realloc_success_move (const call_details &cd) : call_info (cd) {} + + label_text + get_desc (bool can_colorize) const final override + { + return make_label_text (can_colorize, "when %qE succeeds, moving buffer", + get_fndecl ()); + } + + bool + update_model (region_model *model, const exploded_edge *, + region_model_context *ctxt) const final override + { + const call_details cd (get_call_details (model, ctxt)); + region_model_manager *mgr = cd.get_manager (); + const svalue *pylist_sval = cd.get_arg_svalue (0); + const region *pylist_reg = model->deref_rvalue ( + pylist_sval, cd.get_arg_tree (0), cd.get_ctxt ()); + + const svalue *newitem_sval = cd.get_arg_svalue (1); + const region *newitem_reg = model->deref_rvalue ( + newitem_sval, cd.get_arg_tree (1), cd.get_ctxt ()); + + tree ob_size_field = get_field_by_name (varobj_record, "ob_size"); + const region *ob_size_region + = mgr->get_field_region (pylist_reg, ob_size_field); + const svalue *old_ob_size_sval = nullptr; + const svalue *new_ob_size_sval = nullptr; + inc_field_val (mgr, model, ob_size_region, integer_type_node, cd, + &old_ob_size_sval, &new_ob_size_sval); + + const svalue *sizeof_sval = mgr->get_or_create_cast ( + old_ob_size_sval->get_type (), get_sizeof_pyobjptr (mgr)); + const svalue *new_size_sval = mgr->get_or_create_binop ( + size_type_node, MULT_EXPR, sizeof_sval, new_ob_size_sval); + + tree ob_item_field = get_field_by_name (pylistobj_record, "ob_item"); + const region *ob_item_reg + = mgr->get_field_region (pylist_reg, ob_item_field); + const svalue *old_ptr_sval + = model->get_store_value (ob_item_reg, cd.get_ctxt ()); + + /* Create the new region. */ + const region *new_reg = model->get_or_create_region_for_heap_alloc ( + new_size_sval, cd.get_ctxt ()); + const svalue *new_ptr_sval + = mgr->get_ptr_svalue (pyobj_ptr_ptr, new_reg); + if (!model->add_constraint (new_ptr_sval, NE_EXPR, old_ptr_sval, + cd.get_ctxt ())) + return false; + + if (const region_svalue *old_reg + = old_ptr_sval->dyn_cast_region_svalue ()) + { + const region *freed_reg = old_reg->get_pointee (); + const svalue *old_size_sval = model->get_dynamic_extents (freed_reg); + if (old_size_sval) + { + const svalue *copied_size_sval + = get_copied_size (model, old_size_sval, new_size_sval); + const region *copied_old_reg = mgr->get_sized_region ( + freed_reg, pyobj_ptr_ptr, copied_size_sval); + const svalue *buffer_content_sval + = model->get_store_value (copied_old_reg, cd.get_ctxt ()); + const region *copied_new_reg = mgr->get_sized_region ( + new_reg, pyobj_ptr_ptr, copied_size_sval); + model->set_value (copied_new_reg, buffer_content_sval, + cd.get_ctxt ()); + } + else + { + model->mark_region_as_unknown (freed_reg, cd.get_uncertainty ()); + } + + model->unbind_region_and_descendents (freed_reg, POISON_KIND_FREED); + model->unset_dynamic_extents (freed_reg); + } + + const svalue *null_ptr = mgr->get_or_create_null_ptr (pyobj_ptr_ptr); + if (!model->add_constraint (new_ptr_sval, NE_EXPR, null_ptr, + cd.get_ctxt ())) + return false; + + model->set_value (ob_size_region, new_ob_size_sval, ctxt); + model->set_value (ob_item_reg, new_ptr_sval, cd.get_ctxt ()); + + const svalue *offset_sval = mgr->get_or_create_binop ( + size_type_node, MULT_EXPR, sizeof_sval, old_ob_size_sval); + const region *element_region + = mgr->get_offset_region (new_reg, pyobj_ptr_ptr, offset_sval); + model->set_value (element_region, newitem_sval, cd.get_ctxt ()); + + // Increment ob_refcnt of appended item. + tree ob_refcnt_tree = get_field_by_name (pyobj_record, "ob_refcnt"); + const region *ob_refcnt_region + = mgr->get_field_region (newitem_reg, ob_refcnt_tree); + inc_field_val (mgr, model, ob_refcnt_region, size_type_node, cd); + + if (cd.get_lhs_type ()) + { + const svalue *zero + = mgr->get_or_create_int_cst (cd.get_lhs_type (), 0); + cd.maybe_set_lhs(zero); + } + return true; + } + + private: + /* Return the lesser of OLD_SIZE_SVAL and NEW_SIZE_SVAL. + If unknown, OLD_SIZE_SVAL is returned. */ + const svalue * + get_copied_size (region_model *model, const svalue *old_size_sval, + const svalue *new_size_sval) const + { + tristate res + = model->eval_condition (old_size_sval, GT_EXPR, new_size_sval); + switch (res.get_value ()) + { + case tristate::TS_TRUE: + return new_size_sval; + case tristate::TS_FALSE: + case tristate::TS_UNKNOWN: + return old_size_sval; + default: + gcc_unreachable (); + } + } + }; + + /* Body of kf_PyList_Append::impl_call_post. */ + if (cd.get_ctxt ()) + { + cd.get_ctxt ()->bifurcate (make_unique (cd)); + cd.get_ctxt ()->bifurcate (make_unique (cd)); + cd.get_ctxt ()->bifurcate (make_unique (cd)); + cd.get_ctxt ()->terminate_path (); + } +} + +class kf_PyList_New : public known_function +{ +public: + bool + matches_call_types_p (const call_details &cd) const final override + { + return (cd.num_args () == 1 && cd.arg_is_integral_p (0)); + } + void impl_call_post (const call_details &cd) const final override; +}; + +void +kf_PyList_New::impl_call_post (const call_details &cd) const +{ + class success : public call_info + { + public: + success (const call_details &cd) : call_info (cd) {} + + label_text + get_desc (bool can_colorize) const final override + { + return make_label_text (can_colorize, "when %qE succeeds", + get_fndecl ()); + } + + bool + update_model (region_model *model, const exploded_edge *, + region_model_context *ctxt) const final override + { + const call_details cd (get_call_details (model, ctxt)); + region_model_manager *mgr = cd.get_manager (); + + const svalue *pyobj_svalue + = mgr->get_or_create_unknown_svalue (pyobj_record); + const svalue *varobj_svalue + = mgr->get_or_create_unknown_svalue (varobj_record); + const svalue *pylist_svalue + = mgr->get_or_create_unknown_svalue (pylistobj_record); + + const svalue *size_sval = cd.get_arg_svalue (0); + + const region *pylist_region + = init_pyobject_region (mgr, model, pylist_svalue, cd); + + /* + typedef struct + { + PyObject_VAR_HEAD + PyObject **ob_item; + Py_ssize_t allocated; + } PyListObject; + */ + tree varobj_field = get_field_by_name (pylistobj_record, "ob_base"); + const region *varobj_region + = mgr->get_field_region (pylist_region, varobj_field); + model->set_value (varobj_region, varobj_svalue, cd.get_ctxt ()); + + tree ob_item_field = get_field_by_name (pylistobj_record, "ob_item"); + const region *ob_item_region + = mgr->get_field_region (pylist_region, ob_item_field); + + const svalue *zero_sval = mgr->get_or_create_int_cst (size_type_node, 0); + const svalue *casted_size_sval + = mgr->get_or_create_cast (size_type_node, size_sval); + const svalue *size_cond_sval = mgr->get_or_create_binop ( + size_type_node, LE_EXPR, casted_size_sval, zero_sval); + + // if size <= 0, ob_item = NULL + + if (tree_int_cst_equal (size_cond_sval->maybe_get_constant (), + integer_one_node)) + { + const svalue *null_sval + = mgr->get_or_create_null_ptr (pyobj_ptr_ptr); + model->set_value (ob_item_region, null_sval, cd.get_ctxt ()); + } + else // calloc + { + const svalue *sizeof_sval = mgr->get_or_create_cast ( + size_sval->get_type (), get_sizeof_pyobjptr (mgr)); + const svalue *prod_sval = mgr->get_or_create_binop ( + size_type_node, MULT_EXPR, sizeof_sval, size_sval); + const region *ob_item_sized_region + = model->get_or_create_region_for_heap_alloc (prod_sval, + cd.get_ctxt ()); + model->zero_fill_region (ob_item_sized_region); + const svalue *ob_item_ptr_sval + = mgr->get_ptr_svalue (pyobj_ptr_ptr, ob_item_sized_region); + const svalue *ob_item_unmergeable + = mgr->get_or_create_unmergeable (ob_item_ptr_sval); + model->set_value (ob_item_region, ob_item_unmergeable, + cd.get_ctxt ()); + } + + /* + typedef struct { + PyObject ob_base; + Py_ssize_t ob_size; // Number of items in variable part + } PyVarObject; + */ + const region *ob_base_region = get_ob_base_region ( + mgr, model, varobj_region, varobj_record, pyobj_svalue, cd); + + tree ob_size_tree = get_field_by_name (varobj_record, "ob_size"); + const region *ob_size_region + = mgr->get_field_region (varobj_region, ob_size_tree); + model->set_value (ob_size_region, size_sval, cd.get_ctxt ()); + + /* + typedef struct _object { + _PyObject_HEAD_EXTRA + Py_ssize_t ob_refcnt; + PyTypeObject *ob_type; + } PyObject; + */ + + // Initialize ob_refcnt field to 1. + init_ob_refcnt_field(mgr, model, ob_base_region, pyobj_record, cd); + + // Get pointer svalue for PyList_Type then assign it to ob_type field. + set_ob_type_field(mgr, model, ob_base_region, pyobj_record, pylisttype_vardecl, cd); + + if (cd.get_lhs_type ()) + { + const svalue *ptr_sval + = mgr->get_ptr_svalue (cd.get_lhs_type (), pylist_region); + cd.maybe_set_lhs (ptr_sval); + } + return true; + } + }; + + if (cd.get_ctxt ()) + { + cd.get_ctxt ()->bifurcate (make_unique (cd)); + cd.get_ctxt ()->bifurcate (make_unique (cd)); + cd.get_ctxt ()->terminate_path (); + } +} + +class kf_PyLong_FromLong : public known_function +{ +public: + bool + matches_call_types_p (const call_details &cd) const final override + { + return (cd.num_args () == 1 && cd.arg_is_integral_p (0)); + } + void impl_call_post (const call_details &cd) const final override; +}; + +void +kf_PyLong_FromLong::impl_call_post (const call_details &cd) const +{ + class success : public call_info + { + public: + success (const call_details &cd) : call_info (cd) {} + + label_text + get_desc (bool can_colorize) const final override + { + return make_label_text (can_colorize, "when %qE succeeds", + get_fndecl ()); + } + + bool + update_model (region_model *model, const exploded_edge *, + region_model_context *ctxt) const final override + { + const call_details cd (get_call_details (model, ctxt)); + region_model_manager *mgr = cd.get_manager (); + + const svalue *pyobj_svalue + = mgr->get_or_create_unknown_svalue (pyobj_record); + const svalue *pylongobj_sval + = mgr->get_or_create_unknown_svalue (pylongobj_record); + + const region *pylong_region + = init_pyobject_region (mgr, model, pylongobj_sval, cd); + + // Create a region for the base PyObject within the PyLongObject. + const region *ob_base_region = get_ob_base_region ( + mgr, model, pylong_region, pylongobj_record, pyobj_svalue, cd); + + // Initialize ob_refcnt field to 1. + init_ob_refcnt_field(mgr, model, ob_base_region, pyobj_record, cd); + + // Get pointer svalue for PyLong_Type then assign it to ob_type field. + set_ob_type_field(mgr, model, ob_base_region, pyobj_record, pylongtype_vardecl, cd); + + // Set the PyLongObject value. + tree ob_digit_field = get_field_by_name (pylongobj_record, "ob_digit"); + const region *ob_digit_region + = mgr->get_field_region (pylong_region, ob_digit_field); + const svalue *ob_digit_sval = cd.get_arg_svalue (0); + model->set_value (ob_digit_region, ob_digit_sval, cd.get_ctxt ()); + + if (cd.get_lhs_type ()) + { + const svalue *ptr_sval + = mgr->get_ptr_svalue (cd.get_lhs_type (), pylong_region); + cd.maybe_set_lhs (ptr_sval); + } + return true; + } + }; + + if (cd.get_ctxt ()) + { + cd.get_ctxt ()->bifurcate (make_unique (cd)); + cd.get_ctxt ()->bifurcate (make_unique (cd)); + cd.get_ctxt ()->terminate_path (); + } +} + static void maybe_stash_named_type (logger *logger, const translation_unit &tu, const char *name) @@ -179,6 +1265,12 @@ init_py_structs () pylongobj_record = get_stashed_type_by_name ("PyLongObject"); pylongtype_vardecl = get_stashed_global_var_by_name ("PyLong_Type"); pylisttype_vardecl = get_stashed_global_var_by_name ("PyList_Type"); + + if (pyobj_record) + { + pyobj_ptr_tree = build_pointer_type (pyobj_record); + pyobj_ptr_ptr = build_pointer_type (pyobj_ptr_tree); + } } void @@ -205,6 +1297,16 @@ cpython_analyzer_init_cb (void *gcc_data, void * /*user_data */) sorry_no_cpython_plugin (); return; } + + iface->register_known_function ("PyList_Append", + make_unique ()); + iface->register_known_function ("PyList_New", make_unique ()); + iface->register_known_function ("PyLong_FromLong", + make_unique ()); + + iface->register_known_function ( + "__analyzer_cpython_dump_refcounts", + make_unique ()); } } // namespace ana @@ -218,8 +1320,9 @@ plugin_init (struct plugin_name_args *plugin_info, const char *plugin_name = plugin_info->base_name; if (0) inform (input_location, "got here; %qs", plugin_name); - ana::register_finish_translation_unit_callback (&stash_named_types); - ana::register_finish_translation_unit_callback (&stash_global_vars); + register_finish_translation_unit_callback (&stash_named_types); + register_finish_translation_unit_callback (&stash_global_vars); + region_model::register_pop_frame_callback(pyobj_refcnt_checker); register_callback (plugin_info->base_name, PLUGIN_ANALYZER_INIT, ana::cpython_analyzer_init_cb, NULL); /* void *user_data */ @@ -227,4 +1330,4 @@ plugin_init (struct plugin_name_args *plugin_info, sorry_no_analyzer (); #endif return 0; -} \ No newline at end of file +} diff --git a/gcc/testsuite/gcc.dg/plugin/analyzer_kernel_plugin.c b/gcc/testsuite/gcc.dg/plugin/analyzer_kernel_plugin.c index 57bccf4f2eb5..02dba7a3234d 100644 --- a/gcc/testsuite/gcc.dg/plugin/analyzer_kernel_plugin.c +++ b/gcc/testsuite/gcc.dg/plugin/analyzer_kernel_plugin.c @@ -86,8 +86,11 @@ class copy_across_boundary_fn : public known_function if (tree cst = num_bytes_sval->maybe_get_constant ()) if (zerop (cst)) - /* No-op. */ - return; + { + /* No-op. */ + model->update_for_zero_return (cd, true); + return; + } const region *sized_src_reg = mgr->get_sized_region (src_reg, NULL_TREE, diff --git a/gcc/testsuite/gcc.dg/plugin/analyzer_known_fns_plugin.c b/gcc/testsuite/gcc.dg/plugin/analyzer_known_fns_plugin.c index de887dbad837..806cb90ef56a 100644 --- a/gcc/testsuite/gcc.dg/plugin/analyzer_known_fns_plugin.c +++ b/gcc/testsuite/gcc.dg/plugin/analyzer_known_fns_plugin.c @@ -147,8 +147,11 @@ public: if (tree cst = num_bytes_sval->maybe_get_constant ()) if (zerop (cst)) - /* No-op. */ - return; + { + /* No-op. */ + cd.set_any_lhs_with_defaults (); + return; + } const region *sized_src_reg = mgr->get_sized_region (src_reg, NULL_TREE, diff --git a/gcc/testsuite/gcc.dg/plugin/cpython-plugin-test-PyList_Append.c b/gcc/testsuite/gcc.dg/plugin/cpython-plugin-test-PyList_Append.c new file mode 100644 index 000000000000..e1efd9efda5e --- /dev/null +++ b/gcc/testsuite/gcc.dg/plugin/cpython-plugin-test-PyList_Append.c @@ -0,0 +1,78 @@ +/* { dg-do compile } */ +/* { dg-require-effective-target analyzer } */ +/* { dg-options "-fanalyzer" } */ +/* { dg-require-python-h "" } */ + + +#define PY_SSIZE_T_CLEAN +#include +#include "../analyzer/analyzer-decls.h" + +PyObject * +test_PyListAppend (long n) +{ + PyObject *item = PyLong_FromLong (n); + PyObject *list = PyList_New (0); + PyList_Append(list, item); + return list; /* { dg-warning "leak of 'item'" } */ + /* { dg-warning "expected 'item' to have reference count" "" { target *-*-* } .-1 } */ +} + +PyObject * +test_PyListAppend_2 (long n) +{ + PyObject *item = PyLong_FromLong (n); + if (!item) + return NULL; + + __analyzer_eval (item->ob_refcnt == 1); /* { dg-warning "TRUE" } */ + PyObject *list = PyList_New (n); + if (!list) + { + Py_DECREF(item); + return NULL; + } + + __analyzer_eval (list->ob_refcnt == 1); /* { dg-warning "TRUE" } */ + + if (PyList_Append (list, item) < 0) + __analyzer_eval (item->ob_refcnt == 1); /* { dg-warning "TRUE" } */ + else + __analyzer_eval (item->ob_refcnt == 2); /* { dg-warning "TRUE" } */ + return list; /* { dg-warning "leak of 'item'" } */ + /* { dg-warning "expected 'item' to have reference count" "" { target *-*-* } .-1 } */ +} + + +PyObject * +test_PyListAppend_3 (PyObject *item, PyObject *list) +{ + PyList_Append (list, item); + return list; +} + +PyObject * +test_PyListAppend_4 (long n) +{ + PyObject *item = PyLong_FromLong (n); + PyObject *list = NULL; + PyList_Append(list, item); + return list; +} + +PyObject * +test_PyListAppend_5 () +{ + PyObject *list = PyList_New (0); + PyList_Append(list, NULL); + return list; +} + +PyObject * +test_PyListAppend_6 () +{ + PyObject *item = NULL; + PyObject *list = NULL; + PyList_Append(list, item); + return list; +} \ No newline at end of file diff --git a/gcc/testsuite/gcc.dg/plugin/cpython-plugin-test-PyList_New.c b/gcc/testsuite/gcc.dg/plugin/cpython-plugin-test-PyList_New.c new file mode 100644 index 000000000000..1d28e66b4903 --- /dev/null +++ b/gcc/testsuite/gcc.dg/plugin/cpython-plugin-test-PyList_New.c @@ -0,0 +1,38 @@ +/* { dg-do compile } */ +/* { dg-require-effective-target analyzer } */ +/* { dg-options "-fanalyzer" } */ +/* { dg-require-python-h "" } */ + + +#define PY_SSIZE_T_CLEAN +#include +#include "../analyzer/analyzer-decls.h" + +PyObject * +test_PyList_New (Py_ssize_t len) +{ + PyObject *obj = PyList_New (len); + if (obj) + { + __analyzer_eval (obj->ob_refcnt == 1); /* { dg-warning "TRUE" } */ + __analyzer_eval (PyList_CheckExact (obj)); /* { dg-warning "TRUE" } */ + } + else + __analyzer_dump_path (); /* { dg-message "path" } */ + return obj; +} + +void +test_PyList_New_2 () +{ + PyObject *obj = PyList_New (0); +} /* { dg-warning "leak of 'obj'" } */ + +PyObject *test_stray_incref_PyList () +{ + PyObject *p = PyList_New (2); + if (p) + Py_INCREF (p); + return p; + /* { dg-warning "expected 'p' to have reference count" "" { target *-*-* } .-1 } */ +} \ No newline at end of file diff --git a/gcc/testsuite/gcc.dg/plugin/cpython-plugin-test-PyLong_FromLong.c b/gcc/testsuite/gcc.dg/plugin/cpython-plugin-test-PyLong_FromLong.c new file mode 100644 index 000000000000..6ac593964ba3 --- /dev/null +++ b/gcc/testsuite/gcc.dg/plugin/cpython-plugin-test-PyLong_FromLong.c @@ -0,0 +1,38 @@ +/* { dg-do compile } */ +/* { dg-require-effective-target analyzer } */ +/* { dg-options "-fanalyzer" } */ +/* { dg-require-python-h "" } */ + + +#define PY_SSIZE_T_CLEAN +#include +#include "../analyzer/analyzer-decls.h" + +PyObject * +test_PyLong_New (long n) +{ + PyObject *obj = PyLong_FromLong (n); + if (obj) + { + __analyzer_eval (obj->ob_refcnt == 1); /* { dg-warning "TRUE" } */ + __analyzer_eval (PyLong_CheckExact (obj)); /* { dg-warning "TRUE" } */ + } + else + __analyzer_dump_path (); /* { dg-message "path" } */ + return obj; +} + +void +test_PyLong_New_2 (long n) +{ + PyObject *obj = PyLong_FromLong (n); +} /* { dg-warning "leak of 'obj'" } */ + +PyObject *test_stray_incref_PyLong (long val) +{ + PyObject *p = PyLong_FromLong (val); + if (p) + Py_INCREF (p); + return p; + /* { dg-warning "expected 'p' to have reference count" "" { target *-*-* } .-1 } */ +} \ No newline at end of file diff --git a/gcc/testsuite/gcc.dg/plugin/cpython-plugin-test-1.c b/gcc/testsuite/gcc.dg/plugin/cpython-plugin-test-no-Python-h.c similarity index 100% rename from gcc/testsuite/gcc.dg/plugin/cpython-plugin-test-1.c rename to gcc/testsuite/gcc.dg/plugin/cpython-plugin-test-no-Python-h.c diff --git a/gcc/testsuite/gcc.dg/plugin/crash-test-write-though-null-sarif.c b/gcc/testsuite/gcc.dg/plugin/crash-test-write-though-null-sarif.c index 83b38d2ffb5f..513d66c528d5 100644 --- a/gcc/testsuite/gcc.dg/plugin/crash-test-write-though-null-sarif.c +++ b/gcc/testsuite/gcc.dg/plugin/crash-test-write-though-null-sarif.c @@ -61,4 +61,4 @@ void test_inject_write_through_null (void) { dg-final { scan-sarif-file "\"startColumn\": 3" } } { dg-final { scan-sarif-file "\"endColumn\": 31" } } { dg-final { scan-sarif-file "\"message\": " } } - { dg-final { scan-sarif-file "\"text\": \"Segmentation fault\"" } } */ + { dg-final { scan-sarif-file "\"text\": \"Segmentation fault" } } */ diff --git a/gcc/testsuite/gcc.dg/plugin/plugin.exp b/gcc/testsuite/gcc.dg/plugin/plugin.exp index 09c45394b1f0..ed72912309ce 100644 --- a/gcc/testsuite/gcc.dg/plugin/plugin.exp +++ b/gcc/testsuite/gcc.dg/plugin/plugin.exp @@ -161,7 +161,10 @@ set plugin_test_list [list \ taint-CVE-2011-0521-6.c \ taint-antipatterns-1.c } \ { analyzer_cpython_plugin.c \ - cpython-plugin-test-1.c } \ + cpython-plugin-test-no-Python-h.c \ + cpython-plugin-test-PyList_Append.c \ + cpython-plugin-test-PyList_New.c \ + cpython-plugin-test-PyLong_FromLong.c } \ ] foreach plugin_test $plugin_test_list { diff --git a/gcc/testsuite/gcc.dg/plugin/taint-CVE-2011-0521-5-fixed.c b/gcc/testsuite/gcc.dg/plugin/taint-CVE-2011-0521-5-fixed.c index 8cb067c6542b..2e74770a7a33 100644 --- a/gcc/testsuite/gcc.dg/plugin/taint-CVE-2011-0521-5-fixed.c +++ b/gcc/testsuite/gcc.dg/plugin/taint-CVE-2011-0521-5-fixed.c @@ -4,6 +4,9 @@ /* { dg-options "-fanalyzer -fanalyzer-checker=taint --param=analyzer-max-svalue-depth=25" } */ /* { dg-require-effective-target analyzer } */ +/* On darwin, system headers are fortified, which defeats the analysis. Turn it off. */ +/* { dg-additional-options "-D_FORTIFY_SOURCE=0" { target *-*-darwin* } } */ + /* See notes in this header. */ #include "taint-CVE-2011-0521.h" diff --git a/gcc/testsuite/gcc.dg/plugin/taint-CVE-2011-0521-5.c b/gcc/testsuite/gcc.dg/plugin/taint-CVE-2011-0521-5.c index 4ce047902d3e..021d458b66ef 100644 --- a/gcc/testsuite/gcc.dg/plugin/taint-CVE-2011-0521-5.c +++ b/gcc/testsuite/gcc.dg/plugin/taint-CVE-2011-0521-5.c @@ -4,6 +4,9 @@ /* { dg-options "-fanalyzer -fanalyzer-checker=taint --param=analyzer-max-svalue-depth=25" } */ /* { dg-require-effective-target analyzer } */ +/* On darwin, system headers are fortified, which defeats the analysis. Turn it off. */ +/* { dg-additional-options "-D_FORTIFY_SOURCE=0" { target *-*-darwin* } } */ + /* See notes in this header. */ #include "taint-CVE-2011-0521.h" diff --git a/gcc/testsuite/gcc.dg/plugin/taint-CVE-2011-0521-6.c b/gcc/testsuite/gcc.dg/plugin/taint-CVE-2011-0521-6.c index c54af790a564..f27e9eb5f020 100644 --- a/gcc/testsuite/gcc.dg/plugin/taint-CVE-2011-0521-6.c +++ b/gcc/testsuite/gcc.dg/plugin/taint-CVE-2011-0521-6.c @@ -4,6 +4,9 @@ /* { dg-options "-fanalyzer -fanalyzer-checker=taint --param=analyzer-max-svalue-depth=25" } */ /* { dg-require-effective-target analyzer } */ +/* On darwin, system headers are fortified, which defeats the analysis. Turn it off. */ +/* { dg-additional-options "-D_FORTIFY_SOURCE=0" { target *-*-darwin* } } */ + /* See notes in this header. */ #include "taint-CVE-2011-0521.h" diff --git a/gcc/testsuite/gcc.dg/pr102983.c b/gcc/testsuite/gcc.dg/pr102983.c index e1bd24b2e39e..ded748af08a3 100644 --- a/gcc/testsuite/gcc.dg/pr102983.c +++ b/gcc/testsuite/gcc.dg/pr102983.c @@ -18,4 +18,4 @@ int main() { } } -/* { dg-final { scan-tree-dump-times "Folding predicate c_.* to 1" 1 "evrp" } } */ +/* { dg-final { scan-tree-dump-times "Global Exported: c_.*1, 1" 1 "evrp" } } */ diff --git a/gcc/testsuite/gcc.dg/pr108757-1.c b/gcc/testsuite/gcc.dg/pr108757-1.c new file mode 100644 index 000000000000..7908f4bdcb8e --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr108757-1.c @@ -0,0 +1,18 @@ +/* PR tree-optimization/108757 */ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-optimized" } */ + +#include +#define N 5 +#define M 3 +#define GAP 0 +typedef unsigned int UINT; +typedef int INT; +#define UMAX UINT_MAX +#define IMAX INT_MAX +#define IMIN INT_MIN +#include "pr108757.h" + +/* { dg-final { scan-tree-dump-not " = x_\[0-9\]+\\(D\\) \\+ " "optimized" } } * +/* { dg-final { scan-tree-dump-not " = x_\[0-9\]+\\(D\\) \\- " "optimized" } } */ +/* { dg-final { scan-tree-dump-not " = b_\[0-9\]+ \\+ " "optimized" } } */ diff --git a/gcc/testsuite/gcc.dg/pr108757-2.c b/gcc/testsuite/gcc.dg/pr108757-2.c new file mode 100644 index 000000000000..82bebd09944f --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr108757-2.c @@ -0,0 +1,19 @@ +/* PR tree-optimization/108757 */ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-optimized -fwrapv" } */ + +#include +#define N 4 +#define M 3 +#define GAP 2 +typedef unsigned int UINT; +typedef int INT; +#define UMAX UINT_MAX +#define IMAX INT_MAX +#define IMIN INT_MIN +#include "pr108757.h" + +/* { dg-final { scan-tree-dump-times " = x_\[0-9\]+\\(D\\) \\+ " 16 "optimized" } } */ +/* { dg-final { scan-tree-dump-times " = x_\[0-9\]+\\(D\\) \\- " 3 "optimized" } } */ +/* { dg-final { scan-tree-dump-times " \\+ x_\[0-9\]+\\(D\\)" 3 "optimized" } } */ + diff --git a/gcc/testsuite/gcc.dg/pr108757.h b/gcc/testsuite/gcc.dg/pr108757.h new file mode 100644 index 000000000000..5550199c1ef9 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr108757.h @@ -0,0 +1,233 @@ +#define NOINLINE __attribute__ ((noinline)) +UINT NOINLINE +opt_u1 (UINT x) +{ + if (x < (M * N) - GAP) + return 0; + UINT a = x - (M * N); + UINT b = a / N; + return b + M; +} + +UINT NOINLINE +opt_u2 (UINT x) +{ + if (x > (UMAX - (M * N) + GAP)) + return 0; + UINT a = x + (M * N); + UINT b = a / N; + return b - M; +} + +INT NOINLINE +opt_s1 (INT x) +{ + if (x < (M * N) - GAP) + return 0; + INT a = x - (M * N); + INT b = a / N; + return b + M; +} + +INT NOINLINE +opt_s2 (INT x) +{ + if (x < IMIN + (M * N) - GAP || x > 0) + return 0; + INT a = x - (M * N); + INT b = a / N; + return b + M; +} + +INT NOINLINE +opt_s3 (INT x) +{ + if (x < (M * N) - GAP) + return 0; + INT a = x - (M * N); + INT b = a / -N; + return b + -M; +} + +INT NOINLINE +opt_s4 (INT x) +{ + if (x < IMIN + (M * N) - GAP || x > 0) + return 0; + INT a = x - (M * N); + INT b = a / -N; + return b + -M; +} + +INT NOINLINE +opt_s5 (INT x) +{ + if (x > (-M * N) + GAP) + return 0; + INT a = x - (-M * N); + INT b = a / N; + return b + -M; +} + +INT NOINLINE +opt_s6 (INT x) +{ + if (x > IMAX - (M * N) + GAP || x < 0) + return 0; + INT a = x - (-M * N); + INT b = a / N; + return b + -M; +} + +INT NOINLINE +opt_s7 (INT x) +{ + if (x > (M * -N) + GAP) + return 0; + INT a = x - (M * -N); + INT b = a / -N; + return b + M; +} + +INT NOINLINE +opt_s8 (INT x) +{ + if (x > IMAX - (M * N) + GAP || x < 0) + return 0; + INT a = x - (M * -N); + INT b = a / -N; + return b + M; +} + +UINT NOINLINE +opt_u3 (UINT x) +{ + if (x < (M << N) - GAP) + return 0; + UINT a = x - (M << N); + UINT b = a >> N; + return b + M; +} + +UINT NOINLINE +opt_u4 (UINT x) +{ + if (x > (UMAX - (M << N)) + GAP) + return 0; + UINT a = x + (M << N); + UINT b = a >> N; + return b - M; +} + +INT NOINLINE +opt_s9 (INT x) +{ + if (x < (M << N) - GAP) + return 0; + INT a = x - (M << N); + INT b = a >> N; + return b + M; +} + +INT NOINLINE +opt_s10 (INT x) +{ + if (x < IMIN + (M << N) - GAP || x > 0) + return 0; + INT a = x - (M << N); + INT b = a >> N; + return b + M; +} + +INT NOINLINE +opt_s11 (INT x) +{ + if (x > (-M << N) + GAP) + return 0; + INT a = x - (-M << N); + INT b = a >> N; + return b + -M; +} + +INT NOINLINE +opt_s12 (INT x) +{ + if (x > IMAX - (M << N) + GAP || x < 0) + return 0; + INT a = x - (-M << N); + INT b = a >> N; + return b + -M; +} + +UINT NOINLINE +opt_u5 (UINT x, UINT n, UINT m) +{ + if (n > N || m > M) + return 0; + if (x < (M*N) - GAP) + return 0; + UINT a = x - (m * n); + UINT b = a / n; + return b + m; +} + +UINT NOINLINE +opt_u6 (UINT x, UINT n, UINT m) +{ + if (n > N || m > M) + return 0; + if (x > (UMAX - M*N) + GAP) + return 0; + UINT a = x + (m * n); + UINT b = a / n; + return b - m; +} + +INT NOINLINE +opt_s13 (INT x, INT n, INT m) +{ + if (n > N || m > M || n < 0 || m < 0) + return 0; + if (x < (M*N) - GAP) + return 0; + INT a = x - (m * n); + INT b = a / n; + return b + m; +} + +INT NOINLINE +opt_s14 (INT x, INT n, INT m) +{ + if (n > N || m > M || n < 0 || m < 0) + return 0; + if (x > -M*N + GAP) + return 0; + INT a = x + (m * n); + INT b = a / n; + return b - m; +} + +INT +opt_s15 (INT x, INT n, INT m) +{ + if (n > 0 || m > 0 || n < -N || m < -M) + return 0; + if (x < (M*N) - GAP) + return 0; + INT a = x - (m * n); + INT b = a / n; + return b + m; +} + +INT NOINLINE +opt_s16 (INT x, INT n, INT m) +{ + if (n > 0 || m > 0 || n < -N || m < -M) + return 0; + if (x < 0 || x > (IMAX - M*N) + GAP) + return 0; + INT a = x + (m * n); + INT b = a / n; + return b - m; +} + diff --git a/gcc/testsuite/gcc.dg/pr110915-1.c b/gcc/testsuite/gcc.dg/pr110915-1.c new file mode 100644 index 000000000000..c205e0ed79ec --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr110915-1.c @@ -0,0 +1,32 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-ifcombine -Wno-psabi" } */ + +#include + +#define vector __attribute__((vector_size(sizeof(unsigned)*2))) + +vector signed and1(vector unsigned x, vector unsigned y) +{ + /* (x > y) & (x != 0) --> x > y */ + return (x > y) & (x != 0); +} + +vector signed and2(vector unsigned x, vector unsigned y) +{ + /* (x < y) & (x != UINT_MAX) --> x < y */ + return (x < y) & (x != UINT_MAX); +} + +vector signed and3(vector signed x, vector signed y) +{ + /* (x > y) & (x != INT_MIN) --> x > y */ + return (x > y) & (x != INT_MIN); +} + +vector signed and4(vector signed x, vector signed y) +{ + /* (x < y) & (x != INT_MAX) --> x < y */ + return (x < y) & (x != INT_MAX); +} + +/* { dg-final { scan-tree-dump-not " != " "ifcombine" } } */ diff --git a/gcc/testsuite/gcc.dg/pr110915-10.c b/gcc/testsuite/gcc.dg/pr110915-10.c new file mode 100644 index 000000000000..283faec0fa05 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr110915-10.c @@ -0,0 +1,34 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-optimized -Wno-psabi" } */ + +#include + +#define vector __attribute__((vector_size(sizeof(unsigned)*2))) + +vector unsigned or1(vector unsigned x, vector unsigned y) +{ + /* (x <= y) | (x != 0)) --> true */ + return (x <= y) | (x != 0); +} + +vector unsigned or2(vector unsigned x, vector unsigned y) +{ + /* (x >= y) | (x != UINT_MAX) --> true */ + return (x >= y) | (x != UINT_MAX); +} + +vector signed or3(vector signed x, vector signed y) +{ + /* (x <= y) | (x != INT_MIN) --> true */ + return (x <= y) | (x != INT_MIN); +} + +vector signed or4(vector signed x, vector signed y) +{ + /* (x >= y) | (x != INT_MAX) --> true */ + return (x >= y) | (x != INT_MAX); +} + +/* { dg-final { scan-tree-dump-not " != " "optimized" } } */ +/* { dg-final { scan-tree-dump-not " <= " "optimized" } } */ +/* { dg-final { scan-tree-dump-not " >= " "optimized" } } */ diff --git a/gcc/testsuite/gcc.dg/pr110915-11.c b/gcc/testsuite/gcc.dg/pr110915-11.c new file mode 100644 index 000000000000..b3636c6aa26e --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr110915-11.c @@ -0,0 +1,32 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-ifcombine -Wno-psabi" } */ + +#include + +#define vector __attribute__((vector_size(sizeof(unsigned)*2))) + +vector unsigned or1(vector unsigned x, vector unsigned y) +{ + /* (x <= y) | (x == 0) --> x <= y */ + return (x <= y) | (x == 0); +} + +vector unsigned or2(vector unsigned x, vector unsigned y) +{ + /* (x >= y) | (x == UINT_MAX) --> x >= y */ + return (x >= y) | (x == UINT_MAX); +} + +vector signed or3(vector signed x, vector signed y) +{ + /* (x <= y) | (x == INT_MIN) --> x <= y */ + return (x <= y) | (x == INT_MIN); +} + +vector signed or4(vector signed x, vector signed y) +{ + /* (x >= y) | (x == INT_MAX) --> x >= y */ + return (x >= y) | (x == INT_MAX); +} + +/* { dg-final { scan-tree-dump-not " == " "ifcombine" } } */ diff --git a/gcc/testsuite/gcc.dg/pr110915-12.c b/gcc/testsuite/gcc.dg/pr110915-12.c new file mode 100644 index 000000000000..4108fc46319b --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr110915-12.c @@ -0,0 +1,32 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-dce3 -Wno-psabi" } */ + +#include + +#define vector __attribute__((vector_size(sizeof(unsigned)*2))) + +vector unsigned or1(vector unsigned x, vector unsigned y) +{ + /* (x <= y) | (x == 0) --> x <= y */ + return (x <= y) | (x == 0); +} + +vector unsigned or2(vector unsigned x, vector unsigned y) +{ + /* (x >= y) | (x == UINT_MAX) --> x >= y */ + return (x >= y) | (x == UINT_MAX); +} + +vector signed or3(vector signed x, vector signed y) +{ + /* (x <= y) | (x == INT_MIN) --> x <= y */ + return (x <= y) | (x == INT_MIN); +} + +vector signed or4(vector signed x, vector signed y) +{ + /* (x >= y) | (x == INT_MAX) --> x >= y */ + return (x >= y) | (x == INT_MAX); +} + +/* { dg-final { scan-tree-dump-not " == " "dce3" } } */ diff --git a/gcc/testsuite/gcc.dg/pr110915-2.c b/gcc/testsuite/gcc.dg/pr110915-2.c new file mode 100644 index 000000000000..8d406121d9eb --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr110915-2.c @@ -0,0 +1,32 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-optimized -Wno-psabi" } */ + +#include + +#define vector __attribute__((vector_size(sizeof(unsigned)*2))) + +vector signed and1(vector unsigned x, vector unsigned y) +{ + /* (x > y) & (x != 0) --> x > y */ + return (x > y) & (x != 0); +} + +vector signed and2(vector unsigned x, vector unsigned y) +{ + /* (x < y) & (x != UINT_MAX) --> x < y */ + return (x < y) & (x != UINT_MAX); +} + +vector signed and3(vector signed x, vector signed y) +{ + /* (x > y) & (x != INT_MIN) --> x > y */ + return (x > y) & (x != INT_MIN); +} + +vector signed and4(vector signed x, vector signed y) +{ + /* (x < y) & (x != INT_MAX) --> x < y */ + return (x < y) & (x != INT_MAX); +} + +/* { dg-final { scan-tree-dump-not " != " "optimized" } } */ diff --git a/gcc/testsuite/gcc.dg/pr110915-3.c b/gcc/testsuite/gcc.dg/pr110915-3.c new file mode 100644 index 000000000000..3ac70f55c4aa --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr110915-3.c @@ -0,0 +1,34 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-ifcombine -Wno-psabi" } */ + +#include + +#define vector __attribute__((vector_size(sizeof(unsigned)*2))) + +vector signed and1(vector unsigned x, vector unsigned y) +{ + /* (x > y) & (x == 0) --> false */ + return (x > y) & (x == 0); +} + +vector signed and2(vector unsigned x, vector unsigned y) +{ + /* (x < y) & (x == UINT_MAX) --> false */ + return (x < y) & (x == UINT_MAX); +} + +vector signed and3(vector signed x, vector signed y) +{ + /* (x > y) & (x == INT_MIN) --> false */ + return (x > y) & (x == INT_MIN); +} + +vector signed and4(vector signed x, vector signed y) +{ + /* (x < y) & (x == INT_MAX) --> false */ + return (x < y) & (x == INT_MAX); +} + +/* { dg-final { scan-tree-dump-not " == " "ifcombine" } } */ +/* { dg-final { scan-tree-dump-not " > " "ifcombine" } } */ +/* { dg-final { scan-tree-dump-not " < " "ifcombine" } } */ diff --git a/gcc/testsuite/gcc.dg/pr110915-4.c b/gcc/testsuite/gcc.dg/pr110915-4.c new file mode 100644 index 000000000000..7e8528ccee97 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr110915-4.c @@ -0,0 +1,34 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-optimized -Wno-psabi" } */ + +#include + +#define vector __attribute__((vector_size(sizeof(unsigned)*2))) + +vector signed and1(vector unsigned x, vector unsigned y) +{ + /* (x > y) & (x == 0) --> false */ + return (x > y) & (x == 0); +} + +vector signed and2(vector unsigned x, vector unsigned y) +{ + /* (x < y) & (x == UINT_MAX) --> false */ + return (x < y) & (x == UINT_MAX); +} + +vector signed and3(vector signed x, vector signed y) +{ + /* (x > y) & (x == INT_MIN) --> false */ + return (x > y) & (x == INT_MIN); +} + +vector signed and4(vector signed x, vector signed y) +{ + /* (x < y) & (x == INT_MAX) --> false */ + return (x < y) & (x == INT_MAX); +} + +/* { dg-final { scan-tree-dump-not " == " "optimized" } } */ +/* { dg-final { scan-tree-dump-not " > " "optimized" } } */ +/* { dg-final { scan-tree-dump-not " < " "optimized" } } */ diff --git a/gcc/testsuite/gcc.dg/pr110915-5.c b/gcc/testsuite/gcc.dg/pr110915-5.c new file mode 100644 index 000000000000..41f407b7cb53 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr110915-5.c @@ -0,0 +1,33 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-ifcombine -Wno-psabi" } */ + +#include + +#define vector __attribute__((vector_size(sizeof(unsigned)*2))) + +vector signed and1(vector unsigned x, vector unsigned y) +{ + /* (x <= y) & (x == 0) --> x == 0 */ + return (x <= y) & (x == 0); +} + +vector signed and2(vector unsigned x, vector unsigned y) +{ + /* (x >= y) & (x == UINT_MAX) --> x == UINT_MAX */ + return (x >= y) & (x == UINT_MAX); +} + +vector signed and3(vector signed x, vector signed y) +{ + /* (x <= y) & (x == INT_MIN) --> x == INT_MIN */ + return (x <= y) & (x == INT_MIN); +} + +vector signed and4(vector signed x, vector signed y) +{ + /* (x >= y) & (x == INT_MAX) --> x == INT_MAX */ + return (x >= y) & (x == INT_MAX); +} + +/* { dg-final { scan-tree-dump-not " <= " "ifcombine" } } */ +/* { dg-final { scan-tree-dump-not " >= " "ifcombine" } } */ diff --git a/gcc/testsuite/gcc.dg/pr110915-6.c b/gcc/testsuite/gcc.dg/pr110915-6.c new file mode 100644 index 000000000000..c5b14787bf1f --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr110915-6.c @@ -0,0 +1,33 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-optimized -Wno-psabi" } */ + +#include + +#define vector __attribute__((vector_size(sizeof(unsigned)*2))) + +vector signed and1(vector unsigned x, vector unsigned y) +{ + /* (x <= y) & (x == 0) --> x == 0 */ + return (x <= y) & (x == 0); +} + +vector signed and2(vector unsigned x, vector unsigned y) +{ + /* (x >= y) & (x == UINT_MAX) --> x == UINT_MAX */ + return (x >= y) & (x == UINT_MAX); +} + +vector signed and3(vector signed x, vector signed y) +{ + /* (x <= y) & (x == INT_MIN) --> x == INT_MIN */ + return (x <= y) & (x == INT_MIN); +} + +vector signed and4(vector signed x, vector signed y) +{ + /* (x >= y) & (x == INT_MAX) --> x == INT_MAX */ + return (x >= y) & (x == INT_MAX); +} + +/* { dg-final { scan-tree-dump-not " <= " "optimized" } } */ +/* { dg-final { scan-tree-dump-not " >= " "optimized" } } */ diff --git a/gcc/testsuite/gcc.dg/pr110915-7.c b/gcc/testsuite/gcc.dg/pr110915-7.c new file mode 100644 index 000000000000..f6f7645484e1 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr110915-7.c @@ -0,0 +1,33 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-ifcombine -Wno-psabi" } */ + +#include + +#define vector __attribute__((vector_size(sizeof(unsigned)*2))) + +vector signed or1(vector unsigned x, vector unsigned y) +{ + /* (x > y) | (x != 0) --> x != 0 */ + return (x > y) | (x != 0); +} + +vector signed or2(vector unsigned x, vector unsigned y) +{ + /* (x < y) | (x != UINT_MAX) --> x != UINT_MAX */ + return (x < y) | (x != UINT_MAX); +} + +vector signed or3(vector signed x, vector signed y) +{ + /* (x > y) | (x != INT_MIN) --> x != INT_MIN */ + return (x > y) | (x != INT_MIN); +} + +vector signed or4(vector signed x, vector signed y) +{ + /* (x < y) | (x != INT_MAX) --> x != INT_MAX */ + return (x < y) | (x != INT_MAX); +} + +/* { dg-final { scan-tree-dump-not " > " "ifcombine" } } */ +/* { dg-final { scan-tree-dump-not " < " "ifcombine" } } */ diff --git a/gcc/testsuite/gcc.dg/pr110915-8.c b/gcc/testsuite/gcc.dg/pr110915-8.c new file mode 100644 index 000000000000..b6ed99b70aa5 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr110915-8.c @@ -0,0 +1,33 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-optimized -Wno-psabi" } */ + +#include + +#define vector __attribute__((vector_size(sizeof(unsigned)*2))) + +vector signed or1(vector unsigned x, vector unsigned y) +{ + /* (x > y) | (x != 0) --> x != 0 */ + return (x > y) | (x != 0); +} + +vector signed or2(vector unsigned x, vector unsigned y) +{ + /* (x < y) | (x != UINT_MAX) --> x != UINT_MAX */ + return (x < y) | (x != UINT_MAX); +} + +vector signed or3(vector signed x, vector signed y) +{ + /* (x > y) | (x != INT_MIN) --> x != INT_MIN */ + return (x > y) | (x != INT_MIN); +} + +vector signed or4(vector signed x, vector signed y) +{ + /* (x < y) | (x != INT_MAX) --> x != INT_MAX */ + return (x < y) | (x != INT_MAX); +} + +/* { dg-final { scan-tree-dump-not " > " "optimized" } } */ +/* { dg-final { scan-tree-dump-not " < " "optimized" } } */ diff --git a/gcc/testsuite/gcc.dg/pr110915-9.c b/gcc/testsuite/gcc.dg/pr110915-9.c new file mode 100644 index 000000000000..ee4dc4392dbb --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr110915-9.c @@ -0,0 +1,34 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-ifcombine -Wno-psabi" } */ + +#include + +#define vector __attribute__((vector_size(sizeof(unsigned)*2))) + +vector signed or1(vector unsigned x, vector unsigned y) +{ + /* (x <= y) | (x != 0) --> true */ + return (x <= y) | (x != 0); +} + +vector signed or2(vector unsigned x, vector unsigned y) +{ + /* (x >= y) | (x != UINT_MAX) --> true */ + return (x >= y) | (x != UINT_MAX); +} + +vector signed or3(vector signed x, vector signed y) +{ + /* (x <= y) | (x != INT_MIN) --> true */ + return (x <= y) | (x != INT_MIN); +} + +vector signed or4(vector signed x, vector signed y) +{ + /* (x >= y) | (x != INT_MAX) --> true */ + return (x >= y) | (x != INT_MAX); +} + +/* { dg-final { scan-tree-dump-not " != " "ifcombine" } } */ +/* { dg-final { scan-tree-dump-not " <= " "ifcombine" } } */ +/* { dg-final { scan-tree-dump-not " >= " "ifcombine" } } */ diff --git a/gcc/testsuite/gcc.dg/pr110918.c b/gcc/testsuite/gcc.dg/pr110918.c new file mode 100644 index 000000000000..e2dff27e0782 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr110918.c @@ -0,0 +1,26 @@ +/* { dg-do compile } */ +/* { dg-options "-O3 -fdump-tree-optimized" } */ + +static char b = 53; +static unsigned c; +void foo(void); +static int(a)(int d, int e) { return (d ^ e) < 0 ? d : d - e; } +int main() { + { + int f = 2; + c = b; + b = 0; + for (; c <= 6;) { + if (f >= 2) + f = 0; + for (; f >= -9; f = a(f, 8)) + if (!(f >= -8 && f <= 0)) + foo(); + } + } +} + + +/* { dg-final { scan-tree-dump-not "foo" "optimized" } } */ + + diff --git a/gcc/testsuite/gcc.dg/pr111009.c b/gcc/testsuite/gcc.dg/pr111009.c new file mode 100644 index 000000000000..3accd9ac0630 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr111009.c @@ -0,0 +1,38 @@ +/* PR tree-optimization/111009 */ +/* { dg-do run } */ +/* { dg-options "-O3 -fno-strict-overflow" } */ + +struct dso { + struct dso * next; + int maj; +}; + +__attribute__((noipa)) static void __dso_id__cmp_(void) {} + +__attribute__((noipa)) +static int bug(struct dso * d, struct dso *dso) +{ + struct dso **p = &d; + struct dso *curr = 0; + + while (*p) { + curr = *p; + // prevent null deref below + if (!dso) return 1; + if (dso == curr) return 1; + + int *a = &dso->maj; + // null deref + if (!(a && *a)) __dso_id__cmp_(); + + p = &curr->next; + } + return 0; +} + +__attribute__((noipa)) +int main(void) { + struct dso d = { 0, 0, }; + bug(&d, 0); +} + diff --git a/gcc/testsuite/gcc.dg/pr111015.c b/gcc/testsuite/gcc.dg/pr111015.c new file mode 100644 index 000000000000..599a14e6ecc2 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr111015.c @@ -0,0 +1,28 @@ +/* PR tree-optimization/111015 */ +/* { dg-do run { target int128 } } */ +/* { dg-options "-O2" } */ + +struct S { unsigned a : 4, b : 4; unsigned __int128 c : 70; } d; + +__attribute__((noipa)) void +foo (unsigned __int128 x, unsigned char y, unsigned char z) +{ + d.a = y; + d.b = z; + d.c = x; +} + +int +main () +{ + foo (-1, 12, 5); + if (d.a != 12 + || d.b != 5 + || d.c != (-1ULL | (((unsigned __int128) 0x3f) << 64))) + __builtin_abort (); + foo (0x123456789abcdef0ULL | (((unsigned __int128) 26) << 64), 7, 11); + if (d.a != 7 + || d.b != 11 + || d.c != (0x123456789abcdef0ULL | (((unsigned __int128) 26) << 64))) + __builtin_abort (); +} diff --git a/gcc/testsuite/gcc.dg/pr111039.c b/gcc/testsuite/gcc.dg/pr111039.c new file mode 100644 index 000000000000..bec9983b35f8 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr111039.c @@ -0,0 +1,15 @@ +/* { dg-do compile } */ +/* { dg-options "-O" } */ + +int _setjmp (); +void abcd (); +void abcde (); +void compiler_corruption_function(int flags) +{ + int nowait = flags & 1048576, isexpand = flags & 8388608; + abcd(); + _setjmp(flags); + if (nowait && isexpand) + flags &= 0; + abcde(); +} diff --git a/gcc/testsuite/gcc.dg/pr111070.c b/gcc/testsuite/gcc.dg/pr111070.c new file mode 100644 index 000000000000..1ebc7adf7829 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr111070.c @@ -0,0 +1,20 @@ +/* { dg-do compile } */ +/* { dg-options "-O" } */ + +/* common */ +char c; +/* arrays must be 8 byte aligned, regardless of size */ +char c_ary[1]; + +/* data */ +char d = 1; +char d_ary[1] = {1}; + +int main () +{ + if (((unsigned long)&c_ary[0] & 7) != 0) + return 1; + if (((unsigned long)&d_ary[0] & 7) != 0) + return 1; + return 0; +} diff --git a/gcc/testsuite/gcc.dg/pr111082.c b/gcc/testsuite/gcc.dg/pr111082.c new file mode 100644 index 000000000000..46e36e320d11 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr111082.c @@ -0,0 +1,10 @@ +/* { dg-do compile } */ +/* { dg-options "-O3 -fno-vect-cost-model" } */ +/* { dg-additional-options "-mavx512f" { target { x86_64-*-* i?86-*-* } } } */ + +long minarray2(const long *input) +{ + if (input[0] < input[1]) + return input[0] ; + return input[1]; +} diff --git a/gcc/testsuite/gcc.dg/pr87009.c b/gcc/testsuite/gcc.dg/pr87009.c index eb8a4ecd9200..6f0341d17cc3 100644 --- a/gcc/testsuite/gcc.dg/pr87009.c +++ b/gcc/testsuite/gcc.dg/pr87009.c @@ -1,6 +1,6 @@ /* { dg-do compile } */ /* { dg-options "-O -fdump-tree-original" } */ -/* { dg-final { scan-tree-dump-times "return s \\^ x;" 4 "original" } } */ +/* { dg-final { scan-tree-dump-times "return s \\^ x;|return x \\^ s;" 4 "original" } } */ int f1 (int x, int s) { diff --git a/gcc/testsuite/gcc.dg/stdckdint-1.c b/gcc/testsuite/gcc.dg/stdckdint-1.c new file mode 100644 index 000000000000..1525a35c51e8 --- /dev/null +++ b/gcc/testsuite/gcc.dg/stdckdint-1.c @@ -0,0 +1,61 @@ +/* Test C23 Checked Integer Arithmetic macros in . */ +/* { dg-do run } */ +/* { dg-options "-std=c2x" } */ + +#include + +#if __STDC_VERSION_STDCKDINT_H__ != 202311L +# error __STDC_VERSION_STDCKDINT_H__ not defined to 202311L +#endif + +extern void abort (void); + +int +main () +{ + unsigned int a; + if (ckd_add (&a, 1, 2) || a != 3) + abort (); + if (ckd_add (&a, ~2U, 2) || a != ~0U) + abort (); + if (!ckd_add (&a, ~2U, 4) || a != 1) + abort (); + if (ckd_sub (&a, 42, 2) || a != 40) + abort (); + if (!ckd_sub (&a, 11, ~0ULL) || a != 12) + abort (); + if (ckd_mul (&a, 42, 16U) || a != 672) + abort (); + if (ckd_mul (&a, ~0UL, 0) || a != 0) + abort (); + if (ckd_mul (&a, 1, ~0U) || a != ~0U) + abort (); + if (ckd_mul (&a, ~0UL, 1) != (~0UL > ~0U) || a != ~0U) + abort (); + static_assert (_Generic (ckd_add (&a, 1, 1), bool: 1, default: 0)); + static_assert (_Generic (ckd_sub (&a, 1, 1), bool: 1, default: 0)); + static_assert (_Generic (ckd_mul (&a, 1, 1), bool: 1, default: 0)); + signed char b; + if (ckd_add (&b, 8, 12) || b != 20) + abort (); + if (ckd_sub (&b, 8UL, 12ULL) || b != -4) + abort (); + if (ckd_mul (&b, 2, 3) || b != 6) + abort (); + unsigned char c; + if (ckd_add (&c, 8, 12) || c != 20) + abort (); + if (ckd_sub (&c, 8UL, 12ULL) != (-4ULL > (unsigned char) -4U) + || c != (unsigned char) -4U) + abort (); + if (ckd_mul (&c, 2, 3) || c != 6) + abort (); + long long d; + if (ckd_add (&d, ~0U, ~0U) != (~0U + 1ULL < ~0U) + || d != (long long) (2 * (unsigned long long) ~0U)) + abort (); + if (ckd_sub (&d, 0, 0) || d != 0) + abort (); + if (ckd_mul (&d, 16, 1) || d != 16) + abort (); +} diff --git a/gcc/testsuite/gcc.dg/stdckdint-2.c b/gcc/testsuite/gcc.dg/stdckdint-2.c new file mode 100644 index 000000000000..f83e3d7123de --- /dev/null +++ b/gcc/testsuite/gcc.dg/stdckdint-2.c @@ -0,0 +1,95 @@ +/* Test C23 Checked Integer Arithmetic macros in . */ +/* { dg-do compile } */ +/* { dg-options "-std=c2x" } */ + +#include + +int +main () +{ + char a; + bool b; + enum E { E1, E2 } c = E1; + int d; + int *e; + float f; + double g; + long double h; + const int v = 42; + volatile const short w = 5; + ckd_add (&a, 1, 1); + ckd_sub (&a, 1, 1); + ckd_mul (&a, 1, 1); + ckd_add (&b, 1, 1); /* { dg-error "has pointer to boolean type" } */ + ckd_sub (&b, 1, 1); /* { dg-error "has pointer to boolean type" } */ + ckd_mul (&b, 1, 1); /* { dg-error "has pointer to boolean type" } */ + ckd_add (&c, 1, 1); /* { dg-error "has pointer to enumerated type" } */ + ckd_sub (&c, 1, 1); /* { dg-error "has pointer to enumerated type" } */ + ckd_mul (&c, 1, 1); /* { dg-error "has pointer to enumerated type" } */ + ckd_add (&d, (char) 1, 1); + ckd_sub (&d, (char) 1, 1); + ckd_mul (&d, (char) 1, 1); + ckd_add (&d, false, 1); + ckd_sub (&d, false, 1); + ckd_mul (&d, false, 1); + ckd_add (&d, true, 1); + ckd_sub (&d, true, 1); + ckd_mul (&d, true, 1); + ckd_add (&d, c, 1); + ckd_sub (&d, c, 1); + ckd_mul (&d, c, 1); + ckd_add (&d, 1, (char) 1); + ckd_sub (&d, 1, (char) 1); + ckd_mul (&d, 1, (char) 1); + ckd_add (&d, 1, false); + ckd_sub (&d, 1, false); + ckd_mul (&d, 1, false); + ckd_add (&d, 1, true); + ckd_sub (&d, 1, true); + ckd_mul (&d, 1, true); + ckd_add (&d, 1, c); + ckd_sub (&d, 1, c); + ckd_mul (&d, 1, c); + ckd_add (&e, 1, 1); /* { dg-error "does not have pointer to integral type" } */ + ckd_sub (&e, 1, 1); /* { dg-error "does not have pointer to integral type" } */ + ckd_mul (&e, 1, 1); /* { dg-error "does not have pointer to integral type" } */ + ckd_add (&f, 1, 1); /* { dg-error "does not have pointer to integral type" } */ + ckd_sub (&f, 1, 1); /* { dg-error "does not have pointer to integral type" } */ + ckd_mul (&f, 1, 1); /* { dg-error "does not have pointer to integral type" } */ + ckd_add (&g, 1, 1); /* { dg-error "does not have pointer to integral type" } */ + ckd_sub (&g, 1, 1); /* { dg-error "does not have pointer to integral type" } */ + ckd_mul (&g, 1, 1); /* { dg-error "does not have pointer to integral type" } */ + ckd_add (&h, 1, 1); /* { dg-error "does not have pointer to integral type" } */ + ckd_sub (&h, 1, 1); /* { dg-error "does not have pointer to integral type" } */ + ckd_mul (&h, 1, 1); /* { dg-error "does not have pointer to integral type" } */ + ckd_add (&d, 1.0f, 1); /* { dg-error "does not have integral type" } */ + ckd_sub (&d, 1.0f, 1); /* { dg-error "does not have integral type" } */ + ckd_mul (&d, 1.0f, 1); /* { dg-error "does not have integral type" } */ + ckd_add (&d, 1.0, 1); /* { dg-error "does not have integral type" } */ + ckd_sub (&d, 1.0, 1); /* { dg-error "does not have integral type" } */ + ckd_mul (&d, 1.0, 1); /* { dg-error "does not have integral type" } */ + ckd_add (&d, 1.0L, 1); /* { dg-error "does not have integral type" } */ + ckd_sub (&d, 1.0L, 1); /* { dg-error "does not have integral type" } */ + ckd_mul (&d, 1.0L, 1); /* { dg-error "does not have integral type" } */ + ckd_add (&d, 1, 1.0f); /* { dg-error "does not have integral type" } */ + ckd_sub (&d, 1, 1.0f); /* { dg-error "does not have integral type" } */ + ckd_mul (&d, 1, 1.0f); /* { dg-error "does not have integral type" } */ + ckd_add (&d, 1, 1.0); /* { dg-error "does not have integral type" } */ + ckd_sub (&d, 1, 1.0); /* { dg-error "does not have integral type" } */ + ckd_mul (&d, 1, 1.0); /* { dg-error "does not have integral type" } */ + ckd_add (&d, 1, 1.0L); /* { dg-error "does not have integral type" } */ + ckd_sub (&d, 1, 1.0L); /* { dg-error "does not have integral type" } */ + ckd_mul (&d, 1, 1.0L); /* { dg-error "does not have integral type" } */ + ckd_add (&d, (int *) 0, 1); /* { dg-error "does not have integral type" } */ + ckd_sub (&d, (int *) 0, 1); /* { dg-error "does not have integral type" } */ + ckd_mul (&d, (int *) 0, 1); /* { dg-error "does not have integral type" } */ + ckd_add (&d, 1, (int *) 0); /* { dg-error "does not have integral type" } */ + ckd_sub (&d, 1, (int *) 0); /* { dg-error "does not have integral type" } */ + ckd_mul (&d, 1, (int *) 0); /* { dg-error "does not have integral type" } */ + ckd_add (&v, 1, 1); /* { dg-error "has pointer to 'const' type" } */ + ckd_sub (&v, 1, 1); /* { dg-error "has pointer to 'const' type" } */ + ckd_mul (&v, 1, 1); /* { dg-error "has pointer to 'const' type" } */ + ckd_add (&w, 1, 1); /* { dg-error "has pointer to 'const' type" } */ + ckd_sub (&w, 1, 1); /* { dg-error "has pointer to 'const' type" } */ + ckd_mul (&w, 1, 1); /* { dg-error "has pointer to 'const' type" } */ +} diff --git a/gcc/testsuite/gcc.dg/torture/pr110924.c b/gcc/testsuite/gcc.dg/torture/pr110924.c new file mode 100644 index 000000000000..7b395775c096 --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/pr110924.c @@ -0,0 +1,23 @@ +/* { dg-do compile } */ + +int a[1], b, c, d, e, f, g; +void h(int i, int j) { + int *k = 0; + if (*k) + h(0, 0); + g = i && d; +} +int main() { + if (c) + goto l; + if (!a) + while (1) { + f = 1; + while (f) + h(b && main(), e); + while (1) + ; + l:; + } + return 0; +} diff --git a/gcc/testsuite/gcc.dg/torture/pr110979.c b/gcc/testsuite/gcc.dg/torture/pr110979.c new file mode 100644 index 000000000000..c25ad7a8a316 --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/pr110979.c @@ -0,0 +1,25 @@ +/* { dg-do run } */ +/* { dg-additional-options "--param vect-partial-vector-usage=2" } */ + +#define FLT double +#define N 20 + +__attribute__((noipa)) +FLT +foo3 (FLT *a) +{ + FLT sum = -0.0; + for (int i = 0; i != N; i++) + sum += a[i]; + return sum; +} + +int main() +{ + FLT a[N]; + for (int i = 0; i != N; i++) + a[i] = -0.0; + if (!__builtin_signbit(foo3(a))) + __builtin_abort(); + return 0; +} diff --git a/gcc/testsuite/gcc.dg/torture/pr111048.c b/gcc/testsuite/gcc.dg/torture/pr111048.c new file mode 100644 index 000000000000..475978aae2be --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/pr111048.c @@ -0,0 +1,24 @@ +/* { dg-do run } */ +/* { dg-additional-options "-mavx2" { target avx2_runtime } } */ + +typedef unsigned char u8; + +__attribute__((noipa)) +static void check(const u8 * v) { + if (*v != 15) __builtin_trap(); +} + +__attribute__((noipa)) +static void bug(void) { + u8 in_lanes[32]; + for (unsigned i = 0; i < 32; i += 2) { + in_lanes[i + 0] = 0; + in_lanes[i + 1] = ((u8)0xff) >> (i & 7); + } + + check(&in_lanes[13]); + } + +int main() { + bug(); +} diff --git a/gcc/testsuite/gcc.dg/torture/pr111128.c b/gcc/testsuite/gcc.dg/torture/pr111128.c new file mode 100644 index 000000000000..aa623b0d0452 --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/pr111128.c @@ -0,0 +1,16 @@ +/* { dg-do compile } */ + +int a, b, c, e, g; +short *d; +unsigned char f; +int h() { + f &= g; + for (; b; b++) { + a = 2; + for (; a; a--) + c = 0; + if (c) + continue; + e = (unsigned short)*d >> f; + } +} diff --git a/gcc/testsuite/gcc.dg/torture/pr111137.c b/gcc/testsuite/gcc.dg/torture/pr111137.c new file mode 100644 index 000000000000..77560487926e --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/pr111137.c @@ -0,0 +1,30 @@ +/* { dg-do run } */ + +int b[3][8]; +short d; +volatile int t = 1; + +void __attribute__((noipa)) +foo() +{ + int g = t; + for (int e = 1; e >= 0; e--) + { + d = 1; + for (; d >= 0; d--) + { + b[0][d * 2 + 1] = 0; + b[g - 1 + d][0] ^= 1; + b[0][d * 2 + 2] = 0; + b[g - 1 + d][1] ^= 1; + } + } +} + +int +main() +{ + foo (); + if (b[0][1] != 1) + __builtin_abort(); +} diff --git a/gcc/testsuite/gcc.dg/tree-ssa/20030709-2.c b/gcc/testsuite/gcc.dg/tree-ssa/20030709-2.c index 5009cd69cfe8..78938f919d46 100644 --- a/gcc/testsuite/gcc.dg/tree-ssa/20030709-2.c +++ b/gcc/testsuite/gcc.dg/tree-ssa/20030709-2.c @@ -29,15 +29,16 @@ union tree_node }; int make_decl_rtl (tree, int); void * -get_alias_set (t) +get_alias_set (t, t1) tree t; + void *t1; { long set; if (t->decl.rtl) return (t->decl.rtl->fld[1].rtmem ? 0 : (((t->decl.rtl ? t->decl.rtl: (make_decl_rtl (t, 0), t->decl.rtl)))->fld[1]).rtmem); - return (void*)-1; + return t1; } /* There should be precisely one load of ->decl.rtl. If there is diff --git a/gcc/testsuite/gcc.dg/tree-ssa/bit1neg-1.c b/gcc/testsuite/gcc.dg/tree-ssa/bit1neg-1.c new file mode 100644 index 000000000000..2f123fbb9b5c --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/bit1neg-1.c @@ -0,0 +1,23 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-optimized" } */ + +struct f +{ + int a:1; +}; + +void g(struct f *a) +{ + int t = a->a; + t = -t; + a->a = t; +} +void g1(struct f *a, int b) +{ + int t = b; + t = -t; + a->a = t; +} +/* the 2 negates should have been removed as this is basically the same + as (-a) & 1. */ +/* { dg-final { scan-tree-dump-not " = -" "optimized" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/bool-14.c b/gcc/testsuite/gcc.dg/tree-ssa/bool-14.c new file mode 100644 index 000000000000..0149380a63b9 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/bool-14.c @@ -0,0 +1,15 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-optimized-raw" } */ +/* PR tree-optimization/110937 */ + +_Bool f2(_Bool a, _Bool b) +{ + if (a) + return !b; + return b; +} + +/* We should be able to remove the conditional and convert it to an xor. */ +/* { dg-final { scan-tree-dump-not "gimple_cond " "optimized" } } */ +/* { dg-final { scan-tree-dump-not "gimple_phi " "optimized" } } */ +/* { dg-final { scan-tree-dump-times "bit_xor_expr, " 1 "optimized" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/bool-15.c b/gcc/testsuite/gcc.dg/tree-ssa/bool-15.c new file mode 100644 index 000000000000..1f496663863a --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/bool-15.c @@ -0,0 +1,18 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-optimized-raw" } */ +/* PR tree-optimization/110937 */ + +_Bool f2(int x, int y, int w, int z) +{ + _Bool a = x == y; + _Bool b = w == z; + if (a) + return !b; + return b; +} + +/* We should be able to remove the conditional and convert it to an xor. */ +/* { dg-final { scan-tree-dump-not "gimple_cond " "optimized" } } */ +/* { dg-final { scan-tree-dump-not "gimple_phi " "optimized" } } */ +/* { dg-final { scan-tree-dump-not "ne_expr, " "optimized" } } */ +/* { dg-final { scan-tree-dump-times "bit_xor_expr, " 1 "optimized" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/cmpbit-3.c b/gcc/testsuite/gcc.dg/tree-ssa/cmpbit-3.c new file mode 100644 index 000000000000..936c0934a105 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/cmpbit-3.c @@ -0,0 +1,33 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-optimized-raw -fdump-tree-dse1-raw -fdump-tree-forwprop1" } */ + +_Bool f(int a, int b) +{ + _Bool X = a==1, Y = b == 2; +return (X & !Y) | (!X & Y); +} + + +_Bool f1(int a, int b) +{ + _Bool X = a==1, Y = b == 2; + _Bool c = (X & !Y); + _Bool d = (!X & Y); + return c | d; +} + +/* Both of these should be optimized to (a==1) ^ (b==2) or (a != 1) ^ (b != 2) */ +/* { dg-final { scan-tree-dump-not "gimple_cond " "optimized" } } */ +/* { dg-final { scan-tree-dump-not "gimple_phi " "optimized" } } */ +/* { dg-final { scan-tree-dump-times "ne_expr|eq_expr, " 4 "optimized" } } */ +/* { dg-final { scan-tree-dump-times "bit_xor_expr, " 2 "optimized" } } */ +/* { dg-final { scan-tree-dump-times "gimple_assign " 6 "optimized" } } */ + +/* Both of these should be optimized early in the pipeline after forwprop1 */ +/* { dg-final { scan-tree-dump-times "ne_expr|eq_expr, " 4 "forwprop1" { xfail *-*-* } } } */ +/* { dg-final { scan-tree-dump-times "bit_xor_expr, " 2 "forwprop1" { xfail *-*-* } } } */ +/* { dg-final { scan-tree-dump-times "gimple_assign " 6 "forwprop1" { xfail *-*-* } } } */ +/* Note forwprop1 does not remove all unused statements sometimes so test dse1 also. */ +/* { dg-final { scan-tree-dump-times "ne_expr|eq_expr, " 4 "dse1" } } */ +/* { dg-final { scan-tree-dump-times "bit_xor_expr, " 2 "dse1" } } */ +/* { dg-final { scan-tree-dump-times "gimple_assign " 6 "dse1" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/cmpbit-4.c b/gcc/testsuite/gcc.dg/tree-ssa/cmpbit-4.c new file mode 100644 index 000000000000..cdba5d623af4 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/cmpbit-4.c @@ -0,0 +1,47 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-optimized-raw" } */ + +int g(int x, int y) +{ + int xp = ~x; + return (x | y) & (xp ^ y); // x & y +} +int g0(int x, int y) +{ + int xp = ~x; + return (xp | y) & (x ^ y); // ~x & y +} + +_Bool gb(_Bool x, _Bool y) +{ + _Bool xp = !x; + return (x | y) & (xp ^ y); // x & y +} +_Bool gb0(_Bool x, _Bool y) +{ + _Bool xp = !x; + return (xp | y) & (x ^ y); // !x & y +} + + +_Bool gbi(int a, int b) +{ + _Bool x = a < 2; + _Bool y = b < 3; + _Bool xp = !x; + return (x | y) & (xp ^ y); // x & y +} +_Bool gbi0(int a, int b) +{ + _Bool x = a < 2; + _Bool y = b < 3; + _Bool xp = !x; + return (xp | y) & (x ^ y); // !x & y +} + +/* All of these should be optimized to `x & y` or `~x & y` */ +/* { dg-final { scan-tree-dump-times "le_expr, " 3 "optimized" } } */ +/* { dg-final { scan-tree-dump-times "gt_expr, " 1 "optimized" } } */ +/* { dg-final { scan-tree-dump-not "bit_xor_expr, " "optimized" } } */ +/* { dg-final { scan-tree-dump-times "bit_and_expr, " 6 "optimized" } } */ +/* { dg-final { scan-tree-dump-times "bit_not_expr, " 2 "optimized" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/cond-bool-1.c b/gcc/testsuite/gcc.dg/tree-ssa/cond-bool-1.c new file mode 100644 index 000000000000..752a3030ad13 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/cond-bool-1.c @@ -0,0 +1,21 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-optimized-raw" } */ +_Bool f1(int a, int b) +{ + _Bool _1 = b != 0; + _Bool _2 = a != 0; + _Bool _8 = a == 0; + _Bool _13; + if (_1) _13 = _8; else _13 = _2; + return _13; +} + +/* We should be able to optimize this to (a != 0) ^ (b != 0) */ +/* There should be no negate_expr nor gimple_cond here. */ + +/* { dg-final { scan-tree-dump-not "negate_expr, " "optimized" } } */ +/* { dg-final { scan-tree-dump-times "ne_expr, " 2 "optimized" } } */ +/* { dg-final { scan-tree-dump-not "gimple_cond " "optimized" } } */ +/* { dg-final { scan-tree-dump-not "gimple_phi " "optimized" } } */ +/* { dg-final { scan-tree-dump-times "bit_xor_expr, " 1 "optimized" } } */ +/* { dg-final { scan-tree-dump-times "gimple_assign " 3 "optimized" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/cond-bool-2.c b/gcc/testsuite/gcc.dg/tree-ssa/cond-bool-2.c new file mode 100644 index 000000000000..7de89cc0de28 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/cond-bool-2.c @@ -0,0 +1,26 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 --param logical-op-non-short-circuit=1 -fdump-tree-optimized-raw" } */ + +/* PR tree-optimization/95929 */ + + +static inline _Bool nand(_Bool a, _Bool b) +{ + return !(a && b); +} + +_Bool f(int a, int b) +{ + return nand(nand(b, nand(a, a)), nand(a, nand(b, b))); +} + +/* We should be able to optimize this to (a != 0) ^ (b != 0) */ +/* There should be no negate_expr nor gimple_cond here. */ + +/* { dg-final { scan-tree-dump-not "negate_expr, " "optimized" } } */ +/* { dg-final { scan-tree-dump-times "ne_expr, " 2 "optimized" } } */ +/* { dg-final { scan-tree-dump-not "gimple_cond " "optimized" } } */ +/* { dg-final { scan-tree-dump-not "cond_expr, " "optimized" } } */ +/* { dg-final { scan-tree-dump-not "gimple_phi " "optimized" } } */ +/* { dg-final { scan-tree-dump-times "bit_xor_expr, " 1 "optimized" } } */ +/* { dg-final { scan-tree-dump-times "gimple_assign " 3 "optimized" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/copy-headers-9.c b/gcc/testsuite/gcc.dg/tree-ssa/copy-headers-9.c index b49d1fc9576e..11ee29458a2e 100644 --- a/gcc/testsuite/gcc.dg/tree-ssa/copy-headers-9.c +++ b/gcc/testsuite/gcc.dg/tree-ssa/copy-headers-9.c @@ -13,7 +13,6 @@ void test (int m, int n) } while (i<10); } -/* { dg-final { scan-tree-dump-times "Duplicating bb . is a win" 2 "ch2" } } */ -/* { dg-final { scan-tree-dump-times "Duplicating bb . is a win. it has zero" 1 "ch2" } } */ +/* { dg-final { scan-tree-dump-times "Duplicating bb . is a win" 1 "ch2" } } */ /* { dg-final { scan-tree-dump-times "Will duplicate bb" 2 "ch2" } } */ /* { dg-final { scan-tree-dump "is now do-while loop" "ch2" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/cunroll-16.c b/gcc/testsuite/gcc.dg/tree-ssa/cunroll-16.c new file mode 100644 index 000000000000..9bb66ff82995 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/cunroll-16.c @@ -0,0 +1,17 @@ +/* PR/110991 */ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-cunroll-details -fdump-tree-optimized" } */ + +static unsigned char a; +static signed char b; +void foo(void); +int main() { + a = 25; + for (; a > 13; --a) + b = a > 127 ?: a << 3; + if (!b) + foo(); +} + +/* { dg-final { scan-tree-dump "optimized: loop with \[0-9\]\+ iterations completely unrolled" "cunroll" } } */ +/* { dg-final { scan-tree-dump-not "foo" "optimized" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/forwprop-40.c b/gcc/testsuite/gcc.dg/tree-ssa/forwprop-40.c new file mode 100644 index 000000000000..7513497f5520 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/forwprop-40.c @@ -0,0 +1,14 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-optimized -Wno-psabi -w" } */ + +#define vector __attribute__((__vector_size__(16) )) + +vector int g(vector int a) +{ + int b = a[0]; + a[0] = b; + return a; +} + +/* { dg-final { scan-tree-dump-times "BIT_INSERT_EXPR" 0 "optimized" } } */ +/* { dg-final { scan-tree-dump-times "BIT_FIELD_REF" 0 "optimized" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/forwprop-41.c b/gcc/testsuite/gcc.dg/tree-ssa/forwprop-41.c new file mode 100644 index 000000000000..b1e75797a900 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/forwprop-41.c @@ -0,0 +1,16 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-optimized -Wno-psabi -w" } */ + +#define vector __attribute__((__vector_size__(16) )) + +vector int g(vector int a, int c) +{ + int b = a[2]; + a[2] = b; + a[1] = c; + return a; +} + +/* { dg-final { scan-tree-dump-times "BIT_INSERT_EXPR" 1 "optimized" } } */ +/* { dg-final { scan-tree-dump-times "BIT_FIELD_REF" 0 "optimized" } } */ +/* { dg-final { scan-tree-dump-times "VEC_PERM_EXPR" 0 "optimized" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/phi-opt-33.c b/gcc/testsuite/gcc.dg/tree-ssa/phi-opt-33.c new file mode 100644 index 000000000000..b79fe44187a5 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/phi-opt-33.c @@ -0,0 +1,13 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-optimized-raw" } */ +/* PR tree-optimization/100798 */ + +int f(int a, int t) +{ + return (a=='s' ? ~t : t); +} + +/* This should be convert into t^-(a=='s'). */ +/* { dg-final { scan-tree-dump-times "bit_xor_expr, " 1 "optimized" } } */ +/* { dg-final { scan-tree-dump-times "negate_expr, " 1 "optimized" } } */ +/* { dg-final { scan-tree-dump-not "bit_not_expr, " "optimized" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/phi-opt-34.c b/gcc/testsuite/gcc.dg/tree-ssa/phi-opt-34.c new file mode 100644 index 000000000000..61054231b4cb --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/phi-opt-34.c @@ -0,0 +1,23 @@ +/* { dg-do compile } */ +/* Disable early phiopt1 as early ccp1 does not export non-zero bits + so at the point of phiopt1, we don't know that a is [0,1] range */ +/* { dg-options "-O1 -fdisable-tree-phiopt1 -fdump-tree-phiopt2-folding" } */ + +unsigned f(unsigned a) +{ + a &= 1; + if (a > 0) + return a; + return 1; +} +/* PHIOPT2 should be able to change this into just return 1; + (which was `MAX` or `a | 1` but since a is known to be a + range of [0,1], it should be folded into 1) + And not fold it into `(a == 0) | a`. */ +/* { dg-final { scan-tree-dump-not " == " "phiopt2" } } */ +/* { dg-final { scan-tree-dump-not " if " "phiopt2" } } */ +/* { dg-final { scan-tree-dump-not "Folded into the sequence:" "phiopt2" } } */ +/* { dg-final { scan-tree-dump "return 1;" "phiopt2" } } */ +/* We want to make sure that phiopt2 is happening and not some other pass + before it does the transformation. */ +/* { dg-final { scan-tree-dump "Removing basic block" "phiopt2" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/phi-opt-same-1.c b/gcc/testsuite/gcc.dg/tree-ssa/phi-opt-same-1.c new file mode 100644 index 000000000000..24e757b9b9f7 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/phi-opt-same-1.c @@ -0,0 +1,60 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-phiopt1 -fdump-tree-optimized" } */ +/* PR tree-optimization/19832 */ + +static inline int max_(int a, int b) +{ + if (a > b) return a; + return b; +} +static inline int min_(int a, int b) +{ + if (a < b) return a; + return b; +} + +int f_minus(int a, int b) +{ + if (a != b) return a - b; + return a - a; +} +int f_xor(int a, int b) +{ + if (a != b) return a ^ b; + return a ^ a; +} + +int f_ior(int a, int b) +{ + if (a != b) return a | b; + return a | a; +} +int f_and(int a, int b) +{ + if (a != b) return a & b; + return a & a; +} +int f_max(int a, int b) +{ + if (a != b) return max_(a,b); + return max_(a,a); +} +int f_min(int a, int b) +{ + if (a != b) return min_(a,b); + return min_(a,a); +} +int f_mult(int a, int b) +{ + if (a != b) return a * b; + return a * a; +} +int f_plus(int a, int b) +{ + if (a != b) return a + b; + return a + a; +} + +/* All of the above function's if should have been optimized away even in phiopt1. */ +/* { dg-final { scan-tree-dump-not "if " "phiopt1" } } */ +/* { dg-final { scan-tree-dump-not "if " "optimized" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/phi_on_compare-1.c b/gcc/testsuite/gcc.dg/tree-ssa/phi_on_compare-1.c index be504ddb11ae..923497f78968 100644 --- a/gcc/testsuite/gcc.dg/tree-ssa/phi_on_compare-1.c +++ b/gcc/testsuite/gcc.dg/tree-ssa/phi_on_compare-1.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-Ofast -fdump-tree-dom2" } */ +/* { dg-options "-Ofast -fdump-tree-dom2 -fdump-tree-optimized-details-blocks" } */ void g (int); void g1 (int); @@ -33,3 +33,4 @@ f (long a, long b, long c, long d, long x) optimization in the backward threader before killing the forward threader. Similarly for the other phi_on_compare-*.c tests. */ /* { dg-final { scan-tree-dump-times "Removing basic block" 1 "dom2" } } */ +/* { dg-final { scan-tree-dump-not "Invalid sum" "optimized" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr103281-1.c b/gcc/testsuite/gcc.dg/tree-ssa/pr103281-1.c new file mode 100644 index 000000000000..09964d0b46b0 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/pr103281-1.c @@ -0,0 +1,19 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-optimized" } */ +/* PR tree-optmization/103281 */ + +void foo(void); + +static unsigned b; + +int main() { + for (; b < 3; b++) { + char c = b; + char a = c ? c : c << 1; + if (!(a < 1 ^ b)) + foo(); + } +} + +/* the call to foo should be optimized away. */ +/* { dg-final { scan-tree-dump-not "foo " "optimized" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr109938.c b/gcc/testsuite/gcc.dg/tree-ssa/pr109938.c new file mode 100644 index 000000000000..d64ddd6ca611 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/pr109938.c @@ -0,0 +1,125 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-dse2 -Wno-psabi" } */ + +typedef int v4si __attribute__((vector_size(4 * sizeof(int)))); + +/* Generic */ +__attribute__((noipa)) int +t1 (int a, int b, int c) +{ + return ((a ^ c) & b) | a; +} + +__attribute__((noipa)) unsigned int +t2 (int a, unsigned int b, int c) +{ + return ((a ^ c) & b) | a; +} + +__attribute__((noipa)) unsigned long +t3 (unsigned long a, long b, unsigned long c) +{ + return ((a ^ c) & b) | a; +} + +__attribute__((noipa)) unsigned short +t4 (short a, unsigned short b, unsigned short c) +{ + return (unsigned short) ((a ^ c) & b) | a; +} + +__attribute__((noipa)) unsigned char +t5 (unsigned char a, signed char b, signed char c) +{ + return ((a ^ c) & b) | a; +} + +__attribute__((noipa)) long long +t6 (long long a, long long b, long long c) +{ + return ((a ^ c) & (unsigned long long) b) | a; +} + +/* Gimple */ +__attribute__((noipa)) int +t7 (int a, int b, int c) +{ + int t1 = a ^ c; + int t2 = t1 & b; + int t3 = t2 | a; + return t3; +} + +__attribute__((noipa)) int +t8 (int a, unsigned int b, unsigned int c) +{ + unsigned int t1 = a ^ c; + int t2 = t1 & b; + int t3 = t2 | a; + return t3; +} + +__attribute__((noipa)) unsigned int +t9 (unsigned int a, unsigned int b, int c) +{ + unsigned int t1 = a ^ c; + unsigned int t2 = t1 & b; + unsigned int t3 = t2 | a; + return t3; +} + +__attribute__((noipa)) unsigned long +t10 (unsigned long a, long b, unsigned long c) +{ + unsigned long t1 = a ^ c; + unsigned long t2 = t1 & b; + unsigned long t3 = t2 | a; + return t3; +} + +__attribute__((noipa)) unsigned short +t11 (short a, unsigned short b, short c) +{ + short t1 = a ^ c; + unsigned short t2 = t1 & b; + unsigned short t3 = t2 | a; + return t3; +} + +__attribute__((noipa)) unsigned char +t12 (signed char a, unsigned char b, signed char c) +{ + unsigned char t1 = a ^ c; + unsigned char t2 = t1 & b; + unsigned char t3 = t2 | a; + return t3; +} + +__attribute__((noipa)) unsigned long long +t13 (unsigned long long a, long long b, unsigned long long c) +{ + long long t1 = a ^ c; + long long t2 = t1 & b; + unsigned long long t3 = t2 | a; + return t3; +} + +/* Vectors */ +__attribute__((noipa)) v4si +t14 (v4si a, v4si b, v4si c) +{ + return ((a ^ c) & b) | a; +} + +__attribute__((noipa)) v4si +t15 (v4si a, v4si b, v4si c) +{ + v4si t1 = a ^ c; + v4si t2 = t1 & b; + v4si t3 = t2 | a; + return t3; +} + +/* { dg-final { scan-tree-dump-not " \\\^ " "dse2" } } */ +/* { dg-final { scan-tree-dump-times " \\\| " 15 "dse2" } } */ +/* { dg-final { scan-tree-dump-times " & " 15 "dse2" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr110753.c b/gcc/testsuite/gcc.dg/tree-ssa/pr110753.c new file mode 100644 index 000000000000..aa02487e2a7f --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/pr110753.c @@ -0,0 +1,15 @@ +// { dg-do compile } +// { dg-options "-O2" } + +int a, b, c; +static int d(long e, long f) { return f == 0 || e && f == 1 ?: f; } +int g(void) {static int t; return t;} +static void h(long e) { + b = e - 1; + a = d(b || d(e, 8), g()); +} +int tt; +void i(void) { + c = (__SIZE_TYPE__)&tt; + h(c); +} diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr110923.c b/gcc/testsuite/gcc.dg/tree-ssa/pr110923.c new file mode 100644 index 000000000000..8f5720a5e9e1 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/pr110923.c @@ -0,0 +1,14 @@ +/* { dg-do compile } */ +/* { dg-options "-O3 -fdump-tree-lsplit-details-blocks" } */ +int a, b, c, d; +int main() { + for (a = 0; a < 2; a++) { + if (b > 2) + c = 0; + if (b > a) + d = 0; + } + return 0; +} +/* { dg-final { scan-tree-dump-times "loop split" 1 "lsplit" } } */ +/* { dg-final { scan-tree-dump-not "Invalid sum" "lsplit" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-pre-34.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-pre-34.c new file mode 100644 index 000000000000..9ac37c44336a --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-pre-34.c @@ -0,0 +1,56 @@ +/* { dg-do compile } */ +/* { dg-options "-Os -fdump-tree-pre-stats -fdump-tree-optimized" } */ + +void foo(void); +static int c = 76, f, g; +static int *h, *j, *k = &g; +static int **i = &h; +static short a; +static signed char(l)(signed char b) { + if (!(((b) >= 77) && ((b) <= 77))) { + __builtin_unreachable(); + } + return 0; +} +static short(m)(short d, short e) { return d + e; } +static short n(signed char) { + j = *i; + if (j == 0) + ; + else + *i = 0; + *k = 0; + return 0; +} +static signed char o() { + l(0); + return 0; +} +static signed char p(int ad) { + a = m(!0, ad); + l(a); + if (f) { + *i &&n(o()); + *i = 0; + } else + n(0); + if (h == &f || h == 0) + ; + else + foo(); + return 0; +} +int main() { + p(c); + c = 8; +} + +/* Even with main being cold we should optimize the redundant load of h + which is available on all incoming edges (but none considered worth + optimizing for speed) when doing that doesn't needlessly increase + code size. */ + +/* { dg-final { scan-tree-dump "Insertions: 1" "pre" } } */ +/* { dg-final { scan-tree-dump "HOIST inserted: 1" "pre" } } */ +/* { dg-final { scan-tree-dump "Eliminated: 3" "pre" } } */ +/* { dg-final { scan-tree-dump-not "foo" "optimized" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/update-threading.c b/gcc/testsuite/gcc.dg/tree-ssa/update-threading.c index 1435e9ba2e02..9500099cddff 100644 --- a/gcc/testsuite/gcc.dg/tree-ssa/update-threading.c +++ b/gcc/testsuite/gcc.dg/tree-ssa/update-threading.c @@ -20,4 +20,4 @@ main (int argc, char **argv) foo (((A) { ((!(i >> 4) ? 8 : 64 + (i >> 4)) << 8) + (i << 4) } ).a); exit (0); } -/* { dg-final { scan-tree-dump-times "Invalid sum" 0 "optimized" } } */ +/* { dg-final { scan-tree-dump-times "Invalid sum" 0 "optimized" { xfail cris-*-* } } } Xfail: PR110628 */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/vrp-compare-1.c b/gcc/testsuite/gcc.dg/tree-ssa/vrp-compare-1.c new file mode 100644 index 000000000000..9889cf347064 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/vrp-compare-1.c @@ -0,0 +1,13 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-evrp-details" } */ +/* PR tree-optimization/28794 */ + +void g(int); +void f1(int x) +{ + if (x < 0) return; + g(x>0); +} + +/* `x > 0` should be optimized to just `x != 0` */ +/* { dg-final { scan-tree-dump-times "Simplified relational" 1 "evrp" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/vrp-float-12.c b/gcc/testsuite/gcc.dg/tree-ssa/vrp-float-12.c new file mode 100644 index 000000000000..0c9426dfef52 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/vrp-float-12.c @@ -0,0 +1,23 @@ +// { dg-do compile } +// { dg-options "-O2 -fdisable-tree-fre1 -fdump-tree-evrp" } + +void link_error (); +void func (); + +void foo1 (float x, float y) +{ + if (x != y) + if (x == y) + link_error(); +} + +void foo2 (float a, float b) +{ + if (a != b) + // This conditional should be folded away. + if (a != b) + func (); +} + +// { dg-final { scan-tree-dump-not "link_error" "evrp" } } +// { dg-final { scan-tree-dump-times "if \\(a_2\\(D\\) != b_3\\(D\\)" 1 "evrp" } } diff --git a/gcc/testsuite/gcc.dg/unroll-7.c b/gcc/testsuite/gcc.dg/unroll-7.c index 650448df5db1..17c5e533c2cb 100644 --- a/gcc/testsuite/gcc.dg/unroll-7.c +++ b/gcc/testsuite/gcc.dg/unroll-7.c @@ -15,4 +15,4 @@ int t(void) /* { dg-final { scan-rtl-dump "upper bound: 999999" "loop2_unroll" } } */ /* { dg-final { scan-rtl-dump "realistic bound: 999999" "loop2_unroll" } } */ /* { dg-final { scan-rtl-dump "considering unrolling loop with constant number of iterations" "loop2_unroll" } } */ -/* { dg-final { scan-rtl-dump-not "Invalid sum" "loop2_unroll" {xfail *-*-* } } } */ +/* { dg-final { scan-rtl-dump-not "Invalid sum" "loop2_unroll" } } */ diff --git a/gcc/testsuite/gcc.dg/vect/bb-slp-17.c b/gcc/testsuite/gcc.dg/vect/bb-slp-17.c index fc3ef42f51a6..e7bb06bf8167 100644 --- a/gcc/testsuite/gcc.dg/vect/bb-slp-17.c +++ b/gcc/testsuite/gcc.dg/vect/bb-slp-17.c @@ -58,5 +58,6 @@ int main (void) } /* We need V2SI vector add support for the b[] vectorization, if we don't - have that we might only see the store vectorized and thus 2 subgraphs. */ -/* { dg-final { scan-tree-dump-times "optimized: basic block" 1 "slp2" { target { vect_int_mult && vect64 } } } } */ + have that we might only see the store vectorized. In any case we have + two subgraph entries. */ +/* { dg-final { scan-tree-dump-times "optimized: basic block" 2 "slp2" { target { vect_int_mult && vect64 } } } } */ diff --git a/gcc/testsuite/gcc.dg/vect/bb-slp-20.c b/gcc/testsuite/gcc.dg/vect/bb-slp-20.c index 134858c934a4..7b25f91fbd3d 100644 --- a/gcc/testsuite/gcc.dg/vect/bb-slp-20.c +++ b/gcc/testsuite/gcc.dg/vect/bb-slp-20.c @@ -63,6 +63,7 @@ int main (void) return 0; } -/* { dg-final { scan-tree-dump-times "optimized: basic block" 1 "slp2" { target vect_int_mult } } } */ +/* { dg-final { scan-tree-dump-times "Basic block will be vectorized using SLP" 1 "slp2" { target vect_int_mult } } } */ +/* { dg-final { scan-tree-dump-times "optimized: basic block" 2 "slp2" { target vect_int_mult } } } */ /* { dg-final { scan-tree-dump-times "vectorizing stmts using SLP" 2 "slp2" { target vect_int_mult } } } */ diff --git a/gcc/testsuite/gcc.dg/vect/bb-slp-21.c b/gcc/testsuite/gcc.dg/vect/bb-slp-21.c index d4c98d67f551..45054cd3c295 100644 --- a/gcc/testsuite/gcc.dg/vect/bb-slp-21.c +++ b/gcc/testsuite/gcc.dg/vect/bb-slp-21.c @@ -63,6 +63,7 @@ int main (void) return 0; } -/* { dg-final { scan-tree-dump-times "optimized: basic block" 1 "slp2" } } */ +/* { dg-final { scan-tree-dump-times "Basic block will be vectorized using SLP" 1 "slp2" } } */ +/* { dg-final { scan-tree-dump-times "optimized: basic block" 2 "slp2" } } */ /* { dg-final { scan-tree-dump-times "vectorizing stmts using SLP" 2 "slp2" } } */ diff --git a/gcc/testsuite/gcc.dg/vect/bb-slp-22.c b/gcc/testsuite/gcc.dg/vect/bb-slp-22.c index 92cc2a51abd0..7bf7e2c4febb 100644 --- a/gcc/testsuite/gcc.dg/vect/bb-slp-22.c +++ b/gcc/testsuite/gcc.dg/vect/bb-slp-22.c @@ -63,5 +63,5 @@ int main (void) return 0; } -/* { dg-final { scan-tree-dump-times "optimized: basic block" 1 "slp2" } } */ +/* { dg-final { scan-tree-dump-times "Basic block will be vectorized using SLP" 1 "slp2" } } */ /* { dg-final { scan-tree-dump "vectorizing SLP node starting from: _\[0-9\]+ = _\[0-9\]+ \\\* a0" "slp2" { target vect_int_mult } } } */ diff --git a/gcc/testsuite/gcc.dg/vect/bb-slp-46.c b/gcc/testsuite/gcc.dg/vect/bb-slp-46.c index 98b29062a19b..4eceea44efcf 100644 --- a/gcc/testsuite/gcc.dg/vect/bb-slp-46.c +++ b/gcc/testsuite/gcc.dg/vect/bb-slp-46.c @@ -15,7 +15,7 @@ int foo () a[1] = tem1; a[2] = tem2; a[3] = tem3; - return temx + temy; + return temx / temy; } /* We should extract the live lane from the vectorized add rather than diff --git a/gcc/testsuite/gcc.dg/vect/bb-slp-75.c b/gcc/testsuite/gcc.dg/vect/bb-slp-75.c new file mode 100644 index 000000000000..1abac136f726 --- /dev/null +++ b/gcc/testsuite/gcc.dg/vect/bb-slp-75.c @@ -0,0 +1,25 @@ +/* { dg-do compile } */ +/* { dg-require-effective-target vect_float } */ +/* { dg-additional-options "-ffast-math" } */ +/* { dg-additional-options "-msse2 -mfpmath=sse" { target { x86_64-*-* i?86-*-* } } } */ + +float x[4]; + +float test1 (float a) +{ + return x[0] + x[2] + x[1] + x[3] + a; +} + +float test2 (void) +{ + return x[3] + x[2] + x[1] + 1.f + x[0]; +} + +float test3 (float a) +{ + return x[0] + a + x[2] + x[1] + x[3] + 1.f; +} + +/* We currently require a .REDUC_PLUS direct internal function but do not + have a dejagnu target for this. */ +/* { dg-final { scan-tree-dump-times "Basic block will be vectorized using SLP" 3 "slp2" { target { x86_64-*-* i?86-*-* } } } } */ diff --git a/gcc/testsuite/gcc.dg/vect/bb-slp-subgroups-2.c b/gcc/testsuite/gcc.dg/vect/bb-slp-subgroups-2.c index 968cdf1cc515..9431bcb9d5c4 100644 --- a/gcc/testsuite/gcc.dg/vect/bb-slp-subgroups-2.c +++ b/gcc/testsuite/gcc.dg/vect/bb-slp-subgroups-2.c @@ -39,4 +39,5 @@ main (int argc, char **argv) } /* { dg-final { scan-tree-dump-times "Basic block will be vectorized using SLP" 1 "slp2" } } */ -/* { dg-final { scan-tree-dump-times "optimized: basic block" 1 "slp2" } } */ +/* { dg-final { scan-tree-dump-times "optimized: basic block" 2 "slp2" { target { ! vect256 } } } } */ +/* { dg-final { scan-tree-dump-times "optimized: basic block" 1 "slp2" { target { vect256 } } } } */ diff --git a/gcc/testsuite/gcc.dg/vect/no-scevccp-outer-12.c b/gcc/testsuite/gcc.dg/vect/no-scevccp-outer-12.c index e9ec4ca0da31..c2d3031bc0ce 100644 --- a/gcc/testsuite/gcc.dg/vect/no-scevccp-outer-12.c +++ b/gcc/testsuite/gcc.dg/vect/no-scevccp-outer-12.c @@ -47,4 +47,4 @@ int main (void) } /* Until we support multiple types in the inner loop */ -/* { dg-final { scan-tree-dump-times "OUTER LOOP VECTORIZED." 1 "vect" { xfail { ! aarch64*-*-* } } } } */ +/* { dg-final { scan-tree-dump-times "OUTER LOOP VECTORIZED." 1 "vect" { xfail { ! { aarch64*-*-* riscv*-*-* } } } } } */ diff --git a/gcc/testsuite/gcc.dg/vect/pr53773.c b/gcc/testsuite/gcc.dg/vect/pr53773.c index 7f8229571ecf..213e74e0b9d4 100644 --- a/gcc/testsuite/gcc.dg/vect/pr53773.c +++ b/gcc/testsuite/gcc.dg/vect/pr53773.c @@ -1,7 +1,10 @@ /* Disabling epilogues until we find a better way to deal with scans. */ /* { dg-additional-options "--param vect-epilogues-nomask=0" } */ /* { dg-do compile } */ -/* { dg-additional-options "-fdump-tree-optimized" } */ +/* Disable BB vectorization, we now can cover the whole loop with that + when the target supports .REDUC_PLUS for integers, we don't have a + good target selector for this. */ +/* { dg-additional-options "-fdump-tree-optimized -fno-tree-slp-vectorize" } */ int foo (int integral, int decimal, int power_ten) diff --git a/gcc/testsuite/gcc.dg/vect/pr65947-7.c b/gcc/testsuite/gcc.dg/vect/pr65947-7.c index 16cdcd1c6eb8..58c46df5c547 100644 --- a/gcc/testsuite/gcc.dg/vect/pr65947-7.c +++ b/gcc/testsuite/gcc.dg/vect/pr65947-7.c @@ -52,5 +52,5 @@ main (void) return 0; } -/* { dg-final { scan-tree-dump "LOOP VECTORIZED" "vect" { target vect_fold_extract_last } } } */ -/* { dg-final { scan-tree-dump-not "LOOP VECTORIZED" "vect" { target { ! vect_fold_extract_last } } } } */ +/* { dg-final { scan-tree-dump "optimizing condition reduction with FOLD_EXTRACT_LAST" "vect" { target vect_fold_extract_last } } } */ +/* { dg-final { scan-tree-dump "LOOP VECTORIZED" "vect" { target aarch64*-*-* } } } */ diff --git a/gcc/testsuite/gcc.dg/vect/pr88598-1.c b/gcc/testsuite/gcc.dg/vect/pr88598-1.c index e25c6c04543a..ddcebb067ea2 100644 --- a/gcc/testsuite/gcc.dg/vect/pr88598-1.c +++ b/gcc/testsuite/gcc.dg/vect/pr88598-1.c @@ -51,4 +51,4 @@ main () /* ??? We need more constant folding for this to work with fully-masked loops. */ -/* { dg-final { scan-tree-dump-not {REDUC_PLUS} "optimized" { xfail aarch64_sve } } } */ +/* { dg-final { scan-tree-dump-not {REDUC_PLUS} "optimized" { xfail { aarch64_sve || riscv_vector } } } } */ diff --git a/gcc/testsuite/gcc.dg/vect/pr88598-2.c b/gcc/testsuite/gcc.dg/vect/pr88598-2.c index f4c41bd8e58d..ef5ea8a1a86a 100644 --- a/gcc/testsuite/gcc.dg/vect/pr88598-2.c +++ b/gcc/testsuite/gcc.dg/vect/pr88598-2.c @@ -51,4 +51,4 @@ main () /* ??? We need more constant folding for this to work with fully-masked loops. */ -/* { dg-final { scan-tree-dump-not {REDUC_PLUS} "optimized" { xfail aarch64_sve } } } */ +/* { dg-final { scan-tree-dump-not {REDUC_PLUS} "optimized" { xfail { aarch64_sve || riscv_vector } } } } */ diff --git a/gcc/testsuite/gcc.dg/vect/pr88598-3.c b/gcc/testsuite/gcc.dg/vect/pr88598-3.c index 0fc23bf0ee70..75b8d024a95b 100644 --- a/gcc/testsuite/gcc.dg/vect/pr88598-3.c +++ b/gcc/testsuite/gcc.dg/vect/pr88598-3.c @@ -51,4 +51,4 @@ main () /* ??? We need more constant folding for this to work with fully-masked loops. */ -/* { dg-final { scan-tree-dump-not {REDUC_PLUS} "optimized" { xfail aarch64_sve } } } */ +/* { dg-final { scan-tree-dump-not {REDUC_PLUS} "optimized" { xfail { aarch64_sve || riscv_vector } } } } */ diff --git a/gcc/testsuite/gcc.dg/vect/slp-26.c b/gcc/testsuite/gcc.dg/vect/slp-26.c index d398a5acb0cd..196981d83c16 100644 --- a/gcc/testsuite/gcc.dg/vect/slp-26.c +++ b/gcc/testsuite/gcc.dg/vect/slp-26.c @@ -47,7 +47,7 @@ int main (void) return 0; } -/* { dg-final { scan-tree-dump-times "vectorized 0 loops" 1 "vect" { target { ! { mips_msa || amdgcn-*-* } } } } } */ -/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 1 "vect" { target { mips_msa || amdgcn-*-* } } } } */ -/* { dg-final { scan-tree-dump-times "vectorizing stmts using SLP" 0 "vect" { target { ! { mips_msa || amdgcn-*-* } } } } } */ -/* { dg-final { scan-tree-dump-times "vectorizing stmts using SLP" 1 "vect" { target { mips_msa || amdgcn-*-* } } } } */ +/* { dg-final { scan-tree-dump-times "vectorized 0 loops" 1 "vect" { target { ! { mips_msa || { amdgcn-*-* || riscv_vector } } } } } } */ +/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 1 "vect" { target { mips_msa || { amdgcn-*-* || riscv_vector } } } } } */ +/* { dg-final { scan-tree-dump-times "vectorizing stmts using SLP" 0 "vect" { target { ! { mips_msa || { amdgcn-*-* || riscv_vector } } } } } } */ +/* { dg-final { scan-tree-dump-times "vectorizing stmts using SLP" 1 "vect" { target { mips_msa || { amdgcn-*-* || riscv_vector } } } } } */ diff --git a/gcc/testsuite/gcc.dg/vect/slp-mask-store-1.c b/gcc/testsuite/gcc.dg/vect/slp-mask-store-1.c new file mode 100644 index 000000000000..50b7066778e8 --- /dev/null +++ b/gcc/testsuite/gcc.dg/vect/slp-mask-store-1.c @@ -0,0 +1,39 @@ +/* { dg-do run } */ +/* { dg-additional-options "-mavx2" { target avx2 } } */ + +#include "tree-vect.h" + +void __attribute__((noipa)) +foo (unsigned * __restrict x, int * __restrict flag) +{ + for (int i = 0; i < 32; ++i) + { + if (flag[2*i+0]) + x[2*i+0] = x[2*i+0] + 3; + if (flag[2*i+1]) + x[2*i+1] = x[2*i+1] + 177; + } +} + +unsigned x[16]; +int flag[32] = { 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; +unsigned res[16] = { 3, 177, 0, 0, 0, 177, 3, 0, 3, 177, 0, 0, 0, 177, 3, 0 }; + +int +main () +{ + check_vect (); + + foo (x, flag); + + if (__builtin_memcmp (x, res, sizeof (x)) != 0) + abort (); + for (int i = 0; i < 32; ++i) + if (flag[i] != 0 && flag[i] != 1) + abort (); + + return 0; +} + +/* { dg-final { scan-tree-dump-times "LOOP VECTORIZED" 1 "vect" { target { vect_masked_store && vect_masked_load } } } } */ diff --git a/gcc/testsuite/gcc.dg/vect/slp-reduc-7.c b/gcc/testsuite/gcc.dg/vect/slp-reduc-7.c index 7a958f24733a..a8528ab53ee2 100644 --- a/gcc/testsuite/gcc.dg/vect/slp-reduc-7.c +++ b/gcc/testsuite/gcc.dg/vect/slp-reduc-7.c @@ -57,5 +57,5 @@ int main (void) /* { dg-final { scan-tree-dump-times "vectorized 1 loops" 1 "vect" { xfail vect_no_int_add } } } */ /* For variable-length SVE, the number of scalar statements in the reduction exceeds the number of elements in a 128-bit granule. */ -/* { dg-final { scan-tree-dump-times "vectorizing stmts using SLP" 1 "vect" { xfail { vect_no_int_add || { aarch64_sve && vect_variable_length } } } } } */ +/* { dg-final { scan-tree-dump-times "vectorizing stmts using SLP" 1 "vect" { xfail { vect_no_int_add || { { aarch64_sve && vect_variable_length } || { riscv_vector && vect_variable_length } } } } } } */ /* { dg-final { scan-tree-dump-times "VEC_PERM_EXPR" 0 "vect" { xfail { aarch64_sve && vect_variable_length } } } } */ diff --git a/gcc/testsuite/gcc.dg/vect/vect-double-reduc-5.c b/gcc/testsuite/gcc.dg/vect/vect-double-reduc-5.c index 7465eae1c476..b990405745e9 100644 --- a/gcc/testsuite/gcc.dg/vect/vect-double-reduc-5.c +++ b/gcc/testsuite/gcc.dg/vect/vect-double-reduc-5.c @@ -53,5 +53,5 @@ int main () /* Vectorization of loops with multiple types and double reduction is not supported yet. */ -/* { dg-final { scan-tree-dump-times "OUTER LOOP VECTORIZED" 1 "vect" { xfail { ! aarch64*-*-* } } } } */ +/* { dg-final { scan-tree-dump-times "OUTER LOOP VECTORIZED" 1 "vect" { xfail { ! { aarch64*-*-* riscv*-*-* } } } } } */ diff --git a/gcc/testsuite/gcc.dg/vect/vect-outer-4c-big-array.c b/gcc/testsuite/gcc.dg/vect/vect-outer-4c-big-array.c index 658920b38660..5c3eea95476e 100644 --- a/gcc/testsuite/gcc.dg/vect/vect-outer-4c-big-array.c +++ b/gcc/testsuite/gcc.dg/vect/vect-outer-4c-big-array.c @@ -24,4 +24,4 @@ foo (){ } /* { dg-final { scan-tree-dump-times "OUTER LOOP VECTORIZED" 1 "vect" { target { vect_short_mult && { ! vect_no_align } } } } } */ -/* { dg-final { scan-tree-dump-times "zero step in outer loop." 1 "vect" } } */ +/* { dg-final { scan-tree-dump-times "zero step in outer loop.(?:(?!failed)(?!Re-trying).)*succeeded" 1 "vect" } } */ diff --git a/gcc/testsuite/gcc.dg/vect/vect-outer-4e.c b/gcc/testsuite/gcc.dg/vect/vect-outer-4e.c index e65a092f5bfd..cc9e96f5d583 100644 --- a/gcc/testsuite/gcc.dg/vect/vect-outer-4e.c +++ b/gcc/testsuite/gcc.dg/vect/vect-outer-4e.c @@ -23,4 +23,4 @@ foo (){ return; } -/* { dg-final { scan-tree-dump-times "OUTER LOOP VECTORIZED" 1 "vect" { xfail { ! aarch64*-*-* } } } } */ +/* { dg-final { scan-tree-dump-times "OUTER LOOP VECTORIZED" 1 "vect" { xfail { ! { aarch64*-*-* riscv*-*-* } } } } } */ diff --git a/gcc/testsuite/gcc.dg/vect/vect-outer-4f.c b/gcc/testsuite/gcc.dg/vect/vect-outer-4f.c index a88014a2fbff..c903dc9bfea5 100644 --- a/gcc/testsuite/gcc.dg/vect/vect-outer-4f.c +++ b/gcc/testsuite/gcc.dg/vect/vect-outer-4f.c @@ -65,4 +65,4 @@ int main (void) return 0; } -/* { dg-final { scan-tree-dump-times "OUTER LOOP VECTORIZED" 1 "vect" { xfail { ! aarch64*-*-* } } } } */ +/* { dg-final { scan-tree-dump-times "OUTER LOOP VECTORIZED" 1 "vect" { xfail { ! { aarch64*-*-* riscv*-*-* } } } } } */ diff --git a/gcc/testsuite/gcc.dg/vect/vect-outer-4g.c b/gcc/testsuite/gcc.dg/vect/vect-outer-4g.c index a88014a2fbff..c903dc9bfea5 100644 --- a/gcc/testsuite/gcc.dg/vect/vect-outer-4g.c +++ b/gcc/testsuite/gcc.dg/vect/vect-outer-4g.c @@ -65,4 +65,4 @@ int main (void) return 0; } -/* { dg-final { scan-tree-dump-times "OUTER LOOP VECTORIZED" 1 "vect" { xfail { ! aarch64*-*-* } } } } */ +/* { dg-final { scan-tree-dump-times "OUTER LOOP VECTORIZED" 1 "vect" { xfail { ! { aarch64*-*-* riscv*-*-* } } } } } */ diff --git a/gcc/testsuite/gcc.dg/vect/vect-outer-4k.c b/gcc/testsuite/gcc.dg/vect/vect-outer-4k.c index a88014a2fbff..c903dc9bfea5 100644 --- a/gcc/testsuite/gcc.dg/vect/vect-outer-4k.c +++ b/gcc/testsuite/gcc.dg/vect/vect-outer-4k.c @@ -65,4 +65,4 @@ int main (void) return 0; } -/* { dg-final { scan-tree-dump-times "OUTER LOOP VECTORIZED" 1 "vect" { xfail { ! aarch64*-*-* } } } } */ +/* { dg-final { scan-tree-dump-times "OUTER LOOP VECTORIZED" 1 "vect" { xfail { ! { aarch64*-*-* riscv*-*-* } } } } } */ diff --git a/gcc/testsuite/gcc.dg/vect/vect-outer-4l.c b/gcc/testsuite/gcc.dg/vect/vect-outer-4l.c index 4f95c652ee30..a63b9332afaa 100644 --- a/gcc/testsuite/gcc.dg/vect/vect-outer-4l.c +++ b/gcc/testsuite/gcc.dg/vect/vect-outer-4l.c @@ -65,4 +65,4 @@ int main (void) return 0; } -/* { dg-final { scan-tree-dump-times "OUTER LOOP VECTORIZED" 1 "vect" { xfail { ! aarch64*-*-* } } } }*/ +/* { dg-final { scan-tree-dump-times "OUTER LOOP VECTORIZED" 1 "vect" { xfail { ! { aarch64*-*-* riscv*-*-* } } } } }*/ diff --git a/gcc/testsuite/gcc.dg/vect/vect-reduc-dot-s16a.c b/gcc/testsuite/gcc.dg/vect/vect-reduc-dot-s16a.c index ffbc9706901c..d826828e3d6f 100644 --- a/gcc/testsuite/gcc.dg/vect/vect-reduc-dot-s16a.c +++ b/gcc/testsuite/gcc.dg/vect/vect-reduc-dot-s16a.c @@ -51,7 +51,7 @@ main (void) return 0; } -/* { dg-final { scan-tree-dump-times "vect_recog_dot_prod_pattern: detected" 1 "vect" } } */ +/* { dg-final { scan-tree-dump-times "vect_recog_dot_prod_pattern: detected(?:(?!failed)(?!Re-trying).)*succeeded" 1 "vect" } } */ /* { dg-final { scan-tree-dump-times "vectorized 1 loops" 1 "vect" { target vect_sdot_hi } } } */ /* { dg-final { scan-tree-dump-times "vectorized 1 loops" 1 "vect" { target vect_widen_mult_hi_to_si } } } */ diff --git a/gcc/testsuite/gcc.dg/vect/vect-reduc-dot-s8a.c b/gcc/testsuite/gcc.dg/vect/vect-reduc-dot-s8a.c index 05e343ad7820..4e1e0b234f48 100644 --- a/gcc/testsuite/gcc.dg/vect/vect-reduc-dot-s8a.c +++ b/gcc/testsuite/gcc.dg/vect/vect-reduc-dot-s8a.c @@ -55,8 +55,8 @@ int main (void) return 0; } -/* { dg-final { scan-tree-dump-times "vect_recog_dot_prod_pattern: detected" 1 "vect" } } */ -/* { dg-final { scan-tree-dump-times "vect_recog_widen_mult_pattern: detected" 1 "vect" } } */ +/* { dg-final { scan-tree-dump-times "vect_recog_dot_prod_pattern: detected(?:(?!failed)(?!Re-trying).)*succeeded" 1 "vect" } } */ +/* { dg-final { scan-tree-dump-times "vect_recog_widen_mult_pattern: detected(?:(?!failed)(?!Re-trying).)*succeeded" 1 "vect" } } */ /* { dg-final { scan-tree-dump-times "vectorized 1 loops" 1 "vect" { target vect_sdot_qi } } } */ /* { dg-final { scan-tree-dump-times "vectorized 1 loops" 1 "vect" { target { vect_widen_mult_qi_to_hi && vect_widen_sum_hi_to_si } } } } */ diff --git a/gcc/testsuite/gcc.dg/vect/vect-reduc-dot-s8b.c b/gcc/testsuite/gcc.dg/vect/vect-reduc-dot-s8b.c index 82c648cc73c6..cb88ad5b6391 100644 --- a/gcc/testsuite/gcc.dg/vect/vect-reduc-dot-s8b.c +++ b/gcc/testsuite/gcc.dg/vect/vect-reduc-dot-s8b.c @@ -53,8 +53,8 @@ int main (void) return 0; } -/* { dg-final { scan-tree-dump-times "vect_recog_dot_prod_pattern: detected" 1 "vect" { xfail *-*-* } } } */ -/* { dg-final { scan-tree-dump-times "vect_recog_widen_mult_pattern: detected" 1 "vect" } } */ +/* { dg-final { scan-tree-dump-times "vect_recog_dot_prod_pattern: detected(?:(?!failed)(?!Re-trying).)*succeeded" 1 "vect" { xfail *-*-* } } } */ +/* { dg-final { scan-tree-dump-times "vect_recog_widen_mult_pattern: detected(?:(?!failed)(?!Re-trying).)*succeeded" 1 "vect" } } */ /* { dg-final { scan-tree-dump-times "vectorized 1 loops" 1 "vect" { target vect_widen_mult_qi_to_hi } } } */ diff --git a/gcc/testsuite/gcc.dg/vect/vect-reduc-dot-u16a.c b/gcc/testsuite/gcc.dg/vect/vect-reduc-dot-u16a.c index 4bf4a1e3c2cd..9adb23a32f62 100644 --- a/gcc/testsuite/gcc.dg/vect/vect-reduc-dot-u16a.c +++ b/gcc/testsuite/gcc.dg/vect/vect-reduc-dot-u16a.c @@ -37,6 +37,7 @@ int main (void) for (i=0; i diff --git a/gcc/testsuite/gcc.target/i386/pr110832-1.c b/gcc/testsuite/gcc.target/i386/pr110832-1.c new file mode 100644 index 000000000000..f473e40e23ad --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr110832-1.c @@ -0,0 +1,12 @@ +/* PR target/110832 */ +/* { dg-do compile { target { ! ia32 } } } */ +/* { dg-options "-O2 -msse2 -mno-partial-vector-fp-math" } */ + +typedef float __attribute__((vector_size(8))) v2sf; + +v2sf test (v2sf a, v2sf b) +{ + return a + b; +} + +/* { dg-final { scan-assembler-not "addps" } } */ diff --git a/gcc/testsuite/gcc.target/i386/pr110832-2.c b/gcc/testsuite/gcc.target/i386/pr110832-2.c new file mode 100644 index 000000000000..59cf8f9c6662 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr110832-2.c @@ -0,0 +1,13 @@ +/* PR target/110832 */ +/* { dg-do compile { target { ! ia32 } } } */ +/* { dg-options "-O2 -ftrapping-math -msse2 -mpartial-vector-fp-math -dp" } */ + +typedef float __attribute__((vector_size(8))) v2sf; + +v2sf test (v2sf a, v2sf b) +{ + return a + b; +} + +/* { dg-final { scan-assembler "addps" } } */ +/* { dg-final { scan-assembler-times "\\*vec_concatv4sf_0" 2 } } */ diff --git a/gcc/testsuite/gcc.target/i386/pr110832-3.c b/gcc/testsuite/gcc.target/i386/pr110832-3.c new file mode 100644 index 000000000000..19e219e1a11b --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr110832-3.c @@ -0,0 +1,13 @@ +/* PR target/110832 */ +/* { dg-do compile { target { ! ia32 } } } */ +/* { dg-options "-O2 -fno-trapping-math -msse2 -mpartial-vector-fp-math -dp" } */ + +typedef float __attribute__((vector_size(8))) v2sf; + +v2sf test (v2sf a, v2sf b) +{ + return a + b; +} + +/* { dg-final { scan-assembler "addps" } } */ +/* { dg-final { scan-assembler-not "\\*vec_concatv4sf_0" } } */ diff --git a/gcc/testsuite/gcc.target/i386/pr111023-2.c b/gcc/testsuite/gcc.target/i386/pr111023-2.c new file mode 100644 index 000000000000..6c69f9475442 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr111023-2.c @@ -0,0 +1,52 @@ +/* PR target/111023 */ +/* { dg-do compile } */ +/* { dg-options "-O2 -mtune=icelake-server -ftree-vectorize -msse2 -mno-sse4.1" } */ + +typedef char v16qi __attribute__((vector_size (16))); +typedef short v8hi __attribute__((vector_size (16))); +typedef int v4si __attribute__((vector_size (16))); +typedef long long v2di __attribute__((vector_size (16))); + +void +v8hi_v8qi (v8hi *dst, v16qi src) +{ + short tem[8]; + tem[0] = src[0]; + tem[1] = src[1]; + tem[2] = src[2]; + tem[3] = src[3]; + tem[4] = src[4]; + tem[5] = src[5]; + tem[6] = src[6]; + tem[7] = src[7]; + dst[0] = *(v8hi *) tem; +} + +/* { dg-final { scan-assembler "pcmpgtb" } } */ +/* { dg-final { scan-assembler "punpcklbw" } } */ + +void +v4si_v4hi (v4si *dst, v8hi src) +{ + int tem[4]; + tem[0] = src[0]; + tem[1] = src[1]; + tem[2] = src[2]; + tem[3] = src[3]; + dst[0] = *(v4si *) tem; +} + +/* { dg-final { scan-assembler "pcmpgtw" } } */ +/* { dg-final { scan-assembler "punpcklwd" } } */ + +void +v2di_v2si (v2di *dst, v4si src) +{ + long long tem[2]; + tem[0] = src[0]; + tem[1] = src[1]; + dst[0] = *(v2di *) tem; +} + +/* { dg-final { scan-assembler "pcmpgtd" } } */ +/* { dg-final { scan-assembler "punpckldq" } } */ diff --git a/gcc/testsuite/gcc.target/i386/pr111023-4b.c b/gcc/testsuite/gcc.target/i386/pr111023-4b.c new file mode 100644 index 000000000000..061f6a18fff2 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr111023-4b.c @@ -0,0 +1,17 @@ +/* PR target/111023 */ +/* { dg-do compile } */ +/* { dg-options "-O2 -mtune=icelake-server -ftree-vectorize -msse2 -mno-sse4.1" } */ + +typedef unsigned char v4qi __attribute__((vector_size (4))); +typedef unsigned short v2hi __attribute__((vector_size (4))); + +void +v2hi_v2qi (v2hi *dst, v4qi src) +{ + unsigned short tem[2]; + tem[0] = src[0]; + tem[1] = src[1]; + dst[0] = *(v2hi *) tem; +} + +/* { dg-final { scan-assembler "punpcklbw" } } */ diff --git a/gcc/testsuite/gcc.target/i386/pr111023-8b.c b/gcc/testsuite/gcc.target/i386/pr111023-8b.c new file mode 100644 index 000000000000..26c5e2785be1 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr111023-8b.c @@ -0,0 +1,31 @@ +/* PR target/111023 */ +/* { dg-do compile { target { ! ia32 } } } */ +/* { dg-options "-O2 -mtune=icelake-server -ftree-vectorize -msse2 -mno-sse4.1" } */ + +typedef unsigned char v8qi __attribute__((vector_size (8))); +typedef unsigned short v4hi __attribute__((vector_size (8))); +typedef unsigned int v2si __attribute__((vector_size (8))); + +void +v4hi_v4qi (v4hi *dst, v8qi src) +{ + unsigned short tem[4]; + tem[0] = src[0]; + tem[1] = src[1]; + tem[2] = src[2]; + tem[3] = src[3]; + dst[0] = *(v4hi *) tem; +} + +/* { dg-final { scan-assembler "punpcklbw" } } */ + +void +v2si_v2hi (v2si *dst, v4hi src) +{ + unsigned int tem[2]; + tem[0] = src[0]; + tem[1] = src[1]; + dst[0] = *(v2si *) tem; +} + +/* { dg-final { scan-assembler "punpcklwd" } } */ diff --git a/gcc/testsuite/gcc.target/i386/pr111023.c b/gcc/testsuite/gcc.target/i386/pr111023.c new file mode 100644 index 000000000000..6144c371f322 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr111023.c @@ -0,0 +1,49 @@ +/* PR target/111023 */ +/* { dg-do compile } */ +/* { dg-options "-O2 -mtune=icelake-server -ftree-vectorize -msse2 -mno-sse4.1" } */ + +typedef unsigned char v16qi __attribute__((vector_size (16))); +typedef unsigned short v8hi __attribute__((vector_size (16))); +typedef unsigned int v4si __attribute__((vector_size (16))); +typedef unsigned long long v2di __attribute__((vector_size (16))); + +void +v8hi_v8qi (v8hi *dst, v16qi src) +{ + unsigned short tem[8]; + tem[0] = src[0]; + tem[1] = src[1]; + tem[2] = src[2]; + tem[3] = src[3]; + tem[4] = src[4]; + tem[5] = src[5]; + tem[6] = src[6]; + tem[7] = src[7]; + dst[0] = *(v8hi *) tem; +} + +/* { dg-final { scan-assembler "punpcklbw" } } */ + +void +v4si_v4hi (v4si *dst, v8hi src) +{ + unsigned int tem[4]; + tem[0] = src[0]; + tem[1] = src[1]; + tem[2] = src[2]; + tem[3] = src[3]; + dst[0] = *(v4si *) tem; +} + +/* { dg-final { scan-assembler "punpcklwd" } } */ + +void +v2di_v2si (v2di *dst, v4si src) +{ + unsigned long long tem[2]; + tem[0] = src[0]; + tem[1] = src[1]; + dst[0] = *(v2di *) tem; +} + +/* { dg-final { scan-assembler "punpckldq" } } */ diff --git a/gcc/testsuite/gcc.target/i386/pr111127.c b/gcc/testsuite/gcc.target/i386/pr111127.c new file mode 100644 index 000000000000..c124bc18bc4c --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr111127.c @@ -0,0 +1,24 @@ +/* PR target/111127 */ +/* { dg-do compile } */ +/* { dg-options "-O2 -mavx512bf16 -mavx512vl" } */ +/* { dg-final { scan-assembler-times "vcvtne2ps2bf16\[ \\t\]+\[^\{\n\]*%zmm1, %zmm0, %zmm0\{%k\[0-9\]\}\{z\}\[^\n\r]*(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "vcvtne2ps2bf16\[ \\t\]+\[^\{\n\]*%ymm1, %ymm0, %ymm0\{%k\[0-9\]\}\{z\}\[^\n\r]*(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "vcvtne2ps2bf16\[ \\t\]+\[^\{\n\]*%xmm1, %xmm0, %xmm0\{%k\[0-9\]\}\{z\}\[^\n\r]*(?:\n|\[ \\t\]+#)" 1 } } */ + +#include + +__m512bh cvttest(__mmask32 k, __m512 a, __m512 b) +{ + return _mm512_maskz_cvtne2ps_pbh (k,a,b); +} + +__m256bh cvttest2(__mmask16 k, __m256 a, __m256 b) +{ + return _mm256_maskz_cvtne2ps_pbh (k,a,b); +} + +__m128bh cvttest3(__mmask8 k, __m128 a, __m128 b) +{ + return _mm_maskz_cvtne2ps_pbh (k,a,b); +} + diff --git a/gcc/testsuite/gcc.target/i386/pr111228.c b/gcc/testsuite/gcc.target/i386/pr111228.c new file mode 100644 index 000000000000..f0c3f9b77bf9 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr111228.c @@ -0,0 +1,18 @@ +/* { dg-do compile } */ +/* { dg-options "-O -fdump-tree-cddce1" } */ +/* { dg-additional-options "-msse2" { target sse2 } } */ + +typedef __UINT64_TYPE__ v2di __attribute__((vector_size(16))); + +v2di g; +void test (v2di *v) +{ + v2di lo = v[0]; + v2di hi = v[1]; + v2di res; + res[1] = hi[1]; + res[0] = lo[0]; + g = res; +} + +/* { dg-final { scan-tree-dump-times "VEC_PERM_EXPR <\[^>\]*, { 0, 3 }>" 1 "cddce1" { target sse2 } } } */ diff --git a/gcc/testsuite/gcc.target/i386/pr52252-atom.c b/gcc/testsuite/gcc.target/i386/pr52252-atom.c index ee604f2189a2..11f944115757 100644 --- a/gcc/testsuite/gcc.target/i386/pr52252-atom.c +++ b/gcc/testsuite/gcc.target/i386/pr52252-atom.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-O2 -ftree-vectorize -mssse3 -mtune=slm" } */ +/* { dg-options "-O2 -ftree-vectorize -mssse3 -mtune=slm -mprefer-vector-width=128" } */ #define byte unsigned char void diff --git a/gcc/testsuite/gcc.target/i386/pr52252-core.c b/gcc/testsuite/gcc.target/i386/pr52252-core.c index 65d62cfa3658..897026b09975 100644 --- a/gcc/testsuite/gcc.target/i386/pr52252-core.c +++ b/gcc/testsuite/gcc.target/i386/pr52252-core.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-O2 -ftree-vectorize -mssse3 -mtune=corei7" } */ +/* { dg-options "-O2 -ftree-vectorize -mssse3 -mtune=corei7 -mprefer-vector-width=128" } */ #define byte unsigned char void diff --git a/gcc/testsuite/gcc.target/i386/pr79173-12.c b/gcc/testsuite/gcc.target/i386/pr79173-12.c new file mode 100644 index 000000000000..df8033ba1a4d --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr79173-12.c @@ -0,0 +1,48 @@ +/* PR middle-end/79173 */ +/* PR middle-end/111209 */ +/* { dg-do compile } */ +/* { dg-options "-O2 -fno-stack-protector -masm=att" } */ +/* { dg-final { scan-assembler-times "addq\t%r\[^\n\r]*, \\\(%rdi\\\)" 1 { target lp64 } } } */ +/* { dg-final { scan-assembler-times "adcq\t%r\[^\n\r]*, 8\\\(%rdi\\\)" 1 { target lp64 } } } */ +/* { dg-final { scan-assembler-times "subq\t%r\[^\n\r]*, \\\(%rdi\\\)" 1 { target lp64 } } } */ +/* { dg-final { scan-assembler-times "sbbq\t%r\[^\n\r]*, 8\\\(%rdi\\\)" 1 { target lp64 } } } */ +/* { dg-final { scan-assembler-times "addl\t%e\[^\n\r]*, \\\(%e\[^\n\r]*\\\)" 1 { target ia32 } } } */ +/* { dg-final { scan-assembler-times "adcl\t%e\[^\n\r]*, 4\\\(%e\[^\n\r]*\\\)" 1 { target ia32 } } } */ +/* { dg-final { scan-assembler-times "subl\t%e\[^\n\r]*, \\\(%e\[^\n\r]*\\\)" 1 { target ia32 } } } */ +/* { dg-final { scan-assembler-times "sbbl\t%e\[^\n\r]*, 4\\\(%e\[^\n\r]*\\\)" 1 { target ia32 } } } */ + +static unsigned long +uaddc (unsigned long x, unsigned long y, unsigned long carry_in, unsigned long *carry_out) +{ + unsigned long r; + unsigned long c1 = __builtin_add_overflow (x, y, &r); + unsigned long c2 = __builtin_add_overflow (r, carry_in, &r); + *carry_out = c1 + c2; + return r; +} + +static unsigned long +usubc (unsigned long x, unsigned long y, unsigned long carry_in, unsigned long *carry_out) +{ + unsigned long r; + unsigned long c1 = __builtin_sub_overflow (x, y, &r); + unsigned long c2 = __builtin_sub_overflow (r, carry_in, &r); + *carry_out = c1 + c2; + return r; +} + +void +foo (unsigned long *p, unsigned long *q) +{ + unsigned long c; + p[0] = uaddc (p[0], q[0], 0, &c); + p[1] = uaddc (p[1], q[1], c, &c); +} + +void +bar (unsigned long *p, unsigned long *q) +{ + unsigned long c; + p[0] = usubc (p[0], q[0], 0, &c); + p[1] = usubc (p[1], q[1], c, &c); +} diff --git a/gcc/testsuite/gcc.target/i386/pr87007-5.c b/gcc/testsuite/gcc.target/i386/pr87007-5.c index a6cdf11522e5..8f2dc947f6c4 100644 --- a/gcc/testsuite/gcc.target/i386/pr87007-5.c +++ b/gcc/testsuite/gcc.target/i386/pr87007-5.c @@ -1,6 +1,8 @@ /* { dg-do compile } */ /* { dg-options "-Ofast -march=skylake-avx512 -mfpmath=sse -fno-tree-vectorize -fdump-tree-cddce3-details -fdump-tree-lsplit-optimized" } */ -/* Load of d2/d3 is hoisted out, vrndscalesd will reuse loades register to avoid partial dependence. */ +/* Load of d2/d3 is hoisted out, the loop is split, store of d1 and sqrt + are sunk out of the loop and the loop is elided. One vsqrtsd with + memory operand needs a xor to avoid partial dependence. */ #include @@ -17,4 +19,4 @@ foo (int n, int k) /* { dg-final { scan-tree-dump "optimized: loop split" "lsplit" } } */ /* { dg-final { scan-tree-dump-times "removing loop" 2 "cddce3" } } */ -/* { dg-final { scan-assembler-times "vxorps\[^\n\r\]*xmm\[0-9\]" 0 } } */ +/* { dg-final { scan-assembler-times "vxorps\[^\n\r\]*xmm\[0-9\]" 1 } } */ diff --git a/gcc/testsuite/gcc.target/i386/pr88531-1b.c b/gcc/testsuite/gcc.target/i386/pr88531-1b.c index 812c8a10fab1..e6df789de900 100644 --- a/gcc/testsuite/gcc.target/i386/pr88531-1b.c +++ b/gcc/testsuite/gcc.target/i386/pr88531-1b.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-O3 -march=skylake -mfpmath=sse" } */ +/* { dg-options "-O3 -march=skylake -mfpmath=sse -mtune=haswell" } */ #include "pr88531-1a.c" diff --git a/gcc/testsuite/gcc.target/i386/pr88531-1c.c b/gcc/testsuite/gcc.target/i386/pr88531-1c.c index 43fc5913ed36..a093c87c01fd 100644 --- a/gcc/testsuite/gcc.target/i386/pr88531-1c.c +++ b/gcc/testsuite/gcc.target/i386/pr88531-1c.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-O3 -march=skylake-avx512 -mfpmath=sse" } */ +/* { dg-options "-O3 -march=skylake-avx512 -mfpmath=sse -mtune=haswell" } */ #include "pr88531-1a.c" diff --git a/gcc/testsuite/gcc.target/i386/pr89229-4a.c b/gcc/testsuite/gcc.target/i386/pr89229-4a.c index 5bc10d256193..8869650b0ad0 100644 --- a/gcc/testsuite/gcc.target/i386/pr89229-4a.c +++ b/gcc/testsuite/gcc.target/i386/pr89229-4a.c @@ -1,4 +1,4 @@ -/* { dg-do compile { target { ! ia32 } } } */ +/* { dg-do assemble { target { ! ia32 } } } */ /* { dg-options "-O2 -march=skylake-avx512" } */ extern double d; @@ -12,5 +12,3 @@ foo1 (double x) asm volatile ("" : "+v" (xmm17)); d = xmm17; } - -/* { dg-final { scan-assembler-not "vmovapd" } } */ diff --git a/gcc/testsuite/gcc.target/i386/pr94864.c b/gcc/testsuite/gcc.target/i386/pr94864.c new file mode 100644 index 000000000000..69cb481fcfe6 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr94864.c @@ -0,0 +1,13 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -msse2 -mno-avx" } */ + +typedef double v2df __attribute__((vector_size(16))); + +v2df move_sd(v2df a, v2df b) +{ + v2df result = a; + result[0] = b[1]; + return result; +} + +/* { dg-final { scan-assembler "unpckhpd\[\\t \]%xmm0, %xmm1" } } */ diff --git a/gcc/testsuite/gcc.target/i386/pr94865.c b/gcc/testsuite/gcc.target/i386/pr94865.c new file mode 100644 index 000000000000..84065ac24671 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr94865.c @@ -0,0 +1,13 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -msse2 -mno-avx" } */ + +typedef double v2df __attribute__((vector_size(16))); + +v2df move_sd(v2df a, v2df b) +{ + v2df result = a; + result[1] = b[1]; + return result; +} + +/* { dg-final { scan-assembler "shufpd\[\\t \]*.2, %xmm1, %xmm0" } } */ diff --git a/gcc/testsuite/gcc.target/i386/vect-reduc-2.c b/gcc/testsuite/gcc.target/i386/vect-reduc-2.c new file mode 100644 index 000000000000..62559ef8e7bd --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/vect-reduc-2.c @@ -0,0 +1,77 @@ +/* { dg-do compile } */ +/* { dg-options "-fgimple -O2 -msse2 -fdump-tree-slp2-optimized" } */ + +signed char x[16]; + +signed char __GIMPLE (ssa,guessed_local(1073741824)) +foo () +{ + signed char _1; + signed char _3; + signed char _5; + signed char _6; + signed char _8; + signed char _9; + signed char _11; + signed char _12; + signed char _14; + signed char _15; + signed char _17; + signed char _18; + signed char _20; + signed char _21; + signed char _23; + signed char _24; + signed char _26; + signed char _27; + signed char _29; + signed char _30; + signed char _32; + signed char _33; + signed char _35; + signed char _36; + signed char _38; + signed char _39; + signed char _41; + signed char _42; + signed char _44; + signed char _45; + signed char _47; + + __BB(2,guessed_local(1073741824)): + _1 = x[15]; + _3 = x[1]; + _5 = _1 + _3; + _6 = x[2]; + _8 = _5 + _6; + _9 = x[3]; + _11 = _8 + _9; + _12 = x[4]; + _14 = _11 + _12; + _15 = x[5]; + _17 = _14 + _15; + _18 = x[6]; + _20 = _17 + _18; + _21 = x[7]; + _23 = _20 + _21; + _24 = x[8]; + _26 = _23 + _24; + _27 = x[9]; + _29 = _26 + _27; + _30 = x[10]; + _32 = _29 + _30; + _33 = x[11]; + _35 = _32 + _33; + _36 = x[12]; + _38 = _35 + _36; + _39 = x[13]; + _41 = _38 + _39; + _42 = x[14]; + _44 = _41 + _42; + _45 = x[0]; + _47 = _44 + _45; + return _47; + +} + +/* { dg-final { scan-tree-dump "optimized: basic block part vectorized" "slp2" } } */ diff --git a/gcc/testsuite/gcc.target/loongarch/const-double-zero-stx.c b/gcc/testsuite/gcc.target/loongarch/const-double-zero-stx.c new file mode 100644 index 000000000000..8fb04be8ff5d --- /dev/null +++ b/gcc/testsuite/gcc.target/loongarch/const-double-zero-stx.c @@ -0,0 +1,18 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ +/* { dg-final { scan-assembler-times {stx\..\t\$r0} 2 } } */ + +extern float arr_f[]; +extern double arr_d[]; + +void +test_f (int base, int index) +{ + arr_f[base + index] = 0.0; +} + +void +test_d (int base, int index) +{ + arr_d[base + index] = 0.0; +} diff --git a/gcc/testsuite/gcc.target/loongarch/float-load.c b/gcc/testsuite/gcc.target/loongarch/float-load.c new file mode 100644 index 000000000000..c757a795e214 --- /dev/null +++ b/gcc/testsuite/gcc.target/loongarch/float-load.c @@ -0,0 +1,11 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ +/* { dg-final { scan-assembler "fld\\.s" } } */ + +extern int a; +float +test (void) +{ + return (float)a; +} + diff --git a/gcc/testsuite/gcc.target/loongarch/math-float-128.c b/gcc/testsuite/gcc.target/loongarch/math-float-128.c new file mode 100644 index 000000000000..387566a57c9d --- /dev/null +++ b/gcc/testsuite/gcc.target/loongarch/math-float-128.c @@ -0,0 +1,81 @@ +/* { dg-do compile } */ +/* { dg-options " -march=loongarch64 -O2 " } */ +/* { dg-final { scan-assembler-not "my_fabsq2:.*\\bl\t%plt\\(__builtin_fabsq\\).*my_fabsq2" } } */ +/* { dg-final { scan-assembler-not "my_copysignq2:.*\\bl\t%plt\\(__builtin_copysignq\\).*my_copysignq2" } } */ +/* { dg-final { scan-assembler-not "my_infq2:.*\\bl\t%plt\\(__builtin_infq\\).*my_infq2" } } */ +/* { dg-final { scan-assembler-not "my_huge_valq2:.*\\bl\t%plt\\(__builtin_huge_valq\\).*my_huge_valq2" } } */ +/* { dg-final { scan-assembler-not "my_nanq2:.*\\bl\t%plt\\(__builtin_nanq\\).*my_nanq2" } } */ +/* { dg-final { scan-assembler-not "my_nansq2:.*\\bl\t%plt\\(__builtin_nansq\\).*my_nansq2" } } */ + +__float128 +my_fabsq1 (__float128 a) +{ + return __builtin_fabsq (a); +} + +_Float128 +my_fabsq2 (_Float128 a) +{ + return __builtin_fabsq (a); +} + +__float128 +my_copysignq1 (__float128 a, __float128 b) +{ + return __builtin_copysignq (a, b); +} + +_Float128 +my_copysignq2 (_Float128 a, _Float128 b) +{ + return __builtin_copysignq (a, b); +} + +__float128 +my_infq1 (void) +{ + return __builtin_infq (); +} + +_Float128 +my_infq2 (void) +{ + return __builtin_infq (); +} + +__float128 +my_huge_valq1 (void) +{ + return __builtin_huge_valq (); +} + +_Float128 +my_huge_valq2 (void) +{ + return __builtin_huge_valq (); +} + +__float128 +my_nanq1 (void) +{ + return __builtin_nanq (""); +} + +_Float128 +my_nanq2 (void) +{ + return __builtin_nanq (""); +} + +__float128 +my_nansq1 (void) +{ + return __builtin_nansq (""); +} + +_Float128 +my_nansq2 (void) +{ + return __builtin_nansq (""); +} + diff --git a/gcc/testsuite/gcc.target/loongarch/sign-extend.c b/gcc/testsuite/gcc.target/loongarch/sign-extend.c new file mode 100644 index 000000000000..3f339d06bbdb --- /dev/null +++ b/gcc/testsuite/gcc.target/loongarch/sign-extend.c @@ -0,0 +1,25 @@ +/* { dg-do compile } */ +/* { dg-options "-mabi=lp64d -O2" } */ +/* { dg-final { scan-assembler-times "slli.w" 1 } } */ + +extern int PL_savestack_ix; +extern int PL_regsize; +extern int PL_savestack_max; +void Perl_savestack_grow_cnt (int need); +extern void Perl_croak (char *); + +int +S_regcppush(int parenfloor) +{ + int retval = PL_savestack_ix; + int paren_elems_to_push = (PL_regsize - parenfloor) * 4; + int p; + + if (paren_elems_to_push < 0) + Perl_croak ("panic: paren_elems_to_push < 0"); + + if (PL_savestack_ix + (paren_elems_to_push + 6) > PL_savestack_max) + Perl_savestack_grow_cnt (paren_elems_to_push + 6); + + return retval; +} diff --git a/gcc/testsuite/gcc.target/loongarch/slt-sign-extend.c b/gcc/testsuite/gcc.target/loongarch/slt-sign-extend.c new file mode 100644 index 000000000000..ea6b28b7c451 --- /dev/null +++ b/gcc/testsuite/gcc.target/loongarch/slt-sign-extend.c @@ -0,0 +1,14 @@ +/* { dg-do compile } */ +/* { dg-options "-mabi=lp64d -O2" } */ +/* { dg-final { scan-assembler-not "slli.w" } } */ + +extern int src1, src2, src3; + +int +test (void) +{ + int data1 = src1 + src2; + int data2 = src1 + src3; + + return data1 > data2 ? data1 : data2; +} diff --git a/gcc/testsuite/gcc.target/loongarch/switch-qi.c b/gcc/testsuite/gcc.target/loongarch/switch-qi.c new file mode 100644 index 000000000000..dd192fd497f1 --- /dev/null +++ b/gcc/testsuite/gcc.target/loongarch/switch-qi.c @@ -0,0 +1,16 @@ +/* { dg-do compile } */ +/* { dg-options "-march=loongarch64 -mabi=lp64d" } */ +/* { dg-final { scan-assembler-not "bstrpick" } } */ + +/* Test for loongarch_extend_comparands patch. */ +extern void asdf (int); +void +foo (signed char x) { + switch (x) { + case 0: asdf (10); break; + case 1: asdf (11); break; + case 2: asdf (12); break; + case 3: asdf (13); break; + case 4: asdf (14); break; + } +} diff --git a/gcc/testsuite/gcc.target/powerpc/fold-vec-logical-ors-char.c b/gcc/testsuite/gcc.target/powerpc/fold-vec-logical-ors-char.c index 713fed7824a0..7406039d0549 100644 --- a/gcc/testsuite/gcc.target/powerpc/fold-vec-logical-ors-char.c +++ b/gcc/testsuite/gcc.target/powerpc/fold-vec-logical-ors-char.c @@ -120,6 +120,6 @@ test6_nor (vector unsigned char x, vector unsigned char y) return *foo; } -/* { dg-final { scan-assembler-times {\mxxlor\M} 7 } } */ +/* { dg-final { scan-assembler-times {\mxxlor\M} 6 } } */ /* { dg-final { scan-assembler-times {\mxxlxor\M} 6 } } */ -/* { dg-final { scan-assembler-times {\mxxlnor\M} 1 } } */ +/* { dg-final { scan-assembler-times {\mxxlnor\M} 2 } } */ diff --git a/gcc/testsuite/gcc.target/powerpc/fold-vec-logical-ors-int.c b/gcc/testsuite/gcc.target/powerpc/fold-vec-logical-ors-int.c index 4d1c78f40eca..a7c6366b938b 100644 --- a/gcc/testsuite/gcc.target/powerpc/fold-vec-logical-ors-int.c +++ b/gcc/testsuite/gcc.target/powerpc/fold-vec-logical-ors-int.c @@ -119,6 +119,6 @@ test6_nor (vector unsigned int x, vector unsigned int y) return *foo; } -/* { dg-final { scan-assembler-times {\mxxlor\M} 7 } } */ +/* { dg-final { scan-assembler-times {\mxxlor\M} 6 } } */ /* { dg-final { scan-assembler-times {\mxxlxor\M} 6 } } */ -/* { dg-final { scan-assembler-times {\mxxlnor\M} 1 } } */ +/* { dg-final { scan-assembler-times {\mxxlnor\M} 2 } } */ diff --git a/gcc/testsuite/gcc.target/powerpc/fold-vec-logical-ors-longlong.c b/gcc/testsuite/gcc.target/powerpc/fold-vec-logical-ors-longlong.c index 27ef09ada801..10c69d3d87b5 100644 --- a/gcc/testsuite/gcc.target/powerpc/fold-vec-logical-ors-longlong.c +++ b/gcc/testsuite/gcc.target/powerpc/fold-vec-logical-ors-longlong.c @@ -156,6 +156,6 @@ test6_nor (vector unsigned long long x, vector unsigned long long y) // For simplicity, this test now only targets "powerpc_p8vector_ok" environments // where the answer is expected to be 6. -/* { dg-final { scan-assembler-times {\mxxlor\M} 9 } } */ +/* { dg-final { scan-assembler-times {\mxxlor\M} 6 } } */ /* { dg-final { scan-assembler-times {\mxxlxor\M} 6 } } */ -/* { dg-final { scan-assembler-times {\mxxlnor\M} 3 } } */ +/* { dg-final { scan-assembler-times {\mxxlnor\M} 6 } } */ diff --git a/gcc/testsuite/gcc.target/powerpc/fold-vec-logical-ors-short.c b/gcc/testsuite/gcc.target/powerpc/fold-vec-logical-ors-short.c index f796c5b33a9c..8352a7f4dc59 100644 --- a/gcc/testsuite/gcc.target/powerpc/fold-vec-logical-ors-short.c +++ b/gcc/testsuite/gcc.target/powerpc/fold-vec-logical-ors-short.c @@ -119,6 +119,6 @@ test6_nor (vector unsigned short x, vector unsigned short y) return *foo; } -/* { dg-final { scan-assembler-times {\mxxlor\M} 7 } } */ +/* { dg-final { scan-assembler-times {\mxxlor\M} 6 } } */ /* { dg-final { scan-assembler-times {\mxxlxor\M} 6 } } */ -/* { dg-final { scan-assembler-times {\mxxlnor\M} 1 } } */ +/* { dg-final { scan-assembler-times {\mxxlnor\M} 2 } } */ diff --git a/gcc/testsuite/gcc.target/powerpc/fold-vec-logical-other-char.c b/gcc/testsuite/gcc.target/powerpc/fold-vec-logical-other-char.c index e74308ccda29..7fe3e0b8e0e9 100644 --- a/gcc/testsuite/gcc.target/powerpc/fold-vec-logical-other-char.c +++ b/gcc/testsuite/gcc.target/powerpc/fold-vec-logical-other-char.c @@ -104,5 +104,5 @@ test6_nand (vector unsigned char x, vector unsigned char y) return *foo; } -/* { dg-final { scan-assembler-times {\mxxlnand\M} 3 } } */ +/* { dg-final { scan-assembler-times {\mxxlnand\M} 6 } } */ /* { dg-final { scan-assembler-times {\mxxlorc\M} 6 } } */ diff --git a/gcc/testsuite/gcc.target/powerpc/fold-vec-logical-other-int.c b/gcc/testsuite/gcc.target/powerpc/fold-vec-logical-other-int.c index 57edaad52a8a..61d34059b675 100644 --- a/gcc/testsuite/gcc.target/powerpc/fold-vec-logical-other-int.c +++ b/gcc/testsuite/gcc.target/powerpc/fold-vec-logical-other-int.c @@ -104,5 +104,5 @@ test6_nand (vector unsigned int x, vector unsigned int y) return *foo; } -/* { dg-final { scan-assembler-times {\mxxlnand\M} 3 } } */ +/* { dg-final { scan-assembler-times {\mxxlnand\M} 6 } } */ /* { dg-final { scan-assembler-times {\mxxlorc\M} 6 } } */ diff --git a/gcc/testsuite/gcc.target/powerpc/fold-vec-logical-other-longlong.c b/gcc/testsuite/gcc.target/powerpc/fold-vec-logical-other-longlong.c index d4b85796406b..d33006c17e0e 100644 --- a/gcc/testsuite/gcc.target/powerpc/fold-vec-logical-other-longlong.c +++ b/gcc/testsuite/gcc.target/powerpc/fold-vec-logical-other-longlong.c @@ -102,5 +102,5 @@ test6_nand (vector unsigned long long x, vector unsigned long long y) return *foo; } -/* { dg-final { scan-assembler-times {\mxxlnand\M} 3 } } */ +/* { dg-final { scan-assembler-times {\mxxlnand\M} 6 } } */ /* { dg-final { scan-assembler-times {\mxxlorc\M} 6 } } */ diff --git a/gcc/testsuite/gcc.target/powerpc/fold-vec-logical-other-short.c b/gcc/testsuite/gcc.target/powerpc/fold-vec-logical-other-short.c index bf98652750c8..cc354b935dcc 100644 --- a/gcc/testsuite/gcc.target/powerpc/fold-vec-logical-other-short.c +++ b/gcc/testsuite/gcc.target/powerpc/fold-vec-logical-other-short.c @@ -104,5 +104,5 @@ test6_nand (vector unsigned short x, vector unsigned short y) return *foo; } -/* { dg-final { scan-assembler-times {\mxxlnand\M} 3 } } */ +/* { dg-final { scan-assembler-times {\mxxlnand\M} 6 } } */ /* { dg-final { scan-assembler-times {\mxxlorc\M} 6 } } */ diff --git a/gcc/testsuite/gcc.target/powerpc/pr106769-p8.c b/gcc/testsuite/gcc.target/powerpc/pr106769-p8.c new file mode 100644 index 000000000000..e7cdbc762984 --- /dev/null +++ b/gcc/testsuite/gcc.target/powerpc/pr106769-p8.c @@ -0,0 +1,11 @@ +/* { dg-do compile } */ +/* { dg-skip-if "" { powerpc*-*-darwin* } } */ +/* { dg-require-effective-target powerpc_p8vector_ok } */ +/* { dg-options "-mdejagnu-cpu=power8 -O2" } */ +/* { dg-require-effective-target has_arch_ppc64 } */ + +#include "pr106769.h" + +/* { dg-final { scan-assembler {\mmfvsrwz\M} } } */ +/* { dg-final { scan-assembler {\mstxsiwx\M} } } */ +/* { dg-final { scan-assembler-not {\mrldicl\M} } } */ diff --git a/gcc/testsuite/gcc.target/powerpc/pr106769-p9.c b/gcc/testsuite/gcc.target/powerpc/pr106769-p9.c new file mode 100644 index 000000000000..2248b525d430 --- /dev/null +++ b/gcc/testsuite/gcc.target/powerpc/pr106769-p9.c @@ -0,0 +1,13 @@ +/* { dg-do compile } */ +/* { dg-skip-if "" { powerpc*-*-darwin* } } */ +/* { dg-require-effective-target powerpc_p9vector_ok } */ +/* { dg-options "-mdejagnu-cpu=power9 -O2" } */ +/* { dg-require-effective-target has_arch_ppc64 } */ + +#include "pr106769.h" + +/* { dg-final { scan-assembler {\mmfvsrwz\M} } } */ +/* { dg-final { scan-assembler {\mstxsiwx\M} } } */ +/* { dg-final { scan-assembler-not {\mrldicl\M} } } */ +/* { dg-final { scan-assembler-not {\mxxextractuw\M} } } */ +/* { dg-final { scan-assembler-not {\mvextuw[rl]x\M} } } */ diff --git a/gcc/testsuite/gcc.target/powerpc/pr106769.h b/gcc/testsuite/gcc.target/powerpc/pr106769.h new file mode 100644 index 000000000000..1c8c8a024f32 --- /dev/null +++ b/gcc/testsuite/gcc.target/powerpc/pr106769.h @@ -0,0 +1,17 @@ +#include + +#ifdef __BIG_ENDIAN__ +#define LANE 1 +#else +#define LANE 2 +#endif + +unsigned int foo1 (vector unsigned int v) +{ + return vec_extract(v, LANE); +} + +void foo2 (vector unsigned int v, unsigned int* p) +{ + *p = vec_extract(v, LANE); +} diff --git a/gcc/testsuite/gcc.target/powerpc/pr110411-1.c b/gcc/testsuite/gcc.target/powerpc/pr110411-1.c new file mode 100644 index 000000000000..6b0dbb00ea25 --- /dev/null +++ b/gcc/testsuite/gcc.target/powerpc/pr110411-1.c @@ -0,0 +1,21 @@ +/* PR target/110411 */ +/* { dg-options "-O2 -mdejagnu-cpu=power10 -mblock-ops-vector-pair" } */ + +/* Verify we do not ICE on the following. */ + +#include + +struct s { + long a; + long b; + long c; + long d: 1; +}; +unsigned long ptr; + +void +bug (struct s *dst) +{ + struct s *src = (struct s *)(ptr & ~0xFUL); + memcpy (dst, src, sizeof(struct s)); +} diff --git a/gcc/testsuite/gcc.target/powerpc/pr110411-2.c b/gcc/testsuite/gcc.target/powerpc/pr110411-2.c new file mode 100644 index 000000000000..c2046fb9855a --- /dev/null +++ b/gcc/testsuite/gcc.target/powerpc/pr110411-2.c @@ -0,0 +1,12 @@ +/* PR target/110411 */ +/* { dg-require-effective-target power10_ok } */ +/* { dg-options "-O2 -mdejagnu-cpu=power10" } */ + +/* Verify we do not ICE on the following. */ + +void +bug (__vector_quad *dst) +{ + dst = (__vector_quad *)((unsigned long)dst & ~0xFUL); + __builtin_mma_xxsetaccz (dst); +} diff --git a/gcc/testsuite/gcc.target/powerpc/pr110429.c b/gcc/testsuite/gcc.target/powerpc/pr110429.c new file mode 100644 index 000000000000..d0ea3e56ae8d --- /dev/null +++ b/gcc/testsuite/gcc.target/powerpc/pr110429.c @@ -0,0 +1,28 @@ +/* { dg-do compile } */ +/* { dg-skip-if "" { powerpc*-*-darwin* } } */ +/* { dg-require-effective-target powerpc_p9vector_ok } */ +/* { dg-options "-mdejagnu-cpu=power9 -O2" } */ +/* { dg-require-effective-target has_arch_ppc64 } */ + +#include + +#ifdef __BIG_ENDIAN__ +#define DWORD0_FIRST_SHORT 3 +#define DWORD0_FIRST_CHAR 7 +#else +#define DWORD0_FIRST_SHORT 4 +#define DWORD0_FIRST_CHAR 8 +#endif + +void vec_extract_short (vector short v, short* p) +{ + *p = vec_extract(v, DWORD0_FIRST_SHORT); +} + +void vec_extract_char (vector char v, char* p) +{ + *p = vec_extract(v, DWORD0_FIRST_CHAR); +} + +/* { dg-final { scan-assembler-times {\mstxsi[hb]x\M} 2 } } */ +/* { dg-final { scan-assembler-not {\mvextractu[hb]\M} } } */ diff --git a/gcc/testsuite/gcc.target/powerpc/pr93448.c b/gcc/testsuite/gcc.target/powerpc/pr93448.c new file mode 100644 index 000000000000..6b800f8d63d7 --- /dev/null +++ b/gcc/testsuite/gcc.target/powerpc/pr93448.c @@ -0,0 +1,200 @@ +/* { dg-do run } */ +/* { dg-require-effective-target dfp_hw } */ +/* { dg-require-effective-target has_arch_pwr6 } */ +/* { dg-options "-mhard-float -O2 -save-temps" } */ + +/* Test the decimal floating point quantize built-ins. */ + +#define DEBUG 0 + +#ifdef DEBUG +#include +#endif +#include + +void abort (void); + +int main() +{ +#define IMM2 2 +#define IMM3 3 +#define IMM4 4 + + _Decimal64 srcA_dfp64, srcB_dfp64; + _Decimal64 result_dfp64; + _Decimal64 expected_result_dfp64; + _Decimal128 srcA_dfp128, srcB_dfp128; + _Decimal128 result_dfp128; + _Decimal128 expected_result_dfp128; + + /* Third argument of quantize built-ins is the rounding mode value (RMC). + + RMC Rounding Mode + 00 Round to nearest, ties to even + 01 Round toward 0 + 10 Round to nearest, ties toward 0 + 11 Round according to DRN */ + + + /* Tests for quantize with 64-bit DFP variable. */ + srcA_dfp64 = 100.0df; + srcB_dfp64 = 300.456789df; + expected_result_dfp64 = 300.5df; + + result_dfp64 = __builtin_dfp_quantize (srcA_dfp64, srcB_dfp64, 0x0); + + if (result_dfp64 != expected_result_dfp64) +#if DEBUG + printf("DFP 64-bit quantize of variable, RMC = 0 result does not match expected result\n"); +#else + abort(); +#endif + + srcA_dfp64 = 100.00df; + srcB_dfp64 = 300.456789df; + expected_result_dfp64 = 300.45df; + + result_dfp64 = __builtin_dfp_quantize (srcA_dfp64, srcB_dfp64, 0x1); + + if (result_dfp64 != expected_result_dfp64) +#if DEBUG + printf("DFP 64-bit quantize of variable, RMC = 1 result does not match expected result\n"); +#else + abort(); +#endif + + srcA_dfp64 = 100.001df; + srcB_dfp64 = 3001.456789df; + expected_result_dfp64 = 3001.457df; + + result_dfp64 = __builtin_dfp_quantize (srcA_dfp64, srcB_dfp64, 0x2); + + if (result_dfp64 != expected_result_dfp64) +#if DEBUG + printf("DFP 64-bit quantize of variable, RMC = 2 result does not match expected result\n"); +#else + abort(); +#endif + + /* Tests for 64-bit quantize with immediate value. */ + + srcB_dfp64 = 10.4567df; + expected_result_dfp64 = 000.0df; + + result_dfp64 = __builtin_dfp_quantize (IMM2, srcB_dfp64, 0x0); + + if (result_dfp64 != expected_result_dfp64) +#if DEBUG + printf("DFP 64-bit quantize immediate, RMC = 0 result does not match expected result\n"); +#else + abort(); +#endif + + srcB_dfp64 = 104567.891df; + expected_result_dfp64 = 100000.0df; + + result_dfp64 = __builtin_dfp_quantize (IMM4, srcB_dfp64, 0x1); + + if (result_dfp64 != expected_result_dfp64) +#if DEBUG + printf("DFP 64-bit quantize immediate, RMC = 1 result does not match expected result\n"); +#else + abort(); +#endif + + srcB_dfp64 = 109876.54321df; + expected_result_dfp64 = 109900.0df; + + result_dfp64 = __builtin_dfp_quantize (IMM2, srcB_dfp64, 0x2); + + if (result_dfp64 != expected_result_dfp64) +#if DEBUG + printf("DFP 64-bit quantize immediate, RMC = 2 result does not match expected result\n"); +#else + abort(); +#endif + + /* Tests for quantize 128-bit DFP variable. */ + srcA_dfp128 = 0.018df; + srcB_dfp128 = 50000.18345df; + expected_result_dfp128 = 50000.180df; + + result_dfp128 = __builtin_dfp_quantize (srcA_dfp128, srcB_dfp128, 0x0); + + if (result_dfp128 != expected_result_dfp128) +#if DEBUG + printf("DFP 128-bit quantize variable, RMC = 0 result does not match expected result\n"); +#else + abort(); +#endif + + srcA_dfp128 = 8.01df; + srcB_dfp128 = 50000.18345df; + expected_result_dfp128 = 50000.18df; + + result_dfp128 = __builtin_dfp_quantize (srcA_dfp128, srcB_dfp128, 0x1); + + if (result_dfp128 != expected_result_dfp128) +#if DEBUG + printf("DFP 128-bit quantize variable, RMC = 1 result does not match expected result\n"); +#else + abort(); +#endif + + srcA_dfp128 = 0.1234df; + srcB_dfp128 = 50000.18346789df; + expected_result_dfp128 = 50000.1800df; + + result_dfp128 = __builtin_dfp_quantize (srcA_dfp128, srcB_dfp128, 0x2); + + if (result_dfp128 != expected_result_dfp128) +#if DEBUG + printf("DFP 128-bit quantize variable, RMC = 2 result does not match expected result\n"); +#else + abort(); +#endif + + /* Tests for 128-bit quantize with immediate value. */ + srcB_dfp128 = 1234.18345df; + expected_result_dfp128 = 1200.0df; + + result_dfp128 = __builtin_dfp_quantize (IMM2, srcB_dfp128, 0x0); + + if (result_dfp128 != expected_result_dfp128) +#if DEBUG + printf("DFP 128-bit quantize immediate, RMC = 0 result does not match expected result\n"); +#else + abort(); +#endif + + srcB_dfp128 = 123456.18345df; + expected_result_dfp128 = 120000.0df; + + result_dfp128 = __builtin_dfp_quantize (IMM4, srcB_dfp128, 0x1); + + if (result_dfp128 != expected_result_dfp128) +#if DEBUG + printf("DFP 128-bit quantize immediate, RMC = 1 result does not match expected result\n"); +#else + abort(); +#endif + + srcB_dfp128 = 12361834.5df; + expected_result_dfp128 = 12362000.0df; + + result_dfp128 = __builtin_dfp_quantize (IMM3, srcB_dfp128, 0x2); + + if (result_dfp128 != expected_result_dfp128) +#if DEBUG + printf("DFP 128-bit quantize immediate, RMC = 2 result does not match expected result\n"); +#else + abort(); +#endif + + return 0; +} + +/* { dg-final { scan-assembler-times {\mdqua\M} 3 } } */ +/* { dg-final { scan-assembler-times {\mdquai\M} 3 } } */ +/* { dg-final { scan-assembler-times {\mdquaq\M} 3 } } */ +/* { dg-final { scan-assembler-times {\mdquaiq\M} 3 } } */ diff --git a/gcc/testsuite/gcc.target/powerpc/pr96762.c b/gcc/testsuite/gcc.target/powerpc/pr96762.c new file mode 100644 index 000000000000..a59deb427386 --- /dev/null +++ b/gcc/testsuite/gcc.target/powerpc/pr96762.c @@ -0,0 +1,13 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -mdejagnu-cpu=power10" } */ + +/* Verify there is no ICE on ilp32 env. */ + +extern void foo (char *); + +void +bar (void) +{ + char zj[] = "XXXXXXXXXXXXXXXX"; + foo (zj); +} diff --git a/gcc/testsuite/gcc.target/powerpc/vec-cmpne-runnable.c b/gcc/testsuite/gcc.target/powerpc/vec-cmpne-runnable.c new file mode 100644 index 000000000000..c7fff12c69e0 --- /dev/null +++ b/gcc/testsuite/gcc.target/powerpc/vec-cmpne-runnable.c @@ -0,0 +1,36 @@ +/* { dg-do run } */ +/* { dg-require-effective-target vmx_hw } */ +/* { dg-options "-maltivec -O2 " } */ + +/* Test that the vec_cmpne builtin works as expected. */ + +#include "vec-cmpne.h" + +define_test_functions (int, signed int, signed int, si); +define_test_functions (int, unsigned int, unsigned int, ui); +define_test_functions (short, signed short, signed short, ss); +define_test_functions (short, unsigned short, unsigned short, us); +define_test_functions (char, signed char, signed char, sc); +define_test_functions (char, unsigned char, unsigned char, uc); +define_test_functions (int, signed int, float, ff); + +define_init_verify_functions (int, signed int, signed int, si); +define_init_verify_functions (int, unsigned int, unsigned int, ui); +define_init_verify_functions (short, signed short, signed short, ss); +define_init_verify_functions (short, unsigned short, unsigned short, us); +define_init_verify_functions (char, signed char, signed char, sc); +define_init_verify_functions (char, unsigned char, unsigned char, uc); +define_init_verify_functions (int, signed int, float, ff); + +int main () +{ + execute_test_functions (int, signed int, signed int, si); + execute_test_functions (int, unsigned int, unsigned int, ui); + execute_test_functions (short, signed short, signed short, ss); + execute_test_functions (short, unsigned short, unsigned short, us); + execute_test_functions (char, signed char, signed char, sc); + execute_test_functions (char, unsigned char, unsigned char, uc); + execute_test_functions (int, signed int, float, ff); + + return 0; +} diff --git a/gcc/testsuite/gcc.target/powerpc/vec-cmpne.c b/gcc/testsuite/gcc.target/powerpc/vec-cmpne.c index edba9dece66f..b57e0ac86385 100644 --- a/gcc/testsuite/gcc.target/powerpc/vec-cmpne.c +++ b/gcc/testsuite/gcc.target/powerpc/vec-cmpne.c @@ -1,94 +1,11 @@ -/* { dg-do run } */ -/* { dg-require-effective-target powerpc_vsx_ok } */ -/* { dg-options "-mvsx -O3" } */ +/* { dg-do compile } */ +/* { dg-require-effective-target powerpc_altivec_ok } */ +/* { dg-options "-maltivec -O2" } */ -/* Test that the vec_cmpne builtin works as expected. */ - -#include "altivec.h" - -#define N 4096 - -void abort (); - -#define define_test_functions(VBTYPE, RTYPE, STYPE, NAME) \ -\ -RTYPE result_ne_##NAME[N] __attribute__((aligned(16))); \ -RTYPE result_eq_##NAME[N] __attribute__((aligned(16))); \ -STYPE operand1_##NAME[N] __attribute__((aligned(16))); \ -STYPE operand2_##NAME[N] __attribute__((aligned(16))); \ -RTYPE expected_##NAME[N] __attribute__((aligned(16))); \ -\ -__attribute__((noinline)) void vector_tests_##NAME () \ -{ \ - vector STYPE v1_##NAME, v2_##NAME; \ - vector bool VBTYPE tmp_##NAME; \ - int i; \ - for (i = 0; i < N; i+=16/sizeof (STYPE)) \ - { \ - /* result_ne = operand1!=operand2. */ \ - v1_##NAME = vec_vsx_ld (0, (const vector STYPE*)&operand1_##NAME[i]); \ - v2_##NAME = vec_vsx_ld (0, (const vector STYPE*)&operand2_##NAME[i]); \ -\ - tmp_##NAME = vec_cmpeq (v1_##NAME, v2_##NAME); \ - vec_vsx_st (tmp_##NAME, 0, &result_eq_##NAME[i]); \ -\ - tmp_##NAME = vec_cmpne (v1_##NAME, v2_##NAME); \ - vec_vsx_st (tmp_##NAME, 0, &result_ne_##NAME[i]); \ - } \ -} \ -\ -__attribute__((noinline)) void init_##NAME () \ -{ \ - int i; \ - for (i = 0; i < N; ++i) \ - { \ - result_ne_##NAME[i] = 7; \ - result_eq_##NAME[i] = 15; \ - if (i%3 == 0) \ - { \ - /* op1 < op2. */ \ - operand1_##NAME[i] = 1; \ - operand2_##NAME[i] = 2; \ - } \ - else if (i%3 == 1) \ - { \ - /* op1 > op2. */ \ - operand1_##NAME[i] = 2; \ - operand2_##NAME[i] = 1; \ - } \ - else if (i%3 == 2) \ - { \ - /* op1 == op2. */ \ - operand1_##NAME[i] = 3; \ - operand2_##NAME[i] = 3; \ - } \ - /* For vector comparisons: "For each element of the result_ne, the \ - value of each bit is 1 if the corresponding elements of ARG1 and \ - ARG2 are equal." {or whatever the comparison is} "Otherwise, the \ - value of each bit is 0." */ \ - expected_##NAME[i] = -1 * (RTYPE)(operand1_##NAME[i] != operand2_##NAME[i]); \ - } \ -} \ -\ -__attribute__((noinline)) void verify_results_##NAME () \ -{ \ - int i; \ - for (i = 0; i < N; ++i) \ - { \ - if ( ((result_ne_##NAME[i] != expected_##NAME[i]) || \ - (result_ne_##NAME[i] == result_eq_##NAME[i]))) \ - abort (); \ - } \ -} - - -#define execute_test_functions(VBTYPE, RTYPE, STYPE, NAME) \ -{ \ - init_##NAME (); \ - vector_tests_##NAME (); \ - verify_results_##NAME (); \ -} +/* Test that the vec_cmpne builtin generates the expected Altivec + instructions. */ +#include "vec-cmpne.h" define_test_functions (int, signed int, signed int, si); define_test_functions (int, unsigned int, unsigned int, ui); @@ -98,17 +15,6 @@ define_test_functions (char, signed char, signed char, sc); define_test_functions (char, unsigned char, unsigned char, uc); define_test_functions (int, signed int, float, ff); -int main () -{ - execute_test_functions (int, signed int, signed int, si); - execute_test_functions (int, unsigned int, unsigned int, ui); - execute_test_functions (short, signed short, signed short, ss); - execute_test_functions (short, unsigned short, unsigned short, us); - execute_test_functions (char, signed char, signed char, sc); - execute_test_functions (char, unsigned char, unsigned char, uc); - execute_test_functions (int, signed int, float, ff); - - return 0; -} - - +/* { dg-final { scan-assembler-times {\mvcmpequb\M} 2 } } */ +/* { dg-final { scan-assembler-times {\mvcmpequh\M} 2 } } */ +/* { dg-final { scan-assembler-times {\mvcmpequw\M} 2 } } */ diff --git a/gcc/testsuite/gcc.target/powerpc/vec-cmpne.h b/gcc/testsuite/gcc.target/powerpc/vec-cmpne.h new file mode 100644 index 000000000000..a304de01d86b --- /dev/null +++ b/gcc/testsuite/gcc.target/powerpc/vec-cmpne.h @@ -0,0 +1,90 @@ +#include "altivec.h" + +#define N 4096 + +void abort (); + +#define PRAGMA(X) _Pragma (#X) +#define UNROLL0 PRAGMA (GCC unroll 0) + +#define define_test_functions(VBTYPE, RTYPE, STYPE, NAME) \ +\ +RTYPE result_ne_##NAME[N] __attribute__((aligned(16))); \ +RTYPE result_eq_##NAME[N] __attribute__((aligned(16))); \ +STYPE operand1_##NAME[N] __attribute__((aligned(16))); \ +STYPE operand2_##NAME[N] __attribute__((aligned(16))); \ +RTYPE expected_##NAME[N] __attribute__((aligned(16))); \ +\ +__attribute__((noinline)) void vector_tests_##NAME () \ +{ \ + vector STYPE v1_##NAME, v2_##NAME; \ + vector bool VBTYPE tmp_##NAME; \ + int i; \ + UNROLL0 \ + for (i = 0; i < N; i+=16/sizeof (STYPE)) \ + { \ + /* result_ne = operand1!=operand2. */ \ + v1_##NAME = vec_vsx_ld (0, (const vector STYPE*)&operand1_##NAME[i]); \ + v2_##NAME = vec_vsx_ld (0, (const vector STYPE*)&operand2_##NAME[i]); \ +\ + tmp_##NAME = vec_cmpeq (v1_##NAME, v2_##NAME); \ + vec_vsx_st (tmp_##NAME, 0, &result_eq_##NAME[i]); \ +\ + tmp_##NAME = vec_cmpne (v1_##NAME, v2_##NAME); \ + vec_vsx_st (tmp_##NAME, 0, &result_ne_##NAME[i]); \ + } \ +} \ + +#define define_init_verify_functions(VBTYPE, RTYPE, STYPE, NAME) \ +__attribute__((noinline)) void init_##NAME () \ +{ \ + int i; \ + for (i = 0; i < N; ++i) \ + { \ + result_ne_##NAME[i] = 7; \ + result_eq_##NAME[i] = 15; \ + if (i%3 == 0) \ + { \ + /* op1 < op2. */ \ + operand1_##NAME[i] = 1; \ + operand2_##NAME[i] = 2; \ + } \ + else if (i%3 == 1) \ + { \ + /* op1 > op2. */ \ + operand1_##NAME[i] = 2; \ + operand2_##NAME[i] = 1; \ + } \ + else if (i%3 == 2) \ + { \ + /* op1 == op2. */ \ + operand1_##NAME[i] = 3; \ + operand2_##NAME[i] = 3; \ + } \ + /* For vector comparisons: "For each element of the result_ne, the \ + value of each bit is 1 if the corresponding elements of ARG1 and \ + ARG2 are equal." {or whatever the comparison is} "Otherwise, the \ + value of each bit is 0." */ \ + expected_##NAME[i] = -1 * (RTYPE)(operand1_##NAME[i] != operand2_##NAME[i]); \ + } \ +} \ +\ +__attribute__((noinline)) void verify_results_##NAME () \ +{ \ + int i; \ + for (i = 0; i < N; ++i) \ + { \ + if ( ((result_ne_##NAME[i] != expected_##NAME[i]) || \ + (result_ne_##NAME[i] == result_eq_##NAME[i]))) \ + abort (); \ + } \ +} + + +#define execute_test_functions(VBTYPE, RTYPE, STYPE, NAME) \ +{ \ + init_##NAME (); \ + vector_tests_##NAME (); \ + verify_results_##NAME (); \ +} + diff --git a/gcc/testsuite/gcc.target/pru/pr106562-10.c b/gcc/testsuite/gcc.target/pru/pr106562-10.c new file mode 100644 index 000000000000..7f0224ca6306 --- /dev/null +++ b/gcc/testsuite/gcc.target/pru/pr106562-10.c @@ -0,0 +1,8 @@ +/* { dg-do assemble } */ +/* { dg-options "-Os" } */ +/* { dg-final { object-size text <= 16 } } */ + +int test(long long a) +{ + return a == 0; +} diff --git a/gcc/testsuite/gcc.target/pru/pr106562-11.c b/gcc/testsuite/gcc.target/pru/pr106562-11.c new file mode 100644 index 000000000000..017aa497a67f --- /dev/null +++ b/gcc/testsuite/gcc.target/pru/pr106562-11.c @@ -0,0 +1,8 @@ +/* { dg-do assemble } */ +/* { dg-options "-Os" } */ +/* { dg-final { object-size text <= 12 } } */ + +int test(unsigned long long a) +{ + return a > 0; +} diff --git a/gcc/testsuite/gcc.target/pru/pr106562-5.c b/gcc/testsuite/gcc.target/pru/pr106562-5.c new file mode 100644 index 000000000000..16d9dfae5721 --- /dev/null +++ b/gcc/testsuite/gcc.target/pru/pr106562-5.c @@ -0,0 +1,8 @@ +/* { dg-do assemble } */ +/* { dg-options "-Os" } */ +/* { dg-final { object-size text <= 8 } } */ + +int test(int a) +{ + return a != 0; +} diff --git a/gcc/testsuite/gcc.target/pru/pr106562-6.c b/gcc/testsuite/gcc.target/pru/pr106562-6.c new file mode 100644 index 000000000000..59510d348d50 --- /dev/null +++ b/gcc/testsuite/gcc.target/pru/pr106562-6.c @@ -0,0 +1,8 @@ +/* { dg-do assemble } */ +/* { dg-options "-Os" } */ +/* { dg-final { object-size text <= 8 } } */ + +int test(unsigned a) +{ + return a > 0; +} diff --git a/gcc/testsuite/gcc.target/pru/pr106562-7.c b/gcc/testsuite/gcc.target/pru/pr106562-7.c new file mode 100644 index 000000000000..ca833ef3264c --- /dev/null +++ b/gcc/testsuite/gcc.target/pru/pr106562-7.c @@ -0,0 +1,8 @@ +/* { dg-do assemble } */ +/* { dg-options "-Os" } */ +/* { dg-final { object-size text <= 8 } } */ + +int test(unsigned a) +{ + return a >= 1; +} diff --git a/gcc/testsuite/gcc.target/pru/pr106562-8.c b/gcc/testsuite/gcc.target/pru/pr106562-8.c new file mode 100644 index 000000000000..2911d8448143 --- /dev/null +++ b/gcc/testsuite/gcc.target/pru/pr106562-8.c @@ -0,0 +1,8 @@ +/* { dg-do assemble } */ +/* { dg-options "-Os" } */ +/* { dg-final { object-size text <= 12 } } */ + +int test(int a) +{ + return a == 0; +} diff --git a/gcc/testsuite/gcc.target/pru/pr106562-9.c b/gcc/testsuite/gcc.target/pru/pr106562-9.c new file mode 100644 index 000000000000..25ece1ce7dcb --- /dev/null +++ b/gcc/testsuite/gcc.target/pru/pr106562-9.c @@ -0,0 +1,8 @@ +/* { dg-do assemble } */ +/* { dg-options "-Os" } */ +/* { dg-final { object-size text <= 12 } } */ + +int test(long long a) +{ + return a != 0; +} diff --git a/gcc/testsuite/gcc.target/riscv/_Float16-zfhmin-4.c b/gcc/testsuite/gcc.target/riscv/_Float16-zfhmin-4.c new file mode 100644 index 000000000000..42a238a03804 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/_Float16-zfhmin-4.c @@ -0,0 +1,11 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gc_zfhmin -mabi=lp64d -O3 -mcmodel=medany" } */ +/* { dg-final { check-function-bodies "**" "" } } */ + +/* Make sure zfhmin behaves the same way as zfh. */ +/* +** foo: { target { no-opts "-flto" } } +** flh\tfa0,\.LC0,[a-z0-9]+ +** ... +*/ +_Float16 foo() { return 0.8974; } diff --git a/gcc/testsuite/gcc.target/riscv/_Float16-zhinxmin-3.c b/gcc/testsuite/gcc.target/riscv/_Float16-zhinxmin-3.c index 7a43641a5a6e..939b37873836 100644 --- a/gcc/testsuite/gcc.target/riscv/_Float16-zhinxmin-3.c +++ b/gcc/testsuite/gcc.target/riscv/_Float16-zhinxmin-3.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-march=rv64if_zfhmin -mabi=lp64f -O" } */ +/* { dg-options "-march=rv64i_zhinxmin -mabi=lp64 -O" } */ int foo1 (_Float16 a, _Float16 b) { diff --git a/gcc/testsuite/gcc.target/riscv/_Float16-zhinxmin-4.c b/gcc/testsuite/gcc.target/riscv/_Float16-zhinxmin-4.c new file mode 100644 index 000000000000..ebc615a483f0 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/_Float16-zhinxmin-4.c @@ -0,0 +1,12 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64i_zhinxmin -mabi=lp64 -O3 -mcmodel=medany" } */ +/* { dg-final { check-function-bodies "**" "" } } */ + +/* Make sure zfhmin behaves the same way as zfh. */ +/* +** foo: { target { no-opts "-flto" } } +** lla\ta[0-9]+,\.LC0 +** lhu\ta[0-9]+,0\(a[0-9]+\) +** ... +*/ +_Float16 foo() { return 0.8974; } diff --git a/gcc/testsuite/gcc.target/riscv/amo-table-ztso-amo-add-1.c b/gcc/testsuite/gcc.target/riscv/amo-table-ztso-amo-add-1.c new file mode 100644 index 000000000000..a88d08eb3f40 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/amo-table-ztso-amo-add-1.c @@ -0,0 +1,15 @@ +/* { dg-do compile } */ +/* Verify that atomic op mappings match the Ztso suggested mapping. */ +/* { dg-options "-march=rv64id_ztso -mabi=lp64d -O3" } */ +/* { dg-skip-if "" { *-*-* } { "-g" "-flto"} } */ +/* { dg-final { check-function-bodies "**" "" } } */ + +/* +** foo: +** amoadd\.w\tzero,a1,0\(a0\) +** ret +*/ +void foo (int* bar, int* baz) +{ + __atomic_add_fetch(bar, baz, __ATOMIC_RELAXED); +} diff --git a/gcc/testsuite/gcc.target/riscv/amo-table-ztso-amo-add-2.c b/gcc/testsuite/gcc.target/riscv/amo-table-ztso-amo-add-2.c new file mode 100644 index 000000000000..ebd240f9dd2f --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/amo-table-ztso-amo-add-2.c @@ -0,0 +1,15 @@ +/* { dg-do compile } */ +/* Verify that atomic op mappings the Ztso suggested mapping. */ +/* { dg-options "-march=rv64id_ztso -mabi=lp64d -O3" } */ +/* { dg-skip-if "" { *-*-* } { "-g" "-flto"} } */ +/* { dg-final { check-function-bodies "**" "" } } */ + +/* +** foo: +** amoadd\.w\tzero,a1,0\(a0\) +** ret +*/ +void foo (int* bar, int* baz) +{ + __atomic_add_fetch(bar, baz, __ATOMIC_ACQUIRE); +} diff --git a/gcc/testsuite/gcc.target/riscv/amo-table-ztso-amo-add-3.c b/gcc/testsuite/gcc.target/riscv/amo-table-ztso-amo-add-3.c new file mode 100644 index 000000000000..ee00d222ecea --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/amo-table-ztso-amo-add-3.c @@ -0,0 +1,15 @@ +/* { dg-do compile } */ +/* Verify that atomic op mappings match the Ztso suggested mapping. */ +/* { dg-options "-march=rv64id_ztso -mabi=lp64d -O3" } */ +/* { dg-skip-if "" { *-*-* } { "-g" "-flto"} } */ +/* { dg-final { check-function-bodies "**" "" } } */ + +/* +** foo: +** amoadd\.w\tzero,a1,0\(a0\) +** ret +*/ +void foo (int* bar, int* baz) +{ + __atomic_add_fetch(bar, baz, __ATOMIC_RELEASE); +} diff --git a/gcc/testsuite/gcc.target/riscv/amo-table-ztso-amo-add-4.c b/gcc/testsuite/gcc.target/riscv/amo-table-ztso-amo-add-4.c new file mode 100644 index 000000000000..ff08811c5d70 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/amo-table-ztso-amo-add-4.c @@ -0,0 +1,15 @@ +/* { dg-do compile } */ +/* Verify that atomic op mappings match the Ztso suggested mapping. */ +/* { dg-options "-march=rv64id_ztso -mabi=lp64d -O3" } */ +/* { dg-skip-if "" { *-*-* } { "-g" "-flto"} } */ +/* { dg-final { check-function-bodies "**" "" } } */ + +/* +** foo: +** amoadd\.w\tzero,a1,0\(a0\) +** ret +*/ +void foo (int* bar, int* baz) +{ + __atomic_add_fetch(bar, baz, __ATOMIC_ACQ_REL); +} diff --git a/gcc/testsuite/gcc.target/riscv/amo-table-ztso-amo-add-5.c b/gcc/testsuite/gcc.target/riscv/amo-table-ztso-amo-add-5.c new file mode 100644 index 000000000000..b129df4b6071 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/amo-table-ztso-amo-add-5.c @@ -0,0 +1,15 @@ +/* { dg-do compile } */ +/* Verify that atomic op mappings match the Ztso suggested mapping. */ +/* { dg-options "-march=rv64id_ztso -mabi=lp64d -O3" } */ +/* { dg-skip-if "" { *-*-* } { "-g" "-flto"} } */ +/* { dg-final { check-function-bodies "**" "" } } */ + +/* +** foo: +** amoadd\.w\tzero,a1,0\(a0\) +** ret +*/ +void foo (int* bar, int* baz) +{ + __atomic_add_fetch(bar, baz, __ATOMIC_SEQ_CST); +} diff --git a/gcc/testsuite/gcc.target/riscv/amo-table-ztso-compare-exchange-1.c b/gcc/testsuite/gcc.target/riscv/amo-table-ztso-compare-exchange-1.c new file mode 100644 index 000000000000..9d5b8c2a5f63 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/amo-table-ztso-compare-exchange-1.c @@ -0,0 +1,10 @@ +/* { dg-do compile } */ +/* Verify that compare exchange mappings match the Ztso suggested mapping. */ +/* { dg-options "-march=rv64id_ztso -mabi=lp64d" } */ +/* { dg-final { scan-assembler-times "lr.w\t" 1 } } */ +/* { dg-final { scan-assembler-times "sc.w\t" 1 } } */ + +void foo (int bar, int baz, int qux) +{ + __atomic_compare_exchange_n(&bar, &baz, qux, 1, __ATOMIC_RELAXED, __ATOMIC_RELAXED); +} diff --git a/gcc/testsuite/gcc.target/riscv/amo-table-ztso-compare-exchange-2.c b/gcc/testsuite/gcc.target/riscv/amo-table-ztso-compare-exchange-2.c new file mode 100644 index 000000000000..57d6746ee220 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/amo-table-ztso-compare-exchange-2.c @@ -0,0 +1,10 @@ +/* { dg-do compile } */ +/* Verify that compare exchange mappings match the Ztso suggested mapping. */ +/* { dg-options "-march=rv64id_ztso -mabi=lp64d" } */ +/* { dg-final { scan-assembler-times "lr.w\t" 1 } } */ +/* { dg-final { scan-assembler-times "sc.w\t" 1 } } */ + +void foo (int bar, int baz, int qux) +{ + __atomic_compare_exchange_n(&bar, &baz, qux, 1, __ATOMIC_CONSUME, __ATOMIC_CONSUME); +} diff --git a/gcc/testsuite/gcc.target/riscv/amo-table-ztso-compare-exchange-3.c b/gcc/testsuite/gcc.target/riscv/amo-table-ztso-compare-exchange-3.c new file mode 100644 index 000000000000..d0044106d360 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/amo-table-ztso-compare-exchange-3.c @@ -0,0 +1,10 @@ +/* { dg-do compile } */ +/* Verify that compare exchange mappings match the Ztso suggested mapping. */ +/* { dg-options "-march=rv64id_ztso -mabi=lp64d" } */ +/* { dg-final { scan-assembler-times "lr.w\t" 1 } } */ +/* { dg-final { scan-assembler-times "sc.w\t" 1 } } */ + +void foo (int bar, int baz, int qux) +{ + __atomic_compare_exchange_n(&bar, &baz, qux, 1, __ATOMIC_ACQUIRE, __ATOMIC_ACQUIRE); +} diff --git a/gcc/testsuite/gcc.target/riscv/amo-table-ztso-compare-exchange-4.c b/gcc/testsuite/gcc.target/riscv/amo-table-ztso-compare-exchange-4.c new file mode 100644 index 000000000000..6a53473e26bb --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/amo-table-ztso-compare-exchange-4.c @@ -0,0 +1,10 @@ +/* { dg-do compile } */ +/* Verify that compare exchange mappings match the Ztso suggested mapping. */ +/* { dg-options "-march=rv64id_ztso -mabi=lp64d" } */ +/* { dg-final { scan-assembler-times "lr.w\t" 1 } } */ +/* { dg-final { scan-assembler-times "sc.w\t" 1 } } */ + +void foo (int bar, int baz, int qux) +{ + __atomic_compare_exchange_n(&bar, &baz, qux, 1, __ATOMIC_RELEASE, __ATOMIC_RELAXED); +} diff --git a/gcc/testsuite/gcc.target/riscv/amo-table-ztso-compare-exchange-5.c b/gcc/testsuite/gcc.target/riscv/amo-table-ztso-compare-exchange-5.c new file mode 100644 index 000000000000..80729091c730 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/amo-table-ztso-compare-exchange-5.c @@ -0,0 +1,10 @@ +/* { dg-do compile } */ +/* Verify that compare exchange mappings match the Ztso suggested mapping. */ +/* { dg-options "-march=rv64id_ztso -mabi=lp64d" } */ +/* { dg-final { scan-assembler-times "lr.w.aqrl\t" 1 } } */ +/* { dg-final { scan-assembler-times "sc.w.rl\t" 1 } } */ + +void foo (int bar, int baz, int qux) +{ + __atomic_compare_exchange_n(&bar, &baz, qux, 1, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); +} diff --git a/gcc/testsuite/gcc.target/riscv/amo-table-ztso-compare-exchange-6.c b/gcc/testsuite/gcc.target/riscv/amo-table-ztso-compare-exchange-6.c new file mode 100644 index 000000000000..731f7f84af4c --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/amo-table-ztso-compare-exchange-6.c @@ -0,0 +1,10 @@ +/* { dg-do compile } */ +/* Verify that compare exchange mappings match the Ztso suggested mapping. */ +/* { dg-options "-march=rv64id_ztso -mabi=lp64d" } */ +/* { dg-final { scan-assembler-times "lr.w\t" 1 } } */ +/* { dg-final { scan-assembler-times "sc.w\t" 1 } } */ + +void foo (int bar, int baz, int qux) +{ + __atomic_compare_exchange_n(&bar, &baz, qux, 1, __ATOMIC_RELEASE, __ATOMIC_ACQUIRE); +} diff --git a/gcc/testsuite/gcc.target/riscv/amo-table-ztso-compare-exchange-7.c b/gcc/testsuite/gcc.target/riscv/amo-table-ztso-compare-exchange-7.c new file mode 100644 index 000000000000..3806d55da1d8 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/amo-table-ztso-compare-exchange-7.c @@ -0,0 +1,10 @@ +/* { dg-do compile } */ +/* Verify that compare exchange mappings match the Ztso suggested mapping. */ +/* { dg-options "-march=rv64id_ztso -mabi=lp64d" } */ +/* { dg-final { scan-assembler-times "lr.w.aqrl\t" 1 } } */ +/* { dg-final { scan-assembler-times "sc.w.rl\t" 1 } } */ + +void foo (int bar, int baz, int qux) +{ + __atomic_compare_exchange_n(&bar, &baz, qux, 1, __ATOMIC_SEQ_CST, __ATOMIC_RELAXED); +} diff --git a/gcc/testsuite/gcc.target/riscv/amo-table-ztso-fence-1.c b/gcc/testsuite/gcc.target/riscv/amo-table-ztso-fence-1.c new file mode 100644 index 000000000000..81f2f9fbbd68 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/amo-table-ztso-fence-1.c @@ -0,0 +1,14 @@ +/* { dg-do compile } */ +/* Verify that fence mappings match the Ztso suggested mapping. */ +/* { dg-options "-march=rv64id_ztso -mabi=lp64d -O3" } */ +/* { dg-skip-if "" { *-*-* } { "-g" "-flto"} } */ +/* { dg-final { check-function-bodies "**" "" } } */ + +/* +** foo: +** ret +*/ +void foo() +{ + __atomic_thread_fence(__ATOMIC_RELAXED); +} diff --git a/gcc/testsuite/gcc.target/riscv/amo-table-ztso-fence-2.c b/gcc/testsuite/gcc.target/riscv/amo-table-ztso-fence-2.c new file mode 100644 index 000000000000..8e868890bae6 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/amo-table-ztso-fence-2.c @@ -0,0 +1,14 @@ +/* { dg-do compile } */ +/* Verify that fence mappings match the Ztso suggested mapping. */ +/* { dg-options "-march=rv64id_ztso -mabi=lp64d -O3" } */ +/* { dg-skip-if "" { *-*-* } { "-g" "-flto"} } */ +/* { dg-final { check-function-bodies "**" "" } } */ + +/* +** foo: +** ret +*/ +void foo() +{ + __atomic_thread_fence(__ATOMIC_ACQUIRE); +} diff --git a/gcc/testsuite/gcc.target/riscv/amo-table-ztso-fence-3.c b/gcc/testsuite/gcc.target/riscv/amo-table-ztso-fence-3.c new file mode 100644 index 000000000000..5eb1aa7f4720 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/amo-table-ztso-fence-3.c @@ -0,0 +1,14 @@ +/* { dg-do compile } */ +/* Verify that fence mappings match the Ztso suggested mapping. */ +/* { dg-options "-march=rv64id_ztso -mabi=lp64d -O3" } */ +/* { dg-skip-if "" { *-*-* } { "-g" "-flto"} } */ +/* { dg-final { check-function-bodies "**" "" } } */ + +/* +** foo: +** ret +*/ +void foo() +{ + __atomic_thread_fence(__ATOMIC_RELEASE); +} diff --git a/gcc/testsuite/gcc.target/riscv/amo-table-ztso-fence-4.c b/gcc/testsuite/gcc.target/riscv/amo-table-ztso-fence-4.c new file mode 100644 index 000000000000..3df959a3eb02 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/amo-table-ztso-fence-4.c @@ -0,0 +1,14 @@ +/* { dg-do compile } */ +/* Verify that fence mappings match the Ztso suggested mapping. */ +/* { dg-options "-march=rv64id_ztso -mabi=lp64d -O3" } */ +/* { dg-skip-if "" { *-*-* } { "-g" "-flto"} } */ +/* { dg-final { check-function-bodies "**" "" } } */ + +/* +** foo: +** ret +*/ +void foo() +{ + __atomic_thread_fence(__ATOMIC_ACQ_REL); +} diff --git a/gcc/testsuite/gcc.target/riscv/amo-table-ztso-fence-5.c b/gcc/testsuite/gcc.target/riscv/amo-table-ztso-fence-5.c new file mode 100644 index 000000000000..731f9a342677 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/amo-table-ztso-fence-5.c @@ -0,0 +1,15 @@ +/* { dg-do compile } */ +/* Verify that fence mappings match the Ztso suggested mapping. */ +/* { dg-options "-march=rv64id_ztso -mabi=lp64d -O3" } */ +/* { dg-skip-if "" { *-*-* } { "-g" "-flto"} } */ +/* { dg-final { check-function-bodies "**" "" } } */ + +/* +** foo: +** fence\trw,rw +** ret +*/ +void foo() +{ + __atomic_thread_fence(__ATOMIC_SEQ_CST); +} diff --git a/gcc/testsuite/gcc.target/riscv/amo-table-ztso-load-1.c b/gcc/testsuite/gcc.target/riscv/amo-table-ztso-load-1.c new file mode 100644 index 000000000000..b911a6e3207e --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/amo-table-ztso-load-1.c @@ -0,0 +1,16 @@ +/* { dg-do compile } */ +/* Verify that load mappings match the Ztso suggested mapping. */ +/* { dg-options "-march=rv64id_ztso -mabi=lp64d -O3" } */ +/* { dg-skip-if "" { *-*-* } { "-g" "-flto"} } */ +/* { dg-final { check-function-bodies "**" "" } } */ + +/* +** foo: +** lw\ta[0-9]+,0\(a0\) +** sw\ta[0-9]+,0\(a1\) +** ret +*/ +void foo (int* bar, int* baz) +{ + __atomic_load(bar, baz, __ATOMIC_RELAXED); +} diff --git a/gcc/testsuite/gcc.target/riscv/amo-table-ztso-load-2.c b/gcc/testsuite/gcc.target/riscv/amo-table-ztso-load-2.c new file mode 100644 index 000000000000..056506f63702 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/amo-table-ztso-load-2.c @@ -0,0 +1,16 @@ +/* { dg-do compile } */ +/* Verify that load mappings match the Ztso suggested mapping. */ +/* { dg-options "-march=rv64id_ztso -mabi=lp64d -O3" } */ +/* { dg-skip-if "" { *-*-* } { "-g" "-flto"} } */ +/* { dg-final { check-function-bodies "**" "" } } */ + +/* +** foo: +** lw\ta[0-9]+,0\(a0\) +** sw\ta[0-9]+,0\(a1\) +** ret +*/ +void foo (int* bar, int* baz) +{ + __atomic_load(bar, baz, __ATOMIC_ACQUIRE); +} diff --git a/gcc/testsuite/gcc.target/riscv/amo-table-ztso-load-3.c b/gcc/testsuite/gcc.target/riscv/amo-table-ztso-load-3.c new file mode 100644 index 000000000000..35a301f321d9 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/amo-table-ztso-load-3.c @@ -0,0 +1,17 @@ +/* { dg-do compile } */ +/* Verify that load mappings match the Ztso suggested mapping. */ +/* { dg-options "-march=rv64id_ztso -mabi=lp64d -O3" } */ +/* { dg-skip-if "" { *-*-* } { "-g" "-flto"} } */ +/* { dg-final { check-function-bodies "**" "" } } */ + +/* +** foo: +** fence\trw,rw +** lw\ta[0-9]+,0\(a0\) +** sw\ta[0-9]+,0\(a1\) +** ret +*/ +void foo (int* bar, int* baz) +{ + __atomic_load(bar, baz, __ATOMIC_SEQ_CST); +} diff --git a/gcc/testsuite/gcc.target/riscv/amo-table-ztso-store-1.c b/gcc/testsuite/gcc.target/riscv/amo-table-ztso-store-1.c new file mode 100644 index 000000000000..f0bda4b24207 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/amo-table-ztso-store-1.c @@ -0,0 +1,16 @@ +/* { dg-do compile } */ +/* Verify that store mappings match the Ztso suggested mapping. */ +/* { dg-options "-march=rv64id_ztso -mabi=lp64d -O3" } */ +/* { dg-skip-if "" { *-*-* } { "-g" "-flto"} } */ +/* { dg-final { check-function-bodies "**" "" } } */ + +/* +** foo: +** lw\ta[0-9]+,0\(a1\) +** sw\ta[0-9]+,0\(a0\) +** ret +*/ +void foo (int* bar, int* baz) +{ + __atomic_store(bar, baz, __ATOMIC_RELAXED); +} diff --git a/gcc/testsuite/gcc.target/riscv/amo-table-ztso-store-2.c b/gcc/testsuite/gcc.target/riscv/amo-table-ztso-store-2.c new file mode 100644 index 000000000000..45f73056aa4f --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/amo-table-ztso-store-2.c @@ -0,0 +1,16 @@ +/* { dg-do compile } */ +/* Verify that store mappings match the Ztso suggested mapping. */ +/* { dg-options "-march=rv64id_ztso -mabi=lp64d -O3" } */ +/* { dg-skip-if "" { *-*-* } { "-g" "-flto"} } */ +/* { dg-final { check-function-bodies "**" "" } } */ + +/* +** foo: +** lw\ta[0-9]+,0\(a1\) +** sw\ta[0-9]+,0\(a0\) +** ret +*/ +void foo (int* bar, int* baz) +{ + __atomic_store(bar, baz, __ATOMIC_RELEASE); +} diff --git a/gcc/testsuite/gcc.target/riscv/amo-table-ztso-store-3.c b/gcc/testsuite/gcc.target/riscv/amo-table-ztso-store-3.c new file mode 100644 index 000000000000..762468b248e8 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/amo-table-ztso-store-3.c @@ -0,0 +1,17 @@ +/* { dg-do compile } */ +/* Verify that store mappings match the Ztso suggested mapping. */ +/* { dg-options "-march=rv64id_ztso -mabi=lp64d -O3" } */ +/* { dg-skip-if "" { *-*-* } { "-g" "-flto"} } */ +/* { dg-final { check-function-bodies "**" "" } } */ + +/* +** foo: +** lw\ta[0-9]+,0\(a1\) +** sw\ta[0-9]+,0\(a0\) +** fence\trw,rw +** ret +*/ +void foo (int* bar, int* baz) +{ + __atomic_store(bar, baz, __ATOMIC_SEQ_CST); +} diff --git a/gcc/testsuite/gcc.target/riscv/amo-table-ztso-subword-amo-add-1.c b/gcc/testsuite/gcc.target/riscv/amo-table-ztso-subword-amo-add-1.c new file mode 100644 index 000000000000..e9ae506f32c0 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/amo-table-ztso-subword-amo-add-1.c @@ -0,0 +1,10 @@ +/* { dg-do compile } */ +/* Verify that subword atomic op mappings match the Ztso suggested mapping. */ +/* { dg-options "-march=rv64id_ztso -mabi=lp64d" } */ +/* { dg-final { scan-assembler-times "lr.w\t" 1 } } */ +/* { dg-final { scan-assembler-times "sc.w\t" 1 } } */ + +void foo (short* bar, short* baz) +{ + __atomic_add_fetch(bar, baz, __ATOMIC_RELAXED); +} diff --git a/gcc/testsuite/gcc.target/riscv/amo-table-ztso-subword-amo-add-2.c b/gcc/testsuite/gcc.target/riscv/amo-table-ztso-subword-amo-add-2.c new file mode 100644 index 000000000000..f47922f13e46 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/amo-table-ztso-subword-amo-add-2.c @@ -0,0 +1,10 @@ +/* { dg-do compile } */ +/* Verify that subword atomic op mappings match the Ztso suggested mapping. */ +/* { dg-options "-march=rv64id_ztso -mabi=lp64d" } */ +/* { dg-final { scan-assembler-times "lr.w\t" 1 } } */ +/* { dg-final { scan-assembler-times "sc.w\t" 1 } } */ + +void foo (short* bar, short* baz) +{ + __atomic_add_fetch(bar, baz, __ATOMIC_ACQUIRE); +} diff --git a/gcc/testsuite/gcc.target/riscv/amo-table-ztso-subword-amo-add-3.c b/gcc/testsuite/gcc.target/riscv/amo-table-ztso-subword-amo-add-3.c new file mode 100644 index 000000000000..296387ad07cb --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/amo-table-ztso-subword-amo-add-3.c @@ -0,0 +1,10 @@ +/* { dg-do compile } */ +/* Verify that subword atomic op mappings match the Ztso suggested mapping. */ +/* { dg-options "-march=rv64id_ztso -mabi=lp64d" } */ +/* { dg-final { scan-assembler-times "lr.w\t" 1 } } */ +/* { dg-final { scan-assembler-times "sc.w\t" 1 } } */ + +void foo (short* bar, short* baz) +{ + __atomic_add_fetch(bar, baz, __ATOMIC_RELEASE); +} diff --git a/gcc/testsuite/gcc.target/riscv/amo-table-ztso-subword-amo-add-4.c b/gcc/testsuite/gcc.target/riscv/amo-table-ztso-subword-amo-add-4.c new file mode 100644 index 000000000000..f919ede73032 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/amo-table-ztso-subword-amo-add-4.c @@ -0,0 +1,10 @@ +/* { dg-do compile } */ +/* Verify that subword atomic op mappings match the Ztso suggested mapping. */ +/* { dg-options "-march=rv64id_ztso -mabi=lp64d" } */ +/* { dg-final { scan-assembler-times "lr.w\t" 1 } } */ +/* { dg-final { scan-assembler-times "sc.w\t" 1 } } */ + +void foo (short* bar, short* baz) +{ + __atomic_add_fetch(bar, baz, __ATOMIC_ACQ_REL); +} diff --git a/gcc/testsuite/gcc.target/riscv/amo-table-ztso-subword-amo-add-5.c b/gcc/testsuite/gcc.target/riscv/amo-table-ztso-subword-amo-add-5.c new file mode 100644 index 000000000000..2027a93218cb --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/amo-table-ztso-subword-amo-add-5.c @@ -0,0 +1,10 @@ +/* { dg-do compile } */ +/* Verify that subword atomic op mappings match the Ztso suggested mapping. */ +/* { dg-options "-march=rv64id_ztso -mabi=lp64d" } */ +/* { dg-final { scan-assembler-times "lr.w.aqrl\t" 1 } } */ +/* { dg-final { scan-assembler-times "sc.w.rl\t" 1 } } */ + +void foo (short* bar, short* baz) +{ + __atomic_add_fetch(bar, baz, __ATOMIC_SEQ_CST); +} diff --git a/gcc/testsuite/gcc.target/riscv/arch-24.c b/gcc/testsuite/gcc.target/riscv/arch-24.c new file mode 100644 index 000000000000..af15c3234b5e --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/arch-24.c @@ -0,0 +1,3 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv32i_zcf -mabi=ilp32" } */ +int foo() {} diff --git a/gcc/testsuite/gcc.target/riscv/arch-25.c b/gcc/testsuite/gcc.target/riscv/arch-25.c new file mode 100644 index 000000000000..3be4ade65a77 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/arch-25.c @@ -0,0 +1,5 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64i_zcf -mabi=lp64" } */ +int foo() {} +/* { dg-error "'-march=rv64i_zcf': zcf extension supports in rv32 only" "" { target *-*-* } 0 } */ +/* { dg-error "'-march=rv64i_zca_zcf': zcf extension supports in rv32 only" "" { target *-*-* } 0 } */ diff --git a/gcc/testsuite/gcc.target/riscv/attribute-1.c b/gcc/testsuite/gcc.target/riscv/attribute-1.c index bc919c586b67..abfb0b498e0c 100644 --- a/gcc/testsuite/gcc.target/riscv/attribute-1.c +++ b/gcc/testsuite/gcc.target/riscv/attribute-1.c @@ -2,5 +2,17 @@ /* { dg-options "-mriscv-attribute" } */ int foo() { + +/* In absence of -m[no-]strict-align, default mcpu is currently + set to rocket. rocket has slow_unaligned_access=true. */ +#if !defined(__riscv_unaligned_slow) +#error "__riscv_unaligned_slow is not set" +#endif + +#if defined(__riscv_unaligned_avoid) || defined(__riscv_unaligned_fast) +#error "__riscv_unaligned_avoid or __riscv_unaligned_fast is unexpectedly set" +#endif + +return 0; } /* { dg-final { scan-assembler ".attribute arch" } } */ diff --git a/gcc/testsuite/gcc.target/riscv/attribute-4.c b/gcc/testsuite/gcc.target/riscv/attribute-4.c index 7c565c4963ec..545f87cb8992 100644 --- a/gcc/testsuite/gcc.target/riscv/attribute-4.c +++ b/gcc/testsuite/gcc.target/riscv/attribute-4.c @@ -2,5 +2,15 @@ /* { dg-options "-mriscv-attribute -mstrict-align" } */ int foo() { + +#if !defined(__riscv_unaligned_avoid) +#error "__riscv_unaligned_avoid is not set" +#endif + +#if defined(__riscv_unaligned_fast) || defined(__riscv_unaligned_slow) +#error "__riscv_unaligned_fast or __riscv_unaligned_slow is unexpectedly set" +#endif + + return 0; } /* { dg-final { scan-assembler ".attribute unaligned_access, 0" } } */ diff --git a/gcc/testsuite/gcc.target/riscv/attribute-5.c b/gcc/testsuite/gcc.target/riscv/attribute-5.c index ee9cf693be6c..753043c31e93 100644 --- a/gcc/testsuite/gcc.target/riscv/attribute-5.c +++ b/gcc/testsuite/gcc.target/riscv/attribute-5.c @@ -2,5 +2,16 @@ /* { dg-options "-mriscv-attribute -mno-strict-align" } */ int foo() { + +/* Default mcpu is rocket which has slow_unaligned_access=true. */ +#if !defined(__riscv_unaligned_slow) +#error "__riscv_unaligned_slow is not set" +#endif + +#if defined(__riscv_unaligned_avoid) || defined(__riscv_unaligned_fast) +#error "__riscv_unaligned_avoid or __riscv_unaligned_fast is unexpectedly set" +#endif + +return 0; } /* { dg-final { scan-assembler ".attribute unaligned_access, 1" } } */ diff --git a/gcc/testsuite/gcc.target/riscv/builtin_pause.c b/gcc/testsuite/gcc.target/riscv/builtin_pause.c deleted file mode 100644 index 9250937cabb9..000000000000 --- a/gcc/testsuite/gcc.target/riscv/builtin_pause.c +++ /dev/null @@ -1,10 +0,0 @@ -/* { dg-do compile } */ -/* { dg-options "-O2" } */ - -void test_pause() -{ - __builtin_riscv_pause (); -} - -/* { dg-final { scan-assembler "pause" } } */ - diff --git a/gcc/testsuite/gcc.target/riscv/cm_mv_rv32.c b/gcc/testsuite/gcc.target/riscv/cm_mv_rv32.c new file mode 100644 index 000000000000..2c1b3f9cabf9 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/cm_mv_rv32.c @@ -0,0 +1,23 @@ +/* { dg-do compile } */ +/* { dg-options " -Os -march=rv32i_zca_zcmp -mabi=ilp32 " } */ +/* { dg-skip-if "" { *-*-* } {"-O0" "-O1" "-O2" "-Og" "-O3" "-Oz" "-flto"} } */ +/* { dg-final { check-function-bodies "**" "" } } */ + +int +func (int a, int b); + +/* +**sum: +** ... +** cm.mvsa01 s1,s2 +** call func +** mv s0,a0 +** cm.mva01s s1,s2 +** call func +** ... +*/ +int +sum (int a, int b) +{ + return func (a, b) + func (a, b); +} diff --git a/gcc/testsuite/gcc.target/riscv/gcse-const.c b/gcc/testsuite/gcc.target/riscv/gcse-const.c new file mode 100644 index 000000000000..b04707ce9745 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/gcse-const.c @@ -0,0 +1,13 @@ +/* Slightly modified copy of gcc.target/arm/pr40956.c. */ +/* { dg-options "-Os" } */ +/* Make sure the constant "6" is loaded into register only once. */ +/* { dg-final { scan-assembler-times "\tli.*6" 1 } } */ + +int foo(int p, int* q) +{ + if (p!=9) + *q = 6; + else + *(q+1) = 6; + return 3; +} diff --git a/gcc/testsuite/gcc.target/riscv/mode-switch-ice-1.c b/gcc/testsuite/gcc.target/riscv/mode-switch-ice-1.c new file mode 100644 index 000000000000..1b34a4719048 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/mode-switch-ice-1.c @@ -0,0 +1,22 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ + +struct A { char e, f; }; + +struct B +{ + int g; + struct A h[4]; +}; + +extern void bar (int, int); + +struct B foo (void) +{ + bar (2, 1); +} + +void baz () +{ + foo (); +} diff --git a/gcc/testsuite/gcc.target/riscv/pr102957-2.c b/gcc/testsuite/gcc.target/riscv/pr102957-2.c new file mode 100644 index 000000000000..fe6241466354 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/pr102957-2.c @@ -0,0 +1,5 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gzk -mabi=lp64" } */ +int foo() +{ +} diff --git a/gcc/testsuite/gcc.target/riscv/predef-29.c b/gcc/testsuite/gcc.target/riscv/predef-29.c new file mode 100644 index 000000000000..61c6429be558 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/predef-29.c @@ -0,0 +1,35 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64i_smstateen -mabi=lp64 -mcmodel=medlow -misa-spec=20191213" } */ + +int main () { + +#ifndef __riscv_arch_test +#error "__riscv_arch_test" +#endif + +#if __riscv_xlen != 64 +#error "__riscv_xlen" +#endif + +#if !defined(__riscv_i) || (__riscv_i != (2 * 1000 * 1000 + 1 * 1000)) +#error "__riscv_i" +#endif + +#if defined(__riscv_e) +#error "__riscv_e" +#endif + +#if !defined(__riscv_zicsr) +#error "__riscv_zicsr" +#endif + +#if !defined(__riscv_smstateen) +#error "__riscv_smstateen" +#endif + +#if !defined(__riscv_ssstateen) +#error "__riscv_ssstateen" +#endif + + return 0; +} diff --git a/gcc/testsuite/gcc.target/riscv/predef-30.c b/gcc/testsuite/gcc.target/riscv/predef-30.c new file mode 100644 index 000000000000..9784b9ce5033 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/predef-30.c @@ -0,0 +1,27 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64i_xventanacondops -mabi=lp64 -mcmodel=medlow -misa-spec=20191213" } */ + +int main () { + +#ifndef __riscv_arch_test +#error "__riscv_arch_test" +#endif + +#if __riscv_xlen != 64 +#error "__riscv_xlen" +#endif + +#if !defined(__riscv_i) || (__riscv_i != (2 * 1000 * 1000 + 1 * 1000)) +#error "__riscv_i" +#endif + +#if defined(__riscv_e) +#error "__riscv_e" +#endif + +#if !defined(__riscv_xventanacondops) +#error "__riscv_xventanacondops" +#endif + + return 0; +} diff --git a/gcc/testsuite/gcc.target/riscv/predef-31.c b/gcc/testsuite/gcc.target/riscv/predef-31.c new file mode 100644 index 000000000000..4ea11442f995 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/predef-31.c @@ -0,0 +1,31 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64i_zcb -mabi=lp64 -mcmodel=medlow -misa-spec=20191213" } */ + +int main () { + +#ifndef __riscv_arch_test +#error "__riscv_arch_test" +#endif + +#if __riscv_xlen != 64 +#error "__riscv_xlen" +#endif + +#if !defined(__riscv_i) || (__riscv_i != (2 * 1000 * 1000 + 1 * 1000)) +#error "__riscv_i" +#endif + +#if defined(__riscv_e) +#error "__riscv_e" +#endif + +#if !defined(__riscv_zca) +#error "__riscv_zca" +#endif + +#if !defined(__riscv_zcb) +#error "__riscv_zcb" +#endif + + return 0; +} diff --git a/gcc/testsuite/gcc.target/riscv/predef-align-1.c b/gcc/testsuite/gcc.target/riscv/predef-align-1.c new file mode 100644 index 000000000000..9dde37a721ec --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/predef-align-1.c @@ -0,0 +1,16 @@ +/* { dg-do compile } */ +/* { dg-options "-mtune=thead-c906" } */ + +int main() { + +/* thead-c906 default is cpu tune param unaligned access fast */ +#if !defined(__riscv_unaligned_fast) +#error "__riscv_unaligned_fast is not set" +#endif + +#if defined(__riscv_unaligned_avoid) || defined(__riscv_unaligned_slow) +#error "__riscv_unaligned_avoid or __riscv_unaligned_slow is unexpectedly set" +#endif + + return 0; +} diff --git a/gcc/testsuite/gcc.target/riscv/predef-align-2.c b/gcc/testsuite/gcc.target/riscv/predef-align-2.c new file mode 100644 index 000000000000..33d604f5aa0b --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/predef-align-2.c @@ -0,0 +1,15 @@ +/* { dg-do compile } */ +/* { dg-options "-mtune=thead-c906 -mstrict-align" } */ + +int main() { + +#if !defined(__riscv_unaligned_avoid) +#error "__riscv_unaligned_avoid is not set" +#endif + +#if defined(__riscv_unaligned_fast) || defined(__riscv_unaligned_slow) +#error "__riscv_unaligned_fast or __riscv_unaligned_slow is unexpectedly set" +#endif + + return 0; +} diff --git a/gcc/testsuite/gcc.target/riscv/predef-align-3.c b/gcc/testsuite/gcc.target/riscv/predef-align-3.c new file mode 100644 index 000000000000..daf5718a39fb --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/predef-align-3.c @@ -0,0 +1,16 @@ +/* { dg-do compile } */ +/* { dg-options "-mtune=thead-c906 -mno-strict-align" } */ + +int main() { + +/* thead-c906 default is cpu tune param unaligned access fast */ +#if !defined(__riscv_unaligned_fast) +#error "__riscv_unaligned_fast is not set" +#endif + +#if defined(__riscv_unaligned_avoid) || defined(__riscv_unaligned_slow) +#error "__riscv_unaligned_avoid or __riscv_unaligned_slow is unexpectedly set" +#endif + + return 0; +} diff --git a/gcc/testsuite/gcc.target/riscv/predef-align-4.c b/gcc/testsuite/gcc.target/riscv/predef-align-4.c new file mode 100644 index 000000000000..d46a46f252d1 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/predef-align-4.c @@ -0,0 +1,16 @@ +/* { dg-do compile } */ +/* { dg-options "-mtune=rocket" } */ + +int main() { + +/* rocket default is cpu tune param unaligned access slow */ +#if !defined(__riscv_unaligned_slow) +#error "__riscv_unaligned_slow is not set" +#endif + +#if defined(__riscv_unaligned_avoid) || defined(__riscv_unaligned_fast) +#error "__riscv_unaligned_avoid or __riscv_unaligned_fast is unexpectedly set" +#endif + + return 0; +} diff --git a/gcc/testsuite/gcc.target/riscv/predef-align-5.c b/gcc/testsuite/gcc.target/riscv/predef-align-5.c new file mode 100644 index 000000000000..3aa25f8e0e00 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/predef-align-5.c @@ -0,0 +1,15 @@ +/* { dg-do compile } */ +/* { dg-options "-mtune=rocket -mstrict-align" } */ + +int main() { + +#if !defined(__riscv_unaligned_avoid) +#error "__riscv_unaligned_avoid is not set" +#endif + +#if defined(__riscv_unaligned_fast) || defined(__riscv_unaligned_slow) +#error "__riscv_unaligned_fast or __riscv_unaligned_slow is unexpectedly set" +#endif + + return 0; +} diff --git a/gcc/testsuite/gcc.target/riscv/predef-align-6.c b/gcc/testsuite/gcc.target/riscv/predef-align-6.c new file mode 100644 index 000000000000..cb64d7e77789 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/predef-align-6.c @@ -0,0 +1,16 @@ +/* { dg-do compile } */ +/* { dg-options "-mtune=rocket -mno-strict-align" } */ + +int main() { + +/* rocket default is cpu tune param unaligned access slow */ +#if !defined(__riscv_unaligned_slow) +#error "__riscv_unaligned_slow is not set" +#endif + +#if defined(__riscv_unaligned_avoid) || defined(__riscv_unaligned_fast) +#error "__riscv_unaligned_avoid or __riscv_unaligned_fast is unexpectedly set" +#endif + + return 0; +} diff --git a/gcc/testsuite/gcc.target/riscv/rv32e_zcmp.c b/gcc/testsuite/gcc.target/riscv/rv32e_zcmp.c new file mode 100644 index 000000000000..394459c4ed76 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rv32e_zcmp.c @@ -0,0 +1,269 @@ +/* { dg-do compile } */ +/* { dg-options " -Os -march=rv32e_zca_zcmp -mabi=ilp32e -mcmodel=medlow -fno-shrink-wrap-separate" } */ +/* { dg-skip-if "" { *-*-* } {"-O0" "-O1" "-O2" "-Og" "-O3" "-Oz" "-flto"} } */ +/* { dg-final { check-function-bodies "**" "" } } */ + +char +my_getchar (); +float +getf (); +int __attribute__ ((noinline)) +incoming_stack_args (int arg0, int arg1, int arg2, int arg3, int arg4, int arg5, + int arg6, int arg7, int arg8); +int +getint (); +void +PrintInts (int n, ...); // varargs +void __attribute__ ((noinline)) PrintIntsNoVaStart (int n, ...); // varargs +void +PrintInts2 (int arg0, int arg1, int arg2, int arg3, int arg4, int arg5, int n, + ...); +extern void +f1 (void); +extern void +f2 (void); + +/* +**test1: +** ... +** cm.push {ra, s0-s1}, -64 +** ... +** cm.popret {ra, s0-s1}, 64 +** ... +*/ +int +test1 () +{ + char volatile array[3120]; + float volatile farray[3120]; + + float sum = 0; + for (int i = 0; i < 3120; i++) + { + array[i] = my_getchar (); + farray[i] = my_getchar () * 1.2; + sum += array[i] + farray[i]; + } + return sum; +} + +/* +**test2_step1_0_size: +** ... +** cm.push {ra, s0}, -64 +** ... +** cm.popret {ra, s0}, 64 +** ... +*/ +int +test2_step1_0_size () +{ + int volatile iarray[3120 + 1824 / 4 - 8]; + + for (int i = 0; i < 3120 + 1824 / 4 - 8; i++) + { + iarray[i] = my_getchar () * 2; + } + return iarray[0] + iarray[1]; +} + +/* +**test3: +** ... +** cm.push {ra, s0-s1}, -64 +** ... +** cm.popret {ra, s0-s1}, 64 +** ... +*/ +float +test3 () +{ + char volatile array[3120]; + float volatile farray[3120]; + + float sum = 0, f1 = 0, f2 = 0, f3 = 0, f4 = 0, f5 = 0, f6 = 0, f7 = 0; + + for (int i = 0; i < 3120; i++) + { + f1 = getf (); + f2 = getf (); + f3 = getf (); + f4 = getf (); + array[i] = my_getchar (); + farray[i] = my_getchar () * 1.2; + sum += array[i] + farray[i] + f1 + f2 + f3 + f4; + } + return sum; +} + +/* +**outgoing_stack_args: +** ... +** cm.push {ra, s0}, -32 +** ... +** cm.popret {ra, s0}, 32 +** ... +*/ +int +outgoing_stack_args () +{ + int local = getint (); + return local + incoming_stack_args (0, 1, 2, 3, 4, 5, 6, 7, 8); +} + +/* +**callPrintInts: +** ... +** cm.push {ra}, -32 +** ... +** cm.popret {ra}, 32 +** ... +*/ +float +callPrintInts () +{ + volatile float f = getf (); // f in local + PrintInts (9, 1, 2, 3, 4, 5, 6, 7, 8, 9); + return f; +} + +/* +**callPrint: +** ... +** cm.push {ra}, -32 +** ... +** cm.popret {ra}, 32 +** ... +*/ +float +callPrint () +{ + volatile float f = getf (); // f in local + PrintIntsNoVaStart (0, 1, 2, 3, 4, 5, 6, 7, 8, 9); + return f; +} + +/* +**callPrint_S: +** ... +** cm.push {ra, s0}, -32 +** ... +** cm.popret {ra, s0}, 32 +** ... +*/ +float +callPrint_S () +{ + float f = getf (); + PrintIntsNoVaStart (0, 1, 2, 3, 4, 5, 6, 7, 8, 9); + return f; +} + +/* +**callPrint_2: +** ... +** cm.push {ra, s0}, -32 +** ... +** cm.popret {ra, s0}, 32 +** ... +*/ +float +callPrint_2 () +{ + float f = getf (); + PrintInts2 (0, 1, 2, 3, 4, 5, 6, 7, 8, 9); + return f; +} + +/* +**test_step1_0bytes_save_restore: +** ... +** cm.push {ra}, -16 +** ... +** cm.popret {ra}, 16 +** ... +*/ +int +test_step1_0bytes_save_restore () +{ + int a = 9; + int b = my_getchar (); + return a + b; +} + +/* +**test_s0: +** ... +** cm.push {ra, s0}, -16 +** ... +** cm.popret {ra, s0}, 16 +** ... +*/ +int +test_s0 () +{ + int a = my_getchar (); + int b = my_getchar (); + return a + b; +} + +/* +**test_s1: +** ... +** cm.push {ra, s0-s1}, -16 +** ... +** cm.popret {ra, s0-s1}, 16 +** ... +*/ +int +test_s1 () +{ + int s0 = my_getchar (); + int s1 = my_getchar (); + int b = my_getchar (); + return s1 + s0 + b; +} + +/* +**test_f0: +** ... +** cm.push {ra, s0-s1}, -16 +** ... +** cm.popret {ra, s0-s1}, 16 +** ... +*/ +int +test_f0 () +{ + int s0 = my_getchar (); + float f0 = getf (); + int b = my_getchar (); + return f0 + s0 + b; +} + +/* +**foo: +** cm.push {ra}, -16 +** call f1 +** cm.pop {ra}, 16 +** tail f2 +*/ +void +foo (void) +{ + f1 (); + f2 (); +} + +/* +**test_popretz: +** cm.push {ra}, -16 +** call f1 +** cm.popretz {ra}, 16 +*/ +long +test_popretz () +{ + f1 (); + return 0; +} diff --git a/gcc/testsuite/gcc.target/riscv/rv32i_zcmp.c b/gcc/testsuite/gcc.target/riscv/rv32i_zcmp.c new file mode 100644 index 000000000000..f00338a9d179 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rv32i_zcmp.c @@ -0,0 +1,269 @@ +/* { dg-do compile } */ +/* { dg-options " -Os -march=rv32imaf_zca_zcmp -mabi=ilp32f -mcmodel=medlow -fno-shrink-wrap-separate" }*/ +/* { dg-skip-if "" { *-*-* } {"-O0" "-O1" "-O2" "-Og" "-O3" "-Oz" "-flto"} } */ +/* { dg-final { check-function-bodies "**" "" } } */ + +char +my_getchar (); +float +getf (); +int __attribute__ ((noinline)) +incoming_stack_args (int arg0, int arg1, int arg2, int arg3, int arg4, int arg5, + int arg6, int arg7, int arg8); +int +getint (); +void +PrintInts (int n, ...); // varargs +void __attribute__ ((noinline)) PrintIntsNoVaStart (int n, ...); // varargs +void +PrintInts2 (int arg0, int arg1, int arg2, int arg3, int arg4, int arg5, int n, + ...); +extern void +f1 (void); +extern void +f2 (void); + +/* +**test1: +** ... +** cm.push {ra, s0-s4}, -80 +** ... +** cm.popret {ra, s0-s4}, 80 +** ... +*/ +int +test1 () +{ + char volatile array[3120]; + float volatile farray[3120]; + + float sum = 0; + for (int i = 0; i < 3120; i++) + { + array[i] = my_getchar (); + farray[i] = my_getchar () * 1.2; + sum += array[i] + farray[i]; + } + return sum; +} + +/* +**test2_step1_0_size: +** ... +** cm.push {ra, s0-s1}, -64 +** ... +** cm.popret {ra, s0-s1}, 64 +** ... +*/ +int +test2_step1_0_size () +{ + int volatile iarray[3120 + 1824 / 4 - 8]; + + for (int i = 0; i < 3120 + 1824 / 4 - 8; i++) + { + iarray[i] = my_getchar () * 2; + } + return iarray[0] + iarray[1]; +} + +/* +**test3: +** ... +** cm.push {ra, s0-s4}, -80 +** ... +** cm.popret {ra, s0-s4}, 80 +** ... +*/ +float +test3 () +{ + char volatile array[3120]; + float volatile farray[3120]; + + float sum = 0, f1 = 0, f2 = 0, f3 = 0, f4 = 0, f5 = 0, f6 = 0, f7 = 0; + + for (int i = 0; i < 3120; i++) + { + f1 = getf (); + f2 = getf (); + f3 = getf (); + f4 = getf (); + array[i] = my_getchar (); + farray[i] = my_getchar () * 1.2; + sum += array[i] + farray[i] + f1 + f2 + f3 + f4; + } + return sum; +} + +/* +**outgoing_stack_args: +** ... +** cm.push {ra, s0}, -32 +** ... +** cm.popret {ra, s0}, 32 +** ... +*/ +int +outgoing_stack_args () +{ + int local = getint (); + return local + incoming_stack_args (0, 1, 2, 3, 4, 5, 6, 7, 8); +} + +/* +**callPrintInts: +** ... +** cm.push {ra}, -48 +** ... +** cm.popret {ra}, 48 +** ... +*/ +float +callPrintInts () +{ + volatile float f = getf (); // f in local + PrintInts (9, 1, 2, 3, 4, 5, 6, 7, 8, 9); + return f; +} + +/* +**callPrint: +** ... +** cm.push {ra}, -48 +** ... +** cm.popret {ra}, 48 +** ... +*/ +float +callPrint () +{ + volatile float f = getf (); // f in local + PrintIntsNoVaStart (0, 1, 2, 3, 4, 5, 6, 7, 8, 9); + return f; +} + +/* +**callPrint_S: +** ... +** cm.push {ra}, -48 +** ... +** cm.popret {ra}, 48 +** ... +*/ +float +callPrint_S () +{ + float f = getf (); + PrintIntsNoVaStart (0, 1, 2, 3, 4, 5, 6, 7, 8, 9); + return f; +} + +/* +**callPrint_2: +** ... +** cm.push {ra}, -48 +** ... +** cm.popret {ra}, 48 +** ... +*/ +float +callPrint_2 () +{ + float f = getf (); + PrintInts2 (0, 1, 2, 3, 4, 5, 6, 7, 8, 9); + return f; +} + +/* +**test_step1_0bytes_save_restore: +** ... +** cm.push {ra}, -16 +** ... +** cm.popret {ra}, 16 +** ... +*/ +int +test_step1_0bytes_save_restore () +{ + int a = 9; + int b = my_getchar (); + return a + b; +} + +/* +**test_s0: +** ... +** cm.push {ra, s0}, -16 +** ... +** cm.popret {ra, s0}, 16 +** ... +*/ +int +test_s0 () +{ + int a = my_getchar (); + int b = my_getchar (); + return a + b; +} + +/* +**test_s1: +** ... +** cm.push {ra, s0-s1}, -16 +** ... +** cm.popret {ra, s0-s1}, 16 +** ... +*/ +int +test_s1 () +{ + int s0 = my_getchar (); + int s1 = my_getchar (); + int b = my_getchar (); + return s1 + s0 + b; +} + +/* +**test_f0: +** ... +** cm.push {ra, s0}, -32 +** ... +** cm.popret {ra, s0}, 32 +** ... +*/ +int +test_f0 () +{ + int s0 = my_getchar (); + float f0 = getf (); + int b = my_getchar (); + return f0 + s0 + b; +} + +/* +**foo: +** cm.push {ra}, -16 +** call f1 +** cm.pop {ra}, 16 +** tail f2 +*/ +void +foo (void) +{ + f1 (); + f2 (); +} + +/* +**test_popretz: +** cm.push {ra}, -16 +** call f1 +** cm.popretz {ra}, 16 +*/ +long +test_popretz () +{ + f1 (); + return 0; +} diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/narrow-3.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/narrow-3.c index 3b288466394c..315d2de0a8bf 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/narrow-3.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/narrow-3.c @@ -27,5 +27,5 @@ TEST_ALL () -/* { dg-final { scan-assembler-times {\tvnsra\.wx} 4 } } */ +/* { dg-final { scan-assembler-times {\tvnsra\.wx} 8 } } */ /* { dg-final { scan-assembler-times {\tvnsrl\.wx} 4 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/shift-immediate.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/shift-immediate.c new file mode 100644 index 000000000000..a2e1c33f4faa --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/shift-immediate.c @@ -0,0 +1,16 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-std=c99 -march=rv32gcv -mabi=ilp32d -O2 --param=riscv-autovec-preference=scalable" } */ + +#define uint8_t unsigned char + +void foo1 (uint8_t *a) +{ + uint8_t b = a[0]; + int val = 0; + + for (int i = 0; i < 4; i++) + { + a[i] = (val & 1) ? (-val) >> 17 : val; + val += b; + } +} diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vadd-rv32gcv-nofm.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vadd-rv32gcv-nofm.c index 069bc690697d..60c760d939da 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vadd-rv32gcv-nofm.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vadd-rv32gcv-nofm.c @@ -5,9 +5,6 @@ /* { dg-final { scan-assembler-times {\tvadd\.vv} 16 } } */ /* { dg-final { scan-assembler-times {\tvadd\.vi} 8 } } */ -/* { dg-final { scan-assembler-times {\tvfadd\.vv} 7 } } */ -/* There are 2 MINUS operations. */ -/* { dg-final { scan-assembler-times {\tvfsub\.vv} 2 } } */ +/* { dg-final { scan-assembler-times {\tvfadd\.vv} 9 } } */ -/* { dg-final { scan-tree-dump-times "\.COND_LEN_ADD" 7 "optimized" } } */ -/* { dg-final { scan-tree-dump-times "\.COND_LEN_SUB" 2 "optimized" } } */ +/* { dg-final { scan-tree-dump-times "\.COND_LEN_ADD" 9 "optimized" } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vadd-rv64gcv-nofm.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vadd-rv64gcv-nofm.c index 07fa54878ccf..86d5283c4b66 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vadd-rv64gcv-nofm.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vadd-rv64gcv-nofm.c @@ -5,9 +5,6 @@ /* { dg-final { scan-assembler-times {\tvadd\.vv} 16 } } */ /* { dg-final { scan-assembler-times {\tvadd\.vi} 8 } } */ -/* { dg-final { scan-assembler-times {\tvfadd\.vv} 7 } } */ -/* There are 2 MINUS operations. */ -/* { dg-final { scan-assembler-times {\tvfsub\.vv} 2 } } */ +/* { dg-final { scan-assembler-times {\tvfadd\.vv} 9 } } */ -/* { dg-final { scan-tree-dump-times "\.COND_LEN_ADD" 7 "optimized" } } */ -/* { dg-final { scan-tree-dump-times "\.COND_LEN_SUB" 2 "optimized" } } */ +/* { dg-final { scan-tree-dump-times "\.COND_LEN_ADD" 9 "optimized" } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_arith-1.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_arith-1.c new file mode 100644 index 000000000000..e05226cb2e0f --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_arith-1.c @@ -0,0 +1,48 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-march=rv32gcv_zvfh -mabi=ilp32d --param=riscv-autovec-preference=scalable -fno-vect-cost-model -ffast-math -fdump-tree-optimized-details" } */ + +#include + +#define TEST(TYPE, NAME, OP) \ + void __attribute__ ((noinline, noclone)) \ + test_##TYPE##_##NAME (TYPE *__restrict x, TYPE *__restrict y, \ + TYPE *__restrict z, TYPE *__restrict pred, int n) \ + { \ + for (int i = 0; i < n; ++i) \ + x[i] = pred[i] != 1 ? y[i] OP z[i] : y[i]; \ + } + +#define TEST_TYPE(TYPE) \ + TEST (TYPE, add, +) \ + TEST (TYPE, sub, -) \ + TEST (TYPE, mul, *) \ + TEST (TYPE, div, /) + +#define TEST_ALL \ + TEST_TYPE (int8_t) \ + TEST_TYPE (uint8_t) \ + TEST_TYPE (int16_t) \ + TEST_TYPE (uint16_t) \ + TEST_TYPE (int32_t) \ + TEST_TYPE (uint32_t) \ + TEST_TYPE (int64_t) \ + TEST_TYPE (uint64_t) \ + TEST_TYPE (_Float16) \ + TEST_TYPE (float) \ + TEST_TYPE (double) + +TEST_ALL + +/* { dg-final { scan-tree-dump-times "\.COND_LEN_DIV" 8 "optimized" } } */ +/* { dg-final { scan-tree-dump-times "\.COND_ADD" 11 "optimized" } } */ +/* { dg-final { scan-tree-dump-times "\.COND_SUB" 11 "optimized" } } */ +/* { dg-final { scan-tree-dump-times "\.COND_MUL" 11 "optimized" } } */ +/* { dg-final { scan-tree-dump-times "\.COND_RDIV" 3 "optimized" } } */ +/* { dg-final { scan-assembler-times {vadd\.vv\s+v[0-9]+,v[0-9]+,v[0-9]+,v0.t} 8 } } */ +/* { dg-final { scan-assembler-times {vsub\.vv\s+v[0-9]+,v[0-9]+,v[0-9]+,v0.t} 8 } } */ +/* { dg-final { scan-assembler-times {vmul\.vv\s+v[0-9]+,v[0-9]+,v[0-9]+,v0.t} 8 } } */ +/* { dg-final { scan-assembler-times {vdivu?\.vv\s+v[0-9]+,v[0-9]+,v[0-9]+,v0.t} 8 } } */ +/* { dg-final { scan-assembler-times {vfadd\.vv\s+v[0-9]+,v[0-9]+,v[0-9]+,v0.t} 3 } } */ +/* { dg-final { scan-assembler-times {vfsub\.vv\s+v[0-9]+,v[0-9]+,v[0-9]+,v0.t} 3 } } */ +/* { dg-final { scan-assembler-times {vfmul\.vv\s+v[0-9]+,v[0-9]+,v[0-9]+,v0.t} 3 } } */ +/* { dg-final { scan-assembler-times {vfdiv\.vv\s+v[0-9]+,v[0-9]+,v[0-9]+,v0.t} 3 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_arith-2.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_arith-2.c new file mode 100644 index 000000000000..2b73536b13a5 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_arith-2.c @@ -0,0 +1,27 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-march=rv32gcv_zvfh -mabi=ilp32d --param=riscv-autovec-preference=scalable -fno-vect-cost-model -fdump-tree-optimized-details" } */ + +#include "cond_arith-1.c" + +/* { dg-final { scan-tree-dump-times "\.COND_LEN_DIV" 8 "optimized" } } */ +/* { dg-final { scan-tree-dump-times "\.COND_LEN_RDIV" 3 "optimized" } } */ +/* { dg-final { scan-tree-dump-times "\.COND_ADD" 8 "optimized" } } */ +/* { dg-final { scan-tree-dump-times "\.COND_SUB" 8 "optimized" } } */ +/* { dg-final { scan-tree-dump-times "\.COND_MUL" 8 "optimized" } } */ +/* { dg-final { scan-tree-dump-times "\.COND_ADD" 8 "optimized" } } */ +/* { dg-final { scan-tree-dump-times "\.COND_SUB" 8 "optimized" } } */ +/* { dg-final { scan-tree-dump-times "\.COND_MUL" 8 "optimized" } } */ +/* { dg-final { scan-tree-dump-times "\.COND_LEN_ADD" 3 "optimized" } } */ +/* { dg-final { scan-tree-dump-times "\.COND_LEN_SUB" 3 "optimized" } } */ +/* { dg-final { scan-tree-dump-times "\.COND_LEN_MUL" 3 "optimized" } } */ +/* { dg-final { scan-tree-dump-times "\.COND_LEN_ADD" 3 "optimized" } } */ +/* { dg-final { scan-tree-dump-times "\.COND_LEN_SUB" 3 "optimized" } } */ +/* { dg-final { scan-tree-dump-times "\.COND_LEN_MUL" 3 "optimized" } } */ +/* { dg-final { scan-assembler-times {vadd\.vv\s+v[0-9]+,v[0-9]+,v[0-9]+,v0.t} 8 } } */ +/* { dg-final { scan-assembler-times {vsub\.vv\s+v[0-9]+,v[0-9]+,v[0-9]+,v0.t} 8 } } */ +/* { dg-final { scan-assembler-times {vmul\.vv\s+v[0-9]+,v[0-9]+,v[0-9]+,v0.t} 8 } } */ +/* { dg-final { scan-assembler-times {vdivu?\.vv\s+v[0-9]+,v[0-9]+,v[0-9]+,v0.t} 8 } } */ +/* { dg-final { scan-assembler-times {vfadd\.vv\s+v[0-9]+,v[0-9]+,v[0-9]+,v0.t} 3 } } */ +/* { dg-final { scan-assembler-times {vfsub\.vv\s+v[0-9]+,v[0-9]+,v[0-9]+,v0.t} 3 } } */ +/* { dg-final { scan-assembler-times {vfmul\.vv\s+v[0-9]+,v[0-9]+,v[0-9]+,v0.t} 3 } } */ +/* { dg-final { scan-assembler-times {vfdiv\.vv\s+v[0-9]+,v[0-9]+,v[0-9]+,v0.t} 3 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_arith-3.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_arith-3.c new file mode 100644 index 000000000000..5fdeb3837ea0 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_arith-3.c @@ -0,0 +1,55 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-march=rv32gcv_zvfh -mabi=ilp32d --param=riscv-autovec-preference=scalable -fno-vect-cost-model -ffast-math -fdump-tree-optimized-details" } */ + +#include + +#define TEST(DATA_TYPE, PRED_TYPE, NAME, OP) \ + void __attribute__ ((noinline, noclone)) \ + test_##DATA_TYPE##_##PRED_TYPE##_##NAME (DATA_TYPE *__restrict x, \ + DATA_TYPE *__restrict y, \ + DATA_TYPE *__restrict z, \ + PRED_TYPE *__restrict pred, int n) \ + { \ + for (int i = 0; i < n; ++i) \ + x[i] = pred[i] != 1 ? y[i] OP z[i] : y[i]; \ + } + +#define TEST_TYPE(DATA_TYPE, PRED_TYPE) \ + TEST (DATA_TYPE, PRED_TYPE, add, +) \ + TEST (DATA_TYPE, PRED_TYPE, sub, -) \ + TEST (DATA_TYPE, PRED_TYPE, mul, *) \ + TEST (DATA_TYPE, PRED_TYPE, div, /) + +#define TEST_ALL \ + TEST_TYPE (int32_t, int8_t) \ + TEST_TYPE (uint32_t, int8_t) \ + TEST_TYPE (int32_t, int16_t) \ + TEST_TYPE (uint32_t, int16_t) \ + TEST_TYPE (int64_t, int8_t) \ + TEST_TYPE (uint64_t, int8_t) \ + TEST_TYPE (int64_t, int16_t) \ + TEST_TYPE (uint64_t, int16_t) \ + TEST_TYPE (int64_t, int32_t) \ + TEST_TYPE (uint64_t, int32_t) \ + TEST_TYPE (_Float16, int8_t) \ + TEST_TYPE (float, int8_t) \ + TEST_TYPE (float, int16_t) \ + TEST_TYPE (double, int8_t) \ + TEST_TYPE (double, int16_t) \ + TEST_TYPE (double, int32_t) + +TEST_ALL + +/* { dg-final { scan-tree-dump-times "\.COND_LEN_DIV" 10 "optimized" } } */ +/* { dg-final { scan-tree-dump-times "\.COND_ADD" 16 "optimized" } } */ +/* { dg-final { scan-tree-dump-times "\.COND_SUB" 16 "optimized" } } */ +/* { dg-final { scan-tree-dump-times "\.COND_MUL" 16 "optimized" } } */ +/* { dg-final { scan-tree-dump-times "\.COND_RDIV" 6 "optimized" } } */ +/* { dg-final { scan-assembler-times {vadd\.vv\s+v[0-9]+,v[0-9]+,v[0-9]+,v0.t} 10 } } */ +/* { dg-final { scan-assembler-times {vsub\.vv\s+v[0-9]+,v[0-9]+,v[0-9]+,v0.t} 10 } } */ +/* { dg-final { scan-assembler-times {vmul\.vv\s+v[0-9]+,v[0-9]+,v[0-9]+,v0.t} 10 } } */ +/* { dg-final { scan-assembler-times {vdivu?\.vv\s+v[0-9]+,v[0-9]+,v[0-9]+,v0.t} 10 } } */ +/* { dg-final { scan-assembler-times {vfadd\.vv\s+v[0-9]+,v[0-9]+,v[0-9]+,v0.t} 6 } } */ +/* { dg-final { scan-assembler-times {vfsub\.vv\s+v[0-9]+,v[0-9]+,v[0-9]+,v0.t} 6 } } */ +/* { dg-final { scan-assembler-times {vfmul\.vv\s+v[0-9]+,v[0-9]+,v[0-9]+,v0.t} 6 } } */ +/* { dg-final { scan-assembler-times {vfdiv\.vv\s+v[0-9]+,v[0-9]+,v[0-9]+,v0.t} 6 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_arith-4.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_arith-4.c new file mode 100644 index 000000000000..0cbe9bbb479a --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_arith-4.c @@ -0,0 +1,21 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-march=rv32gcv_zvfh -mabi=ilp32d --param=riscv-autovec-preference=scalable -fno-vect-cost-model -fdump-tree-optimized-details" } */ + +#include "cond_arith-3.c" + +/* { dg-final { scan-tree-dump-times "\.COND_LEN_DIV" 10 "optimized" } } */ +/* { dg-final { scan-tree-dump-times "\.COND_ADD" 10 "optimized" } } */ +/* { dg-final { scan-tree-dump-times "\.COND_SUB" 10 "optimized" } } */ +/* { dg-final { scan-tree-dump-times "\.COND_MUL" 10 "optimized" } } */ +/* { dg-final { scan-tree-dump-times "\.COND_LEN_ADD" 6 "optimized" } } */ +/* { dg-final { scan-tree-dump-times "\.COND_LEN_SUB" 6 "optimized" } } */ +/* { dg-final { scan-tree-dump-times "\.COND_LEN_MUL" 6 "optimized" } } */ +/* { dg-final { scan-tree-dump-times "\.COND_LEN_RDIV" 6 "optimized" } } */ +/* { dg-final { scan-assembler-times {vadd\.vv\s+v[0-9]+,v[0-9]+,v[0-9]+,v0.t} 10 } } */ +/* { dg-final { scan-assembler-times {vsub\.vv\s+v[0-9]+,v[0-9]+,v[0-9]+,v0.t} 10 } } */ +/* { dg-final { scan-assembler-times {vmul\.vv\s+v[0-9]+,v[0-9]+,v[0-9]+,v0.t} 10 } } */ +/* { dg-final { scan-assembler-times {vdivu?\.vv\s+v[0-9]+,v[0-9]+,v[0-9]+,v0.t} 10 } } */ +/* { dg-final { scan-assembler-times {vfadd\.vv\s+v[0-9]+,v[0-9]+,v[0-9]+,v0.t} 6 } } */ +/* { dg-final { scan-assembler-times {vfsub\.vv\s+v[0-9]+,v[0-9]+,v[0-9]+,v0.t} 6 } } */ +/* { dg-final { scan-assembler-times {vfmul\.vv\s+v[0-9]+,v[0-9]+,v[0-9]+,v0.t} 6 } } */ +/* { dg-final { scan-assembler-times {vfdiv\.vv\s+v[0-9]+,v[0-9]+,v[0-9]+,v0.t} 6 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_arith-5.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_arith-5.c new file mode 100644 index 000000000000..cf9c95066c38 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_arith-5.c @@ -0,0 +1,48 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-march=rv32gcv_zvfh -mabi=ilp32d --param=riscv-autovec-preference=scalable -fno-vect-cost-model -ffast-math -fdump-tree-optimized-details" } */ + +#include + +#define TEST(TYPE, NAME, OP) \ + void __attribute__ ((noinline, noclone)) \ + test_##TYPE##_##NAME (TYPE *__restrict x, TYPE *__restrict y, \ + TYPE *__restrict z, TYPE *__restrict pred, int n) \ + { \ + for (int i = 0; i < n; ++i) \ + x[i] = pred[i] != 1 ? y[i] OP z[i] : 1; \ + } + +#define TEST_TYPE(TYPE) \ + TEST (TYPE, add, +) \ + TEST (TYPE, sub, -) \ + TEST (TYPE, mul, *) \ + TEST (TYPE, div, /) + +#define TEST_ALL \ + TEST_TYPE (int8_t) \ + TEST_TYPE (uint8_t) \ + TEST_TYPE (int16_t) \ + TEST_TYPE (uint16_t) \ + TEST_TYPE (int32_t) \ + TEST_TYPE (uint32_t) \ + TEST_TYPE (int64_t) \ + TEST_TYPE (uint64_t) \ + TEST_TYPE (_Float16) \ + TEST_TYPE (float) \ + TEST_TYPE (double) + +TEST_ALL + +/* { dg-final { scan-tree-dump-times "\.COND_LEN_DIV" 8 "optimized" } } */ +/* { dg-final { scan-tree-dump-times "\.COND_ADD" 11 "optimized" } } */ +/* { dg-final { scan-tree-dump-times "\.COND_SUB" 11 "optimized" } } */ +/* { dg-final { scan-tree-dump-times "\.COND_MUL" 11 "optimized" } } */ +/* { dg-final { scan-tree-dump-times "\.COND_RDIV" 3 "optimized" } } */ +/* { dg-final { scan-assembler-times {vadd\.vv\s+v[0-9]+,v[0-9]+,v[0-9]+,v0.t} 8 } } */ +/* { dg-final { scan-assembler-times {vsub\.vv\s+v[0-9]+,v[0-9]+,v[0-9]+,v0.t} 8 } } */ +/* { dg-final { scan-assembler-times {vmul\.vv\s+v[0-9]+,v[0-9]+,v[0-9]+,v0.t} 8 } } */ +/* { dg-final { scan-assembler-times {vdivu?\.vv\s+v[0-9]+,v[0-9]+,v[0-9]+,v0.t} 8 } } */ +/* { dg-final { scan-assembler-times {vfadd\.vv\s+v[0-9]+,v[0-9]+,v[0-9]+,v0.t} 3 } } */ +/* { dg-final { scan-assembler-times {vfsub\.vv\s+v[0-9]+,v[0-9]+,v[0-9]+,v0.t} 3 } } */ +/* { dg-final { scan-assembler-times {vfmul\.vv\s+v[0-9]+,v[0-9]+,v[0-9]+,v0.t} 3 } } */ +/* { dg-final { scan-assembler-times {vfdiv\.vv\s+v[0-9]+,v[0-9]+,v[0-9]+,v0.t} 3 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_arith-6.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_arith-6.c new file mode 100644 index 000000000000..487cf51a4110 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_arith-6.c @@ -0,0 +1,27 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-march=rv32gcv_zvfh -mabi=ilp32d --param=riscv-autovec-preference=scalable -fno-vect-cost-model -fdump-tree-optimized-details" } */ + +#include "cond_arith-5.c" + +/* { dg-final { scan-tree-dump-times "\.COND_LEN_DIV" 8 "optimized" } } */ +/* { dg-final { scan-tree-dump-times "\.COND_LEN_RDIV" 3 "optimized" } } */ +/* { dg-final { scan-tree-dump-times "\.COND_ADD" 8 "optimized" } } */ +/* { dg-final { scan-tree-dump-times "\.COND_SUB" 8 "optimized" } } */ +/* { dg-final { scan-tree-dump-times "\.COND_MUL" 8 "optimized" } } */ +/* { dg-final { scan-tree-dump-times "\.COND_ADD" 8 "optimized" } } */ +/* { dg-final { scan-tree-dump-times "\.COND_SUB" 8 "optimized" } } */ +/* { dg-final { scan-tree-dump-times "\.COND_MUL" 8 "optimized" } } */ +/* { dg-final { scan-tree-dump-times "\.COND_LEN_ADD" 3 "optimized" } } */ +/* { dg-final { scan-tree-dump-times "\.COND_LEN_SUB" 3 "optimized" } } */ +/* { dg-final { scan-tree-dump-times "\.COND_LEN_MUL" 3 "optimized" } } */ +/* { dg-final { scan-tree-dump-times "\.COND_LEN_ADD" 3 "optimized" } } */ +/* { dg-final { scan-tree-dump-times "\.COND_LEN_SUB" 3 "optimized" } } */ +/* { dg-final { scan-tree-dump-times "\.COND_LEN_MUL" 3 "optimized" } } */ +/* { dg-final { scan-assembler-times {vadd\.vv\s+v[0-9]+,v[0-9]+,v[0-9]+,v0.t} 8 } } */ +/* { dg-final { scan-assembler-times {vsub\.vv\s+v[0-9]+,v[0-9]+,v[0-9]+,v0.t} 8 } } */ +/* { dg-final { scan-assembler-times {vmul\.vv\s+v[0-9]+,v[0-9]+,v[0-9]+,v0.t} 8 } } */ +/* { dg-final { scan-assembler-times {vdivu?\.vv\s+v[0-9]+,v[0-9]+,v[0-9]+,v0.t} 8 } } */ +/* { dg-final { scan-assembler-times {vfadd\.vv\s+v[0-9]+,v[0-9]+,v[0-9]+,v0.t} 3 } } */ +/* { dg-final { scan-assembler-times {vfsub\.vv\s+v[0-9]+,v[0-9]+,v[0-9]+,v0.t} 3 } } */ +/* { dg-final { scan-assembler-times {vfmul\.vv\s+v[0-9]+,v[0-9]+,v[0-9]+,v0.t} 3 } } */ +/* { dg-final { scan-assembler-times {vfdiv\.vv\s+v[0-9]+,v[0-9]+,v[0-9]+,v0.t} 3 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_arith-7.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_arith-7.c new file mode 100644 index 000000000000..8d4fa8807107 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_arith-7.c @@ -0,0 +1,50 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-march=rv32gcv_zvfh -mabi=ilp32d --param=riscv-autovec-preference=scalable -fno-vect-cost-model -fdump-tree-optimized-details" } */ + +#include + +#define TEST(TYPE, NAME, OP) \ + void __attribute__ ((noinline, noclone)) \ + test_##TYPE##_##NAME (TYPE *__restrict x, TYPE *__restrict y, TYPE z1, \ + TYPE z2, TYPE *__restrict pred, int n) \ + { \ + for (int i = 0; i < n; i += 2) \ + { \ + x[i] = (pred[i] != 1 ? y[i] OP z1 : y[i]); \ + x[i + 1] = (pred[i + 1] != 1 ? y[i + 1] OP z2 : y[i + 1]); \ + } \ + } + +#define TEST_TYPE(TYPE) \ + TEST (TYPE, add, +) \ + TEST (TYPE, sub, -) \ + TEST (TYPE, mul, *) \ + TEST (TYPE, div, /) + +#define TEST_ALL \ + TEST_TYPE (int32_t) \ + TEST_TYPE (uint32_t) \ + TEST_TYPE (int64_t) \ + TEST_TYPE (uint64_t) \ + TEST_TYPE (_Float16) \ + TEST_TYPE (float) \ + TEST_TYPE (double) + +TEST_ALL + +/* { dg-final { scan-tree-dump-times "\.COND_LEN_DIV" 4 "optimized" } } */ +/* { dg-final { scan-tree-dump-times "\.COND_LEN_RDIV" 3 "optimized" } } */ +/* { dg-final { scan-tree-dump-times "\.COND_ADD" 4 "optimized" } } */ +/* { dg-final { scan-tree-dump-times "\.COND_LEN_ADD" 3 "optimized" } } */ +/* { dg-final { scan-tree-dump-times "\.COND_SUB" 4 "optimized" } } */ +/* { dg-final { scan-tree-dump-times "\.COND_LEN_SUB" 3 "optimized" } } */ +/* { dg-final { scan-tree-dump-times "\.COND_MUL" 4 "optimized" } } */ +/* { dg-final { scan-tree-dump-times "\.COND_LEN_MUL" 3 "optimized" } } */ +/* { dg-final { scan-assembler-times {vadd\.vv\s+v[0-9]+,v[0-9]+,v[0-9]+,v0.t} 4 } } */ +/* { dg-final { scan-assembler-times {vsub\.vv\s+v[0-9]+,v[0-9]+,v[0-9]+,v0.t} 4 } } */ +/* { dg-final { scan-assembler-times {vmul\.vv\s+v[0-9]+,v[0-9]+,v[0-9]+,v0.t} 4 } } */ +/* { dg-final { scan-assembler-times {vdivu?\.vv\s+v[0-9]+,v[0-9]+,v[0-9]+,v0.t} 4 } } */ +/* { dg-final { scan-assembler-times {vfadd\.vv\s+v[0-9]+,v[0-9]+,v[0-9]+,v0.t} 3 } } */ +/* { dg-final { scan-assembler-times {vfsub\.vv\s+v[0-9]+,v[0-9]+,v[0-9]+,v0.t} 3 } } */ +/* { dg-final { scan-assembler-times {vfmul\.vv\s+v[0-9]+,v[0-9]+,v[0-9]+,v0.t} 3 } } */ +/* { dg-final { scan-assembler-times {vfdiv\.vv\s+v[0-9]+,v[0-9]+,v[0-9]+,v0.t} 3 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_arith-8.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_arith-8.c new file mode 100644 index 000000000000..d191d4cebab5 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_arith-8.c @@ -0,0 +1,64 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-march=rv32gcv_zvfh -mabi=ilp32d --param=riscv-autovec-preference=scalable -fno-vect-cost-model -fdump-tree-optimized-details" } */ + +#include + +#define TEST(DATA_TYPE, OTHER_TYPE, NAME, OP) \ + void __attribute__ ((noinline, noclone)) \ + test_##DATA_TYPE##_##OTHER_TYPE##_##NAME (DATA_TYPE *__restrict x, \ + DATA_TYPE *__restrict y, \ + DATA_TYPE z1, DATA_TYPE z2, \ + DATA_TYPE *__restrict pred, \ + OTHER_TYPE *__restrict foo, int n) \ + { \ + for (int i = 0; i < n; i += 2) \ + { \ + x[i] = (pred[i] != 1 ? y[i] OP z1 : y[i]); \ + x[i + 1] = (pred[i + 1] != 1 ? y[i + 1] OP z2 : y[i + 1]); \ + foo[i] += 1; \ + foo[i + 1] += 2; \ + } \ + } + +#define TEST_TYPE(DATA_TYPE, OTHER_TYPE) \ + TEST (DATA_TYPE, OTHER_TYPE, add, +) \ + TEST (DATA_TYPE, OTHER_TYPE, sub, -) \ + TEST (DATA_TYPE, OTHER_TYPE, mul, *) \ + TEST (DATA_TYPE, OTHER_TYPE, div, /) + +#define TEST_ALL \ + TEST_TYPE (int32_t, int8_t) \ + TEST_TYPE (int32_t, int16_t) \ + TEST_TYPE (uint32_t, int8_t) \ + TEST_TYPE (uint32_t, int16_t) \ + TEST_TYPE (int64_t, int8_t) \ + TEST_TYPE (int64_t, int16_t) \ + TEST_TYPE (int64_t, int32_t) \ + TEST_TYPE (uint64_t, int8_t) \ + TEST_TYPE (uint64_t, int16_t) \ + TEST_TYPE (uint64_t, int32_t) \ + TEST_TYPE (_Float16, int8_t) \ + TEST_TYPE (float, int8_t) \ + TEST_TYPE (float, int16_t) \ + TEST_TYPE (double, int8_t) \ + TEST_TYPE (double, int16_t) \ + TEST_TYPE (double, int32_t) + +TEST_ALL + +/* { dg-final { scan-tree-dump-times "\.COND_ADD" 40 "optimized" } } */ +/* { dg-final { scan-tree-dump-times "\.COND_SUB" 40 "optimized" } } */ +/* { dg-final { scan-tree-dump-times "\.COND_MUL" 40 "optimized" } } */ +/* { dg-final { scan-tree-dump-times "\.COND_LEN_ADD" 22 "optimized" } } */ +/* { dg-final { scan-tree-dump-times "\.COND_LEN_SUB" 22 "optimized" } } */ +/* { dg-final { scan-tree-dump-times "\.COND_LEN_MUL" 22 "optimized" } } */ +/* { dg-final { scan-tree-dump-times "\.COND_LEN_DIV" 40 "optimized" } } */ +/* { dg-final { scan-tree-dump-times "\.COND_LEN_RDIV" 22 "optimized" } } */ +/* { dg-final { scan-assembler-times {vadd\.vv\s+v[0-9]+,v[0-9]+,v[0-9]+} 104 } } */ +/* { dg-final { scan-assembler-times {vsub\.vv\s+v[0-9]+,v[0-9]+,v[0-9]+,v0.t} 40 } } */ +/* { dg-final { scan-assembler-times {vmul\.vv\s+v[0-9]+,v[0-9]+,v[0-9]+,v0.t} 40 } } */ +/* { dg-final { scan-assembler-times {vdivu?\.vv\s+v[0-9]+,v[0-9]+,v[0-9]+,v0.t} 40 } } */ +/* { dg-final { scan-assembler-times {vfadd\.vv\s+v[0-9]+,v[0-9]+,v[0-9]+,v0.t} 22 } } */ +/* { dg-final { scan-assembler-times {vfsub\.vv\s+v[0-9]+,v[0-9]+,v[0-9]+,v0.t} 22 } } */ +/* { dg-final { scan-assembler-times {vfmul\.vv\s+v[0-9]+,v[0-9]+,v[0-9]+,v0.t} 22 } } */ +/* { dg-final { scan-assembler-times {vfdiv\.vv\s+v[0-9]+,v[0-9]+,v[0-9]+,v0.t} 22 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_arith-9.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_arith-9.c new file mode 100644 index 000000000000..38bb613c67eb --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_arith-9.c @@ -0,0 +1,34 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-march=rv32gcv_zvfh -mabi=ilp32d --param=riscv-autovec-preference=fixed-vlmax -fno-vect-cost-model -fdump-tree-optimized-details" } */ + +#include + +#define TEST(TYPE, NAME, OP) \ + void __attribute__ ((noinline, noclone)) \ + test_##TYPE##_##NAME (TYPE *__restrict x, TYPE *__restrict y, \ + TYPE *__restrict z, TYPE *__restrict pred, int n) \ + { \ + for (int i = 0; i < 128; ++i) \ + x[i] = pred[i] != 1 ? y[i] OP z[i] : y[i]; \ + } + +#define TEST_TYPE(TYPE) \ + TEST (TYPE, add, +) \ + TEST (TYPE, sub, -) \ + TEST (TYPE, mul, *) \ + TEST (TYPE, div, /) + +#define TEST_ALL \ + TEST_TYPE (int8_t) \ + TEST_TYPE (uint8_t) \ + TEST_TYPE (int16_t) \ + TEST_TYPE (uint16_t) \ + TEST_TYPE (int32_t) \ + TEST_TYPE (uint32_t) \ + TEST_TYPE (int64_t) \ + TEST_TYPE (uint64_t) \ + TEST_TYPE (_Float16) \ + TEST_TYPE (float) \ + TEST_TYPE (double) + +TEST_ALL diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_arith_run-1.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_arith_run-1.c new file mode 100644 index 000000000000..9d0ba59ba825 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_arith_run-1.c @@ -0,0 +1,33 @@ +/* { dg-do run { target { riscv_vector } } } */ +/* { dg-additional-options "--param=riscv-autovec-preference=scalable -fno-vect-cost-model -ffast-math" } */ + +#include "cond_arith-1.c" + +#define N 99 + +#undef TEST +#define TEST(TYPE, NAME, OP) \ + { \ + TYPE x[N], y[N], z[N], pred[N]; \ + for (int i = 0; i < N; ++i) \ + { \ + y[i] = i * i; \ + z[i] = ((i + 2) % 3) * (i + 1); \ + pred[i] = i % 3; \ + } \ + test_##TYPE##_##NAME (x, y, z, pred, N); \ + for (int i = 0; i < N; ++i) \ + { \ + TYPE expected = i % 3 != 1 ? y[i] OP z[i] : y[i]; \ + if (x[i] != expected) \ + __builtin_abort (); \ + asm volatile ("" ::: "memory"); \ + } \ + } + +int +main (void) +{ + TEST_ALL + return 0; +} diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_arith_run-2.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_arith_run-2.c new file mode 100644 index 000000000000..608354de60a5 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_arith_run-2.c @@ -0,0 +1,4 @@ +/* { dg-do run { target { riscv_vector } } } */ +/* { dg-additional-options "--param=riscv-autovec-preference=scalable -fno-vect-cost-model" } */ + +#include "cond_arith_run-1.c" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_arith_run-3.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_arith_run-3.c new file mode 100644 index 000000000000..20e49e7563a6 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_arith_run-3.c @@ -0,0 +1,34 @@ +/* { dg-do run { target { riscv_vector } } } */ +/* { dg-additional-options "--param=riscv-autovec-preference=scalable -fno-vect-cost-model -ffast-math" } */ + +#include "cond_arith-3.c" + +#define N 99 + +#undef TEST +#define TEST(DATA_TYPE, PRED_TYPE, NAME, OP) \ + { \ + DATA_TYPE x[N], y[N], z[N]; \ + PRED_TYPE pred[N]; \ + for (int i = 0; i < N; ++i) \ + { \ + y[i] = i * i; \ + z[i] = ((i + 2) % 3) * (i + 1); \ + pred[i] = i % 3; \ + } \ + test_##DATA_TYPE##_##PRED_TYPE##_##NAME (x, y, z, pred, N); \ + for (int i = 0; i < N; ++i) \ + { \ + DATA_TYPE expected = i % 3 != 1 ? y[i] OP z[i] : y[i]; \ + if (x[i] != expected) \ + __builtin_abort (); \ + asm volatile ("" ::: "memory"); \ + } \ + } + +int +main (void) +{ + TEST_ALL + return 0; +} diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_arith_run-4.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_arith_run-4.c new file mode 100644 index 000000000000..a47243c0f8ac --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_arith_run-4.c @@ -0,0 +1,4 @@ +/* { dg-do run { target { riscv_vector } } } */ +/* { dg-additional-options "--param=riscv-autovec-preference=scalable -fno-vect-cost-model" } */ + +#include "cond_arith_run-3.c" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_arith_run-5.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_arith_run-5.c new file mode 100644 index 000000000000..e4cb7a664381 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_arith_run-5.c @@ -0,0 +1,34 @@ +/* { dg-do run { target { riscv_vector } } } */ +/* { dg-additional-options "--param=riscv-autovec-preference=scalable -fno-vect-cost-model -ffast-math" } */ + +#include "cond_arith-5.c" + +#define N 99 + +#undef TEST +#define TEST(TYPE, NAME, OP) \ + { \ + TYPE x[N], y[N], z[N], pred[N]; \ + for (int i = 0; i < N; ++i) \ + { \ + x[i] = -1; \ + y[i] = i * i; \ + z[i] = ((i + 2) % 3) * (i + 1); \ + pred[i] = i % 3; \ + } \ + test_##TYPE##_##NAME (x, y, z, pred, N); \ + for (int i = 0; i < N; ++i) \ + { \ + TYPE expected = i % 3 != 1 ? y[i] OP z[i] : 1; \ + if (x[i] != expected) \ + __builtin_abort (); \ + asm volatile ("" ::: "memory"); \ + } \ + } + +int +main (void) +{ + TEST_ALL + return 0; +} diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_arith_run-6.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_arith_run-6.c new file mode 100644 index 000000000000..717790de0ed5 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_arith_run-6.c @@ -0,0 +1,4 @@ +/* { dg-do run { target { riscv_vector } } } */ +/* { dg-additional-options "--param=riscv-autovec-preference=scalable -fno-vect-cost-model" } */ + +#include "cond_arith_run-5.c" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_arith_run-7.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_arith_run-7.c new file mode 100644 index 000000000000..a49525f296cd --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_arith_run-7.c @@ -0,0 +1,32 @@ +/* { dg-do run { target { riscv_vector } } } */ +/* { dg-additional-options "--param=riscv-autovec-preference=scalable -fno-vect-cost-model" } */ + +#include "cond_arith-7.c" + +#define N 98 + +#undef TEST +#define TEST(TYPE, NAME, OP) \ + { \ + TYPE x[N], y[N], pred[N], z[2] = { 5, 7 }; \ + for (int i = 0; i < N; ++i) \ + { \ + y[i] = i * i; \ + pred[i] = i % 3; \ + } \ + test_##TYPE##_##NAME (x, y, z[0], z[1], pred, N); \ + for (int i = 0; i < N; ++i) \ + { \ + TYPE expected = i % 3 != 1 ? y[i] OP z[i & 1] : y[i]; \ + if (x[i] != expected) \ + __builtin_abort (); \ + asm volatile ("" ::: "memory"); \ + } \ + } + +int +main (void) +{ + TEST_ALL + return 0; +} diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_arith_run-8.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_arith_run-8.c new file mode 100644 index 000000000000..3f06a213591b --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_arith_run-8.c @@ -0,0 +1,35 @@ +/* { dg-do run { target { riscv_vector } } } */ +/* { dg-additional-options "--param=riscv-autovec-preference=scalable -fno-vect-cost-model" } */ + +#include "cond_arith-8.c" + +#define N 98 + +#undef TEST +#define TEST(DATA_TYPE, OTHER_TYPE, NAME, OP) \ + { \ + DATA_TYPE x[N], y[N], pred[N], z[2] = { 5, 7 }; \ + OTHER_TYPE foo[N]; \ + for (int i = 0; i < N; ++i) \ + { \ + y[i] = i * i; \ + pred[i] = i % 3; \ + foo[i] = i * 5; \ + } \ + test_##DATA_TYPE##_##OTHER_TYPE##_##NAME (x, y, z[0], z[1], \ + pred, foo, N); \ + for (int i = 0; i < N; ++i) \ + { \ + DATA_TYPE expected = i % 3 != 1 ? y[i] OP z[i & 1] : y[i]; \ + if (x[i] != expected) \ + __builtin_abort (); \ + asm volatile ("" ::: "memory"); \ + } \ + } + +int +main (void) +{ + TEST_ALL + return 0; +} diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_arith_run-9.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_arith_run-9.c new file mode 100644 index 000000000000..280479df5424 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_arith_run-9.c @@ -0,0 +1,33 @@ +/* { dg-do run { target { riscv_vector } } } */ +/* { dg-additional-options "--param=riscv-autovec-preference=fixed-vlmax -fno-vect-cost-model -ffast-math" } */ + +#include "cond_arith-9.c" + +#define N 128 + +#undef TEST +#define TEST(TYPE, NAME, OP) \ + { \ + TYPE x[N], y[N], z[N], pred[N]; \ + for (int i = 0; i < N; ++i) \ + { \ + y[i] = i * i; \ + z[i] = ((i + 2) % 3) * (i + 1); \ + pred[i] = i % 3; \ + } \ + test_##TYPE##_##NAME (x, y, z, pred, N); \ + for (int i = 0; i < N; ++i) \ + { \ + TYPE expected = i % 3 != 1 ? y[i] OP z[i] : y[i]; \ + if (x[i] != expected) \ + __builtin_abort (); \ + asm volatile ("" ::: "memory"); \ + } \ + } + +int +main (void) +{ + TEST_ALL + return 0; +} diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_convert_float2float-1.h b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_convert_float2float-1.h new file mode 100644 index 000000000000..4742d926af65 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_convert_float2float-1.h @@ -0,0 +1,29 @@ +#include + +#define DEF_LOOP(OLD_TYPE, NEW_TYPE) \ + void __attribute__ ((noipa)) \ + test_##OLD_TYPE##_2_##NEW_TYPE (NEW_TYPE *__restrict r, \ + OLD_TYPE *__restrict a, \ + NEW_TYPE *__restrict b, \ + OLD_TYPE *__restrict pred, int n) \ + { \ + for (int i = 0; i < n; ++i) \ + { \ + r[i] = pred[i] ? (NEW_TYPE) a[i] : b[i]; \ + } \ + } + +/* FP -> wider-FP */ +#define TEST_ALL_F2F_WIDER(T) \ + T (_Float16, float) \ + T (_Float16, double) \ + T (float, double) + +/* FP -> narrower-FP */ +#define TEST_ALL_F2F_NARROWER(T) \ + T (float, _Float16) \ + T (double, _Float16) \ + T (double, float) + +TEST_ALL_F2F_WIDER (DEF_LOOP) +TEST_ALL_F2F_NARROWER (DEF_LOOP) diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_convert_float2float-2.h b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_convert_float2float-2.h new file mode 100644 index 000000000000..b084eaae19d4 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_convert_float2float-2.h @@ -0,0 +1,28 @@ +#include + +#define DEF_LOOP(OLD_TYPE, NEW_TYPE) \ + void __attribute__ ((noipa)) \ + test_##OLD_TYPE##_2_##NEW_TYPE (NEW_TYPE *__restrict r, \ + OLD_TYPE *__restrict a, NEW_TYPE b, \ + OLD_TYPE *__restrict pred, int n) \ + { \ + for (int i = 0; i < n; ++i) \ + { \ + r[i] = pred[i] ? (NEW_TYPE) a[i] : b; \ + } \ + } + +/* FP -> wider-FP */ +#define TEST_ALL_F2F_WIDER(T) \ + T (_Float16, float) \ + T (_Float16, double) \ + T (float, double) + +/* FP -> narrower-FP */ +#define TEST_ALL_F2F_NARROWER(T) \ + T (float, _Float16) \ + T (double, _Float16) \ + T (double, float) + +TEST_ALL_F2F_WIDER (DEF_LOOP) +TEST_ALL_F2F_NARROWER (DEF_LOOP) diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_convert_float2float-rv32-1.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_convert_float2float-rv32-1.c new file mode 100644 index 000000000000..bb4873befdab --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_convert_float2float-rv32-1.c @@ -0,0 +1,11 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-march=rv32gcv_zvfh -mabi=ilp32d --param riscv-autovec-preference=scalable -fno-vect-cost-model -ffast-math" } */ + +#include "cond_convert_float2float-1.h" + +/* { dg-final { scan-assembler-times {\tvfwcvt\.f\.f\.v\tv[0-9]+,v[0-9]+,v0\.t} 3 } } */ +/* { dg-final { scan-assembler-times {\tvfwcvt\.f\.f\.v\tv[0-9]+,v[0-9]+\n} 1 } } */ +/* { dg-final { scan-assembler-times {\tvfncvt\.f\.f\.w\tv[0-9]+,v[0-9]+,v0\.t} 3 } } */ +/* { dg-final { scan-assembler-times {\tvfncvt\.rod\.f\.f\.w\tv[0-9]+,v[0-9]+\n} 1 } } */ + +/* { dg-final { scan-assembler {\tvsetvli\t[a-z0-9]+,[a-z0-9]+,e[0-9]+,m[f0-9]+,t[au],mu} } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_convert_float2float-rv32-2.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_convert_float2float-rv32-2.c new file mode 100644 index 000000000000..4ec20e5ff23d --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_convert_float2float-rv32-2.c @@ -0,0 +1,11 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-march=rv32gcv_zvfh -mabi=ilp32d --param riscv-autovec-preference=scalable -fno-vect-cost-model -ffast-math" } */ + +#include "cond_convert_float2float-2.h" + +/* { dg-final { scan-assembler-times {\tvfwcvt\.f\.f\.v\tv[0-9]+,v[0-9]+,v0\.t} 3 } } */ +/* { dg-final { scan-assembler-times {\tvfwcvt\.f\.f\.v\tv[0-9]+,v[0-9]+\n} 1 } } */ +/* { dg-final { scan-assembler-times {\tvfncvt\.f\.f\.w\tv[0-9]+,v[0-9]+,v0\.t} 3 } } */ +/* { dg-final { scan-assembler-times {\tvfncvt\.rod\.f\.f\.w\tv[0-9]+,v[0-9]+\n} 1 } } */ + +/* { dg-final { scan-assembler {\tvsetvli\t[a-z0-9]+,[a-z0-9]+,e[0-9]+,m[f0-9]+,t[au],mu} } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_convert_float2float-rv64-1.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_convert_float2float-rv64-1.c new file mode 100644 index 000000000000..ec861fe16587 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_convert_float2float-rv64-1.c @@ -0,0 +1,11 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-march=rv64gcv_zvfh -mabi=lp64d --param riscv-autovec-preference=scalable -fno-vect-cost-model -ffast-math" } */ + +#include "cond_convert_float2float-1.h" + +/* { dg-final { scan-assembler-times {\tvfwcvt\.f\.f\.v\tv[0-9]+,v[0-9]+,v0\.t} 3 } } */ +/* { dg-final { scan-assembler-times {\tvfwcvt\.f\.f\.v\tv[0-9]+,v[0-9]+\n} 1 } } */ +/* { dg-final { scan-assembler-times {\tvfncvt\.f\.f\.w\tv[0-9]+,v[0-9]+,v0\.t} 3 } } */ +/* { dg-final { scan-assembler-times {\tvfncvt\.rod\.f\.f\.w\tv[0-9]+,v[0-9]+\n} 1 } } */ + +/* { dg-final { scan-assembler {\tvsetvli\t[a-z0-9]+,[a-z0-9]+,e[0-9]+,m[f0-9]+,t[au],mu} } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_convert_float2float-rv64-2.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_convert_float2float-rv64-2.c new file mode 100644 index 000000000000..455a4b369532 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_convert_float2float-rv64-2.c @@ -0,0 +1,11 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-march=rv64gcv_zvfh -mabi=lp64d --param riscv-autovec-preference=scalable -fno-vect-cost-model -ffast-math" } */ + +#include "cond_convert_float2float-2.h" + +/* { dg-final { scan-assembler-times {\tvfwcvt\.f\.f\.v\tv[0-9]+,v[0-9]+,v0\.t} 3 } } */ +/* { dg-final { scan-assembler-times {\tvfwcvt\.f\.f\.v\tv[0-9]+,v[0-9]+\n} 1 } } */ +/* { dg-final { scan-assembler-times {\tvfncvt\.f\.f\.w\tv[0-9]+,v[0-9]+,v0\.t} 3 } } */ +/* { dg-final { scan-assembler-times {\tvfncvt\.rod\.f\.f\.w\tv[0-9]+,v[0-9]+\n} 1 } } */ + +/* { dg-final { scan-assembler {\tvsetvli\t[a-z0-9]+,[a-z0-9]+,e[0-9]+,m[f0-9]+,t[au],mu} } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_convert_float2float_run-1.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_convert_float2float_run-1.c new file mode 100644 index 000000000000..407bbc27c2f9 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_convert_float2float_run-1.c @@ -0,0 +1,31 @@ +/* { dg-do run { target { riscv_vector } } } */ +/* { dg-additional-options "--param=riscv-autovec-preference=scalable -fno-vect-cost-model -ffast-math" } */ + +#include "cond_convert_float2float-1.h" + +#define N 99 + +#define TEST_LOOP(OLD_TYPE, NEW_TYPE) \ + { \ + NEW_TYPE r[N], b[N]; \ + OLD_TYPE a[N], pred[N]; \ + for (int i = 0; i < N; ++i) \ + { \ + a[i] = (i & 1 ? i : 3 * i) * (i % 3 == 0 ? 1 : -1); \ + b[i] = (i % 9) * (i % 7 + 1); \ + pred[i] = (i % 7 < 4); \ + asm volatile("" ::: "memory"); \ + } \ + test_##OLD_TYPE##_2_##NEW_TYPE (r, a, b, pred, N); \ + for (int i = 0; i < N; ++i) \ + if (r[i] != (pred[i] ? (NEW_TYPE) a[i] : b[i])) \ + __builtin_abort (); \ + } + +int +main () +{ + TEST_ALL_F2F_WIDER (TEST_LOOP) + TEST_ALL_F2F_NARROWER (TEST_LOOP) + return 0; +} diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_convert_float2float_run-2.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_convert_float2float_run-2.c new file mode 100644 index 000000000000..05d217da6252 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_convert_float2float_run-2.c @@ -0,0 +1,30 @@ +/* { dg-do run { target { riscv_vector } } } */ +/* { dg-additional-options "--param=riscv-autovec-preference=scalable -fno-vect-cost-model -ffast-math" } */ + +#include "cond_convert_float2float-2.h" + +#define N 99 + +#define TEST_LOOP(OLD_TYPE, NEW_TYPE) \ + { \ + NEW_TYPE r[N], b = 18.02; \ + OLD_TYPE a[N], pred[N]; \ + for (int i = 0; i < N; ++i) \ + { \ + a[i] = (i & 1 ? i : 3 * i) * (i % 3 == 0 ? 1 : -1); \ + pred[i] = (i % 7 < 4); \ + asm volatile("" ::: "memory"); \ + } \ + test_##OLD_TYPE##_2_##NEW_TYPE (r, a, b, pred, N); \ + for (int i = 0; i < N; ++i) \ + if (r[i] != (pred[i] ? (NEW_TYPE) a[i] : b)) \ + __builtin_abort (); \ + } + +int +main () +{ + TEST_ALL_F2F_WIDER (TEST_LOOP) + TEST_ALL_F2F_NARROWER (TEST_LOOP) + return 0; +} diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_convert_float2int-1.h b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_convert_float2int-1.h new file mode 100644 index 000000000000..2df68aa2d1ea --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_convert_float2int-1.h @@ -0,0 +1,51 @@ +#include + +#define DEF_LOOP(OLD_TYPE, NEW_TYPE) \ + void __attribute__ ((noipa)) \ + test_##OLD_TYPE##_2_##NEW_TYPE (NEW_TYPE *__restrict r, \ + OLD_TYPE *__restrict a, \ + NEW_TYPE *__restrict b, \ + OLD_TYPE *__restrict pred, int n) \ + { \ + for (int i = 0; i < n; ++i) \ + { \ + r[i] = pred[i] ? (NEW_TYPE) a[i] : b[i]; \ + } \ + } + +/* FP -> INT */ +#define TEST_ALL_F2X_SAME(T) \ + T (_Float16, uint16_t) \ + T (_Float16, int16_t) \ + T (float, uint32_t) \ + T (float, int32_t) \ + T (double, uint64_t) \ + T (double, int64_t) + +/* FP -> wider-INT */ +#define TEST_ALL_F2X_WIDER(T) \ + T (_Float16, uint32_t) \ + T (_Float16, int32_t) \ + T (_Float16, uint64_t) \ + T (_Float16, int64_t) \ + T (float, uint64_t) \ + T (float, int64_t) + +/* FP -> narrower-INT */ +#define TEST_ALL_F2X_NARROWER(T) \ + T (_Float16, uint8_t) \ + T (_Float16, int8_t) \ + T (float, uint8_t) \ + T (float, int8_t) \ + T (float, uint16_t) \ + T (float, int16_t) \ + T (double, uint8_t) \ + T (double, int8_t) \ + T (double, uint16_t) \ + T (double, int16_t) \ + T (double, uint32_t) \ + T (double, int32_t) + +TEST_ALL_F2X_SAME (DEF_LOOP) +TEST_ALL_F2X_WIDER (DEF_LOOP) +TEST_ALL_F2X_NARROWER (DEF_LOOP) diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_convert_float2int-2.h b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_convert_float2int-2.h new file mode 100644 index 000000000000..9735141faa11 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_convert_float2int-2.h @@ -0,0 +1,50 @@ +#include + +#define DEF_LOOP(OLD_TYPE, NEW_TYPE) \ + void __attribute__ ((noipa)) \ + test_##OLD_TYPE##_2_##NEW_TYPE (NEW_TYPE *__restrict r, \ + OLD_TYPE *__restrict a, NEW_TYPE b, \ + OLD_TYPE *__restrict pred, int n) \ + { \ + for (int i = 0; i < n; ++i) \ + { \ + r[i] = pred[i] ? (NEW_TYPE) a[i] : b; \ + } \ + } + +/* FP -> INT */ +#define TEST_ALL_F2X_SAME(T) \ + T (_Float16, uint16_t) \ + T (_Float16, int16_t) \ + T (float, uint32_t) \ + T (float, int32_t) \ + T (double, uint64_t) \ + T (double, int64_t) + +/* FP -> wider-INT */ +#define TEST_ALL_F2X_WIDER(T) \ + T (_Float16, uint32_t) \ + T (_Float16, int32_t) \ + T (_Float16, uint64_t) \ + T (_Float16, int64_t) \ + T (float, uint64_t) \ + T (float, int64_t) + +/* FP -> narrower-INT */ +#define TEST_ALL_F2X_NARROWER(T) \ + T (_Float16, uint8_t) \ + T (_Float16, int8_t) \ + T (float, uint8_t) \ + T (float, int8_t) \ + T (float, uint16_t) \ + T (float, int16_t) \ + T (double, uint8_t) \ + T (double, int8_t) \ + T (double, uint16_t) \ + T (double, int16_t) \ + T (double, uint32_t) \ + T (double, int32_t) + +TEST_ALL_F2X_SAME (DEF_LOOP) +TEST_ALL_F2X_WIDER (DEF_LOOP) +TEST_ALL_F2X_NARROWER (DEF_LOOP) diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_convert_float2int-rv32-1.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_convert_float2int-rv32-1.c new file mode 100644 index 000000000000..9dcbaa9b0a20 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_convert_float2int-rv32-1.c @@ -0,0 +1,17 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-march=rv32gcv_zvfh -mabi=ilp32d --param riscv-autovec-preference=scalable -fno-vect-cost-model -ffast-math" } */ + +#include "cond_convert_float2int-1.h" + +/* { dg-final { scan-assembler-times {\tvfcvt\.rtz\.xu\.f\.v\tv[0-9]+,v[0-9]+,v0\.t} 3 } } */ +/* { dg-final { scan-assembler-times {\tvfcvt\.rtz\.x\.f\.v\tv[0-9]+,v[0-9]+,v0\.t} 3 } } */ + +/* { dg-final { scan-assembler-times {\tvfwcvt\.rtz\.xu\.f\.v\tv[0-9]+,v[0-9]+,v0\.t} 2 } } */ +/* { dg-final { scan-assembler-times {\tvfwcvt\.rtz\.x\.f\.v\tv[0-9]+,v[0-9]+,v0\.t} 2 } } */ +/* { dg-final { scan-assembler-times {\tvfwcvt\.rtz\.x\.f\.v\tv[0-9]+,v[0-9]+\n} 2 } } */ + +/* { dg-final { scan-assembler-times {\tvfncvt\.rtz\.xu\.f\.w\tv[0-9]+,v[0-9]+,v0\.t} 3 } } */ +/* { dg-final { scan-assembler-times {\tvfncvt\.rtz\.x\.f\.w\tv[0-9]+,v[0-9]+,v0\.t} 3 } } */ +/* { dg-final { scan-assembler-times {\tvfncvt\.rtz\.x\.f\.w\tv[0-9]+,v[0-9]+\n} 6 } } */ + +/* { dg-final { scan-assembler {\tvsetvli\t[a-z0-9]+,[a-z0-9]+,e[0-9]+,m[f0-9]+,t[au],mu} } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_convert_float2int-rv32-2.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_convert_float2int-rv32-2.c new file mode 100644 index 000000000000..25d54247fede --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_convert_float2int-rv32-2.c @@ -0,0 +1,17 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-march=rv32gcv_zvfh -mabi=ilp32d --param riscv-autovec-preference=scalable -fno-vect-cost-model -ffast-math" } */ + +#include "cond_convert_float2int-2.h" + +/* { dg-final { scan-assembler-times {\tvfcvt\.rtz\.xu\.f\.v\tv[0-9]+,v[0-9]+,v0\.t} 3 } } */ +/* { dg-final { scan-assembler-times {\tvfcvt\.rtz\.x\.f\.v\tv[0-9]+,v[0-9]+,v0\.t} 3 } } */ + +/* { dg-final { scan-assembler-times {\tvfwcvt\.rtz\.xu\.f\.v\tv[0-9]+,v[0-9]+,v0\.t} 2 } } */ +/* { dg-final { scan-assembler-times {\tvfwcvt\.rtz\.x\.f\.v\tv[0-9]+,v[0-9]+,v0\.t} 2 } } */ +/* { dg-final { scan-assembler-times {\tvfwcvt\.rtz\.x\.f\.v\tv[0-9]+,v[0-9]+\n} 2 } } */ + +/* { dg-final { scan-assembler-times {\tvfncvt\.rtz\.xu\.f\.w\tv[0-9]+,v[0-9]+,v0\.t} 3 } } */ +/* { dg-final { scan-assembler-times {\tvfncvt\.rtz\.x\.f\.w\tv[0-9]+,v[0-9]+,v0\.t} 3 } } */ +/* { dg-final { scan-assembler-times {\tvfncvt\.rtz\.x\.f\.w\tv[0-9]+,v[0-9]+\n} 6 } } */ + +/* { dg-final { scan-assembler {\tvsetvli\t[a-z0-9]+,[a-z0-9]+,e[0-9]+,m[f0-9]+,t[au],mu} } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_convert_float2int-rv64-1.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_convert_float2int-rv64-1.c new file mode 100644 index 000000000000..495f4b56a4d3 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_convert_float2int-rv64-1.c @@ -0,0 +1,17 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-march=rv64gcv_zvfh -mabi=lp64d --param riscv-autovec-preference=scalable -fno-vect-cost-model -ffast-math" } */ + +#include "cond_convert_float2int-1.h" + +/* { dg-final { scan-assembler-times {\tvfcvt\.rtz\.xu\.f\.v\tv[0-9]+,v[0-9]+,v0\.t} 3 } } */ +/* { dg-final { scan-assembler-times {\tvfcvt\.rtz\.x\.f\.v\tv[0-9]+,v[0-9]+,v0\.t} 3 } } */ + +/* { dg-final { scan-assembler-times {\tvfwcvt\.rtz\.xu\.f\.v\tv[0-9]+,v[0-9]+,v0\.t} 2 } } */ +/* { dg-final { scan-assembler-times {\tvfwcvt\.rtz\.x\.f\.v\tv[0-9]+,v[0-9]+,v0\.t} 2 } } */ +/* { dg-final { scan-assembler-times {\tvfwcvt\.rtz\.x\.f\.v\tv[0-9]+,v[0-9]+\n} 2 } } */ + +/* { dg-final { scan-assembler-times {\tvfncvt\.rtz\.xu\.f\.w\tv[0-9]+,v[0-9]+,v0\.t} 3 } } */ +/* { dg-final { scan-assembler-times {\tvfncvt\.rtz\.x\.f\.w\tv[0-9]+,v[0-9]+,v0\.t} 3 } } */ +/* { dg-final { scan-assembler-times {\tvfncvt\.rtz\.x\.f\.w\tv[0-9]+,v[0-9]+\n} 6 } } */ + +/* { dg-final { scan-assembler {\tvsetvli\t[a-z0-9]+,[a-z0-9]+,e[0-9]+,m[f0-9]+,t[au],mu} } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_convert_float2int-rv64-2.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_convert_float2int-rv64-2.c new file mode 100644 index 000000000000..520c9df2dfb4 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_convert_float2int-rv64-2.c @@ -0,0 +1,17 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-march=rv64gcv_zvfh -mabi=lp64d --param riscv-autovec-preference=scalable -fno-vect-cost-model -ffast-math" } */ + +#include "cond_convert_float2int-2.h" + +/* { dg-final { scan-assembler-times {\tvfcvt\.rtz\.xu\.f\.v\tv[0-9]+,v[0-9]+,v0\.t} 3 } } */ +/* { dg-final { scan-assembler-times {\tvfcvt\.rtz\.x\.f\.v\tv[0-9]+,v[0-9]+,v0\.t} 3 } } */ + +/* { dg-final { scan-assembler-times {\tvfwcvt\.rtz\.xu\.f\.v\tv[0-9]+,v[0-9]+,v0\.t} 2 } } */ +/* { dg-final { scan-assembler-times {\tvfwcvt\.rtz\.x\.f\.v\tv[0-9]+,v[0-9]+,v0\.t} 2 } } */ +/* { dg-final { scan-assembler-times {\tvfwcvt\.rtz\.x\.f\.v\tv[0-9]+,v[0-9]+\n} 2 } } */ + +/* { dg-final { scan-assembler-times {\tvfncvt\.rtz\.xu\.f\.w\tv[0-9]+,v[0-9]+,v0\.t} 3 } } */ +/* { dg-final { scan-assembler-times {\tvfncvt\.rtz\.x\.f\.w\tv[0-9]+,v[0-9]+,v0\.t} 3 } } */ +/* { dg-final { scan-assembler-times {\tvfncvt\.rtz\.x\.f\.w\tv[0-9]+,v[0-9]+\n} 6 } } */ + +/* { dg-final { scan-assembler {\tvsetvli\t[a-z0-9]+,[a-z0-9]+,e[0-9]+,m[f0-9]+,t[au],mu} } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_convert_float2int_run-1.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_convert_float2int_run-1.c new file mode 100644 index 000000000000..65b54bb3c83e --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_convert_float2int_run-1.c @@ -0,0 +1,32 @@ +/* { dg-do run { target { riscv_vector } } } */ +/* { dg-additional-options "--param=riscv-autovec-preference=scalable -fno-vect-cost-model" } */ + +#include "cond_convert_float2int-1.h" + +#define N 99 + +#define TEST_LOOP(OLD_TYPE, NEW_TYPE) \ + { \ + NEW_TYPE r[N], b[N]; \ + OLD_TYPE a[N], pred[N]; \ + for (int i = 0; i < N; ++i) \ + { \ + a[i] = (i & 1 ? i : 3 * i) * (i % 3 == 0 ? 1 : -1); \ + b[i] = (i % 9) * (i % 7 + 1); \ + pred[i] = (i % 7 < 4); \ + asm volatile("" ::: "memory"); \ + } \ + test_##OLD_TYPE##_2_##NEW_TYPE (r, a, b, pred, N); \ + for (int i = 0; i < N; ++i) \ + if (r[i] != (pred[i] ? (NEW_TYPE) a[i] : b[i])) \ + __builtin_abort (); \ + } + +int +main () +{ + TEST_ALL_F2X_SAME (TEST_LOOP) + TEST_ALL_F2X_WIDER (TEST_LOOP) + TEST_ALL_F2X_NARROWER (TEST_LOOP) + return 0; +} diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_convert_float2int_run-2.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_convert_float2int_run-2.c new file mode 100644 index 000000000000..030ea2c19642 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_convert_float2int_run-2.c @@ -0,0 +1,31 @@ +/* { dg-do run { target { riscv_vector } } } */ +/* { dg-additional-options "--param=riscv-autovec-preference=scalable -fno-vect-cost-model" } */ + +#include "cond_convert_float2int-2.h" + +#define N 99 + +#define TEST_LOOP(OLD_TYPE, NEW_TYPE) \ + { \ + NEW_TYPE r[N], b = 192; \ + OLD_TYPE a[N], pred[N]; \ + for (int i = 0; i < N; ++i) \ + { \ + a[i] = (i & 1 ? i : 3 * i) * (i % 3 == 0 ? 1 : -1); \ + pred[i] = (i % 7 < 4); \ + asm volatile("" ::: "memory"); \ + } \ + test_##OLD_TYPE##_2_##NEW_TYPE (r, a, b, pred, N); \ + for (int i = 0; i < N; ++i) \ + if (r[i] != (pred[i] ? (NEW_TYPE) a[i] : b)) \ + __builtin_abort (); \ + } + +int +main () +{ + TEST_ALL_F2X_SAME (TEST_LOOP) + TEST_ALL_F2X_WIDER (TEST_LOOP) + TEST_ALL_F2X_NARROWER (TEST_LOOP) + return 0; +} diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_convert_int2float-1.h b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_convert_int2float-1.h new file mode 100644 index 000000000000..5b0baeece41c --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_convert_int2float-1.h @@ -0,0 +1,45 @@ +#include + +#define DEF_LOOP(OLD_TYPE, NEW_TYPE) \ + void __attribute__ ((noipa)) \ + test_##OLD_TYPE##_2_##NEW_TYPE (NEW_TYPE *__restrict r, \ + OLD_TYPE *__restrict a, \ + NEW_TYPE *__restrict b, \ + OLD_TYPE *__restrict pred, int n) \ + { \ + for (int i = 0; i < n; ++i) \ + { \ + r[i] = pred[i] ? (NEW_TYPE) a[i] : b[i]; \ + } \ + } + +/* INT -> FP */ +#define TEST_ALL_X2F_SAME(T) \ + T (uint16_t, _Float16) \ + T (int16_t, _Float16) \ + T (uint32_t, float) \ + T (int32_t, float) \ + T (uint64_t, double) \ + T (int64_t, double) + +/* INT -> wider-FP */ +#define TEST_ALL_X2F_WIDER(T) \ + T (uint16_t, float) \ + T (int16_t, float) \ + T (uint16_t, double) \ + T (int16_t, double) \ + T (uint32_t, double) \ + T (int32_t, double) + +/* INT -> narrower-FP */ +#define TEST_ALL_X2F_NARROWER(T) \ + T (uint32_t, _Float16) \ + T (int32_t, _Float16) \ + T (uint64_t, _Float16) \ + T (int64_t, _Float16) \ + T (uint64_t, float) \ + T (int64_t, float) + +TEST_ALL_X2F_SAME (DEF_LOOP) +TEST_ALL_X2F_WIDER (DEF_LOOP) +TEST_ALL_X2F_NARROWER (DEF_LOOP) diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_convert_int2float-2.h b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_convert_int2float-2.h new file mode 100644 index 000000000000..2177c946de89 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_convert_int2float-2.h @@ -0,0 +1,44 @@ +#include + +#define DEF_LOOP(OLD_TYPE, NEW_TYPE) \ + void __attribute__ ((noipa)) \ + test_##OLD_TYPE##_2_##NEW_TYPE (NEW_TYPE *__restrict r, \ + OLD_TYPE *__restrict a, NEW_TYPE b, \ + OLD_TYPE *__restrict pred, int n) \ + { \ + for (int i = 0; i < n; ++i) \ + { \ + r[i] = pred[i] ? (NEW_TYPE) a[i] : b; \ + } \ + } + +/* INT -> FP */ +#define TEST_ALL_X2F_SAME(T) \ + T (uint16_t, _Float16) \ + T (int16_t, _Float16) \ + T (uint32_t, float) \ + T (int32_t, float) \ + T (uint64_t, double) \ + T (int64_t, double) + +/* INT -> wider-FP */ +#define TEST_ALL_X2F_WIDER(T) \ + T (uint16_t, float) \ + T (int16_t, float) \ + T (uint16_t, double) \ + T (int16_t, double) \ + T (uint32_t, double) \ + T (int32_t, double) + +/* INT -> narrower-FP */ +#define TEST_ALL_X2F_NARROWER(T) \ + T (uint32_t, _Float16) \ + T (int32_t, _Float16) \ + T (uint64_t, _Float16) \ + T (int64_t, _Float16) \ + T (uint64_t, float) \ + T (int64_t, float) + +TEST_ALL_X2F_SAME (DEF_LOOP) +TEST_ALL_X2F_WIDER (DEF_LOOP) +TEST_ALL_X2F_NARROWER (DEF_LOOP) diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_convert_int2float-rv32-1.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_convert_int2float-rv32-1.c new file mode 100644 index 000000000000..f5d3bb4c7894 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_convert_int2float-rv32-1.c @@ -0,0 +1,15 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-march=rv32gcv_zvfh -mabi=ilp32d --param riscv-autovec-preference=scalable -fno-vect-cost-model -ffast-math" } */ + +#include "cond_convert_int2float-2.h" + +/* { dg-final { scan-assembler-times {\tvfcvt\.f\.xu\.v\tv[0-9]+,v[0-9]+,v0\.t} 3 } } */ +/* { dg-final { scan-assembler-times {\tvfcvt\.f\.x\.v\tv[0-9]+,v[0-9]+,v0\.t} 3 } } */ + +/* { dg-final { scan-assembler-times {\tvfwcvt\.f\.xu\.v\tv[0-9]+,v[0-9]+,v0\.t} 2 } } */ +/* { dg-final { scan-assembler-times {\tvfwcvt\.f\.x\.v\tv[0-9]+,v[0-9]+,v0\.t} 4 } } */ + +/* { dg-final { scan-assembler-times {\tvfncvt\.f\.xu\.w\tv[0-9]+,v[0-9]+,v0\.t} 2 } } */ +/* { dg-final { scan-assembler-times {\tvfncvt\.f\.x\.w\tv[0-9]+,v[0-9]+,v0\.t} 2 } } */ + +/* { dg-final { scan-assembler {\tvsetvli\t[a-z0-9]+,[a-z0-9]+,e[0-9]+,m[f0-9]+,t[au],mu} } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_convert_int2float-rv32-2.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_convert_int2float-rv32-2.c new file mode 100644 index 000000000000..f5d3bb4c7894 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_convert_int2float-rv32-2.c @@ -0,0 +1,15 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-march=rv32gcv_zvfh -mabi=ilp32d --param riscv-autovec-preference=scalable -fno-vect-cost-model -ffast-math" } */ + +#include "cond_convert_int2float-2.h" + +/* { dg-final { scan-assembler-times {\tvfcvt\.f\.xu\.v\tv[0-9]+,v[0-9]+,v0\.t} 3 } } */ +/* { dg-final { scan-assembler-times {\tvfcvt\.f\.x\.v\tv[0-9]+,v[0-9]+,v0\.t} 3 } } */ + +/* { dg-final { scan-assembler-times {\tvfwcvt\.f\.xu\.v\tv[0-9]+,v[0-9]+,v0\.t} 2 } } */ +/* { dg-final { scan-assembler-times {\tvfwcvt\.f\.x\.v\tv[0-9]+,v[0-9]+,v0\.t} 4 } } */ + +/* { dg-final { scan-assembler-times {\tvfncvt\.f\.xu\.w\tv[0-9]+,v[0-9]+,v0\.t} 2 } } */ +/* { dg-final { scan-assembler-times {\tvfncvt\.f\.x\.w\tv[0-9]+,v[0-9]+,v0\.t} 2 } } */ + +/* { dg-final { scan-assembler {\tvsetvli\t[a-z0-9]+,[a-z0-9]+,e[0-9]+,m[f0-9]+,t[au],mu} } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_convert_int2float-rv64-1.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_convert_int2float-rv64-1.c new file mode 100644 index 000000000000..5ebed2f7fdcd --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_convert_int2float-rv64-1.c @@ -0,0 +1,15 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-march=rv64gcv_zvfh -mabi=lp64d --param riscv-autovec-preference=scalable -fno-vect-cost-model -ffast-math" } */ + +#include "cond_convert_int2float-1.h" + +/* { dg-final { scan-assembler-times {\tvfcvt\.f\.xu\.v\tv[0-9]+,v[0-9]+,v0\.t} 3 } } */ +/* { dg-final { scan-assembler-times {\tvfcvt\.f\.x\.v\tv[0-9]+,v[0-9]+,v0\.t} 3 } } */ + +/* { dg-final { scan-assembler-times {\tvfwcvt\.f\.xu\.v\tv[0-9]+,v[0-9]+,v0\.t} 2 } } */ +/* { dg-final { scan-assembler-times {\tvfwcvt\.f\.x\.v\tv[0-9]+,v[0-9]+,v0\.t} 4 } } */ + +/* { dg-final { scan-assembler-times {\tvfncvt\.f\.xu\.w\tv[0-9]+,v[0-9]+,v0\.t} 2 } } */ +/* { dg-final { scan-assembler-times {\tvfncvt\.f\.x\.w\tv[0-9]+,v[0-9]+,v0\.t} 2 } } */ + +/* { dg-final { scan-assembler {\tvsetvli\t[a-z0-9]+,[a-z0-9]+,e[0-9]+,m[f0-9]+,t[au],mu} } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_convert_int2float-rv64-2.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_convert_int2float-rv64-2.c new file mode 100644 index 000000000000..097e377f1077 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_convert_int2float-rv64-2.c @@ -0,0 +1,15 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-march=rv64gcv_zvfh -mabi=lp64d --param riscv-autovec-preference=scalable -fno-vect-cost-model -ffast-math" } */ + +#include "cond_convert_int2float-2.h" + +/* { dg-final { scan-assembler-times {\tvfcvt\.f\.xu\.v\tv[0-9]+,v[0-9]+,v0\.t} 3 } } */ +/* { dg-final { scan-assembler-times {\tvfcvt\.f\.x\.v\tv[0-9]+,v[0-9]+,v0\.t} 3 } } */ + +/* { dg-final { scan-assembler-times {\tvfwcvt\.f\.xu\.v\tv[0-9]+,v[0-9]+,v0\.t} 2 } } */ +/* { dg-final { scan-assembler-times {\tvfwcvt\.f\.x\.v\tv[0-9]+,v[0-9]+,v0\.t} 4 } } */ + +/* { dg-final { scan-assembler-times {\tvfncvt\.f\.xu\.w\tv[0-9]+,v[0-9]+,v0\.t} 2 } } */ +/* { dg-final { scan-assembler-times {\tvfncvt\.f\.x\.w\tv[0-9]+,v[0-9]+,v0\.t} 2 } } */ + +/* { dg-final { scan-assembler {\tvsetvli\t[a-z0-9]+,[a-z0-9]+,e[0-9]+,m[f0-9]+,t[au],mu} } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_convert_int2float_run-1.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_convert_int2float_run-1.c new file mode 100644 index 000000000000..10bc06757c13 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_convert_int2float_run-1.c @@ -0,0 +1,32 @@ +/* { dg-do run { target { riscv_vector } } } */ +/* { dg-additional-options "--param=riscv-autovec-preference=scalable -fno-vect-cost-model" } */ + +#include "cond_convert_int2float-1.h" + +#define N 99 + +#define TEST_LOOP(OLD_TYPE, NEW_TYPE) \ + { \ + NEW_TYPE r[N], b[N]; \ + OLD_TYPE a[N], pred[N]; \ + for (int i = 0; i < N; ++i) \ + { \ + a[i] = (i & 1 ? i : 3 * i) * (i % 3 == 0 ? 1 : -1); \ + b[i] = (i % 9) * (i % 7 + 1); \ + pred[i] = (i % 7 < 4); \ + asm volatile("" ::: "memory"); \ + } \ + test_##OLD_TYPE##_2_##NEW_TYPE (r, a, b, pred, N); \ + for (int i = 0; i < N; ++i) \ + if (r[i] != (pred[i] ? (NEW_TYPE) a[i] : b[i])) \ + __builtin_abort (); \ + } + +int +main () +{ + TEST_ALL_X2F_SAME (TEST_LOOP) + TEST_ALL_X2F_WIDER (TEST_LOOP) + TEST_ALL_X2F_NARROWER (TEST_LOOP) + return 0; +} diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_convert_int2float_run-2.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_convert_int2float_run-2.c new file mode 100644 index 000000000000..08d27e6dca19 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_convert_int2float_run-2.c @@ -0,0 +1,31 @@ +/* { dg-do run { target { riscv_vector } } } */ +/* { dg-additional-options "--param=riscv-autovec-preference=scalable -fno-vect-cost-model" } */ + +#include "cond_convert_int2float-2.h" + +#define N 99 + +#define TEST_LOOP(OLD_TYPE, NEW_TYPE) \ + { \ + NEW_TYPE r[N], b = 192.12; \ + OLD_TYPE a[N], pred[N]; \ + for (int i = 0; i < N; ++i) \ + { \ + a[i] = (i & 1 ? i : 3 * i) * (i % 3 == 0 ? 1 : -1); \ + pred[i] = (i % 7 < 4); \ + asm volatile("" ::: "memory"); \ + } \ + test_##OLD_TYPE##_2_##NEW_TYPE (r, a, b, pred, N); \ + for (int i = 0; i < N; ++i) \ + if (r[i] != (pred[i] ? (NEW_TYPE) a[i] : b)) \ + __builtin_abort (); \ + } + +int +main () +{ + TEST_ALL_X2F_SAME (TEST_LOOP) + TEST_ALL_X2F_WIDER (TEST_LOOP) + TEST_ALL_X2F_NARROWER (TEST_LOOP) + return 0; +} diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_convert_int2int-1.h b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_convert_int2int-1.h new file mode 100644 index 000000000000..c8ef6df399d8 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_convert_int2int-1.h @@ -0,0 +1,47 @@ +#include + +#define DEF_LOOP(OLD_TYPE, NEW_TYPE) \ + void __attribute__ ((noipa)) \ + test_##OLD_TYPE##_2_##NEW_TYPE (NEW_TYPE *__restrict r, \ + OLD_TYPE *__restrict a, \ + NEW_TYPE *__restrict b, \ + OLD_TYPE *__restrict pred, int n) \ + { \ + for (int i = 0; i < n; ++i) \ + { \ + r[i] = pred[i] ? (NEW_TYPE) a[i] : b[i]; \ + } \ + } + +/* INT -> wider-INT */ +#define TEST_ALL_X2X_WIDER(T) \ + T (uint8_t, uint16_t) \ + T (uint8_t, uint32_t) \ + T (uint8_t, uint64_t) \ + T (int8_t, int16_t) \ + T (int8_t, int32_t) \ + T (int8_t, int64_t) \ + T (uint16_t, uint32_t) \ + T (uint16_t, uint64_t) \ + T (int16_t, int32_t) \ + T (int16_t, int64_t) \ + T (uint32_t, uint64_t) \ + T (int32_t, int64_t) + +/* INT -> narrower-INT */ +#define TEST_ALL_X2X_NARROWER(T) \ + T (uint16_t, uint8_t) \ + T (int16_t, int8_t) \ + T (uint32_t, uint8_t) \ + T (int32_t, int8_t) \ + T (uint64_t, uint8_t) \ + T (int64_t, int8_t) \ + T (uint32_t, uint16_t) \ + T (int32_t, int16_t) \ + T (uint64_t, uint16_t) \ + T (int64_t, int16_t) \ + T (uint64_t, uint32_t) \ + T (int64_t, int32_t) + +TEST_ALL_X2X_WIDER (DEF_LOOP) +TEST_ALL_X2X_NARROWER (DEF_LOOP) diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_convert_int2int-2.h b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_convert_int2int-2.h new file mode 100644 index 000000000000..f53c1b3fde93 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_convert_int2int-2.h @@ -0,0 +1,46 @@ +#include + +#define DEF_LOOP(OLD_TYPE, NEW_TYPE) \ + void __attribute__ ((noipa)) \ + test_##OLD_TYPE##_2_##NEW_TYPE (NEW_TYPE *__restrict r, \ + OLD_TYPE *__restrict a, NEW_TYPE b, \ + OLD_TYPE *__restrict pred, int n) \ + { \ + for (int i = 0; i < n; ++i) \ + { \ + r[i] = pred[i] ? (NEW_TYPE) a[i] : b; \ + } \ + } + +/* INT -> wider-INT */ +#define TEST_ALL_X2X_WIDER(T) \ + T (uint8_t, uint16_t) \ + T (uint8_t, uint32_t) \ + T (uint8_t, uint64_t) \ + T (int8_t, int16_t) \ + T (int8_t, int32_t) \ + T (int8_t, int64_t) \ + T (uint16_t, uint32_t) \ + T (uint16_t, uint64_t) \ + T (int16_t, int32_t) \ + T (int16_t, int64_t) \ + T (uint32_t, uint64_t) \ + T (int32_t, int64_t) + +/* INT -> narrower-INT */ +#define TEST_ALL_X2X_NARROWER(T) \ + T (uint16_t, uint8_t) \ + T (int16_t, int8_t) \ + T (uint32_t, uint8_t) \ + T (int32_t, int8_t) \ + T (uint64_t, uint8_t) \ + T (int64_t, int8_t) \ + T (uint32_t, uint16_t) \ + T (int32_t, int16_t) \ + T (uint64_t, uint16_t) \ + T (int64_t, int16_t) \ + T (uint64_t, uint32_t) \ + T (int64_t, int32_t) + +TEST_ALL_X2X_WIDER (DEF_LOOP) +TEST_ALL_X2X_NARROWER (DEF_LOOP) diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_convert_int2int-rv32-1.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_convert_int2int-rv32-1.c new file mode 100644 index 000000000000..8c07e427560b --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_convert_int2int-rv32-1.c @@ -0,0 +1,17 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-march=rv32gcv_zvfh -mabi=ilp32d --param riscv-autovec-preference=scalable -fno-vect-cost-model" } */ + +#include "cond_convert_int2int-1.h" + +/* { dg-final { scan-assembler-times {\tvzext\.vf2\tv[0-9]+,v[0-9]+,v0\.t} 3 } } */ +/* { dg-final { scan-assembler-times {\tvsext\.vf2\tv[0-9]+,v[0-9]+,v0\.t} 3 } } */ +/* { dg-final { scan-assembler-times {\tvzext\.vf4\tv[0-9]+,v[0-9]+,v0\.t} 2 } } */ +/* { dg-final { scan-assembler-times {\tvsext\.vf4\tv[0-9]+,v[0-9]+,v0\.t} 2 } } */ +/* { dg-final { scan-assembler-times {\tvzext\.vf8\tv[0-9]+,v[0-9]+,v0\.t} 1 } } */ +/* { dg-final { scan-assembler-times {\tvsext\.vf8\tv[0-9]+,v[0-9]+,v0\.t} 1 } } */ + +/* { dg-final { scan-assembler-times {\tvncvt\.x\.x\.w\tv[0-9]+,v[0-9]+,v0\.t} 12 } } */ +/* { dg-final { scan-assembler-times {\tvncvt\.x\.x\.w\tv[0-9]+,v[0-9]+\n} 8 } } */ + +/* { dg-final { scan-assembler {\tvsetvli\t[a-z0-9]+,[a-z0-9]+,e[0-9]+,m[f0-9]+,t[au],mu} } } */ + diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_convert_int2int-rv32-2.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_convert_int2int-rv32-2.c new file mode 100644 index 000000000000..74490cdc055d --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_convert_int2int-rv32-2.c @@ -0,0 +1,16 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-march=rv32gcv_zvfh -mabi=ilp32d --param riscv-autovec-preference=scalable -fno-vect-cost-model" } */ + +#include "cond_convert_int2int-2.h" + +/* { dg-final { scan-assembler-times {\tvzext\.vf2\tv[0-9]+,v[0-9]+,v0\.t} 3 } } */ +/* { dg-final { scan-assembler-times {\tvsext\.vf2\tv[0-9]+,v[0-9]+,v0\.t} 3 } } */ +/* { dg-final { scan-assembler-times {\tvzext\.vf4\tv[0-9]+,v[0-9]+,v0\.t} 2 } } */ +/* { dg-final { scan-assembler-times {\tvsext\.vf4\tv[0-9]+,v[0-9]+,v0\.t} 2 } } */ +/* { dg-final { scan-assembler-times {\tvzext\.vf8\tv[0-9]+,v[0-9]+,v0\.t} 1 } } */ +/* { dg-final { scan-assembler-times {\tvsext\.vf8\tv[0-9]+,v[0-9]+,v0\.t} 1 } } */ + +/* { dg-final { scan-assembler-times {\tvncvt\.x\.x\.w\tv[0-9]+,v[0-9]+,v0\.t} 12 } } */ +/* { dg-final { scan-assembler-times {\tvncvt\.x\.x\.w\tv[0-9]+,v[0-9]+\n} 8 } } */ + +/* { dg-final { scan-assembler {\tvsetvli\t[a-z0-9]+,[a-z0-9]+,e[0-9]+,m[f0-9]+,t[au],mu} } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_convert_int2int-rv64-1.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_convert_int2int-rv64-1.c new file mode 100644 index 000000000000..00357966ba6c --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_convert_int2int-rv64-1.c @@ -0,0 +1,16 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-march=rv64gcv_zvfh -mabi=lp64d --param riscv-autovec-preference=scalable -fno-vect-cost-model" } */ + +#include "cond_convert_int2int-1.h" + +/* { dg-final { scan-assembler-times {\tvzext\.vf2\tv[0-9]+,v[0-9]+,v0\.t} 3 } } */ +/* { dg-final { scan-assembler-times {\tvsext\.vf2\tv[0-9]+,v[0-9]+,v0\.t} 3 } } */ +/* { dg-final { scan-assembler-times {\tvzext\.vf4\tv[0-9]+,v[0-9]+,v0\.t} 2 } } */ +/* { dg-final { scan-assembler-times {\tvsext\.vf4\tv[0-9]+,v[0-9]+,v0\.t} 2 } } */ +/* { dg-final { scan-assembler-times {\tvzext\.vf8\tv[0-9]+,v[0-9]+,v0\.t} 1 } } */ +/* { dg-final { scan-assembler-times {\tvsext\.vf8\tv[0-9]+,v[0-9]+,v0\.t} 1 } } */ + +/* { dg-final { scan-assembler-times {\tvncvt\.x\.x\.w\tv[0-9]+,v[0-9]+,v0\.t} 12 } } */ +/* { dg-final { scan-assembler-times {\tvncvt\.x\.x\.w\tv[0-9]+,v[0-9]+\n} 8 } } */ + +/* { dg-final { scan-assembler {\tvsetvli\t[a-z0-9]+,[a-z0-9]+,e[0-9]+,m[f0-9]+,t[au],mu} } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_convert_int2int-rv64-2.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_convert_int2int-rv64-2.c new file mode 100644 index 000000000000..3c4ad9c4f665 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_convert_int2int-rv64-2.c @@ -0,0 +1,16 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-march=rv64gcv_zvfh -mabi=lp64d --param riscv-autovec-preference=scalable -fno-vect-cost-model" } */ + +#include "cond_convert_int2int-2.h" + +/* { dg-final { scan-assembler-times {\tvzext\.vf2\tv[0-9]+,v[0-9]+,v0\.t} 3 } } */ +/* { dg-final { scan-assembler-times {\tvsext\.vf2\tv[0-9]+,v[0-9]+,v0\.t} 3 } } */ +/* { dg-final { scan-assembler-times {\tvzext\.vf4\tv[0-9]+,v[0-9]+,v0\.t} 2 } } */ +/* { dg-final { scan-assembler-times {\tvsext\.vf4\tv[0-9]+,v[0-9]+,v0\.t} 2 } } */ +/* { dg-final { scan-assembler-times {\tvzext\.vf8\tv[0-9]+,v[0-9]+,v0\.t} 1 } } */ +/* { dg-final { scan-assembler-times {\tvsext\.vf8\tv[0-9]+,v[0-9]+,v0\.t} 1 } } */ + +/* { dg-final { scan-assembler-times {\tvncvt\.x\.x\.w\tv[0-9]+,v[0-9]+,v0\.t} 12 } } */ +/* { dg-final { scan-assembler-times {\tvncvt\.x\.x\.w\tv[0-9]+,v[0-9]+\n} 8 } } */ + +/* { dg-final { scan-assembler {\tvsetvli\t[a-z0-9]+,[a-z0-9]+,e[0-9]+,m[f0-9]+,t[au],mu} } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_convert_int2int_run-1.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_convert_int2int_run-1.c new file mode 100644 index 000000000000..04f24168a38a --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_convert_int2int_run-1.c @@ -0,0 +1,31 @@ +/* { dg-do run { target { riscv_vector } } } */ +/* { dg-additional-options "--param=riscv-autovec-preference=scalable -fno-vect-cost-model" } */ + +#include "cond_convert_int2int-1.h" + +#define N 99 + +#define TEST_LOOP(OLD_TYPE, NEW_TYPE) \ + { \ + NEW_TYPE r[N], b[N]; \ + OLD_TYPE a[N], pred[N]; \ + for (int i = 0; i < N; ++i) \ + { \ + a[i] = (i & 1 ? i : 3 * i) * (i % 3 == 0 ? 1 : -1); \ + b[i] = (i % 9) * (i % 7 + 1); \ + pred[i] = (i % 7 < 4); \ + asm volatile("" ::: "memory"); \ + } \ + test_##OLD_TYPE##_2_##NEW_TYPE (r, a, b, pred, N); \ + for (int i = 0; i < N; ++i) \ + if (r[i] != (pred[i] ? (NEW_TYPE) a[i] : b[i])) \ + __builtin_abort (); \ + } + +int +main () +{ + TEST_ALL_X2X_WIDER (TEST_LOOP) + TEST_ALL_X2X_NARROWER (TEST_LOOP) + return 0; +} diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_convert_int2int_run-2.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_convert_int2int_run-2.c new file mode 100644 index 000000000000..7a6897bf029d --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_convert_int2int_run-2.c @@ -0,0 +1,30 @@ +/* { dg-do run { target { riscv_vector } } } */ +/* { dg-additional-options "--param=riscv-autovec-preference=scalable -fno-vect-cost-model" } */ + +#include "cond_convert_int2int-2.h" + +#define N 99 + +#define TEST_LOOP(OLD_TYPE, NEW_TYPE) \ + { \ + NEW_TYPE r[N], b = 189; \ + OLD_TYPE a[N], pred[N]; \ + for (int i = 0; i < N; ++i) \ + { \ + a[i] = (i & 1 ? i : 3 * i) * (i % 3 == 0 ? 1 : -1); \ + pred[i] = (i % 7 < 4); \ + asm volatile("" ::: "memory"); \ + } \ + test_##OLD_TYPE##_2_##NEW_TYPE (r, a, b, pred, N); \ + for (int i = 0; i < N; ++i) \ + if (r[i] != (pred[i] ? (NEW_TYPE) a[i] : b)) \ + __builtin_abort (); \ + } + +int +main () +{ + TEST_ALL_X2X_WIDER (TEST_LOOP) + TEST_ALL_X2X_NARROWER (TEST_LOOP) + return 0; +} diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fadd-1.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fadd-1.c new file mode 100644 index 000000000000..c9d14f27e5dd --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fadd-1.c @@ -0,0 +1,32 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-march=rv32gcv_zvfh -mabi=ilp32d --param=riscv-autovec-preference=scalable -fno-vect-cost-model" } */ + +#include + +#define DEF_LOOP(TYPE, PRED_TYPE, NAME, CONST) \ + void __attribute__ ((noipa)) \ + test_##TYPE##_##NAME (TYPE *__restrict x, \ + TYPE *__restrict y, \ + PRED_TYPE *__restrict pred, \ + int n) \ + { \ + for (int i = 0; i < n; ++i) \ + x[i] = pred[i] != 1 ? y[i] + (TYPE) CONST : y[i]; \ + } + +#define TEST_TYPE(T, TYPE, PRED_TYPE) \ + T (TYPE, PRED_TYPE, half, 0.5) \ + T (TYPE, PRED_TYPE, one, 1.0) \ + T (TYPE, PRED_TYPE, two, 2.0) \ + T (TYPE, PRED_TYPE, minus_half, -0.5) \ + T (TYPE, PRED_TYPE, minus_one, -1.0) \ + T (TYPE, PRED_TYPE, minus_two, -2.0) + +#define TEST_ALL(T) \ + TEST_TYPE (T, _Float16, int16_t) \ + TEST_TYPE (T, float, int32_t) \ + TEST_TYPE (T, double, int64_t) + +TEST_ALL (DEF_LOOP) + +/* { dg-final { scan-assembler-times {vfadd\.vv\s+v[0-9]+,v[0-9]+,v[0-9]+,v0.t} 18 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fadd-2.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fadd-2.c new file mode 100644 index 000000000000..21f9f9f91078 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fadd-2.c @@ -0,0 +1,31 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-march=rv32gcv_zvfh -mabi=ilp32d --param=riscv-autovec-preference=scalable -fno-vect-cost-model" } */ + +#include + +#define DEF_LOOP(TYPE, NAME, CONST) \ + void __attribute__ ((noipa)) \ + test_##TYPE##_##NAME (TYPE *__restrict x, \ + TYPE *__restrict y, \ + TYPE *__restrict z, \ + int n) \ + { \ + for (int i = 0; i < n; ++i) \ + x[i] = y[i] < 8 ? z[i] + (TYPE) CONST : y[i]; \ + } + +#define TEST_TYPE(T, TYPE) \ + T (TYPE, half, 0.5) \ + T (TYPE, one, 1.0) \ + T (TYPE, two, 2.0) \ + T (TYPE, minus_half, -0.5) \ + T (TYPE, minus_one, -1.0) \ + T (TYPE, minus_two, -2.0) + +#define TEST_ALL(T) \ + TEST_TYPE (T, float) \ + TEST_TYPE (T, double) + +TEST_ALL (DEF_LOOP) + +/* { dg-final { scan-assembler-times {vfadd\.vv\s+v[0-9]+,v[0-9]+,v[0-9]+,v0.t} 12 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fadd-3.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fadd-3.c new file mode 100644 index 000000000000..f71dbaa80ed9 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fadd-3.c @@ -0,0 +1,32 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-march=rv32gcv_zvfh -mabi=ilp32d --param=riscv-autovec-preference=scalable -fno-vect-cost-model" } */ + +#include + +#define DEF_LOOP(TYPE, PRED_TYPE, NAME, CONST) \ + void __attribute__ ((noipa)) \ + test_##TYPE##_##NAME (TYPE *__restrict x, \ + TYPE *__restrict y, \ + PRED_TYPE *__restrict pred, \ + int n) \ + { \ + for (int i = 0; i < n; ++i) \ + x[i] = pred[i] != 1 ? y[i] + (TYPE) CONST : 4; \ + } + +#define TEST_TYPE(T, TYPE, PRED_TYPE) \ + T (TYPE, PRED_TYPE, half, 0.5) \ + T (TYPE, PRED_TYPE, one, 1.0) \ + T (TYPE, PRED_TYPE, two, 2.0) \ + T (TYPE, PRED_TYPE, minus_half, -0.5) \ + T (TYPE, PRED_TYPE, minus_one, -1.0) \ + T (TYPE, PRED_TYPE, minus_two, -2.0) + +#define TEST_ALL(T) \ + TEST_TYPE (T, _Float16, int16_t) \ + TEST_TYPE (T, float, int32_t) \ + TEST_TYPE (T, double, int64_t) + +TEST_ALL (DEF_LOOP) + +/* { dg-final { scan-assembler-times {vfadd\.vv\s+v[0-9]+,v[0-9]+,v[0-9]+,v0.t} 18 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fadd-4.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fadd-4.c new file mode 100644 index 000000000000..ffbe9a47cd9c --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fadd-4.c @@ -0,0 +1,32 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-march=rv32gcv_zvfh -mabi=ilp32d --param=riscv-autovec-preference=scalable -fno-vect-cost-model" } */ + +#include + +#define DEF_LOOP(TYPE, PRED_TYPE, NAME, CONST) \ + void __attribute__ ((noipa)) \ + test_##TYPE##_##NAME (TYPE *__restrict x, \ + TYPE *__restrict y, \ + PRED_TYPE *__restrict pred, \ + int n) \ + { \ + for (int i = 0; i < n; ++i) \ + x[i] = pred[i] != 1 ? y[i] + (TYPE) CONST : 0; \ + } + +#define TEST_TYPE(T, TYPE, PRED_TYPE) \ + T (TYPE, PRED_TYPE, half, 0.5) \ + T (TYPE, PRED_TYPE, one, 1.0) \ + T (TYPE, PRED_TYPE, two, 2.0) \ + T (TYPE, PRED_TYPE, minus_half, -0.5) \ + T (TYPE, PRED_TYPE, minus_one, -1.0) \ + T (TYPE, PRED_TYPE, minus_two, -2.0) + +#define TEST_ALL(T) \ + TEST_TYPE (T, _Float16, int16_t) \ + TEST_TYPE (T, float, int32_t) \ + TEST_TYPE (T, double, int64_t) + +TEST_ALL (DEF_LOOP) + +/* { dg-final { scan-assembler-times {vfadd\.vv\s+v[0-9]+,v[0-9]+,v[0-9]+,v0.t} 18 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fadd_run-1.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fadd_run-1.c new file mode 100644 index 000000000000..4ceedeb8a72e --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fadd_run-1.c @@ -0,0 +1,32 @@ +/* { dg-do run { target { riscv_vector } } } */ +/* { dg-additional-options "--param=riscv-autovec-preference=scalable -fno-vect-cost-model" } */ + +#include "cond_fadd-1.c" + +#define N 99 + +#define TEST_LOOP(TYPE, PRED_TYPE, NAME, CONST) \ + { \ + TYPE x[N], y[N]; \ + PRED_TYPE pred[N]; \ + for (int i = 0; i < N; ++i) \ + { \ + y[i] = i * i; \ + pred[i] = i % 3; \ + } \ + test_##TYPE##_##NAME (x, y, pred, N); \ + for (int i = 0; i < N; ++i) \ + { \ + TYPE expected = i % 3 != 1 ? y[i] + (TYPE) CONST : y[i]; \ + if (x[i] != expected) \ + __builtin_abort (); \ + asm volatile ("" ::: "memory"); \ + } \ + } + +int +main (void) +{ + TEST_ALL (TEST_LOOP) + return 0; +} diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fadd_run-2.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fadd_run-2.c new file mode 100644 index 000000000000..d10c42c373be --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fadd_run-2.c @@ -0,0 +1,31 @@ +/* { dg-do run { target { riscv_vector } } } */ +/* { dg-additional-options "--param=riscv-autovec-preference=scalable -fno-vect-cost-model" } */ + +#include "cond_fadd-2.c" + +#define N 99 + +#define TEST_LOOP(TYPE, NAME, CONST) \ + { \ + TYPE x[N], y[N], z[N]; \ + for (int i = 0; i < N; ++i) \ + { \ + y[i] = i % 13; \ + z[i] = i * i; \ + } \ + test_##TYPE##_##NAME (x, y, z, N); \ + for (int i = 0; i < N; ++i) \ + { \ + TYPE expected = y[i] < 8 ? z[i] + (TYPE) CONST : y[i]; \ + if (x[i] != expected) \ + __builtin_abort (); \ + asm volatile ("" ::: "memory"); \ + } \ + } + +int +main (void) +{ + TEST_ALL (TEST_LOOP) + return 0; +} diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fadd_run-3.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fadd_run-3.c new file mode 100644 index 000000000000..7ee291b49518 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fadd_run-3.c @@ -0,0 +1,32 @@ +/* { dg-do run { target { riscv_vector } } } */ +/* { dg-additional-options "--param=riscv-autovec-preference=scalable -fno-vect-cost-model" } */ + +#include "cond_fadd-3.c" + +#define N 99 + +#define TEST_LOOP(TYPE, PRED_TYPE, NAME, CONST) \ + { \ + TYPE x[N], y[N]; \ + PRED_TYPE pred[N]; \ + for (int i = 0; i < N; ++i) \ + { \ + y[i] = i * i; \ + pred[i] = i % 3; \ + } \ + test_##TYPE##_##NAME (x, y, pred, N); \ + for (int i = 0; i < N; ++i) \ + { \ + TYPE expected = i % 3 != 1 ? y[i] + (TYPE) CONST : 4; \ + if (x[i] != expected) \ + __builtin_abort (); \ + asm volatile ("" ::: "memory"); \ + } \ + } + +int +main (void) +{ + TEST_ALL (TEST_LOOP) + return 0; +} diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fadd_run-4.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fadd_run-4.c new file mode 100644 index 000000000000..2502b6014a25 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fadd_run-4.c @@ -0,0 +1,32 @@ +/* { dg-do run { target { riscv_vector } } } */ +/* { dg-additional-options "--param=riscv-autovec-preference=scalable -fno-vect-cost-model" } */ + +#include "cond_fadd-4.c" + +#define N 99 + +#define TEST_LOOP(TYPE, PRED_TYPE, NAME, CONST) \ + { \ + TYPE x[N], y[N]; \ + PRED_TYPE pred[N]; \ + for (int i = 0; i < N; ++i) \ + { \ + y[i] = i * i; \ + pred[i] = i % 3; \ + } \ + test_##TYPE##_##NAME (x, y, pred, N); \ + for (int i = 0; i < N; ++i) \ + { \ + TYPE expected = i % 3 != 1 ? y[i] + (TYPE) CONST : 0; \ + if (x[i] != expected) \ + __builtin_abort (); \ + asm volatile ("" ::: "memory"); \ + } \ + } + +int +main (void) +{ + TEST_ALL (TEST_LOOP) + return 0; +} diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fma_fnma-1.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fma_fnma-1.c new file mode 100644 index 000000000000..0b19c54b562f --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fma_fnma-1.c @@ -0,0 +1,35 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-march=rv32gcv_zvfh -mabi=ilp32d --param=riscv-autovec-preference=scalable -fno-vect-cost-model -ffast-math" } */ + +#include + +#define DEF_LOOP(TYPE, NAME, OP) \ + void __attribute__ ((noipa)) \ + test_##TYPE##_##NAME (TYPE *__restrict r, \ + TYPE *__restrict a, \ + TYPE *__restrict b, TYPE c, \ + TYPE *__restrict pred, int n) \ + { \ + for (int i = 0; i < n; ++i) \ + r[i] = pred[i] != 1 ? a[i] OP b[i] * c : b[i]; \ + } + +#define TEST_TYPE(T, TYPE) \ + T (TYPE, add, +) \ + T (TYPE, sub, -) + +#define TEST_ALL(T) \ + TEST_TYPE (T, uint8_t) \ + TEST_TYPE (T, uint16_t) \ + TEST_TYPE (T, uint32_t) \ + TEST_TYPE (T, uint64_t) \ + TEST_TYPE (T, _Float16) \ + TEST_TYPE (T, float) \ + TEST_TYPE (T, double) + +TEST_ALL (DEF_LOOP) + +/* { dg-final { scan-assembler-times {vmadd\.vv\s+v[0-9]+,v[0-9]+,v[0-9]+,v0.t} 4 } } */ +/* { dg-final { scan-assembler-times {vnmsub\.vv\s+v[0-9]+,v[0-9]+,v[0-9]+,v0.t} 4 } } */ +/* { dg-final { scan-assembler-times {vfmadd\.vv\s+v[0-9]+,v[0-9]+,v[0-9]+,v0.t} 3 } } */ +/* { dg-final { scan-assembler-times {vfnmsub\.vv\s+v[0-9]+,v[0-9]+,v[0-9]+,v0.t} 3 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fma_fnma-2.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fma_fnma-2.c new file mode 100644 index 000000000000..bd61c0e2edcf --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fma_fnma-2.c @@ -0,0 +1,35 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-march=rv32gcv_zvfh -mabi=ilp32d --param=riscv-autovec-preference=scalable -fno-vect-cost-model -ffast-math" } */ + +#include + +#define DEF_LOOP(TYPE, NAME, OP) \ + void __attribute__ ((noipa)) \ + test_##TYPE##_##NAME (TYPE *__restrict r, \ + TYPE *__restrict a, \ + TYPE *__restrict b, TYPE c, \ + TYPE *__restrict pred, int n) \ + { \ + for (int i = 0; i < n; ++i) \ + r[i] = pred[i] != 1 ? a[i] OP b[i] * c : c; \ + } + +#define TEST_TYPE(T, TYPE) \ + T (TYPE, add, +) \ + T (TYPE, sub, -) + +#define TEST_ALL(T) \ + TEST_TYPE (T, uint8_t) \ + TEST_TYPE (T, uint16_t) \ + TEST_TYPE (T, uint32_t) \ + TEST_TYPE (T, uint64_t) \ + TEST_TYPE (T, _Float16) \ + TEST_TYPE (T, float) \ + TEST_TYPE (T, double) + +TEST_ALL (DEF_LOOP) + +/* { dg-final { scan-assembler-times {vmadd\.vv\s+v[0-9]+,v[0-9]+,v[0-9]+,v0.t} 4 } } */ +/* { dg-final { scan-assembler-times {vnmsub\.vv\s+v[0-9]+,v[0-9]+,v[0-9]+,v0.t} 4 } } */ +/* { dg-final { scan-assembler-times {vfmadd\.vv\s+v[0-9]+,v[0-9]+,v[0-9]+,v0.t} 3 } } */ +/* { dg-final { scan-assembler-times {vfnmsub\.vv\s+v[0-9]+,v[0-9]+,v[0-9]+,v0.t} 3 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fma_fnma-3.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fma_fnma-3.c new file mode 100644 index 000000000000..c011a290908a --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fma_fnma-3.c @@ -0,0 +1,35 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-march=rv32gcv_zvfh -mabi=ilp32d --param=riscv-autovec-preference=scalable -fno-vect-cost-model -ffast-math" } */ + +#include + +#define DEF_LOOP(TYPE, NAME, OP) \ + void __attribute__ ((noipa)) \ + test_##TYPE##_##NAME (TYPE *__restrict r, \ + TYPE *__restrict a, \ + TYPE *__restrict b, TYPE c, \ + TYPE *__restrict pred, int n) \ + { \ + for (int i = 0; i < n; ++i) \ + r[i] = pred[i] != 1 ? a[i] OP b[i] * c : a[i]; \ + } + +#define TEST_TYPE(T, TYPE) \ + T (TYPE, add, +) \ + T (TYPE, sub, -) + +#define TEST_ALL(T) \ + TEST_TYPE (T, uint8_t) \ + TEST_TYPE (T, uint16_t) \ + TEST_TYPE (T, uint32_t) \ + TEST_TYPE (T, uint64_t) \ + TEST_TYPE (T, _Float16) \ + TEST_TYPE (T, float) \ + TEST_TYPE (T, double) + +TEST_ALL (DEF_LOOP) + +/* { dg-final { scan-assembler-times {vmacc\.vv\s+v[0-9]+,v[0-9]+,v[0-9]+,v0.t} 4 } } */ +/* { dg-final { scan-assembler-times {vnmsac\.vv\s+v[0-9]+,v[0-9]+,v[0-9]+,v0.t} 4 } } */ +/* { dg-final { scan-assembler-times {vfmacc\.vv\s+v[0-9]+,v[0-9]+,v[0-9]+,v0.t} 3 } } */ +/* { dg-final { scan-assembler-times {vfnmsac\.vv\s+v[0-9]+,v[0-9]+,v[0-9]+,v0.t} 3 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fma_fnma-4.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fma_fnma-4.c new file mode 100644 index 000000000000..98ba3c1a58d6 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fma_fnma-4.c @@ -0,0 +1,35 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-march=rv32gcv_zvfh -mabi=ilp32d --param=riscv-autovec-preference=scalable -fno-vect-cost-model -ffast-math" } */ + +#include + +#define DEF_LOOP(TYPE, NAME, OP) \ + void __attribute__ ((noipa)) \ + test_##TYPE##_##NAME (TYPE *__restrict r, \ + TYPE *__restrict a, \ + TYPE *__restrict b, TYPE c, \ + TYPE *__restrict pred, int n) \ + { \ + for (int i = 0; i < n; ++i) \ + r[i] = pred[i] == 1 ? a[i] OP b[i] * c : pred[i]; \ + } + +#define TEST_TYPE(T, TYPE) \ + T (TYPE, add, +) \ + T (TYPE, sub, -) + +#define TEST_ALL(T) \ + TEST_TYPE (T, uint8_t) \ + TEST_TYPE (T, uint16_t) \ + TEST_TYPE (T, uint32_t) \ + TEST_TYPE (T, uint64_t) \ + TEST_TYPE (T, _Float16) \ + TEST_TYPE (T, float) \ + TEST_TYPE (T, double) + +TEST_ALL (DEF_LOOP) + +/* { dg-final { scan-assembler-times {vmacc\.vv\s+v[0-9]+,v[0-9]+,v[0-9]+,v0.t} 4 } } */ +/* { dg-final { scan-assembler-times {vnmsac\.vv\s+v[0-9]+,v[0-9]+,v[0-9]+,v0.t} 4 } } */ +/* { dg-final { scan-assembler-times {vfmacc\.vv\s+v[0-9]+,v[0-9]+,v[0-9]+,v0.t} 3 } } */ +/* { dg-final { scan-assembler-times {vfnmsac\.vv\s+v[0-9]+,v[0-9]+,v[0-9]+,v0.t} 3 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fma_fnma-5.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fma_fnma-5.c new file mode 100644 index 000000000000..98ba3c1a58d6 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fma_fnma-5.c @@ -0,0 +1,35 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-march=rv32gcv_zvfh -mabi=ilp32d --param=riscv-autovec-preference=scalable -fno-vect-cost-model -ffast-math" } */ + +#include + +#define DEF_LOOP(TYPE, NAME, OP) \ + void __attribute__ ((noipa)) \ + test_##TYPE##_##NAME (TYPE *__restrict r, \ + TYPE *__restrict a, \ + TYPE *__restrict b, TYPE c, \ + TYPE *__restrict pred, int n) \ + { \ + for (int i = 0; i < n; ++i) \ + r[i] = pred[i] == 1 ? a[i] OP b[i] * c : pred[i]; \ + } + +#define TEST_TYPE(T, TYPE) \ + T (TYPE, add, +) \ + T (TYPE, sub, -) + +#define TEST_ALL(T) \ + TEST_TYPE (T, uint8_t) \ + TEST_TYPE (T, uint16_t) \ + TEST_TYPE (T, uint32_t) \ + TEST_TYPE (T, uint64_t) \ + TEST_TYPE (T, _Float16) \ + TEST_TYPE (T, float) \ + TEST_TYPE (T, double) + +TEST_ALL (DEF_LOOP) + +/* { dg-final { scan-assembler-times {vmacc\.vv\s+v[0-9]+,v[0-9]+,v[0-9]+,v0.t} 4 } } */ +/* { dg-final { scan-assembler-times {vnmsac\.vv\s+v[0-9]+,v[0-9]+,v[0-9]+,v0.t} 4 } } */ +/* { dg-final { scan-assembler-times {vfmacc\.vv\s+v[0-9]+,v[0-9]+,v[0-9]+,v0.t} 3 } } */ +/* { dg-final { scan-assembler-times {vfnmsac\.vv\s+v[0-9]+,v[0-9]+,v[0-9]+,v0.t} 3 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fma_fnma-6.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fma_fnma-6.c new file mode 100644 index 000000000000..e72eb5e7603c --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fma_fnma-6.c @@ -0,0 +1,35 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-march=rv32gcv_zvfh -mabi=ilp32d --param=riscv-autovec-preference=scalable -fno-vect-cost-model -ffast-math" } */ + +#include + +#define DEF_LOOP(TYPE, NAME, OP) \ + void __attribute__ ((noipa)) \ + test_##TYPE##_##NAME (TYPE *__restrict r, \ + TYPE *__restrict a, \ + TYPE *__restrict b, TYPE c, \ + TYPE *__restrict pred, int n) \ + { \ + for (int i = 0; i < n; ++i) \ + r[i] = pred[i] ? a[i] OP b[i] * c : 5; \ + } + +#define TEST_TYPE(T, TYPE) \ + T (TYPE, add, +) \ + T (TYPE, sub, -) + +#define TEST_ALL(T) \ + TEST_TYPE (T, uint8_t) \ + TEST_TYPE (T, uint16_t) \ + TEST_TYPE (T, uint32_t) \ + TEST_TYPE (T, uint64_t) \ + TEST_TYPE (T, _Float16) \ + TEST_TYPE (T, float) \ + TEST_TYPE (T, double) + +TEST_ALL (DEF_LOOP) + +/* { dg-final { scan-assembler-times {vmacc\.vv\s+v[0-9]+,v[0-9]+,v[0-9]+,v0.t} 4 } } */ +/* { dg-final { scan-assembler-times {vnmsac\.vv\s+v[0-9]+,v[0-9]+,v[0-9]+,v0.t} 4 } } */ +/* { dg-final { scan-assembler-times {vfmacc\.vv\s+v[0-9]+,v[0-9]+,v[0-9]+,v0.t} 3 } } */ +/* { dg-final { scan-assembler-times {vfnmsac\.vv\s+v[0-9]+,v[0-9]+,v[0-9]+,v0.t} 3 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fma_fnma-7.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fma_fnma-7.c new file mode 100644 index 000000000000..3a69a59e8e8c --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fma_fnma-7.c @@ -0,0 +1,35 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-march=rv32gcv_zvfh -mabi=ilp32d --param=riscv-autovec-preference=scalable -fno-vect-cost-model -ffast-math" } */ + +#include + +#define DEF_LOOP(TYPE, NAME, OP, CONST) \ + void __attribute__ ((noipa)) \ + test_##TYPE##_##NAME##_##CONST (TYPE *__restrict r, \ + TYPE *__restrict a, \ + TYPE *__restrict b, \ + TYPE *__restrict pred, int n) \ + { \ + for (int i = 0; i < n; ++i) \ + r[i] = pred[i] != 1 ? a[i] OP b[i] * CONST : a[i]; \ + } + +#define TEST_COUNT(T, TYPE, CONST) \ + T (TYPE, add, +, CONST) \ + T (TYPE, sub, -, CONST) + +#define TEST_TYPE(T, TYPE, CONST) \ + TEST_COUNT (T, TYPE, 2) \ + TEST_COUNT (T, TYPE, 4) \ + TEST_COUNT (T, TYPE, CONST) + +#define TEST_ALL(T) \ + TEST_TYPE (T, uint8_t, 0x80) \ + TEST_TYPE (T, uint16_t, 0x8000) \ + TEST_TYPE (T, uint32_t, 0x80000000) \ + TEST_TYPE (T, uint64_t, 0x8000000000000000ULL) + +TEST_ALL (DEF_LOOP) + +/* { dg-final { scan-assembler-times {vmacc\.vv\s+v[0-9]+,v[0-9]+,v[0-9]+,v0.t} 12 } } */ +/* { dg-final { scan-assembler-times {vnmsac\.vv\s+v[0-9]+,v[0-9]+,v[0-9]+,v0.t} 12 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fma_fnma-8.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fma_fnma-8.c new file mode 100644 index 000000000000..4df9da8ea4e2 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fma_fnma-8.c @@ -0,0 +1,35 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-march=rv32gcv_zvfh -mabi=ilp32d --param=riscv-autovec-preference=scalable -fno-vect-cost-model -ffast-math" } */ + +#include + +#define DEF_LOOP(TYPE, NAME, OP, CONST) \ + void __attribute__ ((noipa)) \ + test_##TYPE##_##NAME##_##CONST (TYPE *__restrict r, \ + TYPE *__restrict a, \ + TYPE *__restrict b, \ + TYPE *__restrict pred, int n) \ + { \ + for (int i = 0; i < n; ++i) \ + r[i] = pred[i] != 1 ? a[i] OP b[i] * -CONST : a[i]; \ + } + +#define TEST_COUNT(T, TYPE, CONST) \ + T (TYPE, add, +, CONST) \ + T (TYPE, sub, -, CONST) + +#define TEST_TYPE(T, TYPE, CONST) \ + TEST_COUNT (T, TYPE, 2) \ + TEST_COUNT (T, TYPE, 4) \ + TEST_COUNT (T, TYPE, CONST) + +#define TEST_ALL(T) \ + TEST_TYPE (T, uint8_t, 0x80) \ + TEST_TYPE (T, uint16_t, 0x8000) \ + TEST_TYPE (T, uint32_t, 0x80000000) \ + TEST_TYPE (T, uint64_t, 0x8000000000000000ULL) + +TEST_ALL (DEF_LOOP) + +/* { dg-final { scan-assembler-times {vmacc\.vv\s+v[0-9]+,v[0-9]+,v[0-9]+,v0.t} 12 } } */ +/* { dg-final { scan-assembler-times {vnmsac\.vv\s+v[0-9]+,v[0-9]+,v[0-9]+,v0.t} 12 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fma_fnma_run-1.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fma_fnma_run-1.c new file mode 100644 index 000000000000..91578a490980 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fma_fnma_run-1.c @@ -0,0 +1,35 @@ +/* { dg-do run { target { riscv_vector } } } */ +/* { dg-additional-options "--param=riscv-autovec-preference=scalable -fno-vect-cost-model -ffast-math" } */ + +#include "cond_fma_fnma-1.c" + +#define FACTOR 17 +#define N 99 + +#define TEST_LOOP(TYPE, NAME, OP) \ + { \ + TYPE r[N], a[N], b[N], pred[N]; \ + for (int i = 0; i < N; ++i) \ + { \ + a[i] = (i & 1 ? i : 3 * i); \ + b[i] = (i >> 4) << (i & 15); \ + pred[i] = i % 3 < i % 5; \ + asm volatile ("" ::: "memory"); \ + } \ + test_##TYPE##_##NAME (r, a, b, FACTOR, pred, N); \ + for (int i = 0; i < N; ++i) \ + { \ + TYPE expected \ + = pred[i] != 1 ? a[i] OP b[i] * (TYPE) FACTOR : b[i]; \ + if (r[i] != expected) \ + __builtin_abort (); \ + asm volatile ("" ::: "memory"); \ + } \ + } + +int +main (void) +{ + TEST_ALL (TEST_LOOP) + return 0; +} diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fma_fnma_run-2.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fma_fnma_run-2.c new file mode 100644 index 000000000000..61526b6cf79a --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fma_fnma_run-2.c @@ -0,0 +1,36 @@ +/* { dg-do run { target { riscv_vector } } } */ +/* { dg-additional-options "--param=riscv-autovec-preference=scalable -fno-vect-cost-model -ffast-math" } */ + +#include "cond_fma_fnma-2.c" + +#define FACTOR 17 +#define N 99 + +#define TEST_LOOP(TYPE, NAME, OP) \ + { \ + TYPE r[N], a[N], b[N], pred[N]; \ + for (int i = 0; i < N; ++i) \ + { \ + a[i] = (i & 1 ? i : 3 * i); \ + b[i] = (i >> 4) << (i & 15); \ + pred[i] = i % 3 < i % 5; \ + asm volatile ("" ::: "memory"); \ + } \ + test_##TYPE##_##NAME (r, a, b, FACTOR, pred, N); \ + for (int i = 0; i < N; ++i) \ + { \ + TYPE expected = (pred[i] != 1 \ + ? a[i] OP b[i] * (TYPE) FACTOR \ + : (TYPE) FACTOR); \ + if (r[i] != expected) \ + __builtin_abort (); \ + asm volatile ("" ::: "memory"); \ + } \ + } + +int +main (void) +{ + TEST_ALL (TEST_LOOP) + return 0; +} diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fma_fnma_run-3.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fma_fnma_run-3.c new file mode 100644 index 000000000000..af446d9dfcf3 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fma_fnma_run-3.c @@ -0,0 +1,35 @@ +/* { dg-do run { target { riscv_vector } } } */ +/* { dg-additional-options "--param=riscv-autovec-preference=scalable -fno-vect-cost-model -ffast-math" } */ + +#include "cond_fma_fnma-3.c" + +#define FACTOR 17 +#define N 99 + +#define TEST_LOOP(TYPE, NAME, OP) \ + { \ + TYPE r[N], a[N], b[N], pred[N]; \ + for (int i = 0; i < N; ++i) \ + { \ + a[i] = (i & 1 ? i : 3 * i); \ + b[i] = (i >> 4) << (i & 15); \ + pred[i] = i % 3 < i % 5; \ + asm volatile ("" ::: "memory"); \ + } \ + test_##TYPE##_##NAME (r, a, b, FACTOR, pred, N); \ + for (int i = 0; i < N; ++i) \ + { \ + TYPE expected \ + = pred[i] != 1 ? a[i] OP b[i] * (TYPE) FACTOR : a[i]; \ + if (r[i] != expected) \ + __builtin_abort (); \ + asm volatile ("" ::: "memory"); \ + } \ + } + +int +main (void) +{ + TEST_ALL (TEST_LOOP) + return 0; +} diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fma_fnma_run-4.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fma_fnma_run-4.c new file mode 100644 index 000000000000..4880a4647b98 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fma_fnma_run-4.c @@ -0,0 +1,36 @@ +/* { dg-do run { target { riscv_vector } } } */ +/* { dg-additional-options "--param=riscv-autovec-preference=scalable -fno-vect-cost-model -ffast-math" } */ + +#include "cond_fma_fnma-4.c" + +#define FACTOR 17 +#define N 99 + +#define TEST_LOOP(TYPE, NAME, OP) \ + { \ + TYPE r[N], a[N], b[N], pred[N]; \ + for (int i = 0; i < N; ++i) \ + { \ + a[i] = (i & 1 ? i : 3 * i); \ + b[i] = (i >> 4) << (i & 15); \ + pred[i] = i % 3; \ + asm volatile ("" ::: "memory"); \ + } \ + test_##TYPE##_##NAME (r, a, b, FACTOR, pred, N); \ + for (int i = 0; i < N; ++i) \ + { \ + TYPE expected = (pred[i] == 1 \ + ? a[i] OP b[i] * (TYPE) FACTOR \ + : pred[i]); \ + if (r[i] != expected) \ + __builtin_abort (); \ + asm volatile ("" ::: "memory"); \ + } \ + } + +int +main (void) +{ + TEST_ALL (TEST_LOOP) + return 0; +} diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fma_fnma_run-5.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fma_fnma_run-5.c new file mode 100644 index 000000000000..2aa252456697 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fma_fnma_run-5.c @@ -0,0 +1,35 @@ +/* { dg-do run { target { riscv_vector } } } */ +/* { dg-additional-options "--param=riscv-autovec-preference=scalable -fno-vect-cost-model -ffast-math" } */ + +#include "cond_fma_fnma-5.c" + +#define FACTOR 17 +#define N 99 + +#define TEST_LOOP(TYPE, NAME, OP) \ + { \ + TYPE r[N], a[N], b[N], pred[N]; \ + for (int i = 0; i < N; ++i) \ + { \ + a[i] = (i & 1 ? i : 3 * i); \ + b[i] = (i >> 4) << (i & 15); \ + pred[i] = i % 3 < i % 5; \ + asm volatile ("" ::: "memory"); \ + } \ + test_##TYPE##_##NAME (r, a, b, FACTOR, pred, N); \ + for (int i = 0; i < N; ++i) \ + { \ + TYPE expected \ + = pred[i] ? a[i] OP b[i] * (TYPE) FACTOR : 0; \ + if (r[i] != expected) \ + __builtin_abort (); \ + asm volatile ("" ::: "memory"); \ + } \ + } + +int +main (void) +{ + TEST_ALL (TEST_LOOP) + return 0; +} diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fma_fnma_run-6.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fma_fnma_run-6.c new file mode 100644 index 000000000000..36c3c6409a4c --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fma_fnma_run-6.c @@ -0,0 +1,35 @@ +/* { dg-do run { target { riscv_vector } } } */ +/* { dg-additional-options "--param=riscv-autovec-preference=scalable -fno-vect-cost-model -ffast-math" } */ + +#include "cond_fma_fnma-6.c" + +#define FACTOR 17 +#define N 99 + +#define TEST_LOOP(TYPE, NAME, OP) \ + { \ + TYPE r[N], a[N], b[N], pred[N]; \ + for (int i = 0; i < N; ++i) \ + { \ + a[i] = (i & 1 ? i : 3 * i); \ + b[i] = (i >> 4) << (i & 15); \ + pred[i] = i % 3 < i % 5; \ + asm volatile ("" ::: "memory"); \ + } \ + test_##TYPE##_##NAME (r, a, b, FACTOR, pred, N); \ + for (int i = 0; i < N; ++i) \ + { \ + TYPE expected \ + = pred[i] ? a[i] OP b[i] * (TYPE) FACTOR : 5; \ + if (r[i] != expected) \ + __builtin_abort (); \ + asm volatile ("" ::: "memory"); \ + } \ + } + +int +main (void) +{ + TEST_ALL (TEST_LOOP) + return 0; +} diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fma_fnma_run-7.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fma_fnma_run-7.c new file mode 100644 index 000000000000..b74b4d266f19 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fma_fnma_run-7.c @@ -0,0 +1,34 @@ +/* { dg-do run { target { riscv_vector } } } */ +/* { dg-additional-options "--param=riscv-autovec-preference=scalable -fno-vect-cost-model -ffast-math" } */ + +#include "cond_fma_fnma-7.c" + +#define N 99 + +#define TEST_LOOP(TYPE, NAME, OP, CONST) \ + { \ + TYPE r[N], a[N], b[N], pred[N]; \ + for (int i = 0; i < N; ++i) \ + { \ + a[i] = (i & 1 ? i : 3 * i); \ + b[i] = (i >> 4) << (i & 15); \ + pred[i] = i % 3 < i % 5; \ + asm volatile ("" ::: "memory"); \ + } \ + test_##TYPE##_##NAME##_##CONST (r, a, b, pred, N); \ + for (int i = 0; i < N; ++i) \ + { \ + TYPE expected \ + = pred[i] != 1 ? a[i] OP b[i] * CONST : a[i]; \ + if (r[i] != expected) \ + __builtin_abort (); \ + asm volatile ("" ::: "memory"); \ + } \ + } + +int +main (void) +{ + TEST_ALL (TEST_LOOP) + return 0; +} diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fma_fnma_run-8.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fma_fnma_run-8.c new file mode 100644 index 000000000000..fb9b6f28ed11 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fma_fnma_run-8.c @@ -0,0 +1,34 @@ +/* { dg-do run { target { riscv_vector } } } */ +/* { dg-additional-options "--param=riscv-autovec-preference=scalable -fno-vect-cost-model -ffast-math" } */ + +#include "cond_fma_fnma-8.c" + +#define N 99 + +#define TEST_LOOP(TYPE, NAME, OP, CONST) \ + { \ + TYPE r[N], a[N], b[N], pred[N]; \ + for (int i = 0; i < N; ++i) \ + { \ + a[i] = (i & 1 ? i : 3 * i); \ + b[i] = (i >> 4) << (i & 15); \ + pred[i] = i % 3 < i % 5; \ + asm volatile ("" ::: "memory"); \ + } \ + test_##TYPE##_##NAME##_##CONST (r, a, b, pred, N); \ + for (int i = 0; i < N; ++i) \ + { \ + TYPE expected \ + = pred[i] != 1 ? a[i] OP b[i] * -CONST : a[i]; \ + if (r[i] != expected) \ + __builtin_abort (); \ + asm volatile ("" ::: "memory"); \ + } \ + } + +int +main (void) +{ + TEST_ALL (TEST_LOOP) + return 0; +} diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fmax-1.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fmax-1.c new file mode 100644 index 000000000000..fe37794afeb5 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fmax-1.c @@ -0,0 +1,33 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-march=rv32gcv_zvfh -mabi=ilp32d --param=riscv-autovec-preference=scalable -fno-vect-cost-model -ffast-math" } */ + +#include + +#ifndef FN +#define FN(X) __builtin_fmax##X +#endif + +#define DEF_LOOP(FN, TYPE, PRED_TYPE, NAME, CONST) \ + void __attribute__ ((noipa)) \ + test_##TYPE##_##NAME (TYPE *__restrict x, \ + TYPE *__restrict y, \ + PRED_TYPE *__restrict pred, \ + int n) \ + { \ + for (int i = 0; i < n; ++i) \ + x[i] = pred[i] != 1 ? FN (y[i], CONST) : y[i]; \ + } + +#define TEST_TYPE(T, FN, TYPE, PRED_TYPE) \ + T (FN, TYPE, PRED_TYPE, zero, 0) \ + T (FN, TYPE, PRED_TYPE, one, 1) \ + T (FN, TYPE, PRED_TYPE, two, 2) + +#define TEST_ALL(T) \ + TEST_TYPE (T, FN (f16), _Float16, int16_t) \ + TEST_TYPE (T, FN (f32), float, int32_t) \ + TEST_TYPE (T, FN (f64), double, int64_t) + +TEST_ALL (DEF_LOOP) + +/* { dg-final { scan-assembler-times {vfmax\.vv\s+v[0-9]+,v[0-9]+,v[0-9]+,v0.t} 9 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fmax-2.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fmax-2.c new file mode 100644 index 000000000000..f25562b22ddc --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fmax-2.c @@ -0,0 +1,32 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-march=rv32gcv_zvfh -mabi=ilp32d --param=riscv-autovec-preference=scalable -fno-vect-cost-model -ffast-math" } */ + +#include + +#ifndef FN +#define FN(X) __builtin_fmax##X +#endif + +#define DEF_LOOP(FN, TYPE, NAME, CONST) \ + void __attribute__ ((noipa)) \ + test_##TYPE##_##NAME (TYPE *__restrict x, \ + TYPE *__restrict y, \ + TYPE *__restrict z, \ + int n) \ + { \ + for (int i = 0; i < n; ++i) \ + x[i] = y[i] < 8 ? FN (z[i], CONST) : y[i]; \ + } + +#define TEST_TYPE(T, FN, TYPE) \ + T (FN, TYPE, zero, 0) \ + T (FN, TYPE, one, 1) \ + T (FN, TYPE, two, 2) + +#define TEST_ALL(T) \ + TEST_TYPE (T, FN (f32), float) \ + TEST_TYPE (T, FN (f64), double) + +TEST_ALL (DEF_LOOP) + +/* { dg-final { scan-assembler-times {vfmax\.vv\s+v[0-9]+,v[0-9]+,v[0-9]+,v0.t} 6 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fmax-3.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fmax-3.c new file mode 100644 index 000000000000..a23f4916caaa --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fmax-3.c @@ -0,0 +1,33 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-march=rv32gcv_zvfh -mabi=ilp32d --param=riscv-autovec-preference=scalable -fno-vect-cost-model -ffast-math" } */ + +#include + +#ifndef FN +#define FN(X) __builtin_fmax##X +#endif + +#define DEF_LOOP(FN, TYPE, PRED_TYPE, NAME, CONST) \ + void __attribute__ ((noipa)) \ + test_##TYPE##_##NAME (TYPE *__restrict x, \ + TYPE *__restrict y, \ + PRED_TYPE *__restrict pred, \ + int n) \ + { \ + for (int i = 0; i < n; ++i) \ + x[i] = pred[i] != 1 ? FN (y[i], CONST) : 4; \ + } + +#define TEST_TYPE(T, FN, TYPE, PRED_TYPE) \ + T (FN, TYPE, PRED_TYPE, zero, 0) \ + T (FN, TYPE, PRED_TYPE, one, 1) \ + T (FN, TYPE, PRED_TYPE, two, 2) + +#define TEST_ALL(T) \ + TEST_TYPE (T, FN (f16), _Float16, int16_t) \ + TEST_TYPE (T, FN (f32), float, int32_t) \ + TEST_TYPE (T, FN (f64), double, int64_t) + +TEST_ALL (DEF_LOOP) + +/* { dg-final { scan-assembler-times {vfmax\.vv\s+v[0-9]+,v[0-9]+,v[0-9]+,v0.t} 9 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fmax-4.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fmax-4.c new file mode 100644 index 000000000000..79e4771eaf3a --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fmax-4.c @@ -0,0 +1,33 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-march=rv32gcv_zvfh -mabi=ilp32d --param=riscv-autovec-preference=scalable -fno-vect-cost-model -ffast-math" } */ + +#include + +#ifndef FN +#define FN(X) __builtin_fmax##X +#endif + +#define DEF_LOOP(FN, TYPE, PRED_TYPE, NAME, CONST) \ + void __attribute__ ((noipa)) \ + test_##TYPE##_##NAME (TYPE *__restrict x, \ + TYPE *__restrict y, \ + PRED_TYPE *__restrict pred, \ + int n) \ + { \ + for (int i = 0; i < n; ++i) \ + x[i] = pred[i] != 1 ? FN (y[i], CONST) : 0; \ + } + +#define TEST_TYPE(T, FN, TYPE, PRED_TYPE) \ + T (FN, TYPE, PRED_TYPE, zero, 0) \ + T (FN, TYPE, PRED_TYPE, one, 1) \ + T (FN, TYPE, PRED_TYPE, two, 2) + +#define TEST_ALL(T) \ + TEST_TYPE (T, FN (f16), _Float16, int16_t) \ + TEST_TYPE (T, FN (f32), float, int32_t) \ + TEST_TYPE (T, FN (f64), double, int64_t) + +TEST_ALL (DEF_LOOP) + +/* { dg-final { scan-assembler-times {vfmax\.vv\s+v[0-9]+,v[0-9]+,v[0-9]+,v0.t} 9 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fmax_run-1.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fmax_run-1.c new file mode 100644 index 000000000000..bbf04f61daad --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fmax_run-1.c @@ -0,0 +1,32 @@ +/* { dg-do run { target { riscv_vector } } } */ +/* { dg-additional-options "--param=riscv-autovec-preference=scalable -fno-vect-cost-model -ffast-math" } */ + +#include "cond_fmax-1.c" + +#define N 99 + +#define TEST_LOOP(FN, TYPE, PRED_TYPE, NAME, CONST) \ + { \ + TYPE x[N], y[N]; \ + PRED_TYPE pred[N]; \ + for (int i = 0; i < N; ++i) \ + { \ + y[i] = i * i; \ + pred[i] = i % 3; \ + } \ + test_##TYPE##_##NAME (x, y, pred, N); \ + for (int i = 0; i < N; ++i) \ + { \ + TYPE expected = i % 3 != 1 ? FN (y[i], CONST) : y[i]; \ + if (x[i] != expected) \ + __builtin_abort (); \ + asm volatile ("" ::: "memory"); \ + } \ + } + +int +main (void) +{ + TEST_ALL (TEST_LOOP) + return 0; +} diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fmax_run-2.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fmax_run-2.c new file mode 100644 index 000000000000..ae2740f3bfe5 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fmax_run-2.c @@ -0,0 +1,31 @@ +/* { dg-do run { target { riscv_vector } } } */ +/* { dg-additional-options "--param=riscv-autovec-preference=scalable -fno-vect-cost-model -ffast-math" } */ + +#include "cond_fmax-2.c" + +#define N 99 + +#define TEST_LOOP(FN, TYPE, NAME, CONST) \ + { \ + TYPE x[N], y[N], z[N]; \ + for (int i = 0; i < N; ++i) \ + { \ + y[i] = i % 13; \ + z[i] = i * i; \ + } \ + test_##TYPE##_##NAME (x, y, z, N); \ + for (int i = 0; i < N; ++i) \ + { \ + TYPE expected = y[i] < 8 ? FN (z[i], CONST) : y[i]; \ + if (x[i] != expected) \ + __builtin_abort (); \ + asm volatile ("" ::: "memory"); \ + } \ + } + +int +main (void) +{ + TEST_ALL (TEST_LOOP) + return 0; +} diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fmax_run-3.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fmax_run-3.c new file mode 100644 index 000000000000..d02eba1bf711 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fmax_run-3.c @@ -0,0 +1,32 @@ +/* { dg-do run { target { riscv_vector } } } */ +/* { dg-additional-options "--param=riscv-autovec-preference=scalable -fno-vect-cost-model -ffast-math" } */ + +#include "cond_fmax-3.c" + +#define N 99 + +#define TEST_LOOP(FN, TYPE, PRED_TYPE, NAME, CONST) \ + { \ + TYPE x[N], y[N]; \ + PRED_TYPE pred[N]; \ + for (int i = 0; i < N; ++i) \ + { \ + y[i] = i * i; \ + pred[i] = i % 3; \ + } \ + test_##TYPE##_##NAME (x, y, pred, N); \ + for (int i = 0; i < N; ++i) \ + { \ + TYPE expected = i % 3 != 1 ? FN (y[i], CONST) : 4; \ + if (x[i] != expected) \ + __builtin_abort (); \ + asm volatile ("" ::: "memory"); \ + } \ + } + +int +main (void) +{ + TEST_ALL (TEST_LOOP) + return 0; +} diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fmax_run-4.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fmax_run-4.c new file mode 100644 index 000000000000..608a3dd0feae --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fmax_run-4.c @@ -0,0 +1,32 @@ +/* { dg-do run { target { riscv_vector } } } */ +/* { dg-additional-options "--param=riscv-autovec-preference=scalable -fno-vect-cost-model -ffast-math" } */ + +#include "cond_fmax-4.c" + +#define N 99 + +#define TEST_LOOP(FN, TYPE, PRED_TYPE, NAME, CONST) \ + { \ + TYPE x[N], y[N]; \ + PRED_TYPE pred[N]; \ + for (int i = 0; i < N; ++i) \ + { \ + y[i] = i * i; \ + pred[i] = i % 3; \ + } \ + test_##TYPE##_##NAME (x, y, pred, N); \ + for (int i = 0; i < N; ++i) \ + { \ + TYPE expected = i % 3 != 1 ? FN (y[i], CONST) : 0; \ + if (x[i] != expected) \ + __builtin_abort (); \ + asm volatile ("" ::: "memory"); \ + } \ + } + +int +main (void) +{ + TEST_ALL (TEST_LOOP) + return 0; +} diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fmin-1.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fmin-1.c new file mode 100644 index 000000000000..f15964093121 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fmin-1.c @@ -0,0 +1,10 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-march=rv32gcv_zvfh -mabi=ilp32d --param=riscv-autovec-preference=scalable -fno-vect-cost-model -ffast-math" } */ + +#include + +#define FN(X) __builtin_fmin##X +#include "cond_fmax-1.c" + +/* { dg-final { scan-assembler-times {vfmin\.vv\s+v[0-9]+,v[0-9]+,v[0-9]+,v0.t} 9 } } */ + diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fmin-2.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fmin-2.c new file mode 100644 index 000000000000..7c8c79ee251c --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fmin-2.c @@ -0,0 +1,9 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-march=rv32gcv_zvfh -mabi=ilp32d --param=riscv-autovec-preference=scalable -fno-vect-cost-model -ffast-math" } */ + +#include + +#define FN(X) __builtin_fmin##X +#include "cond_fmax-2.c" + +/* { dg-final { scan-assembler-times {vfmin\.vv\s+v[0-9]+,v[0-9]+,v[0-9]+,v0.t} 6 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fmin-3.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fmin-3.c new file mode 100644 index 000000000000..aee0e3572b0f --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fmin-3.c @@ -0,0 +1,9 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-march=rv32gcv_zvfh -mabi=ilp32d --param=riscv-autovec-preference=scalable -fno-vect-cost-model -ffast-math" } */ + +#include + +#define FN(X) __builtin_fmin##X +#include "cond_fmax-3.c" + +/* { dg-final { scan-assembler-times {vfmin\.vv\s+v[0-9]+,v[0-9]+,v[0-9]+,v0.t} 9 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fmin-4.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fmin-4.c new file mode 100644 index 000000000000..223c8a6938ba --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fmin-4.c @@ -0,0 +1,9 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-march=rv32gcv_zvfh -mabi=ilp32d --param=riscv-autovec-preference=scalable -fno-vect-cost-model -ffast-math" } */ + +#include + +#define FN(X) __builtin_fmin##X +#include "cond_fmax-4.c" + +/* { dg-final { scan-assembler-times {vfmin\.vv\s+v[0-9]+,v[0-9]+,v[0-9]+,v0.t} 9 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fmin_run-1.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fmin_run-1.c new file mode 100644 index 000000000000..31fa50aea18c --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fmin_run-1.c @@ -0,0 +1,5 @@ +/* { dg-do run { target { riscv_vector } } } */ +/* { dg-additional-options "--param=riscv-autovec-preference=scalable -fno-vect-cost-model -ffast-math" } */ + +#define FN(X) __builtin_fmin##X +#include "cond_fmax_run-1.c" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fmin_run-2.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fmin_run-2.c new file mode 100644 index 000000000000..13b21896c2c7 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fmin_run-2.c @@ -0,0 +1,5 @@ +/* { dg-do run { target { riscv_vector } } } */ +/* { dg-additional-options "--param=riscv-autovec-preference=scalable -fno-vect-cost-model -ffast-math" } */ + +#define FN(X) __builtin_fmin##X +#include "cond_fmax_run-2.c" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fmin_run-3.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fmin_run-3.c new file mode 100644 index 000000000000..61e347bb09e2 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fmin_run-3.c @@ -0,0 +1,5 @@ +/* { dg-do run { target { riscv_vector } } } */ +/* { dg-additional-options "--param=riscv-autovec-preference=scalable -fno-vect-cost-model -ffast-math" } */ + +#define FN(X) __builtin_fmin##X +#include "cond_fmax_run-3.c" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fmin_run-4.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fmin_run-4.c new file mode 100644 index 000000000000..4921464c8dc8 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fmin_run-4.c @@ -0,0 +1,5 @@ +/* { dg-do run { target { riscv_vector } } } */ +/* { dg-additional-options "--param=riscv-autovec-preference=scalable -fno-vect-cost-model -ffast-math" } */ + +#define FN(X) __builtin_fmin##X +#include "cond_fmax_run-4.c" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fms_fnms-1.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fms_fnms-1.c new file mode 100644 index 000000000000..2a28941eee2c --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fms_fnms-1.c @@ -0,0 +1,29 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-march=rv32gcv_zvfh -mabi=ilp32d --param=riscv-autovec-preference=scalable -fno-vect-cost-model -ffast-math" } */ + +#include + +#define DEF_LOOP(TYPE, NAME, OP) \ + void __attribute__ ((noipa)) \ + test_##TYPE##_##NAME (TYPE *__restrict r, \ + TYPE *__restrict a, \ + TYPE *__restrict b, TYPE c, \ + TYPE *__restrict pred, int n) \ + { \ + for (int i = 0; i < n; ++i) \ + r[i] = pred[i] != 1 ? -a[i] OP b[i] * c : b[i]; \ + } + +#define TEST_TYPE(T, TYPE) \ + T (TYPE, add, +) \ + T (TYPE, sub, -) + +#define TEST_ALL(T) \ + TEST_TYPE (T, _Float16) \ + TEST_TYPE (T, float) \ + TEST_TYPE (T, double) + +TEST_ALL (DEF_LOOP) + +/* { dg-final { scan-assembler-times {vfnmacc\.vv\s+v[0-9]+,v[0-9]+,v[0-9]+,v0.t} 3 { xfail riscv*-*-* } } } */ +/* { dg-final { scan-assembler-times {vfmsub\.vv\s+v[0-9]+,v[0-9]+,v[0-9]+,v0.t} 3 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fms_fnms-2.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fms_fnms-2.c new file mode 100644 index 000000000000..d1826f3fde10 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fms_fnms-2.c @@ -0,0 +1,29 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-march=rv32gcv_zvfh -mabi=ilp32d --param=riscv-autovec-preference=scalable -fno-vect-cost-model -ffast-math" } */ + +#include + +#define DEF_LOOP(TYPE, NAME, OP) \ + void __attribute__ ((noipa)) \ + test_##TYPE##_##NAME (TYPE *__restrict r, \ + TYPE *__restrict a, \ + TYPE *__restrict b, TYPE c, \ + TYPE *__restrict pred, int n) \ + { \ + for (int i = 0; i < n; ++i) \ + r[i] = pred[i] != 1 ? -a[i] OP b[i] * c : c; \ + } + +#define TEST_TYPE(T, TYPE) \ + T (TYPE, add, +) \ + T (TYPE, sub, -) + +#define TEST_ALL(T) \ + TEST_TYPE (T, _Float16) \ + TEST_TYPE (T, float) \ + TEST_TYPE (T, double) + +TEST_ALL (DEF_LOOP) + +/* { dg-final { scan-assembler-times {vfnmacc\.vv\s+v[0-9]+,v[0-9]+,v[0-9]+,v0.t} 3 { xfail riscv*-*-* } } } */ +/* { dg-final { scan-assembler-times {vfmsub\.vv\s+v[0-9]+,v[0-9]+,v[0-9]+,v0.t} 3 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fms_fnms-3.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fms_fnms-3.c new file mode 100644 index 000000000000..57458239b802 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fms_fnms-3.c @@ -0,0 +1,29 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-march=rv32gcv_zvfh -mabi=ilp32d --param=riscv-autovec-preference=scalable -fno-vect-cost-model -ffast-math" } */ + +#include + +#define DEF_LOOP(TYPE, NAME, OP) \ + void __attribute__ ((noipa)) \ + test_##TYPE##_##NAME (TYPE *__restrict r, \ + TYPE *__restrict a, \ + TYPE *__restrict b, TYPE c, \ + TYPE *__restrict pred, int n) \ + { \ + for (int i = 0; i < n; ++i) \ + r[i] = pred[i] != 1 ? -a[i] OP b[i] * c : a[i]; \ + } + +#define TEST_TYPE(T, TYPE) \ + T (TYPE, add, +) \ + T (TYPE, sub, -) + +#define TEST_ALL(T) \ + TEST_TYPE (T, _Float16) \ + TEST_TYPE (T, float) \ + TEST_TYPE (T, double) + +TEST_ALL (DEF_LOOP) + +/* { dg-final { scan-assembler-times {vfnmacc\.vv\s+v[0-9]+,v[0-9]+,v[0-9]+,v0.t} 3 { xfail riscv*-*-* } } } */ +/* { dg-final { scan-assembler-times {vfmsac\.vv\s+v[0-9]+,v[0-9]+,v[0-9]+,v0.t} 3 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fms_fnms-4.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fms_fnms-4.c new file mode 100644 index 000000000000..b5ed7045ae25 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fms_fnms-4.c @@ -0,0 +1,29 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-march=rv32gcv_zvfh -mabi=ilp32d --param=riscv-autovec-preference=scalable -fno-vect-cost-model -ffast-math" } */ + +#include + +#define DEF_LOOP(TYPE, NAME, OP) \ + void __attribute__ ((noipa)) \ + test_##TYPE##_##NAME (TYPE *__restrict r, \ + TYPE *__restrict a, \ + TYPE *__restrict b, TYPE c, \ + TYPE *__restrict pred, int n) \ + { \ + for (int i = 0; i < n; ++i) \ + r[i] = pred[i] == 1 ? -a[i] OP b[i] * c : pred[i]; \ + } + +#define TEST_TYPE(T, TYPE) \ + T (TYPE, add, +) \ + T (TYPE, sub, -) + +#define TEST_ALL(T) \ + TEST_TYPE (T, _Float16) \ + TEST_TYPE (T, float) \ + TEST_TYPE (T, double) + +TEST_ALL (DEF_LOOP) + +/* { dg-final { scan-assembler-times {vfnmacc\.vv\s+v[0-9]+,v[0-9]+,v[0-9]+,v0.t} 3 { xfail riscv*-*-* } } } */ +/* { dg-final { scan-assembler-times {vfmsac\.vv\s+v[0-9]+,v[0-9]+,v[0-9]+,v0.t} 3 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fms_fnms-5.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fms_fnms-5.c new file mode 100644 index 000000000000..b5ed7045ae25 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fms_fnms-5.c @@ -0,0 +1,29 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-march=rv32gcv_zvfh -mabi=ilp32d --param=riscv-autovec-preference=scalable -fno-vect-cost-model -ffast-math" } */ + +#include + +#define DEF_LOOP(TYPE, NAME, OP) \ + void __attribute__ ((noipa)) \ + test_##TYPE##_##NAME (TYPE *__restrict r, \ + TYPE *__restrict a, \ + TYPE *__restrict b, TYPE c, \ + TYPE *__restrict pred, int n) \ + { \ + for (int i = 0; i < n; ++i) \ + r[i] = pred[i] == 1 ? -a[i] OP b[i] * c : pred[i]; \ + } + +#define TEST_TYPE(T, TYPE) \ + T (TYPE, add, +) \ + T (TYPE, sub, -) + +#define TEST_ALL(T) \ + TEST_TYPE (T, _Float16) \ + TEST_TYPE (T, float) \ + TEST_TYPE (T, double) + +TEST_ALL (DEF_LOOP) + +/* { dg-final { scan-assembler-times {vfnmacc\.vv\s+v[0-9]+,v[0-9]+,v[0-9]+,v0.t} 3 { xfail riscv*-*-* } } } */ +/* { dg-final { scan-assembler-times {vfmsac\.vv\s+v[0-9]+,v[0-9]+,v[0-9]+,v0.t} 3 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fms_fnms-6.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fms_fnms-6.c new file mode 100644 index 000000000000..c5c8af86a815 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fms_fnms-6.c @@ -0,0 +1,29 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-march=rv32gcv_zvfh -mabi=ilp32d --param=riscv-autovec-preference=scalable -fno-vect-cost-model -ffast-math" } */ + +#include + +#define DEF_LOOP(TYPE, NAME, OP) \ + void __attribute__ ((noipa)) \ + test_##TYPE##_##NAME (TYPE *__restrict r, \ + TYPE *__restrict a, \ + TYPE *__restrict b, TYPE c, \ + TYPE *__restrict pred, int n) \ + { \ + for (int i = 0; i < n; ++i) \ + r[i] = pred[i] ? -a[i] OP b[i] * c : 5; \ + } + +#define TEST_TYPE(T, TYPE) \ + T (TYPE, add, +) \ + T (TYPE, sub, -) + +#define TEST_ALL(T) \ + TEST_TYPE (T, _Float16) \ + TEST_TYPE (T, float) \ + TEST_TYPE (T, double) + +TEST_ALL (DEF_LOOP) + +/* { dg-final { scan-assembler-times {vfnmacc\.vv\s+v[0-9]+,v[0-9]+,v[0-9]+,v0.t} 3 { xfail riscv*-*-* } } } */ +/* { dg-final { scan-assembler-times {vfmsac\.vv\s+v[0-9]+,v[0-9]+,v[0-9]+,v0.t} 3 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fms_fnms_run-1.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fms_fnms_run-1.c new file mode 100644 index 000000000000..29cabc9347d4 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fms_fnms_run-1.c @@ -0,0 +1,35 @@ +/* { dg-do run { target { riscv_vector } } } */ +/* { dg-additional-options "--param=riscv-autovec-preference=scalable -fno-vect-cost-model -ffast-math" } */ + +#include "cond_fms_fnms-1.c" + +#define FACTOR 17 +#define N 99 + +#define TEST_LOOP(TYPE, NAME, OP) \ + { \ + TYPE r[N], a[N], b[N], pred[N]; \ + for (int i = 0; i < N; ++i) \ + { \ + a[i] = (i & 1 ? i : 3 * i); \ + b[i] = (i >> 4) << (i & 15); \ + pred[i] = i % 3 < i % 5; \ + asm volatile ("" ::: "memory"); \ + } \ + test_##TYPE##_##NAME (r, a, b, FACTOR, pred, N); \ + for (int i = 0; i < N; ++i) \ + { \ + TYPE expected \ + = pred[i] != 1 ? -a[i] OP b[i] * (TYPE) FACTOR : b[i]; \ + if (r[i] != expected) \ + __builtin_abort (); \ + asm volatile ("" ::: "memory"); \ + } \ + } + +int +main (void) +{ + TEST_ALL (TEST_LOOP) + return 0; +} diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fms_fnms_run-2.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fms_fnms_run-2.c new file mode 100644 index 000000000000..ef691725b354 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fms_fnms_run-2.c @@ -0,0 +1,36 @@ +/* { dg-do run { target { riscv_vector } } } */ +/* { dg-additional-options "--param=riscv-autovec-preference=scalable -fno-vect-cost-model -ffast-math" } */ + +#include "cond_fms_fnms-2.c" + +#define FACTOR 17 +#define N 99 + +#define TEST_LOOP(TYPE, NAME, OP) \ + { \ + TYPE r[N], a[N], b[N], pred[N]; \ + for (int i = 0; i < N; ++i) \ + { \ + a[i] = (i & 1 ? i : 3 * i); \ + b[i] = (i >> 4) << (i & 15); \ + pred[i] = i % 3 < i % 5; \ + asm volatile ("" ::: "memory"); \ + } \ + test_##TYPE##_##NAME (r, a, b, FACTOR, pred, N); \ + for (int i = 0; i < N; ++i) \ + { \ + TYPE expected = (pred[i] != 1 \ + ? -a[i] OP b[i] * (TYPE) FACTOR \ + : (TYPE) FACTOR); \ + if (r[i] != expected) \ + __builtin_abort (); \ + asm volatile ("" ::: "memory"); \ + } \ + } + +int +main (void) +{ + TEST_ALL (TEST_LOOP) + return 0; +} diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fms_fnms_run-3.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fms_fnms_run-3.c new file mode 100644 index 000000000000..fe8b5f2b62b4 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fms_fnms_run-3.c @@ -0,0 +1,35 @@ +/* { dg-do run { target { riscv_vector } } } */ +/* { dg-additional-options "--param=riscv-autovec-preference=scalable -fno-vect-cost-model -ffast-math" } */ + +#include "cond_fms_fnms-3.c" + +#define FACTOR 17 +#define N 99 + +#define TEST_LOOP(TYPE, NAME, OP) \ + { \ + TYPE r[N], a[N], b[N], pred[N]; \ + for (int i = 0; i < N; ++i) \ + { \ + a[i] = (i & 1 ? i : 3 * i); \ + b[i] = (i >> 4) << (i & 15); \ + pred[i] = i % 3 < i % 5; \ + asm volatile ("" ::: "memory"); \ + } \ + test_##TYPE##_##NAME (r, a, b, FACTOR, pred, N); \ + for (int i = 0; i < N; ++i) \ + { \ + TYPE expected \ + = pred[i] != 1 ? -a[i] OP b[i] * (TYPE) FACTOR : a[i];\ + if (r[i] != expected) \ + __builtin_abort (); \ + asm volatile ("" ::: "memory"); \ + } \ + } + +int +main (void) +{ + TEST_ALL (TEST_LOOP) + return 0; +} diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fms_fnms_run-4.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fms_fnms_run-4.c new file mode 100644 index 000000000000..b68448de033b --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fms_fnms_run-4.c @@ -0,0 +1,36 @@ +/* { dg-do run { target { riscv_vector } } } */ +/* { dg-additional-options "--param=riscv-autovec-preference=scalable -fno-vect-cost-model -ffast-math" } */ + +#include "cond_fms_fnms-4.c" + +#define FACTOR 17 +#define N 99 + +#define TEST_LOOP(TYPE, NAME, OP) \ + { \ + TYPE r[N], a[N], b[N], pred[N]; \ + for (int i = 0; i < N; ++i) \ + { \ + a[i] = (i & 1 ? i : 3 * i); \ + b[i] = (i >> 4) << (i & 15); \ + pred[i] = i % 3; \ + asm volatile ("" ::: "memory"); \ + } \ + test_##TYPE##_##NAME (r, a, b, FACTOR, pred, N); \ + for (int i = 0; i < N; ++i) \ + { \ + TYPE expected = (pred[i] == 1 \ + ? -a[i] OP b[i] * (TYPE) FACTOR \ + : pred[i]); \ + if (r[i] != expected) \ + __builtin_abort (); \ + asm volatile ("" ::: "memory"); \ + } \ + } + +int +main (void) +{ + TEST_ALL (TEST_LOOP) + return 0; +} diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fms_fnms_run-5.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fms_fnms_run-5.c new file mode 100644 index 000000000000..575494a4e6ff --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fms_fnms_run-5.c @@ -0,0 +1,35 @@ +/* { dg-do run { target { riscv_vector } } } */ +/* { dg-additional-options "--param=riscv-autovec-preference=scalable -fno-vect-cost-model -ffast-math" } */ + +#include "cond_fms_fnms-5.c" + +#define FACTOR 17 +#define N 99 + +#define TEST_LOOP(TYPE, NAME, OP) \ + { \ + TYPE r[N], a[N], b[N], pred[N]; \ + for (int i = 0; i < N; ++i) \ + { \ + a[i] = (i & 1 ? i : 3 * i); \ + b[i] = (i >> 4) << (i & 15); \ + pred[i] = i % 3 < i % 5; \ + asm volatile ("" ::: "memory"); \ + } \ + test_##TYPE##_##NAME (r, a, b, FACTOR, pred, N); \ + for (int i = 0; i < N; ++i) \ + { \ + TYPE expected \ + = pred[i] ? -a[i] OP b[i] * (TYPE) FACTOR : 0; \ + if (r[i] != expected) \ + __builtin_abort (); \ + asm volatile ("" ::: "memory"); \ + } \ + } + +int +main (void) +{ + TEST_ALL (TEST_LOOP) + return 0; +} diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fms_fnms_run-6.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fms_fnms_run-6.c new file mode 100644 index 000000000000..e0e5bd953aea --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fms_fnms_run-6.c @@ -0,0 +1,35 @@ +/* { dg-do run { target { riscv_vector } } } */ +/* { dg-additional-options "--param=riscv-autovec-preference=scalable -fno-vect-cost-model -ffast-math" } */ + +#include "cond_fms_fnms-6.c" + +#define FACTOR 17 +#define N 99 + +#define TEST_LOOP(TYPE, NAME, OP) \ + { \ + TYPE r[N], a[N], b[N], pred[N]; \ + for (int i = 0; i < N; ++i) \ + { \ + a[i] = (i & 1 ? i : 3 * i); \ + b[i] = (i >> 4) << (i & 15); \ + pred[i] = i % 3 < i % 5; \ + asm volatile ("" ::: "memory"); \ + } \ + test_##TYPE##_##NAME (r, a, b, FACTOR, pred, N); \ + for (int i = 0; i < N; ++i) \ + { \ + TYPE expected \ + = pred[i] ? -a[i] OP b[i] * (TYPE) FACTOR : 5; \ + if (r[i] != expected) \ + __builtin_abort (); \ + asm volatile ("" ::: "memory"); \ + } \ + } + +int +main (void) +{ + TEST_ALL (TEST_LOOP) + return 0; +} diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fmul-1.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fmul-1.c new file mode 100644 index 000000000000..94cec7ff0b16 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fmul-1.c @@ -0,0 +1,29 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-march=rv32gcv_zvfh -mabi=ilp32d --param=riscv-autovec-preference=scalable -fno-vect-cost-model" } */ + +#include + +#define DEF_LOOP(TYPE, PRED_TYPE, NAME, CONST) \ + void __attribute__ ((noipa)) \ + test_##TYPE##_##NAME (TYPE *__restrict x, \ + TYPE *__restrict y, \ + PRED_TYPE *__restrict pred, \ + int n) \ + { \ + for (int i = 0; i < n; ++i) \ + x[i] = pred[i] != 1 ? y[i] * (TYPE) CONST : y[i]; \ + } + +#define TEST_TYPE(T, TYPE, PRED_TYPE) \ + T (TYPE, PRED_TYPE, half, 0.5) \ + T (TYPE, PRED_TYPE, two, 2.0) \ + T (TYPE, PRED_TYPE, four, 4.0) + +#define TEST_ALL(T) \ + TEST_TYPE (T, _Float16, int16_t) \ + TEST_TYPE (T, float, int32_t) \ + TEST_TYPE (T, double, int64_t) + +TEST_ALL (DEF_LOOP) + +/* { dg-final { scan-assembler-times {vfmul\.vv\s+v[0-9]+,v[0-9]+,v[0-9]+,v0.t} 9 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fmul-2.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fmul-2.c new file mode 100644 index 000000000000..c8ada38c0025 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fmul-2.c @@ -0,0 +1,28 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-march=rv32gcv_zvfh -mabi=ilp32d --param=riscv-autovec-preference=scalable -fno-vect-cost-model" } */ + +#include + +#define DEF_LOOP(TYPE, NAME, CONST) \ + void __attribute__ ((noipa)) \ + test_##TYPE##_##NAME (TYPE *__restrict x, \ + TYPE *__restrict y, \ + TYPE *__restrict z, \ + int n) \ + { \ + for (int i = 0; i < n; ++i) \ + x[i] = y[i] < 8 ? z[i] * (TYPE) CONST : y[i]; \ + } + +#define TEST_TYPE(T, TYPE) \ + T (TYPE, half, 0.5) \ + T (TYPE, two, 2.0) \ + T (TYPE, four, 4.0) + +#define TEST_ALL(T) \ + TEST_TYPE (T, float) \ + TEST_TYPE (T, double) + +TEST_ALL (DEF_LOOP) + +/* { dg-final { scan-assembler-times {vfmul\.vv\s+v[0-9]+,v[0-9]+,v[0-9]+,v0.t} 6 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fmul-3.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fmul-3.c new file mode 100644 index 000000000000..bd325ea84eea --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fmul-3.c @@ -0,0 +1,29 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-march=rv32gcv_zvfh -mabi=ilp32d --param=riscv-autovec-preference=scalable -fno-vect-cost-model" } */ + +#include + +#define DEF_LOOP(TYPE, PRED_TYPE, NAME, CONST) \ + void __attribute__ ((noipa)) \ + test_##TYPE##_##NAME (TYPE *__restrict x, \ + TYPE *__restrict y, \ + PRED_TYPE *__restrict pred, \ + int n) \ + { \ + for (int i = 0; i < n; ++i) \ + x[i] = pred[i] != 1 ? y[i] * (TYPE) CONST : 8; \ + } + +#define TEST_TYPE(T, TYPE, PRED_TYPE) \ + T (TYPE, PRED_TYPE, half, 0.5) \ + T (TYPE, PRED_TYPE, two, 2.0) \ + T (TYPE, PRED_TYPE, four, 4.0) + +#define TEST_ALL(T) \ + TEST_TYPE (T, _Float16, int16_t) \ + TEST_TYPE (T, float, int32_t) \ + TEST_TYPE (T, double, int64_t) + +TEST_ALL (DEF_LOOP) + +/* { dg-final { scan-assembler-times {vfmul\.vv\s+v[0-9]+,v[0-9]+,v[0-9]+,v0.t} 9 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fmul-4.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fmul-4.c new file mode 100644 index 000000000000..118c9a40e8fd --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fmul-4.c @@ -0,0 +1,29 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-march=rv32gcv_zvfh -mabi=ilp32d --param=riscv-autovec-preference=scalable -fno-vect-cost-model" } */ + +#include + +#define DEF_LOOP(TYPE, PRED_TYPE, NAME, CONST) \ + void __attribute__ ((noipa)) \ + test_##TYPE##_##NAME (TYPE *__restrict x, \ + TYPE *__restrict y, \ + PRED_TYPE *__restrict pred, \ + int n) \ + { \ + for (int i = 0; i < n; ++i) \ + x[i] = pred[i] != 1 ? y[i] * (TYPE) CONST : 0; \ + } + +#define TEST_TYPE(T, TYPE, PRED_TYPE) \ + T (TYPE, PRED_TYPE, half, 0.5) \ + T (TYPE, PRED_TYPE, two, 2.0) \ + T (TYPE, PRED_TYPE, four, 4.0) + +#define TEST_ALL(T) \ + TEST_TYPE (T, _Float16, int16_t) \ + TEST_TYPE (T, float, int32_t) \ + TEST_TYPE (T, double, int64_t) + +TEST_ALL (DEF_LOOP) + +/* { dg-final { scan-assembler-times {vfmul\.vv\s+v[0-9]+,v[0-9]+,v[0-9]+,v0.t} 9 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fmul_run-1.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fmul_run-1.c new file mode 100644 index 000000000000..49290a878d66 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fmul_run-1.c @@ -0,0 +1,32 @@ +/* { dg-do run { target { riscv_vector } } } */ +/* { dg-additional-options "--param=riscv-autovec-preference=scalable -fno-vect-cost-model" } */ + +#include "cond_fmul-1.c" + +#define N 99 + +#define TEST_LOOP(TYPE, PRED_TYPE, NAME, CONST) \ + { \ + TYPE x[N], y[N]; \ + PRED_TYPE pred[N]; \ + for (int i = 0; i < N; ++i) \ + { \ + y[i] = i * i; \ + pred[i] = i % 3; \ + } \ + test_##TYPE##_##NAME (x, y, pred, N); \ + for (int i = 0; i < N; ++i) \ + { \ + TYPE expected = i % 3 != 1 ? y[i] * (TYPE) CONST : y[i]; \ + if (x[i] != expected) \ + __builtin_abort (); \ + asm volatile ("" ::: "memory"); \ + } \ + } + +int +main (void) +{ + TEST_ALL (TEST_LOOP) + return 0; +} diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fmul_run-2.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fmul_run-2.c new file mode 100644 index 000000000000..f25a24cdb9c2 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fmul_run-2.c @@ -0,0 +1,31 @@ +/* { dg-do run { target { riscv_vector } } } */ +/* { dg-additional-options "--param=riscv-autovec-preference=scalable -fno-vect-cost-model" } */ + +#include "cond_fmul-2.c" + +#define N 99 + +#define TEST_LOOP(TYPE, NAME, CONST) \ + { \ + TYPE x[N], y[N], z[N]; \ + for (int i = 0; i < N; ++i) \ + { \ + y[i] = i % 13; \ + z[i] = i * i; \ + } \ + test_##TYPE##_##NAME (x, y, z, N); \ + for (int i = 0; i < N; ++i) \ + { \ + TYPE expected = y[i] < 8 ? z[i] * (TYPE) CONST : y[i]; \ + if (x[i] != expected) \ + __builtin_abort (); \ + asm volatile ("" ::: "memory"); \ + } \ + } + +int +main (void) +{ + TEST_ALL (TEST_LOOP) + return 0; +} diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fmul_run-3.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fmul_run-3.c new file mode 100644 index 000000000000..fc958e1f02e1 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fmul_run-3.c @@ -0,0 +1,32 @@ +/* { dg-do run { target { riscv_vector } } } */ +/* { dg-additional-options "--param=riscv-autovec-preference=scalable -fno-vect-cost-model" } */ + +#include "cond_fmul-3.c" + +#define N 99 + +#define TEST_LOOP(TYPE, PRED_TYPE, NAME, CONST) \ + { \ + TYPE x[N], y[N]; \ + PRED_TYPE pred[N]; \ + for (int i = 0; i < N; ++i) \ + { \ + y[i] = i * i; \ + pred[i] = i % 3; \ + } \ + test_##TYPE##_##NAME (x, y, pred, N); \ + for (int i = 0; i < N; ++i) \ + { \ + TYPE expected = i % 3 != 1 ? y[i] * (TYPE) CONST : 8; \ + if (x[i] != expected) \ + __builtin_abort (); \ + asm volatile ("" ::: "memory"); \ + } \ + } + +int +main (void) +{ + TEST_ALL (TEST_LOOP) + return 0; +} diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fmul_run-4.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fmul_run-4.c new file mode 100644 index 000000000000..692f4cd394c1 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_fmul_run-4.c @@ -0,0 +1,32 @@ +/* { dg-do run { target { riscv_vector } } } */ +/* { dg-additional-options "--param=riscv-autovec-preference=scalable -fno-vect-cost-model" } */ + +#include "cond_fmul-4.c" + +#define N 99 + +#define TEST_LOOP(TYPE, PRED_TYPE, NAME, CONST) \ + { \ + TYPE x[N], y[N]; \ + PRED_TYPE pred[N]; \ + for (int i = 0; i < N; ++i) \ + { \ + y[i] = i * i; \ + pred[i] = i % 3; \ + } \ + test_##TYPE##_##NAME (x, y, pred, N); \ + for (int i = 0; i < N; ++i) \ + { \ + TYPE expected = i % 3 != 1 ? y[i] * (TYPE) CONST : 0; \ + if (x[i] != expected) \ + __builtin_abort (); \ + asm volatile ("" ::: "memory"); \ + } \ + } + +int +main (void) +{ + TEST_ALL (TEST_LOOP) + return 0; +} diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_logical-1.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_logical-1.c new file mode 100644 index 000000000000..af1a2614f523 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_logical-1.c @@ -0,0 +1,43 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-march=rv32gcv_zvfh -mabi=ilp32d --param=riscv-autovec-preference=scalable -fno-vect-cost-model" } */ + +#include + +#define bit_and(A, B) ((A) & (B)) +#define bit_or(A, B) ((A) | (B)) +#define bit_xor(A, B) ((A) ^ (B)) +#define bit_bic(A, B) ((A) & ~(B)) + +#define DEF_LOOP(TYPE, OP) \ + void __attribute__ ((noinline, noclone)) \ + test_##TYPE##_##OP (TYPE *__restrict r, \ + TYPE *__restrict a, \ + TYPE *__restrict b, \ + TYPE *__restrict c, int n) \ + { \ + for (int i = 0; i < n; ++i) \ + r[i] = a[i] < 20 ? OP (b[i], c[i]) : b[i]; \ + } + +#define TEST_TYPE(T, TYPE) \ + T (TYPE, bit_and) \ + T (TYPE, bit_or) \ + T (TYPE, bit_xor) \ + T (TYPE, bit_bic) + +#define TEST_ALL(T) \ + TEST_TYPE (T, int8_t) \ + TEST_TYPE (T, uint8_t) \ + TEST_TYPE (T, int16_t) \ + TEST_TYPE (T, uint16_t) \ + TEST_TYPE (T, int32_t) \ + TEST_TYPE (T, uint32_t) \ + TEST_TYPE (T, int64_t) \ + TEST_TYPE (T, uint64_t) + +TEST_ALL (DEF_LOOP) + +/* { dg-final { scan-assembler-times {vnot\.v\s+v[0-9]+,v[0-9]+} 8 } } */ +/* { dg-final { scan-assembler-times {vand\.vv\s+v[0-9]+,v[0-9]+,v[0-9]+,v0.t} 16 } } */ +/* { dg-final { scan-assembler-times {vor\.vv\s+v[0-9]+,v[0-9]+,v[0-9]+,v0.t} 8 } } */ +/* { dg-final { scan-assembler-times {vxor\.vv\s+v[0-9]+,v[0-9]+,v[0-9]+,v0.t} 8 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_logical-2.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_logical-2.c new file mode 100644 index 000000000000..5f7614dd092d --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_logical-2.c @@ -0,0 +1,43 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-march=rv32gcv_zvfh -mabi=ilp32d --param=riscv-autovec-preference=scalable -fno-vect-cost-model" } */ + +#include + +#define bit_and(A, B) ((A) & (B)) +#define bit_or(A, B) ((A) | (B)) +#define bit_xor(A, B) ((A) ^ (B)) +#define bit_bic(A, B) ((A) & ~(B)) + +#define DEF_LOOP(TYPE, OP) \ + void __attribute__ ((noinline, noclone)) \ + test_##TYPE##_##OP (TYPE *__restrict r, \ + TYPE *__restrict a, \ + TYPE *__restrict b, \ + TYPE *__restrict c, int n) \ + { \ + for (int i = 0; i < n; ++i) \ + r[i] = a[i] < 20 ? OP (b[i], c[i]) : c[i]; \ + } + +#define TEST_TYPE(T, TYPE) \ + T (TYPE, bit_and) \ + T (TYPE, bit_or) \ + T (TYPE, bit_xor) \ + T (TYPE, bit_bic) + +#define TEST_ALL(T) \ + TEST_TYPE (T, int8_t) \ + TEST_TYPE (T, uint8_t) \ + TEST_TYPE (T, int16_t) \ + TEST_TYPE (T, uint16_t) \ + TEST_TYPE (T, int32_t) \ + TEST_TYPE (T, uint32_t) \ + TEST_TYPE (T, int64_t) \ + TEST_TYPE (T, uint64_t) + +TEST_ALL (DEF_LOOP) + +/* { dg-final { scan-assembler-times {vnot\.v\s+v[0-9]+,v[0-9]+} 8 } } */ +/* { dg-final { scan-assembler-times {vand\.vv\s+v[0-9]+,v[0-9]+,v[0-9]+,v0.t} 16 } } */ +/* { dg-final { scan-assembler-times {vor\.vv\s+v[0-9]+,v[0-9]+,v[0-9]+,v0.t} 8 } } */ +/* { dg-final { scan-assembler-times {vxor\.vv\s+v[0-9]+,v[0-9]+,v[0-9]+,v0.t} 8 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_logical-3.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_logical-3.c new file mode 100644 index 000000000000..032d12c393fe --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_logical-3.c @@ -0,0 +1,43 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-march=rv32gcv_zvfh -mabi=ilp32d --param=riscv-autovec-preference=scalable -fno-vect-cost-model" } */ + +#include + +#define bit_and(A, B) ((A) & (B)) +#define bit_or(A, B) ((A) | (B)) +#define bit_xor(A, B) ((A) ^ (B)) +#define bit_bic(A, B) ((A) & ~(B)) + +#define DEF_LOOP(TYPE, OP) \ + void __attribute__ ((noinline, noclone)) \ + test_##TYPE##_##OP (TYPE *__restrict r, \ + TYPE *__restrict a, \ + TYPE *__restrict b, \ + TYPE *__restrict c, int n) \ + { \ + for (int i = 0; i < n; ++i) \ + r[i] = a[i] < 20 ? OP (b[i], c[i]) : a[i]; \ + } + +#define TEST_TYPE(T, TYPE) \ + T (TYPE, bit_and) \ + T (TYPE, bit_or) \ + T (TYPE, bit_xor) \ + T (TYPE, bit_bic) + +#define TEST_ALL(T) \ + TEST_TYPE (T, int8_t) \ + TEST_TYPE (T, uint8_t) \ + TEST_TYPE (T, int16_t) \ + TEST_TYPE (T, uint16_t) \ + TEST_TYPE (T, int32_t) \ + TEST_TYPE (T, uint32_t) \ + TEST_TYPE (T, int64_t) \ + TEST_TYPE (T, uint64_t) + +TEST_ALL (DEF_LOOP) + +/* { dg-final { scan-assembler-times {vnot\.v\s+v[0-9]+,v[0-9]+} 8 } } */ +/* { dg-final { scan-assembler-times {vand\.vv\s+v[0-9]+,v[0-9]+,v[0-9]+,v0.t} 16 } } */ +/* { dg-final { scan-assembler-times {vor\.vv\s+v[0-9]+,v[0-9]+,v[0-9]+,v0.t} 8 } } */ +/* { dg-final { scan-assembler-times {vxor\.vv\s+v[0-9]+,v[0-9]+,v[0-9]+,v0.t} 8 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_logical-4.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_logical-4.c new file mode 100644 index 000000000000..e8d93377861d --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_logical-4.c @@ -0,0 +1,43 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-march=rv32gcv_zvfh -mabi=ilp32d --param=riscv-autovec-preference=scalable -fno-vect-cost-model" } */ + +#include + +#define bit_and(A, B) ((A) & (B)) +#define bit_or(A, B) ((A) | (B)) +#define bit_xor(A, B) ((A) ^ (B)) +#define bit_bic(A, B) ((A) & ~(B)) + +#define DEF_LOOP(TYPE, OP) \ + void __attribute__ ((noinline, noclone)) \ + test_##TYPE##_##OP (TYPE *__restrict r, \ + TYPE *__restrict a, \ + TYPE *__restrict b, \ + TYPE *__restrict c, int n) \ + { \ + for (int i = 0; i < n; ++i) \ + r[i] = a[i] < 20 ? OP (b[i], c[i]) : 42; \ + } + +#define TEST_TYPE(T, TYPE) \ + T (TYPE, bit_and) \ + T (TYPE, bit_or) \ + T (TYPE, bit_xor) \ + T (TYPE, bit_bic) + +#define TEST_ALL(T) \ + TEST_TYPE (T, int8_t) \ + TEST_TYPE (T, uint8_t) \ + TEST_TYPE (T, int16_t) \ + TEST_TYPE (T, uint16_t) \ + TEST_TYPE (T, int32_t) \ + TEST_TYPE (T, uint32_t) \ + TEST_TYPE (T, int64_t) \ + TEST_TYPE (T, uint64_t) + +TEST_ALL (DEF_LOOP) + +/* { dg-final { scan-assembler-times {vnot\.v\s+v[0-9]+,v[0-9]+} 8 } } */ +/* { dg-final { scan-assembler-times {vand\.vv\s+v[0-9]+,v[0-9]+,v[0-9]+,v0.t} 16 } } */ +/* { dg-final { scan-assembler-times {vor\.vv\s+v[0-9]+,v[0-9]+,v[0-9]+,v0.t} 8 } } */ +/* { dg-final { scan-assembler-times {vxor\.vv\s+v[0-9]+,v[0-9]+,v[0-9]+,v0.t} 8 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_logical-5.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_logical-5.c new file mode 100644 index 000000000000..c59ef510fd7a --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_logical-5.c @@ -0,0 +1,43 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-march=rv32gcv_zvfh -mabi=ilp32d --param=riscv-autovec-preference=scalable -fno-vect-cost-model" } */ + +#include + +#define bit_and(A, B) ((A) & (B)) +#define bit_or(A, B) ((A) | (B)) +#define bit_xor(A, B) ((A) ^ (B)) +#define bit_bic(A, B) ((A) & ~(B)) + +#define DEF_LOOP(TYPE, OP) \ + void __attribute__ ((noinline, noclone)) \ + test_##TYPE##_##OP (TYPE *__restrict r, \ + TYPE *__restrict a, \ + TYPE *__restrict b, \ + TYPE *__restrict c, int n) \ + { \ + for (int i = 0; i < n; ++i) \ + r[i] = a[i] < 20 ? OP (b[i], c[i]) : 0; \ + } + +#define TEST_TYPE(T, TYPE) \ + T (TYPE, bit_and) \ + T (TYPE, bit_or) \ + T (TYPE, bit_xor) \ + T (TYPE, bit_bic) + +#define TEST_ALL(T) \ + TEST_TYPE (T, int8_t) \ + TEST_TYPE (T, uint8_t) \ + TEST_TYPE (T, int16_t) \ + TEST_TYPE (T, uint16_t) \ + TEST_TYPE (T, int32_t) \ + TEST_TYPE (T, uint32_t) \ + TEST_TYPE (T, int64_t) \ + TEST_TYPE (T, uint64_t) + +TEST_ALL (DEF_LOOP) + +/* { dg-final { scan-assembler-times {vnot\.v\s+v[0-9]+,v[0-9]+} 8 } } */ +/* { dg-final { scan-assembler-times {vand\.vv\s+v[0-9]+,v[0-9]+,v[0-9]+,v0.t} 16 } } */ +/* { dg-final { scan-assembler-times {vor\.vv\s+v[0-9]+,v[0-9]+,v[0-9]+,v0.t} 8 } } */ +/* { dg-final { scan-assembler-times {vxor\.vv\s+v[0-9]+,v[0-9]+,v[0-9]+,v0.t} 8 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_logical_run-1.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_logical_run-1.c new file mode 100644 index 000000000000..e741f7d6aaca --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_logical_run-1.c @@ -0,0 +1,33 @@ +/* { dg-do run { target { riscv_vector } } } */ +/* { dg-additional-options "--param=riscv-autovec-preference=scalable -fno-vect-cost-model" } */ + +#include "cond_logical-1.c" + +#define N 99 + +#define TEST_LOOP(TYPE, OP) \ + { \ + TYPE r[N], a[N], b[N], c[N]; \ + for (int i = 0; i < N; ++i) \ + { \ + a[i] = (i & 1 ? i : 3 * i); \ + b[i] = (i >> 4) << (i & 15); \ + c[i] = ((i + 2) % 3) * (i + 1); \ + asm volatile ("" ::: "memory"); \ + } \ + test_##TYPE##_##OP (r, a, b, c, N); \ + for (int i = 0; i < N; ++i) \ + { \ + TYPE expected = a[i] < 20 ? OP (b[i], c[i]) : b[i]; \ + if (r[i] != expected) \ + __builtin_abort (); \ + asm volatile ("" ::: "memory"); \ + } \ + } + +int +main (void) +{ + TEST_ALL (TEST_LOOP) + return 0; +} diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_logical_run-2.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_logical_run-2.c new file mode 100644 index 000000000000..bdd697ec9913 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_logical_run-2.c @@ -0,0 +1,33 @@ +/* { dg-do run { target { riscv_vector } } } */ +/* { dg-additional-options "--param=riscv-autovec-preference=scalable -fno-vect-cost-model" } */ + +#include "cond_logical-2.c" + +#define N 99 + +#define TEST_LOOP(TYPE, OP) \ + { \ + TYPE r[N], a[N], b[N], c[N]; \ + for (int i = 0; i < N; ++i) \ + { \ + a[i] = (i & 1 ? i : 3 * i); \ + b[i] = (i >> 4) << (i & 15); \ + c[i] = ((i + 2) % 3) * (i + 1); \ + asm volatile ("" ::: "memory"); \ + } \ + test_##TYPE##_##OP (r, a, b, c, N); \ + for (int i = 0; i < N; ++i) \ + { \ + TYPE expected = a[i] < 20 ? OP (b[i], c[i]) : c[i]; \ + if (r[i] != expected) \ + __builtin_abort (); \ + asm volatile ("" ::: "memory"); \ + } \ + } + +int +main (void) +{ + TEST_ALL (TEST_LOOP) + return 0; +} diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_logical_run-3.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_logical_run-3.c new file mode 100644 index 000000000000..b48bcb19d269 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_logical_run-3.c @@ -0,0 +1,33 @@ +/* { dg-do run { target { riscv_vector } } } */ +/* { dg-additional-options "--param=riscv-autovec-preference=scalable -fno-vect-cost-model" } */ + +#include "cond_logical-3.c" + +#define N 99 + +#define TEST_LOOP(TYPE, OP) \ + { \ + TYPE r[N], a[N], b[N], c[N]; \ + for (int i = 0; i < N; ++i) \ + { \ + a[i] = (i & 1 ? i : 3 * i); \ + b[i] = (i >> 4) << (i & 15); \ + c[i] = ((i + 2) % 3) * (i + 1); \ + asm volatile ("" ::: "memory"); \ + } \ + test_##TYPE##_##OP (r, a, b, c, N); \ + for (int i = 0; i < N; ++i) \ + { \ + TYPE expected = a[i] < 20 ? OP (b[i], c[i]) : a[i]; \ + if (r[i] != expected) \ + __builtin_abort (); \ + asm volatile ("" ::: "memory"); \ + } \ + } + +int +main (void) +{ + TEST_ALL (TEST_LOOP) + return 0; +} diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_logical_run-4.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_logical_run-4.c new file mode 100644 index 000000000000..0d04e69177f9 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_logical_run-4.c @@ -0,0 +1,33 @@ +/* { dg-do run { target { riscv_vector } } } */ +/* { dg-additional-options "--param=riscv-autovec-preference=scalable -fno-vect-cost-model" } */ + +#include "cond_logical-4.c" + +#define N 99 + +#define TEST_LOOP(TYPE, OP) \ + { \ + TYPE r[N], a[N], b[N], c[N]; \ + for (int i = 0; i < N; ++i) \ + { \ + a[i] = (i & 1 ? i : 3 * i); \ + b[i] = (i >> 4) << (i & 15); \ + c[i] = ((i + 2) % 3) * (i + 1); \ + asm volatile ("" ::: "memory"); \ + } \ + test_##TYPE##_##OP (r, a, b, c, N); \ + for (int i = 0; i < N; ++i) \ + { \ + TYPE expected = a[i] < 20 ? OP (b[i], c[i]) : 42; \ + if (r[i] != expected) \ + __builtin_abort (); \ + asm volatile ("" ::: "memory"); \ + } \ + } + +int +main (void) +{ + TEST_ALL (TEST_LOOP) + return 0; +} diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_logical_run-5.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_logical_run-5.c new file mode 100644 index 000000000000..87501057c20d --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_logical_run-5.c @@ -0,0 +1,33 @@ +/* { dg-do run { target { riscv_vector } } } */ +/* { dg-additional-options "--param=riscv-autovec-preference=scalable -fno-vect-cost-model" } */ + +#include "cond_logical-5.c" + +#define N 99 + +#define TEST_LOOP(TYPE, OP) \ + { \ + TYPE r[N], a[N], b[N], c[N]; \ + for (int i = 0; i < N; ++i) \ + { \ + a[i] = (i & 1 ? i : 3 * i); \ + b[i] = (i >> 4) << (i & 15); \ + c[i] = ((i + 2) % 3) * (i + 1); \ + asm volatile ("" ::: "memory"); \ + } \ + test_##TYPE##_##OP (r, a, b, c, N); \ + for (int i = 0; i < N; ++i) \ + { \ + TYPE expected = a[i] < 20 ? OP (b[i], c[i]) : 0; \ + if (r[i] != expected) \ + __builtin_abort (); \ + asm volatile ("" ::: "memory"); \ + } \ + } + +int +main (void) +{ + TEST_ALL (TEST_LOOP) + return 0; +} diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_shift-1.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_shift-1.c new file mode 100644 index 000000000000..6bf25383deed --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_shift-1.c @@ -0,0 +1,33 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-march=rv32gcv_zvfh -mabi=ilp32d --param=riscv-autovec-preference=scalable -fno-vect-cost-model" } */ + +#include + +#define DEF_LOOP(TYPE, NAME, OP) \ + void __attribute__ ((noipa)) \ + test_##TYPE##_##NAME (TYPE *__restrict r, TYPE *__restrict a, \ + TYPE *__restrict b, int n) \ + { \ + for (int i = 0; i < n; ++i) \ + r[i] = a[i] > 20 ? b[i] OP 3 : b[i]; \ + } + +#define TEST_TYPE(T, TYPE) \ + T (TYPE, shl, <<) \ + T (TYPE, shr, >>) + +#define TEST_ALL(T) \ + TEST_TYPE (T, int8_t) \ + TEST_TYPE (T, uint8_t) \ + TEST_TYPE (T, int16_t) \ + TEST_TYPE (T, uint16_t) \ + TEST_TYPE (T, int32_t) \ + TEST_TYPE (T, uint32_t) \ + TEST_TYPE (T, int64_t) \ + TEST_TYPE (T, uint64_t) + +TEST_ALL (DEF_LOOP) + +/* { dg-final { scan-assembler-times {vsll\.vi\s+v[0-9]+,v[0-9]+,3,v0.t} 8 } } */ +/* { dg-final { scan-assembler-times {vsra\.vi\s+v[0-9]+,v[0-9]+,3,v0.t} 4 } } */ +/* { dg-final { scan-assembler-times {vsrl\.vi\s+v[0-9]+,v[0-9]+,3,v0.t} 4 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_shift-2.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_shift-2.c new file mode 100644 index 000000000000..2edf38f89bd2 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_shift-2.c @@ -0,0 +1,33 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-march=rv32gcv_zvfh -mabi=ilp32d --param=riscv-autovec-preference=scalable -fno-vect-cost-model" } */ + +#include + +#define DEF_LOOP(TYPE, NAME, OP) \ + void __attribute__ ((noipa)) \ + test_##TYPE##_##NAME (TYPE *__restrict r, TYPE *__restrict a, \ + TYPE *__restrict b, int n) \ + { \ + for (int i = 0; i < n; ++i) \ + r[i] = a[i] > 20 ? b[i] OP 3 : a[i]; \ + } + +#define TEST_TYPE(T, TYPE) \ + T (TYPE, shl, <<) \ + T (TYPE, shr, >>) + +#define TEST_ALL(T) \ + TEST_TYPE (T, int8_t) \ + TEST_TYPE (T, uint8_t) \ + TEST_TYPE (T, int16_t) \ + TEST_TYPE (T, uint16_t) \ + TEST_TYPE (T, int32_t) \ + TEST_TYPE (T, uint32_t) \ + TEST_TYPE (T, int64_t) \ + TEST_TYPE (T, uint64_t) + +TEST_ALL (DEF_LOOP) + +/* { dg-final { scan-assembler-times {vsll\.vi\s+v[0-9]+,v[0-9]+,3,v0.t} 8 } } */ +/* { dg-final { scan-assembler-times {vsra\.vi\s+v[0-9]+,v[0-9]+,3,v0.t} 4 } } */ +/* { dg-final { scan-assembler-times {vsrl\.vi\s+v[0-9]+,v[0-9]+,3,v0.t} 4 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_shift-3.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_shift-3.c new file mode 100644 index 000000000000..84f91ee26681 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_shift-3.c @@ -0,0 +1,33 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-march=rv32gcv_zvfh -mabi=ilp32d --param=riscv-autovec-preference=scalable -fno-vect-cost-model" } */ + +#include + +#define DEF_LOOP(TYPE, NAME, OP) \ + void __attribute__ ((noipa)) \ + test_##TYPE##_##NAME (TYPE *__restrict r, TYPE *__restrict a, \ + TYPE *__restrict b, int n) \ + { \ + for (int i = 0; i < n; ++i) \ + r[i] = a[i] > 20 ? b[i] OP 3 : 72; \ + } + +#define TEST_TYPE(T, TYPE) \ + T (TYPE, shl, <<) \ + T (TYPE, shr, >>) + +#define TEST_ALL(T) \ + TEST_TYPE (T, int8_t) \ + TEST_TYPE (T, uint8_t) \ + TEST_TYPE (T, int16_t) \ + TEST_TYPE (T, uint16_t) \ + TEST_TYPE (T, int32_t) \ + TEST_TYPE (T, uint32_t) \ + TEST_TYPE (T, int64_t) \ + TEST_TYPE (T, uint64_t) + +TEST_ALL (DEF_LOOP) + +/* { dg-final { scan-assembler-times {vsll\.vi\s+v[0-9]+,v[0-9]+,3,v0.t} 8 } } */ +/* { dg-final { scan-assembler-times {vsra\.vi\s+v[0-9]+,v[0-9]+,3,v0.t} 4 } } */ +/* { dg-final { scan-assembler-times {vsrl\.vi\s+v[0-9]+,v[0-9]+,3,v0.t} 4 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_shift-4.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_shift-4.c new file mode 100644 index 000000000000..a4be0b35aaf1 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_shift-4.c @@ -0,0 +1,33 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-march=rv32gcv_zvfh -mabi=ilp32d --param=riscv-autovec-preference=scalable -fno-vect-cost-model" } */ + +#include + +#define DEF_LOOP(TYPE, NAME, OP) \ + void __attribute__ ((noipa)) \ + test_##TYPE##_##NAME (TYPE *__restrict r, TYPE *__restrict a, \ + TYPE *__restrict b, int n) \ + { \ + for (int i = 0; i < n; ++i) \ + r[i] = a[i] > 20 ? b[i] OP 3 : 0; \ + } + +#define TEST_TYPE(T, TYPE) \ + T (TYPE, shl, <<) \ + T (TYPE, shr, >>) + +#define TEST_ALL(T) \ + TEST_TYPE (T, int8_t) \ + TEST_TYPE (T, uint8_t) \ + TEST_TYPE (T, int16_t) \ + TEST_TYPE (T, uint16_t) \ + TEST_TYPE (T, int32_t) \ + TEST_TYPE (T, uint32_t) \ + TEST_TYPE (T, int64_t) \ + TEST_TYPE (T, uint64_t) + +TEST_ALL (DEF_LOOP) + +/* { dg-final { scan-assembler-times {vsll\.vi\s+v[0-9]+,v[0-9]+,3,v0.t} 8 } } */ +/* { dg-final { scan-assembler-times {vsra\.vi\s+v[0-9]+,v[0-9]+,3,v0.t} 4 } } */ +/* { dg-final { scan-assembler-times {vsrl\.vi\s+v[0-9]+,v[0-9]+,3,v0.t} 4 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_shift-5.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_shift-5.c new file mode 100644 index 000000000000..06a0a1aaecdc --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_shift-5.c @@ -0,0 +1,29 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-march=rv32gcv_zvfh -mabi=ilp32d --param=riscv-autovec-preference=scalable -fno-vect-cost-model" } */ + +#include + +#define DEF_LOOP(TYPE, NAME, OP) \ + void __attribute__ ((noipa)) \ + test_##TYPE##_##NAME (TYPE *__restrict r, TYPE *__restrict a, \ + TYPE *__restrict b, TYPE *__restrict c, int n) \ + { \ + for (int i = 0; i < n; ++i) \ + r[i] = a[i] > 20 ? b[i] OP c[i] : b[i]; \ + } + +#define TEST_TYPE(T, TYPE) \ + T (TYPE, shl, <<) \ + T (TYPE, shr, >>) + +#define TEST_ALL(T) \ + TEST_TYPE (T, int32_t) \ + TEST_TYPE (T, uint32_t) \ + TEST_TYPE (T, int64_t) \ + TEST_TYPE (T, uint64_t) + +TEST_ALL (DEF_LOOP) + +/* { dg-final { scan-assembler-times {vsll\.vv\s+v[0-9]+,v[0-9]+,v[0-9]+,v0.t} 4 } } */ +/* { dg-final { scan-assembler-times {vsra\.vv\s+v[0-9]+,v[0-9]+,v[0-9]+,v0.t} 2 } } */ +/* { dg-final { scan-assembler-times {vsrl\.vv\s+v[0-9]+,v[0-9]+,v[0-9]+,v0.t} 2 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_shift-6.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_shift-6.c new file mode 100644 index 000000000000..3b1c4859e05b --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_shift-6.c @@ -0,0 +1,27 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-march=rv32gcv_zvfh -mabi=ilp32d --param=riscv-autovec-preference=scalable -fno-vect-cost-model" } */ + +#include + +#define DEF_LOOP(TYPE, NAME, OP) \ + void __attribute__ ((noipa)) \ + test_##TYPE##_##NAME (TYPE *__restrict r, TYPE *__restrict a, \ + TYPE *__restrict b, TYPE *__restrict c, int n) \ + { \ + for (int i = 0; i < n; ++i) \ + r[i] = a[i] > 20 ? b[i] OP c[i] : c[i]; \ + } + +#define TEST_TYPE(T, TYPE) \ + T (TYPE, shl, <<) \ + T (TYPE, shr, >>) + +#define TEST_ALL(T) \ + TEST_TYPE (T, int32_t) \ + TEST_TYPE (T, uint32_t) + +TEST_ALL (DEF_LOOP) + +/* { dg-final { scan-assembler-times {vsll\.vv\s+v[0-9]+,v[0-9]+,v[0-9]+,v0.t} 2 } } */ +/* { dg-final { scan-assembler-times {vsra\.vv\s+v[0-9]+,v[0-9]+,v[0-9]+,v0.t} 1 } } */ +/* { dg-final { scan-assembler-times {vsrl\.vv\s+v[0-9]+,v[0-9]+,v[0-9]+,v0.t} 1 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_shift-7.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_shift-7.c new file mode 100644 index 000000000000..d44cf43eeb0f --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_shift-7.c @@ -0,0 +1,29 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-march=rv32gcv_zvfh -mabi=ilp32d --param=riscv-autovec-preference=scalable -fno-vect-cost-model" } */ + +#include + +#define DEF_LOOP(TYPE, NAME, OP) \ + void __attribute__ ((noipa)) \ + test_##TYPE##_##NAME (TYPE *__restrict r, TYPE *__restrict a, \ + TYPE *__restrict b, TYPE *__restrict c, int n) \ + { \ + for (int i = 0; i < n; ++i) \ + r[i] = a[i] > 20 ? b[i] OP c[i] : a[i]; \ + } + +#define TEST_TYPE(T, TYPE) \ + T (TYPE, shl, <<) \ + T (TYPE, shr, >>) + +#define TEST_ALL(T) \ + TEST_TYPE (T, int32_t) \ + TEST_TYPE (T, uint32_t) \ + TEST_TYPE (T, int64_t) \ + TEST_TYPE (T, uint64_t) + +TEST_ALL (DEF_LOOP) + +/* { dg-final { scan-assembler-times {vsll\.vv\s+v[0-9]+,v[0-9]+,v[0-9]+,v0.t} 4 } } */ +/* { dg-final { scan-assembler-times {vsra\.vv\s+v[0-9]+,v[0-9]+,v[0-9]+,v0.t} 2 } } */ +/* { dg-final { scan-assembler-times {vsrl\.vv\s+v[0-9]+,v[0-9]+,v[0-9]+,v0.t} 2 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_shift-8.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_shift-8.c new file mode 100644 index 000000000000..e68289be5e07 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_shift-8.c @@ -0,0 +1,29 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-march=rv32gcv_zvfh -mabi=ilp32d --param=riscv-autovec-preference=scalable -fno-vect-cost-model" } */ + +#include + +#define DEF_LOOP(TYPE, NAME, OP) \ + void __attribute__ ((noipa)) \ + test_##TYPE##_##NAME (TYPE *__restrict r, TYPE *__restrict a, \ + TYPE *__restrict b, TYPE *__restrict c, int n) \ + { \ + for (int i = 0; i < n; ++i) \ + r[i] = a[i] > 20 ? b[i] OP c[i] : 91; \ + } + +#define TEST_TYPE(T, TYPE) \ + T (TYPE, shl, <<) \ + T (TYPE, shr, >>) + +#define TEST_ALL(T) \ + TEST_TYPE (T, int32_t) \ + TEST_TYPE (T, uint32_t) \ + TEST_TYPE (T, int64_t) \ + TEST_TYPE (T, uint64_t) + +TEST_ALL (DEF_LOOP) + +/* { dg-final { scan-assembler-times {vsll\.vv\s+v[0-9]+,v[0-9]+,v[0-9]+,v0.t} 4 } } */ +/* { dg-final { scan-assembler-times {vsra\.vv\s+v[0-9]+,v[0-9]+,v[0-9]+,v0.t} 2 } } */ +/* { dg-final { scan-assembler-times {vsrl\.vv\s+v[0-9]+,v[0-9]+,v[0-9]+,v0.t} 2 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_shift-9.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_shift-9.c new file mode 100644 index 000000000000..892bc08407d2 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_shift-9.c @@ -0,0 +1,29 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-march=rv32gcv_zvfh -mabi=ilp32d --param=riscv-autovec-preference=scalable -fno-vect-cost-model" } */ + +#include + +#define DEF_LOOP(TYPE, NAME, OP) \ + void __attribute__ ((noipa)) \ + test_##TYPE##_##NAME (TYPE *__restrict r, TYPE *__restrict a, \ + TYPE *__restrict b, TYPE *__restrict c, int n) \ + { \ + for (int i = 0; i < n; ++i) \ + r[i] = a[i] > 20 ? b[i] OP c[i] : 0; \ + } + +#define TEST_TYPE(T, TYPE) \ + T (TYPE, shl, <<) \ + T (TYPE, shr, >>) + +#define TEST_ALL(T) \ + TEST_TYPE (T, int32_t) \ + TEST_TYPE (T, uint32_t) \ + TEST_TYPE (T, int64_t) \ + TEST_TYPE (T, uint64_t) + +TEST_ALL (DEF_LOOP) + +/* { dg-final { scan-assembler-times {vsll\.vv\s+v[0-9]+,v[0-9]+,v[0-9]+,v0.t} 4 } } */ +/* { dg-final { scan-assembler-times {vsra\.vv\s+v[0-9]+,v[0-9]+,v[0-9]+,v0.t} 2 } } */ +/* { dg-final { scan-assembler-times {vsrl\.vv\s+v[0-9]+,v[0-9]+,v[0-9]+,v0.t} 2 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_shift_run-1.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_shift_run-1.c new file mode 100644 index 000000000000..d4ddc1cfa486 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_shift_run-1.c @@ -0,0 +1,27 @@ +/* { dg-do run { target { riscv_vector } } } */ +/* { dg-additional-options "--param=riscv-autovec-preference=scalable -fno-vect-cost-model" } */ + +#include "cond_shift-1.c" + +#define N 99 + +#define TEST_LOOP(TYPE, NAME, OP) \ + { \ + TYPE r[N], a[N], b[N]; \ + for (int i = 0; i < N; ++i) \ + { \ + a[i] = (i & 1 ? i : 3 * i); \ + b[i] = (i >> 4) << (i & 15); \ + asm volatile ("" ::: "memory"); \ + } \ + test_##TYPE##_##NAME (r, a, b, N); \ + for (int i = 0; i < N; ++i) \ + if (r[i] != (TYPE) (a[i] > 20 ? b[i] OP 3 : b[i])) \ + __builtin_abort (); \ + } + +int main () +{ + TEST_ALL (TEST_LOOP) + return 0; +} diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_shift_run-2.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_shift_run-2.c new file mode 100644 index 000000000000..a2eb673fbcfe --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_shift_run-2.c @@ -0,0 +1,28 @@ +/* { dg-do run { target { riscv_vector } } } */ +/* { dg-additional-options "--param=riscv-autovec-preference=scalable -fno-vect-cost-model" } */ + +#include "cond_shift-2.c" + +#define N 99 + +#define TEST_LOOP(TYPE, NAME, OP) \ + { \ + TYPE r[N], a[N], b[N]; \ + for (int i = 0; i < N; ++i) \ + { \ + a[i] = (i & 1 ? i : 3 * i); \ + b[i] = (i >> 4) << (i & 15); \ + asm volatile ("" ::: "memory"); \ + } \ + test_##TYPE##_##NAME (r, a, b, N); \ + for (int i = 0; i < N; ++i) \ + if (r[i] != (TYPE) (a[i] > 20 ? b[i] OP 3 : a[i])) \ + __builtin_abort (); \ + } + +int main () +{ + TEST_ALL (TEST_LOOP) + return 0; +} + diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_shift_run-3.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_shift_run-3.c new file mode 100644 index 000000000000..e1bb44ed00f3 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_shift_run-3.c @@ -0,0 +1,27 @@ +/* { dg-do run { target { riscv_vector } } } */ +/* { dg-additional-options "--param=riscv-autovec-preference=scalable -fno-vect-cost-model" } */ + +#include "cond_shift-3.c" + +#define N 99 + +#define TEST_LOOP(TYPE, NAME, OP) \ + { \ + TYPE r[N], a[N], b[N]; \ + for (int i = 0; i < N; ++i) \ + { \ + a[i] = (i & 1 ? i : 3 * i); \ + b[i] = (i >> 4) << (i & 15); \ + asm volatile ("" ::: "memory"); \ + } \ + test_##TYPE##_##NAME (r, a, b, N); \ + for (int i = 0; i < N; ++i) \ + if (r[i] != (TYPE) (a[i] > 20 ? b[i] OP 3 : 72)) \ + __builtin_abort (); \ + } + +int main () +{ + TEST_ALL (TEST_LOOP) + return 0; +} diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_shift_run-4.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_shift_run-4.c new file mode 100644 index 000000000000..c1bbe6bcc67e --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_shift_run-4.c @@ -0,0 +1,27 @@ +/* { dg-do run { target { riscv_vector } } } */ +/* { dg-additional-options "--param=riscv-autovec-preference=scalable -fno-vect-cost-model" } */ + +#include "cond_shift-4.c" + +#define N 99 + +#define TEST_LOOP(TYPE, NAME, OP) \ + { \ + TYPE r[N], a[N], b[N]; \ + for (int i = 0; i < N; ++i) \ + { \ + a[i] = (i & 1 ? i : 3 * i); \ + b[i] = (i >> 4) << (i & 15); \ + asm volatile ("" ::: "memory"); \ + } \ + test_##TYPE##_##NAME (r, a, b, N); \ + for (int i = 0; i < N; ++i) \ + if (r[i] != (TYPE) (a[i] > 20 ? b[i] OP 3 : 0)) \ + __builtin_abort (); \ + } + +int main () +{ + TEST_ALL (TEST_LOOP) + return 0; +} diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_shift_run-5.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_shift_run-5.c new file mode 100644 index 000000000000..ff6b78ce5760 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_shift_run-5.c @@ -0,0 +1,28 @@ +/* { dg-do run { target { riscv_vector } } } */ +/* { dg-additional-options "--param=riscv-autovec-preference=scalable -fno-vect-cost-model" } */ + +#include "cond_shift-5.c" + +#define N 99 + +#define TEST_LOOP(TYPE, NAME, OP) \ + { \ + TYPE r[N], a[N], b[N], c[N]; \ + for (int i = 0; i < N; ++i) \ + { \ + a[i] = (i & 1 ? i : 3 * i); \ + b[i] = (i >> 4) << (i & 15); \ + c[i] = ~i & 7; \ + asm volatile ("" ::: "memory"); \ + } \ + test_##TYPE##_##NAME (r, a, b, c, N); \ + for (int i = 0; i < N; ++i) \ + if (r[i] != (TYPE) (a[i] > 20 ? b[i] OP c[i] : b[i])) \ + __builtin_abort (); \ + } + +int main () +{ + TEST_ALL (TEST_LOOP) + return 0; +} diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_shift_run-6.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_shift_run-6.c new file mode 100644 index 000000000000..1a3a6e938d55 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_shift_run-6.c @@ -0,0 +1,28 @@ +/* { dg-do run { target { riscv_vector } } } */ +/* { dg-additional-options "--param=riscv-autovec-preference=scalable -fno-vect-cost-model" } */ + +#include "cond_shift-6.c" + +#define N 99 + +#define TEST_LOOP(TYPE, NAME, OP) \ + { \ + TYPE r[N], a[N], b[N], c[N]; \ + for (int i = 0; i < N; ++i) \ + { \ + a[i] = (i & 1 ? i : 3 * i); \ + b[i] = (i >> 4) << (i & 15); \ + c[i] = ~i & 7; \ + asm volatile ("" ::: "memory"); \ + } \ + test_##TYPE##_##NAME (r, a, b, c, N); \ + for (int i = 0; i < N; ++i) \ + if (r[i] != (TYPE) (a[i] > 20 ? b[i] OP c[i] : c[i])) \ + __builtin_abort (); \ + } + +int main () +{ + TEST_ALL (TEST_LOOP) + return 0; +} diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_shift_run-7.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_shift_run-7.c new file mode 100644 index 000000000000..45823c8c888d --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_shift_run-7.c @@ -0,0 +1,28 @@ +/* { dg-do run { target { riscv_vector } } } */ +/* { dg-additional-options "--param=riscv-autovec-preference=scalable -fno-vect-cost-model" } */ + +#include "cond_shift-7.c" + +#define N 99 + +#define TEST_LOOP(TYPE, NAME, OP) \ + { \ + TYPE r[N], a[N], b[N], c[N]; \ + for (int i = 0; i < N; ++i) \ + { \ + a[i] = (i & 1 ? i : 3 * i); \ + b[i] = (i >> 4) << (i & 15); \ + c[i] = ~i & 7; \ + asm volatile ("" ::: "memory"); \ + } \ + test_##TYPE##_##NAME (r, a, b, c, N); \ + for (int i = 0; i < N; ++i) \ + if (r[i] != (TYPE) (a[i] > 20 ? b[i] OP c[i] : a[i])) \ + __builtin_abort (); \ + } + +int main () +{ + TEST_ALL (TEST_LOOP) + return 0; +} diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_shift_run-8.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_shift_run-8.c new file mode 100644 index 000000000000..dd34df0b4cda --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_shift_run-8.c @@ -0,0 +1,28 @@ +/* { dg-do run { target { riscv_vector } } } */ +/* { dg-additional-options "--param=riscv-autovec-preference=scalable -fno-vect-cost-model" } */ + +#include "cond_shift-8.c" + +#define N 99 + +#define TEST_LOOP(TYPE, NAME, OP) \ + { \ + TYPE r[N], a[N], b[N], c[N]; \ + for (int i = 0; i < N; ++i) \ + { \ + a[i] = (i & 1 ? i : 3 * i); \ + b[i] = (i >> 4) << (i & 15); \ + c[i] = ~i & 7; \ + asm volatile ("" ::: "memory"); \ + } \ + test_##TYPE##_##NAME (r, a, b, c, N); \ + for (int i = 0; i < N; ++i) \ + if (r[i] != (TYPE) (a[i] > 20 ? b[i] OP c[i] : 91)) \ + __builtin_abort (); \ + } + +int main () +{ + TEST_ALL (TEST_LOOP) + return 0; +} diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_shift_run-9.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_shift_run-9.c new file mode 100644 index 000000000000..d822796372bf --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_shift_run-9.c @@ -0,0 +1,28 @@ +/* { dg-do run { target { riscv_vector } } } */ +/* { dg-additional-options "--param=riscv-autovec-preference=scalable -fno-vect-cost-model" } */ + +#include "cond_shift-9.c" + +#define N 99 + +#define TEST_LOOP(TYPE, NAME, OP) \ + { \ + TYPE r[N], a[N], b[N], c[N]; \ + for (int i = 0; i < N; ++i) \ + { \ + a[i] = (i & 1 ? i : 3 * i); \ + b[i] = (i >> 4) << (i & 15); \ + c[i] = ~i & 7; \ + asm volatile ("" ::: "memory"); \ + } \ + test_##TYPE##_##NAME (r, a, b, c, N); \ + for (int i = 0; i < N; ++i) \ + if (r[i] != (TYPE) (a[i] > 20 ? b[i] OP c[i] : 0)) \ + __builtin_abort (); \ + } + +int main () +{ + TEST_ALL (TEST_LOOP) + return 0; +} diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_unary-1.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_unary-1.c new file mode 100644 index 000000000000..8076243f7d4a --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_unary-1.c @@ -0,0 +1,43 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-march=rv64gcv_zvfh -mabi=lp64d --param riscv-autovec-preference=scalable -fno-vect-cost-model" } */ + +#include + +#define abs(A) ((A) < 0 ? -(A) : (A)) +#define neg(A) (-(A)) +#define not(A) (~(A)) + +#define DEF_LOOP(TYPE, OP) \ + void __attribute__ ((noipa)) \ + test_##TYPE##_##OP (TYPE *__restrict r, TYPE *__restrict a, \ + TYPE *__restrict pred, int n) \ + { \ + for (int i = 0; i < n; ++i) \ + r[i] = pred[i] ? OP (a[i]) : a[i]; \ + } + +#define TEST_INT_TYPE(T, TYPE) \ + T (TYPE, abs) \ + T (TYPE, neg) \ + T (TYPE, not ) + +#define TEST_FLOAT_TYPE(T, TYPE, SUFFIX) \ + T (TYPE, __builtin_fabs##SUFFIX) \ + T (TYPE, neg) + +#define TEST_ALL(T) \ + TEST_INT_TYPE (T, int8_t) \ + TEST_INT_TYPE (T, int16_t) \ + TEST_INT_TYPE (T, int32_t) \ + TEST_INT_TYPE (T, int64_t) \ + TEST_FLOAT_TYPE (T, _Float16, f16) \ + TEST_FLOAT_TYPE (T, float, f) \ + TEST_FLOAT_TYPE (T, double, ) + +TEST_ALL (DEF_LOOP) + +/* NOTE: int abs operator is converted to vmslt + vneg.v */ +/* { dg-final { scan-assembler-times {\tvneg\.v\tv[0-9]+,v[0-9]+,v0\.t} 8 } } */ +/* { dg-final { scan-assembler-times {\tvnot\.v\tv[0-9]+,v[0-9]+,v0\.t} 4 } } */ +/* { dg-final { scan-assembler-times {\tvfabs\.v\tv[0-9]+,v[0-9]+,v0\.t} 3 } } */ +/* { dg-final { scan-assembler-times {\tvfneg\.v\tv[0-9]+,v[0-9]+,v0\.t} 3 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_unary-2.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_unary-2.c new file mode 100644 index 000000000000..8e44301ae805 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_unary-2.c @@ -0,0 +1,46 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-march=rv64gcv_zvfh -mabi=lp64d --param riscv-autovec-preference=scalable -fno-vect-cost-model" } */ + +#include + +#define abs(A) ((A) < 0 ? -(A) : (A)) +#define neg(A) (-(A)) +#define not(A) (~(A)) + +#define DEF_LOOP(TYPE, OP) \ + void __attribute__ ((noipa)) \ + test_##TYPE##_##OP (TYPE *__restrict r, TYPE *__restrict a, \ + TYPE *__restrict b, TYPE *__restrict pred, int n) \ + { \ + for (int i = 0; i < n; ++i) \ + { \ + TYPE bi = b[i]; \ + r[i] = pred[i] ? OP (a[i]) : bi; \ + } \ + } + +#define TEST_INT_TYPE(T, TYPE) \ + T (TYPE, abs) \ + T (TYPE, neg) \ + T (TYPE, not ) + +#define TEST_FLOAT_TYPE(T, TYPE, SUFFIX) \ + T (TYPE, __builtin_fabs##SUFFIX) \ + T (TYPE, neg) + +#define TEST_ALL(T) \ + TEST_INT_TYPE (T, int8_t) \ + TEST_INT_TYPE (T, int16_t) \ + TEST_INT_TYPE (T, int32_t) \ + TEST_INT_TYPE (T, int64_t) \ + TEST_FLOAT_TYPE (T, _Float16, f16) \ + TEST_FLOAT_TYPE (T, float, f) \ + TEST_FLOAT_TYPE (T, double, ) + +TEST_ALL (DEF_LOOP) + +/* NOTE: int abs operator is converted to vmslt + vneg.v */ +/* { dg-final { scan-assembler-times {\tvneg\.v\tv[0-9]+,v[0-9]+,v0\.t} 8 } } */ +/* { dg-final { scan-assembler-times {\tvnot\.v\tv[0-9]+,v[0-9]+,v0\.t} 4 } } */ +/* { dg-final { scan-assembler-times {\tvfabs\.v\tv[0-9]+,v[0-9]+,v0\.t} 3 } } */ +/* { dg-final { scan-assembler-times {\tvfneg\.v\tv[0-9]+,v[0-9]+,v0\.t} 3 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_unary-3.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_unary-3.c new file mode 100644 index 000000000000..6da5b6e42e3c --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_unary-3.c @@ -0,0 +1,43 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-march=rv64gcv_zvfh -mabi=lp64d --param riscv-autovec-preference=scalable -fno-vect-cost-model" } */ + +#include + +#define abs(A) ((A) < 0 ? -(A) : (A)) +#define neg(A) (-(A)) +#define not(A) (~(A)) + +#define DEF_LOOP(TYPE, OP) \ + void __attribute__ ((noipa)) \ + test_##TYPE##_##OP (TYPE *__restrict r, TYPE *__restrict a, \ + TYPE *__restrict pred, int n) \ + { \ + for (int i = 0; i < n; ++i) \ + r[i] = pred[i] ? OP (a[i]) : 5; \ + } + +#define TEST_INT_TYPE(T, TYPE) \ + T (TYPE, abs) \ + T (TYPE, neg) \ + T (TYPE, not ) + +#define TEST_FLOAT_TYPE(T, TYPE, SUFFIX) \ + T (TYPE, __builtin_fabs##SUFFIX) \ + T (TYPE, neg) + +#define TEST_ALL(T) \ + TEST_INT_TYPE (T, int8_t) \ + TEST_INT_TYPE (T, int16_t) \ + TEST_INT_TYPE (T, int32_t) \ + TEST_INT_TYPE (T, int64_t) \ + TEST_FLOAT_TYPE (T, _Float16, f16) \ + TEST_FLOAT_TYPE (T, float, f) \ + TEST_FLOAT_TYPE (T, double, ) + +TEST_ALL (DEF_LOOP) + +/* NOTE: int abs operator is converted to vmslt + vneg.v */ +/* { dg-final { scan-assembler-times {\tvneg\.v\tv[0-9]+,v[0-9]+,v0\.t} 8 } } */ +/* { dg-final { scan-assembler-times {\tvnot\.v\tv[0-9]+,v[0-9]+,v0\.t} 4 } } */ +/* { dg-final { scan-assembler-times {\tvfabs\.v\tv[0-9]+,v[0-9]+,v0\.t} 3 } } */ +/* { dg-final { scan-assembler-times {\tvfneg\.v\tv[0-9]+,v[0-9]+,v0\.t} 3 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_unary-4.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_unary-4.c new file mode 100644 index 000000000000..5428c289d22f --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_unary-4.c @@ -0,0 +1,43 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-march=rv64gcv_zvfh -mabi=lp64d --param riscv-autovec-preference=scalable -fno-vect-cost-model" } */ + +#include + +#define abs(A) ((A) < 0 ? -(A) : (A)) +#define neg(A) (-(A)) +#define not(A) (~(A)) + +#define DEF_LOOP(TYPE, OP) \ + void __attribute__ ((noipa)) \ + test_##TYPE##_##OP (TYPE *__restrict r, TYPE *__restrict a, \ + TYPE *__restrict pred, int n) \ + { \ + for (int i = 0; i < n; ++i) \ + r[i] = pred[i] ? OP (a[i]) : 0; \ + } + +#define TEST_INT_TYPE(T, TYPE) \ + T (TYPE, abs) \ + T (TYPE, neg) \ + T (TYPE, not ) + +#define TEST_FLOAT_TYPE(T, TYPE, SUFFIX) \ + T (TYPE, __builtin_fabs##SUFFIX) \ + T (TYPE, neg) + +#define TEST_ALL(T) \ + TEST_INT_TYPE (T, int8_t) \ + TEST_INT_TYPE (T, int16_t) \ + TEST_INT_TYPE (T, int32_t) \ + TEST_INT_TYPE (T, int64_t) \ + TEST_FLOAT_TYPE (T, _Float16, f16) \ + TEST_FLOAT_TYPE (T, float, f) \ + TEST_FLOAT_TYPE (T, double, ) + +TEST_ALL (DEF_LOOP) + +/* NOTE: int abs operator is converted to vmslt + vneg.v */ +/* { dg-final { scan-assembler-times {\tvneg\.v\tv[0-9]+,v[0-9]+,v0\.t} 8 } } */ +/* { dg-final { scan-assembler-times {\tvnot\.v\tv[0-9]+,v[0-9]+,v0\.t} 4 } } */ +/* { dg-final { scan-assembler-times {\tvfabs\.v\tv[0-9]+,v[0-9]+,v0\.t} 3 } } */ +/* { dg-final { scan-assembler-times {\tvfneg\.v\tv[0-9]+,v[0-9]+,v0\.t} 3 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_unary-5.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_unary-5.c new file mode 100644 index 000000000000..8e567378d0d9 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_unary-5.c @@ -0,0 +1,36 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-march=rv64gcv_zvfh -mabi=lp64d --param riscv-autovec-preference=scalable -fno-vect-cost-model" } */ + +#include + +#define abs(A) ((A) < 0 ? -(A) : (A)) +#define neg(A) (-(A)) +#define not(A) (~(A)) + +#define DEF_LOOP(TYPE1, TYPE2, COUNT, OP) \ + void __attribute__ ((noipa)) \ + test_##TYPE1##_##TYPE2##_##OP (TYPE2 *__restrict r, TYPE2 *__restrict a, \ + TYPE1 *__restrict pred) \ + { \ + for (int i = 0; i < COUNT; ++i) \ + r[i] = pred[i] ? OP (a[i]) : a[i]; \ + } + +#define TEST_TYPES(T, TYPE1, TYPE2, COUNT) \ + T (TYPE1, TYPE2, COUNT, abs) \ + T (TYPE1, TYPE2, COUNT, neg) \ + T (TYPE1, TYPE2, COUNT, not ) + +#define TEST_ALL(T) \ + TEST_TYPES (T, int16_t, int8_t, 7) \ + TEST_TYPES (T, int32_t, int8_t, 3) \ + TEST_TYPES (T, int32_t, int16_t, 3) \ + TEST_TYPES (T, int64_t, int8_t, 42) \ + TEST_TYPES (T, int64_t, int16_t, 42) \ + TEST_TYPES (T, int64_t, int32_t, 42) + +TEST_ALL (DEF_LOOP) + +/* NOTE: int abs operator is converted to vmslt + vneg.v */ +/* { dg-final { scan-assembler-times {\tvneg\.v\tv[0-9]+,v[0-9]+,v0\.t} 12 } } */ +/* { dg-final { scan-assembler-times {\tvnot\.v\tv[0-9]+,v[0-9]+,v0\.t} 6 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_unary-6.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_unary-6.c new file mode 100644 index 000000000000..65a36d0e52a4 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_unary-6.c @@ -0,0 +1,39 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-march=rv64gcv_zvfh -mabi=lp64d --param riscv-autovec-preference=scalable -fno-vect-cost-model" } */ + +#include + +#define abs(A) ((A) < 0 ? -(A) : (A)) +#define neg(A) (-(A)) +#define not(A) (~(A)) + +#define DEF_LOOP(TYPE1, TYPE2, COUNT, OP) \ + void __attribute__ ((noipa)) \ + test_##TYPE1##_##TYPE2##_##OP (TYPE2 *__restrict r, TYPE2 *__restrict a, \ + TYPE2 *__restrict b, TYPE1 *__restrict pred) \ + { \ + for (int i = 0; i < COUNT; ++i) \ + { \ + TYPE2 bi = b[i]; \ + r[i] = pred[i] ? OP (a[i]) : bi; \ + } \ + } + +#define TEST_TYPES(T, TYPE1, TYPE2, COUNT) \ + T (TYPE1, TYPE2, COUNT, abs) \ + T (TYPE1, TYPE2, COUNT, neg) \ + T (TYPE1, TYPE2, COUNT, not ) + +#define TEST_ALL(T) \ + TEST_TYPES (T, int16_t, int8_t, 7) \ + TEST_TYPES (T, int32_t, int8_t, 3) \ + TEST_TYPES (T, int32_t, int16_t, 3) \ + TEST_TYPES (T, int64_t, int8_t, 42) \ + TEST_TYPES (T, int64_t, int16_t, 42) \ + TEST_TYPES (T, int64_t, int32_t, 42) + +TEST_ALL (DEF_LOOP) + +/* NOTE: int abs operator is converted to vmslt + vneg.v */ +/* { dg-final { scan-assembler-times {\tvneg\.v\tv[0-9]+,v[0-9]+,v0\.t} 12 } } */ +/* { dg-final { scan-assembler-times {\tvnot\.v\tv[0-9]+,v[0-9]+,v0\.t} 6 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_unary-7.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_unary-7.c new file mode 100644 index 000000000000..356fe9fc25a0 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_unary-7.c @@ -0,0 +1,36 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-march=rv64gcv_zvfh -mabi=lp64d --param riscv-autovec-preference=scalable -fno-vect-cost-model" } */ + +#include + +#define abs(A) ((A) < 0 ? -(A) : (A)) +#define neg(A) (-(A)) +#define not(A) (~(A)) + +#define DEF_LOOP(TYPE1, TYPE2, COUNT, OP) \ + void __attribute__ ((noipa)) \ + test_##TYPE1##_##TYPE2##_##OP (TYPE2 *__restrict r, TYPE2 *__restrict a, \ + TYPE1 *__restrict pred) \ + { \ + for (int i = 0; i < COUNT; ++i) \ + r[i] = pred[i] ? OP (a[i]) : 5; \ + } + +#define TEST_TYPES(T, TYPE1, TYPE2, COUNT) \ + T (TYPE1, TYPE2, COUNT, abs) \ + T (TYPE1, TYPE2, COUNT, neg) \ + T (TYPE1, TYPE2, COUNT, not ) + +#define TEST_ALL(T) \ + TEST_TYPES (T, int16_t, int8_t, 7) \ + TEST_TYPES (T, int32_t, int8_t, 3) \ + TEST_TYPES (T, int32_t, int16_t, 3) \ + TEST_TYPES (T, int64_t, int8_t, 42) \ + TEST_TYPES (T, int64_t, int16_t, 42) \ + TEST_TYPES (T, int64_t, int32_t, 42) + +TEST_ALL (DEF_LOOP) + +/* NOTE: int abs operator is converted to vmslt + vneg.v */ +/* { dg-final { scan-assembler-times {\tvneg\.v\tv[0-9]+,v[0-9]+,v0\.t} 12 } } */ +/* { dg-final { scan-assembler-times {\tvnot\.v\tv[0-9]+,v[0-9]+,v0\.t} 6 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_unary-8.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_unary-8.c new file mode 100644 index 000000000000..5208a858882d --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_unary-8.c @@ -0,0 +1,36 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-march=rv64gcv_zvfh -mabi=lp64d --param riscv-autovec-preference=scalable -fno-vect-cost-model" } */ + +#include + +#define abs(A) ((A) < 0 ? -(A) : (A)) +#define neg(A) (-(A)) +#define not(A) (~(A)) + +#define DEF_LOOP(TYPE1, TYPE2, COUNT, OP) \ + void __attribute__ ((noipa)) \ + test_##TYPE1##_##TYPE2##_##OP (TYPE2 *__restrict r, TYPE2 *__restrict a, \ + TYPE1 *__restrict pred) \ + { \ + for (int i = 0; i < COUNT; ++i) \ + r[i] = pred[i] ? OP (a[i]) : 0; \ + } + +#define TEST_TYPES(T, TYPE1, TYPE2, COUNT) \ + T (TYPE1, TYPE2, COUNT, abs) \ + T (TYPE1, TYPE2, COUNT, neg) \ + T (TYPE1, TYPE2, COUNT, not ) + +#define TEST_ALL(T) \ + TEST_TYPES (T, int16_t, int8_t, 7) \ + TEST_TYPES (T, int32_t, int8_t, 3) \ + TEST_TYPES (T, int32_t, int16_t, 3) \ + TEST_TYPES (T, int64_t, int8_t, 42) \ + TEST_TYPES (T, int64_t, int16_t, 42) \ + TEST_TYPES (T, int64_t, int32_t, 42) + +TEST_ALL (DEF_LOOP) + +/* NOTE: int abs operator is converted to vmslt + vneg.v */ +/* { dg-final { scan-assembler-times {\tvneg\.v\tv[0-9]+,v[0-9]+,v0\.t} 12 } } */ +/* { dg-final { scan-assembler-times {\tvnot\.v\tv[0-9]+,v[0-9]+,v0\.t} 6 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_unary_run-1.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_unary_run-1.c new file mode 100644 index 000000000000..3de65aa7af18 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_unary_run-1.c @@ -0,0 +1,27 @@ +/* { dg-do run { target { riscv_vector } } } */ +/* { dg-additional-options "--param riscv-autovec-preference=scalable -fno-vect-cost-model" } */ + +#include "cond_unary-1.c" + +#define N 99 + +#define TEST_LOOP(TYPE, OP) \ + { \ + TYPE r[N], a[N], pred[N]; \ + for (int i = 0; i < N; ++i) \ + { \ + a[i] = (i & 1 ? i : 3 * i) * (i % 3 == 0 ? 1 : -1); \ + pred[i] = (i % 7 < 4); \ + asm volatile ("" ::: "memory"); \ + } \ + test_##TYPE##_##OP (r, a, pred, N); \ + for (int i = 0; i < N; ++i) \ + if (r[i] != (pred[i] ? OP (a[i]) : a[i])) \ + __builtin_abort (); \ + } + +int main () +{ + TEST_ALL (TEST_LOOP) + return 0; +} diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_unary_run-2.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_unary_run-2.c new file mode 100644 index 000000000000..799f1f7f9d26 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_unary_run-2.c @@ -0,0 +1,28 @@ +/* { dg-do run { target { riscv_vector } } } */ +/* { dg-additional-options "--param riscv-autovec-preference=scalable -fno-vect-cost-model" } */ + +#include "cond_unary-2.c" + +#define N 99 + +#define TEST_LOOP(TYPE, OP) \ + { \ + TYPE r[N], a[N], b[N], pred[N]; \ + for (int i = 0; i < N; ++i) \ + { \ + a[i] = (i & 1 ? i : 3 * i) * (i % 3 == 0 ? 1 : -1); \ + b[i] = (i % 9) * (i % 7 + 1); \ + pred[i] = (i % 7 < 4); \ + asm volatile ("" ::: "memory"); \ + } \ + test_##TYPE##_##OP (r, a, b, pred, N); \ + for (int i = 0; i < N; ++i) \ + if (r[i] != (pred[i] ? OP (a[i]) : b[i])) \ + __builtin_abort (); \ + } + +int main () +{ + TEST_ALL (TEST_LOOP) + return 0; +} diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_unary_run-3.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_unary_run-3.c new file mode 100644 index 000000000000..6ad7e6178768 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_unary_run-3.c @@ -0,0 +1,27 @@ +/* { dg-do run { target { riscv_vector } } } */ +/* { dg-additional-options "--param riscv-autovec-preference=scalable -fno-vect-cost-model" } */ + +#include "cond_unary-3.c" + +#define N 99 + +#define TEST_LOOP(TYPE, OP) \ + { \ + TYPE r[N], a[N], pred[N]; \ + for (int i = 0; i < N; ++i) \ + { \ + a[i] = (i & 1 ? i : 3 * i) * (i % 3 == 0 ? 1 : -1); \ + pred[i] = (i % 7 < 4); \ + asm volatile ("" ::: "memory"); \ + } \ + test_##TYPE##_##OP (r, a, pred, N); \ + for (int i = 0; i < N; ++i) \ + if (r[i] != (pred[i] ? OP (a[i]) : 5)) \ + __builtin_abort (); \ + } + +int main () +{ + TEST_ALL (TEST_LOOP) + return 0; +} diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_unary_run-4.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_unary_run-4.c new file mode 100644 index 000000000000..cd7934b4f1aa --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_unary_run-4.c @@ -0,0 +1,27 @@ +/* { dg-do run { target { riscv_vector } } } */ +/* { dg-additional-options "--param riscv-autovec-preference=scalable -fno-vect-cost-model" } */ + +#include "cond_unary-4.c" + +#define N 99 + +#define TEST_LOOP(TYPE, OP) \ + { \ + TYPE r[N], a[N], pred[N]; \ + for (int i = 0; i < N; ++i) \ + { \ + a[i] = (i & 1 ? i : 3 * i) * (i % 3 == 0 ? 1 : -1); \ + pred[i] = (i % 7 < 4); \ + asm volatile ("" ::: "memory"); \ + } \ + test_##TYPE##_##OP (r, a, pred, N); \ + for (int i = 0; i < N; ++i) \ + if (r[i] != (pred[i] ? OP (a[i]) : 0)) \ + __builtin_abort (); \ + } + +int main () +{ + TEST_ALL (TEST_LOOP) + return 0; +} diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_unary_run-5.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_unary_run-5.c new file mode 100644 index 000000000000..38e9fb86b7e2 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_unary_run-5.c @@ -0,0 +1,26 @@ +/* { dg-do run { target { riscv_vector } } } */ +/* { dg-additional-options "--param riscv-autovec-preference=scalable -fno-vect-cost-model" } */ + +#include "cond_unary-5.c" + +#define TEST_LOOP(TYPE1, TYPE2, N, OP) \ + { \ + TYPE1 pred[N]; \ + TYPE2 r[N], a[N]; \ + for (int i = 0; i < N; ++i) \ + { \ + a[i] = (i & 1 ? i : 3 * i) * (i % 3 == 0 ? 1 : -1); \ + pred[i] = (i % 4 < 2); \ + asm volatile ("" ::: "memory"); \ + } \ + test_##TYPE1##_##TYPE2##_##OP (r, a, pred); \ + for (int i = 0; i < N; ++i) \ + if (r[i] != (pred[i] ? OP (a[i]) : a[i])) \ + __builtin_abort (); \ + } + +int main () +{ + TEST_ALL (TEST_LOOP) + return 0; +} diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_unary_run-6.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_unary_run-6.c new file mode 100644 index 000000000000..71f846437092 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_unary_run-6.c @@ -0,0 +1,27 @@ +/* { dg-do run { target { riscv_vector } } } */ +/* { dg-additional-options "--param riscv-autovec-preference=scalable -fno-vect-cost-model" } */ + +#include "cond_unary-6.c" + +#define TEST_LOOP(TYPE1, TYPE2, N, OP) \ + { \ + TYPE1 pred[N]; \ + TYPE2 r[N], a[N], b[N]; \ + for (int i = 0; i < N; ++i) \ + { \ + a[i] = (i & 1 ? i : 3 * i) * (i % 3 == 0 ? 1 : -1); \ + b[i] = (i % 5) * (i % 6 + 3); \ + pred[i] = (i % 4 < 2); \ + asm volatile ("" ::: "memory"); \ + } \ + test_##TYPE1##_##TYPE2##_##OP (r, a, b, pred); \ + for (int i = 0; i < N; ++i) \ + if (r[i] != (pred[i] ? OP (a[i]) : b[i])) \ + __builtin_abort (); \ + } + +int main () +{ + TEST_ALL (TEST_LOOP) + return 0; +} diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_unary_run-7.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_unary_run-7.c new file mode 100644 index 000000000000..7a52b0cea739 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_unary_run-7.c @@ -0,0 +1,26 @@ +/* { dg-do run { target { riscv_vector } } } */ +/* { dg-additional-options "--param riscv-autovec-preference=scalable -fno-vect-cost-model" } */ + +#include "cond_unary-7.c" + +#define TEST_LOOP(TYPE1, TYPE2, N, OP) \ + { \ + TYPE1 pred[N]; \ + TYPE2 r[N], a[N]; \ + for (int i = 0; i < N; ++i) \ + { \ + a[i] = (i & 1 ? i : 3 * i) * (i % 3 == 0 ? 1 : -1); \ + pred[i] = (i % 4 < 2); \ + asm volatile ("" ::: "memory"); \ + } \ + test_##TYPE1##_##TYPE2##_##OP (r, a, pred); \ + for (int i = 0; i < N; ++i) \ + if (r[i] != (pred[i] ? OP (a[i]) : 5)) \ + __builtin_abort (); \ + } + +int main () +{ + TEST_ALL (TEST_LOOP) + return 0; +} diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_unary_run-8.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_unary_run-8.c new file mode 100644 index 000000000000..ee5c2f384968 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_unary_run-8.c @@ -0,0 +1,28 @@ +/* { dg-do run { target { riscv_vector } } } */ +/* { dg-additional-options "--param riscv-autovec-preference=scalable -fno-vect-cost-model" } */ + +#include "cond_unary-8.c" + +#define N 99 + +#define TEST_LOOP(TYPE1, TYPE2, N, OP) \ + { \ + TYPE1 pred[N]; \ + TYPE2 r[N], a[N]; \ + for (int i = 0; i < N; ++i) \ + { \ + a[i] = (i & 1 ? i : 3 * i) * (i % 3 == 0 ? 1 : -1); \ + pred[i] = (i % 4 < 2); \ + asm volatile ("" ::: "memory"); \ + } \ + test_##TYPE1##_##TYPE2##_##OP (r, a, pred); \ + for (int i = 0; i < N; ++i) \ + if (r[i] != (pred[i] ? OP (a[i]) : 0)) \ + __builtin_abort (); \ + } + +int main () +{ + TEST_ALL (TEST_LOOP) + return 0; +} diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vfncvt-ftoi-run.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vfncvt-ftoi-run.c index ce3fcfa9af83..73eda067ba31 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vfncvt-ftoi-run.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vfncvt-ftoi-run.c @@ -62,6 +62,38 @@ main () RUN2 (float, uint16_t, 4096) RUN2 (float, uint16_t, 5975) + RUN (float, int8_t, 3) + RUN (float, int8_t, 4) + RUN (float, int8_t, 7) + RUN (float, int8_t, 99) + RUN (float, int8_t, 119) + RUN (float, int8_t, 128) + RUN (float, int8_t, 256) + RUN (float, int8_t, 279) + RUN (float, int8_t, 555) + RUN (float, int8_t, 1024) + RUN (float, int8_t, 1389) + RUN (float, int8_t, 2048) + RUN (float, int8_t, 3989) + RUN (float, int8_t, 4096) + RUN (float, int8_t, 5975) + + RUN2 (float, uint8_t, 3) + RUN2 (float, uint8_t, 4) + RUN2 (float, uint8_t, 7) + RUN2 (float, uint8_t, 99) + RUN2 (float, uint8_t, 119) + RUN2 (float, uint8_t, 128) + RUN2 (float, uint8_t, 256) + RUN2 (float, uint8_t, 279) + RUN2 (float, uint8_t, 555) + RUN2 (float, uint8_t, 1024) + RUN2 (float, uint8_t, 1389) + RUN2 (float, uint8_t, 2048) + RUN2 (float, uint8_t, 3989) + RUN2 (float, uint8_t, 4096) + RUN2 (float, uint8_t, 5975) + RUN (double, int32_t, 3) RUN (double, int32_t, 4) RUN (double, int32_t, 7) @@ -93,4 +125,68 @@ main () RUN2 (double, uint32_t, 3989) RUN2 (double, uint32_t, 4096) RUN2 (double, uint32_t, 5975) + + RUN (double, int16_t, 3) + RUN (double, int16_t, 4) + RUN (double, int16_t, 7) + RUN (double, int16_t, 99) + RUN (double, int16_t, 119) + RUN (double, int16_t, 128) + RUN (double, int16_t, 256) + RUN (double, int16_t, 279) + RUN (double, int16_t, 555) + RUN (double, int16_t, 1024) + RUN (double, int16_t, 1389) + RUN (double, int16_t, 2048) + RUN (double, int16_t, 3989) + RUN (double, int16_t, 4096) + RUN (double, int16_t, 5975) + + RUN2 (double, uint16_t, 3) + RUN2 (double, uint16_t, 4) + RUN2 (double, uint16_t, 7) + RUN2 (double, uint16_t, 99) + RUN2 (double, uint16_t, 119) + RUN2 (double, uint16_t, 128) + RUN2 (double, uint16_t, 256) + RUN2 (double, uint16_t, 279) + RUN2 (double, uint16_t, 555) + RUN2 (double, uint16_t, 1024) + RUN2 (double, uint16_t, 1389) + RUN2 (double, uint16_t, 2048) + RUN2 (double, uint16_t, 3989) + RUN2 (double, uint16_t, 4096) + RUN2 (double, uint16_t, 5975) + + RUN (double, int8_t, 3) + RUN (double, int8_t, 4) + RUN (double, int8_t, 7) + RUN (double, int8_t, 99) + RUN (double, int8_t, 119) + RUN (double, int8_t, 128) + RUN (double, int8_t, 256) + RUN (double, int8_t, 279) + RUN (double, int8_t, 555) + RUN (double, int8_t, 1024) + RUN (double, int8_t, 1389) + RUN (double, int8_t, 2048) + RUN (double, int8_t, 3989) + RUN (double, int8_t, 4096) + RUN (double, int8_t, 5975) + + RUN2 (double, uint8_t, 3) + RUN2 (double, uint8_t, 4) + RUN2 (double, uint8_t, 7) + RUN2 (double, uint8_t, 99) + RUN2 (double, uint8_t, 119) + RUN2 (double, uint8_t, 128) + RUN2 (double, uint8_t, 256) + RUN2 (double, uint8_t, 279) + RUN2 (double, uint8_t, 555) + RUN2 (double, uint8_t, 1024) + RUN2 (double, uint8_t, 1389) + RUN2 (double, uint8_t, 2048) + RUN2 (double, uint8_t, 3989) + RUN2 (double, uint8_t, 4096) + RUN2 (double, uint8_t, 5975) } diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vfncvt-ftoi-rv32gcv.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vfncvt-ftoi-rv32gcv.c index 4bed5eb7fff2..43967af1cd52 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vfncvt-ftoi-rv32gcv.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vfncvt-ftoi-rv32gcv.c @@ -1,7 +1,9 @@ /* { dg-do compile } */ -/* { dg-additional-options "-std=c99 -fno-vect-cost-model -march=rv32gcv_zvfh -mabi=ilp32d --param=riscv-autovec-preference=scalable" } */ +/* { dg-additional-options "-std=c99 -fno-vect-cost-model -march=rv32gcv_zvfh -mabi=ilp32d -fno-trapping-math --param=riscv-autovec-preference=scalable" } */ #include "vfncvt-ftoi-template.h" -/* { dg-final { scan-assembler-times {\tvfncvt\.rtz\.x\.f\.w} 3 } } */ +/* The vectorizer only performs int -> float conversions with + intermediate types with -fno-trapping-math. */ +/* { dg-final { scan-assembler-times {\tvfncvt\.rtz\.x\.f\.w} 9 } } */ /* { dg-final { scan-assembler-times {\tvfncvt\.rtz\.xu\.f\.w} 3 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vfncvt-ftoi-rv64gcv.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vfncvt-ftoi-rv64gcv.c index 7efc3f31c267..d49370bb925a 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vfncvt-ftoi-rv64gcv.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vfncvt-ftoi-rv64gcv.c @@ -1,7 +1,9 @@ /* { dg-do compile } */ -/* { dg-additional-options "-std=c99 -fno-vect-cost-model -march=rv64gcv_zvfh -mabi=lp64d --param=riscv-autovec-preference=scalable" } */ +/* { dg-additional-options "-std=c99 -fno-vect-cost-model -march=rv64gcv_zvfh -mabi=lp64d -fno-trapping-math --param=riscv-autovec-preference=scalable" } */ #include "vfncvt-ftoi-template.h" -/* { dg-final { scan-assembler-times {\tvfncvt\.rtz\.x\.f\.w} 3 } } */ +/* The vectorizer only performs int -> float conversions with + intermediate types with -fno-trapping-math. */ +/* { dg-final { scan-assembler-times {\tvfncvt\.rtz\.x\.f\.w} 9 } } */ /* { dg-final { scan-assembler-times {\tvfncvt\.rtz\.xu\.f\.w} 3 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vfncvt-ftoi-template.h b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vfncvt-ftoi-template.h index c6efbf15ecac..c334e26e60ce 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vfncvt-ftoi-template.h +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vfncvt-ftoi-template.h @@ -11,8 +11,14 @@ #define TEST_ALL() \ TEST (double, int32_t) \ TEST (double, uint32_t) \ + TEST (double, int16_t) \ + TEST (double, uint16_t) \ + TEST (double, int8_t) \ + TEST (double, uint8_t) \ TEST (float, int16_t) \ TEST (float, uint16_t) \ + TEST (float, int8_t) \ + TEST (float, uint8_t) \ TEST (_Float16, int8_t) \ TEST (_Float16, uint8_t) \ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vfncvt-itof-rv32gcv.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vfncvt-itof-rv32gcv.c index dd5b95c903d4..73e4644658b3 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vfncvt-itof-rv32gcv.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vfncvt-itof-rv32gcv.c @@ -3,5 +3,6 @@ #include "vfncvt-itof-template.h" +/* { dg-final { scan-assembler-times {\tvfcvt\.f\.x\.v} 2 } } */ /* { dg-final { scan-assembler-times {\tvfncvt\.f\.x\.w} 2 } } */ /* { dg-final { scan-assembler-times {\tvfncvt\.f\.xu\.w} 2 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vfncvt-itof-rv64gcv.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vfncvt-itof-rv64gcv.c index b3bdeced81dc..e9d31a70e6a1 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vfncvt-itof-rv64gcv.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vfncvt-itof-rv64gcv.c @@ -3,5 +3,5 @@ #include "vfncvt-itof-template.h" -/* { dg-final { scan-assembler-times {\tvfncvt\.f\.x\.w} 2 } } */ -/* { dg-final { scan-assembler-times {\tvfncvt\.f\.xu\.w} 2 } } */ +/* { dg-final { scan-assembler-times {\tvfncvt\.f\.x\.w} 5 } } */ +/* { dg-final { scan-assembler-times {\tvfncvt\.f\.xu\.w} 1 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vfncvt-itof-template.h b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vfncvt-itof-template.h index b06deeb3d724..c427cd167f6d 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vfncvt-itof-template.h +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vfncvt-itof-template.h @@ -6,12 +6,15 @@ TYPE1 *restrict a, int n) \ { \ for (int i = 0; i < n; i++) \ - dst[i] = (TYPE2) a[i]; \ + dst[i] = (TYPE2) (a[i] & 0x7ffffffful); \ } + #define TEST_ALL() \ TEST (int64_t, float) \ TEST (uint64_t, float) \ + TEST (int64_t, _Float16) \ + TEST (uint64_t, _Float16) \ TEST (int32_t, _Float16) \ TEST (uint32_t, _Float16) \ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vfncvt-itof-zvfh-run.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vfncvt-itof-zvfh-run.c index b4e59c65ac7c..2fb9b0c7b89a 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vfncvt-itof-zvfh-run.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vfncvt-itof-zvfh-run.c @@ -61,4 +61,36 @@ main () RUN2 (uint32_t, _Float16, 3989) RUN2 (uint32_t, _Float16, 4096) RUN2 (uint32_t, _Float16, 5975) + + RUN (int64_t, _Float16, 3) + RUN (int64_t, _Float16, 4) + RUN (int64_t, _Float16, 7) + RUN (int64_t, _Float16, 99) + RUN (int64_t, _Float16, 119) + RUN (int64_t, _Float16, 128) + RUN (int64_t, _Float16, 256) + RUN (int64_t, _Float16, 279) + RUN (int64_t, _Float16, 555) + RUN (int64_t, _Float16, 1024) + RUN (int64_t, _Float16, 1389) + RUN (int64_t, _Float16, 2048) + RUN (int64_t, _Float16, 3989) + RUN (int64_t, _Float16, 4096) + RUN (int64_t, _Float16, 5975) + + RUN2 (uint64_t, _Float16, 3) + RUN2 (uint64_t, _Float16, 4) + RUN2 (uint64_t, _Float16, 7) + RUN2 (uint64_t, _Float16, 99) + RUN2 (uint64_t, _Float16, 119) + RUN2 (uint64_t, _Float16, 128) + RUN2 (uint64_t, _Float16, 256) + RUN2 (uint64_t, _Float16, 279) + RUN2 (uint64_t, _Float16, 555) + RUN2 (uint64_t, _Float16, 1024) + RUN2 (uint64_t, _Float16, 1389) + RUN2 (uint64_t, _Float16, 2048) + RUN2 (uint64_t, _Float16, 3989) + RUN2 (uint64_t, _Float16, 4096) + RUN2 (uint64_t, _Float16, 5975) } diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vfwcvt-ftoi-rv32gcv.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vfwcvt-ftoi-rv32gcv.c index ce2bea480672..0ab42af6d700 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vfwcvt-ftoi-rv32gcv.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vfwcvt-ftoi-rv32gcv.c @@ -1,7 +1,7 @@ /* { dg-do compile } */ -/* { dg-additional-options "-std=c99 -fno-vect-cost-model -march=rv32gcv_zvfh -mabi=ilp32d --param=riscv-autovec-preference=scalable" } */ +/* { dg-additional-options "-std=c99 -fno-vect-cost-model -march=rv32gcv_zvfh -mabi=ilp32d -fno-trapping-math --param=riscv-autovec-preference=scalable" } */ #include "vfwcvt-ftoi-template.h" -/* { dg-final { scan-assembler-times {\tvfwcvt\.rtz\.x\.f\.v} 2 } } */ +/* { dg-final { scan-assembler-times {\tvfwcvt\.rtz\.x\.f\.v} 4 } } */ /* { dg-final { scan-assembler-times {\tvfwcvt\.rtz\.xu\.f\.v} 2 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vfwcvt-ftoi-rv64gcv.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vfwcvt-ftoi-rv64gcv.c index 99aa3de42811..e1a4b6314236 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vfwcvt-ftoi-rv64gcv.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vfwcvt-ftoi-rv64gcv.c @@ -1,7 +1,7 @@ /* { dg-do compile } */ -/* { dg-additional-options "-std=c99 -fno-vect-cost-model -march=rv64gcv_zvfh -mabi=lp64d --param=riscv-autovec-preference=scalable" } */ +/* { dg-additional-options "-std=c99 -fno-vect-cost-model -march=rv64gcv_zvfh -mabi=lp64d -fno-trapping-math --param=riscv-autovec-preference=scalable" } */ #include "vfwcvt-ftoi-template.h" -/* { dg-final { scan-assembler-times {\tvfwcvt\.rtz\.x\.f\.v} 2 } } */ +/* { dg-final { scan-assembler-times {\tvfwcvt\.rtz\.x\.f\.v} 4 } } */ /* { dg-final { scan-assembler-times {\tvfwcvt\.rtz\.xu\.f\.v} 2 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vfwcvt-ftoi-template.h b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vfwcvt-ftoi-template.h index a276351bf691..aef03859d2b1 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vfwcvt-ftoi-template.h +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vfwcvt-ftoi-template.h @@ -9,6 +9,8 @@ } #define TEST_ALL() \ + TEST (_Float16, int64_t) \ + TEST (_Float16, uint64_t) \ TEST (_Float16, int32_t) \ TEST (_Float16, uint32_t) \ TEST (float, int64_t) \ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vfwcvt-ftoi-zvfh-run.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vfwcvt-ftoi-zvfh-run.c index 15bcd05b5928..5bf4bc990372 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vfwcvt-ftoi-zvfh-run.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vfwcvt-ftoi-zvfh-run.c @@ -61,4 +61,36 @@ main () RUN2 (_Float16, uint32_t, 3989) RUN2 (_Float16, uint32_t, 4096) RUN2 (_Float16, uint32_t, 5975) + + RUN (_Float16, int64_t, 3) + RUN (_Float16, int64_t, 4) + RUN (_Float16, int64_t, 7) + RUN (_Float16, int64_t, 99) + RUN (_Float16, int64_t, 119) + RUN (_Float16, int64_t, 128) + RUN (_Float16, int64_t, 256) + RUN (_Float16, int64_t, 279) + RUN (_Float16, int64_t, 555) + RUN (_Float16, int64_t, 1024) + RUN (_Float16, int64_t, 1389) + RUN (_Float16, int64_t, 2048) + RUN (_Float16, int64_t, 3989) + RUN (_Float16, int64_t, 4096) + RUN (_Float16, int64_t, 5975) + + RUN2 (_Float16, uint64_t, 3) + RUN2 (_Float16, uint64_t, 4) + RUN2 (_Float16, uint64_t, 7) + RUN2 (_Float16, uint64_t, 99) + RUN2 (_Float16, uint64_t, 119) + RUN2 (_Float16, uint64_t, 128) + RUN2 (_Float16, uint64_t, 256) + RUN2 (_Float16, uint64_t, 279) + RUN2 (_Float16, uint64_t, 555) + RUN2 (_Float16, uint64_t, 1024) + RUN2 (_Float16, uint64_t, 1389) + RUN2 (_Float16, uint64_t, 2048) + RUN2 (_Float16, uint64_t, 3989) + RUN2 (_Float16, uint64_t, 4096) + RUN2 (_Float16, uint64_t, 5975) } diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vfwcvt-itof-run.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vfwcvt-itof-run.c index b9287f695587..a90faef462f0 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vfwcvt-itof-run.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vfwcvt-itof-run.c @@ -30,6 +30,70 @@ int main () { + RUN (int8_t, float, 3) + RUN (int8_t, float, 4) + RUN (int8_t, float, 7) + RUN (int8_t, float, 99) + RUN (int8_t, float, 119) + RUN (int8_t, float, 128) + RUN (int8_t, float, 256) + RUN (int8_t, float, 279) + RUN (int8_t, float, 555) + RUN (int8_t, float, 1024) + RUN (int8_t, float, 1389) + RUN (int8_t, float, 2048) + RUN (int8_t, float, 3989) + RUN (int8_t, float, 4096) + RUN (int8_t, float, 5975) + + RUN2 (uint8_t, float, 3) + RUN2 (uint8_t, float, 4) + RUN2 (uint8_t, float, 7) + RUN2 (uint8_t, float, 99) + RUN2 (uint8_t, float, 119) + RUN2 (uint8_t, float, 128) + RUN2 (uint8_t, float, 256) + RUN2 (uint8_t, float, 279) + RUN2 (uint8_t, float, 555) + RUN2 (uint8_t, float, 1024) + RUN2 (uint8_t, float, 1389) + RUN2 (uint8_t, float, 2048) + RUN2 (uint8_t, float, 3989) + RUN2 (uint8_t, float, 4096) + RUN2 (uint8_t, float, 5975) + + RUN (int8_t, double, 3) + RUN (int8_t, double, 4) + RUN (int8_t, double, 7) + RUN (int8_t, double, 99) + RUN (int8_t, double, 119) + RUN (int8_t, double, 128) + RUN (int8_t, double, 256) + RUN (int8_t, double, 279) + RUN (int8_t, double, 555) + RUN (int8_t, double, 1024) + RUN (int8_t, double, 1389) + RUN (int8_t, double, 2048) + RUN (int8_t, double, 3989) + RUN (int8_t, double, 4096) + RUN (int8_t, double, 5975) + + RUN2 (uint8_t, double, 3) + RUN2 (uint8_t, double, 4) + RUN2 (uint8_t, double, 7) + RUN2 (uint8_t, double, 99) + RUN2 (uint8_t, double, 119) + RUN2 (uint8_t, double, 128) + RUN2 (uint8_t, double, 256) + RUN2 (uint8_t, double, 279) + RUN2 (uint8_t, double, 555) + RUN2 (uint8_t, double, 1024) + RUN2 (uint8_t, double, 1389) + RUN2 (uint8_t, double, 2048) + RUN2 (uint8_t, double, 3989) + RUN2 (uint8_t, double, 4096) + RUN2 (uint8_t, double, 5975) + RUN (int16_t, float, 3) RUN (int16_t, float, 4) RUN (int16_t, float, 7) @@ -62,6 +126,38 @@ main () RUN2 (uint16_t, float, 4096) RUN2 (uint16_t, float, 5975) + RUN (int16_t, double, 3) + RUN (int16_t, double, 4) + RUN (int16_t, double, 7) + RUN (int16_t, double, 99) + RUN (int16_t, double, 119) + RUN (int16_t, double, 128) + RUN (int16_t, double, 256) + RUN (int16_t, double, 279) + RUN (int16_t, double, 555) + RUN (int16_t, double, 1024) + RUN (int16_t, double, 1389) + RUN (int16_t, double, 2048) + RUN (int16_t, double, 3989) + RUN (int16_t, double, 4096) + RUN (int16_t, double, 5975) + + RUN2 (uint16_t, double, 3) + RUN2 (uint16_t, double, 4) + RUN2 (uint16_t, double, 7) + RUN2 (uint16_t, double, 99) + RUN2 (uint16_t, double, 119) + RUN2 (uint16_t, double, 128) + RUN2 (uint16_t, double, 256) + RUN2 (uint16_t, double, 279) + RUN2 (uint16_t, double, 555) + RUN2 (uint16_t, double, 1024) + RUN2 (uint16_t, double, 1389) + RUN2 (uint16_t, double, 2048) + RUN2 (uint16_t, double, 3989) + RUN2 (uint16_t, double, 4096) + RUN2 (uint16_t, double, 5975) + RUN (int32_t, double, 3) RUN (int32_t, double, 4) RUN (int32_t, double, 7) diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vfwcvt-itof-rv32gcv.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vfwcvt-itof-rv32gcv.c index 898b9c172313..cf180992c5dc 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vfwcvt-itof-rv32gcv.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vfwcvt-itof-rv32gcv.c @@ -3,5 +3,7 @@ #include "vfwcvt-itof-template.h" -/* { dg-final { scan-assembler-times {\tvfwcvt\.f\.x\.v} 3 } } */ +/* Conversions that the vectorizer does via multiple intermediate + types end up as signed conversions. */ +/* { dg-final { scan-assembler-times {\tvfwcvt\.f\.x\.v} 9 } } */ /* { dg-final { scan-assembler-times {\tvfwcvt\.f\.xu\.v} 3 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vfwcvt-itof-rv64gcv.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vfwcvt-itof-rv64gcv.c index e177b63738cd..b1153887bd8d 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vfwcvt-itof-rv64gcv.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vfwcvt-itof-rv64gcv.c @@ -3,5 +3,7 @@ #include "vfwcvt-itof-template.h" -/* { dg-final { scan-assembler-times {\tvfwcvt\.f\.x\.v} 3 } } */ +/* Conversions that the vectorizer does via multiple intermediate + types end up as signed conversions. */ +/* { dg-final { scan-assembler-times {\tvfwcvt\.f\.x\.v} 9 } } */ /* { dg-final { scan-assembler-times {\tvfwcvt\.f\.xu\.v} 3 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vfwcvt-itof-template.h b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vfwcvt-itof-template.h index bd6d23870639..e78647f63a08 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vfwcvt-itof-template.h +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vfwcvt-itof-template.h @@ -10,11 +10,17 @@ } #define TEST_ALL() \ - TEST (int16_t, float) \ - TEST (uint16_t, float) \ - TEST (int32_t, double) \ - TEST (uint32_t, double) \ TEST (int8_t, _Float16) \ TEST (uint8_t, _Float16) \ + TEST (int8_t, float) \ + TEST (uint8_t, float) \ + TEST (int8_t, double) \ + TEST (uint8_t, double) \ + TEST (int16_t, float) \ + TEST (uint16_t, float) \ + TEST (int16_t, double) \ + TEST (uint16_t, double) \ + TEST (int32_t, double) \ + TEST (uint32_t, double) \ TEST_ALL () diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vfwcvt-itof-zvfh-run.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vfwcvt-itof-zvfh-run.c index f89dc46d65f6..15e33200f10a 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vfwcvt-itof-zvfh-run.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vfwcvt-itof-zvfh-run.c @@ -37,9 +37,9 @@ main () RUN (int8_t, _Float16, 20) RUN (int8_t, _Float16, 27) - RUN (int8_t, _Float16, 4) - RUN (int8_t, _Float16, 8) - RUN (int8_t, _Float16, 11) - RUN (int8_t, _Float16, 29) - RUN (int8_t, _Float16, 49) + RUN (uint8_t, _Float16, 4) + RUN (uint8_t, _Float16, 8) + RUN (uint8_t, _Float16, 11) + RUN (uint8_t, _Float16, 29) + RUN (uint8_t, _Float16, 49) } diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/gather-scatter/gather_load_run-12.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/gather-scatter/gather_load_run-12.c index b4e2ead8ca9b..2fb525d8ffca 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/gather-scatter/gather_load_run-12.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/gather-scatter/gather_load_run-12.c @@ -7,6 +7,12 @@ int main (void) { + /* FIXME: The purpose of this assembly is to ensure that the vtype register is + initialized befor instructions such as vmv1r.v are executed. Otherwise you + will get illegal instruction errors when running with spike+pk. This is an + interim solution for reduce unnecessary failures and a unified solution + will come later. */ + asm volatile("vsetivli x0, 0, e8, m1, ta, ma"); #define RUN_LOOP(DATA_TYPE, INDEX_TYPE) \ DATA_TYPE dest_##DATA_TYPE##_##INDEX_TYPE[202] = {0}; \ DATA_TYPE src_##DATA_TYPE##_##INDEX_TYPE[202] = {0}; \ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/gather-scatter/strided_load-2.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/gather-scatter/strided_load-2.c index ee5f509b9ac9..2c9e7dd14a8f 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/gather-scatter/strided_load-2.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/gather-scatter/strided_load-2.c @@ -40,6 +40,6 @@ TEST_ALL (TEST_LOOP) -/* { dg-final { scan-tree-dump-times " \.MASK_LEN_GATHER_LOAD" 46 "optimized" } } */ +/* { dg-final { scan-tree-dump-times " \.MASK_LEN_GATHER_LOAD" 33 "optimized" } } */ /* { dg-final { scan-tree-dump-not " \.GATHER_LOAD" "optimized" } } */ /* { dg-final { scan-tree-dump-not " \.MASK_GATHER_LOAD" "optimized" } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/gather-scatter/strided_load_run-1.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/gather-scatter/strided_load_run-1.c index 4b03c25a907d..7eeb22aade27 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/gather-scatter/strided_load_run-1.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/gather-scatter/strided_load_run-1.c @@ -1,4 +1,5 @@ /* { dg-do run { target { riscv_vector } } } */ +/* { dg-additional-options "-mcmodel=medany" } */ #include "strided_load-1.c" #include @@ -6,6 +7,12 @@ int main (void) { + /* FIXME: The purpose of this assembly is to ensure that the vtype register is + initialized befor instructions such as vmv1r.v are executed. Otherwise you + will get illegal instruction errors when running with spike+pk. This is an + interim solution for reduce unnecessary failures and a unified solution + will come later. */ + asm volatile("vsetivli x0, 0, e8, m1, ta, ma"); #define RUN_LOOP(DATA_TYPE, BITS) \ DATA_TYPE dest_##DATA_TYPE##_##BITS[(BITS - 3) * (BITS + 13)]; \ DATA_TYPE dest2_##DATA_TYPE##_##BITS[(BITS - 3) * (BITS + 13)]; \ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/partial/live-1.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/partial/live-1.c new file mode 100644 index 000000000000..15ce74a0c4c6 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/partial/live-1.c @@ -0,0 +1,34 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-march=rv32gcv_zvfh -mabi=ilp32d -fno-vect-cost-model --param riscv-autovec-preference=scalable -fdump-tree-optimized-details" } */ + +#include + +#define EXTRACT_LAST(TYPE) \ + TYPE __attribute__ ((noinline, noclone)) \ + test_##TYPE (TYPE *x, int n, TYPE value) \ + { \ + TYPE last; \ + for (int j = 0; j < n; ++j) \ + { \ + last = x[j]; \ + x[j] = last * value; \ + } \ + return last; \ + } + +#define TEST_ALL(T) \ + T (int8_t) \ + T (int16_t) \ + T (int32_t) \ + T (int64_t) \ + T (uint8_t) \ + T (uint16_t) \ + T (uint32_t) \ + T (uint64_t) \ + T (_Float16) \ + T (float) \ + T (double) + +TEST_ALL (EXTRACT_LAST) + +/* { dg-final { scan-tree-dump-times "\.VEC_EXTRACT" 11 "optimized" } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/partial/live-2.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/partial/live-2.c new file mode 100644 index 000000000000..69c2a44219ae --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/partial/live-2.c @@ -0,0 +1,31 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-march=rv32gcv_zvfh -mabi=ilp32d -fno-vect-cost-model --param riscv-autovec-preference=scalable -fdump-tree-optimized-details" } */ + +#include + +#define EXTRACT_LAST(TYPE) \ + _Bool __attribute__ ((noipa)) \ + test_##TYPE (TYPE *restrict x, TYPE *restrict y, int n) \ + { \ + _Bool last; \ + for (int j = 0; j < n; ++j) \ + { \ + last = !x[j]; \ + y[j] = last; \ + } \ + return last; \ + } + +#define TEST_ALL(T) \ + T (int8_t) \ + T (int16_t) \ + T (int32_t) \ + T (int64_t) \ + T (uint8_t) \ + T (uint16_t) \ + T (uint32_t) \ + T (uint64_t) + +TEST_ALL (EXTRACT_LAST) + +/* { dg-final { scan-tree-dump-times "\.VEC_EXTRACT" 8 "optimized" } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/partial/live_run-1.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/partial/live_run-1.c new file mode 100644 index 000000000000..42913a112c6d --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/partial/live_run-1.c @@ -0,0 +1,35 @@ +/* { dg-do run { target { riscv_vector } } } */ +/* { dg-additional-options "--param riscv-autovec-preference=scalable" } */ + +#include "live-1.c" + +#define N 107 +#define OP 70 + +#define TEST_LOOP(TYPE) \ + { \ + TYPE a[N]; \ + for (int i = 0; i < N; ++i) \ + { \ + a[i] = i * 2 + (i % 3); \ + asm volatile ("" ::: "memory"); \ + } \ + TYPE expected = a[N - 1]; \ + TYPE res = test_##TYPE (a, N, OP); \ + if (res != expected) \ + __builtin_abort (); \ + for (int i = 0; i < N; ++i) \ + { \ + TYPE old = i * 2 + (i % 3); \ + if (a[i] != (TYPE) (old * (TYPE) OP)) \ + __builtin_abort (); \ + asm volatile ("" ::: "memory"); \ + } \ + } + +int __attribute__ ((optimize (1))) +main (void) +{ + TEST_ALL (TEST_LOOP); + return 0; +} diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/partial/live_run-2.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/partial/live_run-2.c new file mode 100644 index 000000000000..80d076bcf74e --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/partial/live_run-2.c @@ -0,0 +1,54 @@ +/* { dg-do run { target { riscv_vector } } } */ +/* { dg-additional-options "--param riscv-autovec-preference=scalable" } */ + +#include "live-2.c" + +#define TEST_LOOP(TYPE, N) \ + { \ + TYPE a##N[N]; \ + TYPE b##N[N]; \ + for (int i = 0; i < N; ++i) \ + { \ + a##N[i] = i & 1; \ + b##N[i] = 0; \ + asm volatile ("" ::: "memory"); \ + } \ + TYPE expected##N = !(a##N[N - 1]); \ + TYPE res##N = test_##TYPE (a##N, b##N, N); \ + if (res##N != expected##N) \ + __builtin_abort (); \ + for (int i = 0; i < N; ++i) \ + { \ + if (b##N[i] != !a##N[i]) \ + __builtin_abort (); \ + asm volatile ("" ::: "memory"); \ + } \ + } + +#define TEST_ALL_N(T, N) \ + T (int8_t, N) \ + T (int16_t, N) \ + T (int32_t, N) \ + T (int64_t, N) \ + T (uint8_t, N) \ + T (uint16_t, N) \ + T (uint32_t, N) \ + T (uint64_t, N) + +int __attribute__ ((optimize (1))) main (void) +{ + TEST_ALL_N (TEST_LOOP, 2); + TEST_ALL_N (TEST_LOOP, 3); + TEST_ALL_N (TEST_LOOP, 4); + TEST_ALL_N (TEST_LOOP, 5); + TEST_ALL_N (TEST_LOOP, 6); + TEST_ALL_N (TEST_LOOP, 7); + TEST_ALL_N (TEST_LOOP, 8); + TEST_ALL_N (TEST_LOOP, 17); + TEST_ALL_N (TEST_LOOP, 64); + TEST_ALL_N (TEST_LOOP, 107); + TEST_ALL_N (TEST_LOOP, 255); + TEST_ALL_N (TEST_LOOP, 256); + TEST_ALL_N (TEST_LOOP, 4389); + return 0; +} diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/partial/slp-1.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/partial/slp-1.c index 0bce83613271..3571a325f73a 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/partial/slp-1.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/partial/slp-1.c @@ -19,6 +19,8 @@ f (int8_t *restrict a, int8_t *restrict b, int n) } } -/* { dg-final { scan-tree-dump-times "\.VEC_PERM" 1 "optimized" } } */ -/* { dg-final { scan-assembler {\tvid\.v} } } */ -/* { dg-final { scan-assembler {\tvand} } } */ +/* FIXME: Since we don't have VECT cost model yet, LOAD_LANES/STORE_LANES are chosen + instead of SLP when riscv-autovec-lmul=m1 or m2. */ +/* { dg-final { scan-tree-dump-times "\.VEC_PERM" 1 "optimized" { xfail { any-opts "--param riscv-autovec-lmul=m1" "--param riscv-autovec-lmul=m2" } } } } */ +/* { dg-final { scan-assembler {\tvid\.v} { xfail { any-opts "--param riscv-autovec-lmul=m1" "--param riscv-autovec-lmul=m2" } } } } */ +/* { dg-final { scan-assembler {\tvand} { xfail { any-opts "--param riscv-autovec-lmul=m1" "--param riscv-autovec-lmul=m2" } } } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/partial/slp-16.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/partial/slp-16.c index 1a35bba013b1..8c5c65152c83 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/partial/slp-16.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/partial/slp-16.c @@ -19,6 +19,8 @@ f (uint8_t *restrict a, uint8_t *restrict b, int n) } } -/* { dg-final { scan-tree-dump-times "\.VEC_PERM" 1 "optimized" } } */ -/* { dg-final { scan-assembler {\tvid\.v} } } */ +/* FIXME: Since we don't have VECT cost model yet, LOAD_LANES/STORE_LANES are chosen + instead of SLP when riscv-autovec-lmul=m1 or m2. */ +/* { dg-final { scan-tree-dump-times "\.VEC_PERM" 1 "optimized" { xfail { any-opts "--param riscv-autovec-lmul=m1" "--param riscv-autovec-lmul=m2" } } } } */ +/* { dg-final { scan-assembler {\tvid\.v} { xfail { any-opts "--param riscv-autovec-lmul=m1" "--param riscv-autovec-lmul=m2" } } } } */ /* { dg-final { scan-assembler-not {\tvmul} } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/partial/slp-17.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/partial/slp-17.c index 2f2c3d11c2ae..67dbadafc48c 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/partial/slp-17.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/partial/slp-17.c @@ -29,6 +29,8 @@ f (uint8_t *restrict a, uint8_t *restrict b, } } -/* { dg-final { scan-tree-dump-times "\.VEC_PERM" 2 "optimized" } } */ -/* { dg-final { scan-assembler {\tvid\.v} } } */ +/* FIXME: Since we don't have VECT cost model yet, LOAD_LANES/STORE_LANES are chosen + instead of SLP when riscv-autovec-lmul=m1. */ +/* { dg-final { scan-tree-dump-times "\.VEC_PERM" 2 "optimized" { xfail { any-opts "--param riscv-autovec-lmul=m1" } } } } */ +/* { dg-final { scan-assembler {\tvid\.v} { xfail { any-opts "--param riscv-autovec-lmul=m1" } } } } */ /* { dg-final { scan-assembler-not {\tvmul} } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/partial/slp-18.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/partial/slp-18.c index 72103314b1ab..6e60dabb85f8 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/partial/slp-18.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/partial/slp-18.c @@ -21,6 +21,8 @@ f (float *restrict a, float *restrict b, } } -/* { dg-final { scan-tree-dump "\.VEC_PERM" "optimized" } } */ -/* { dg-final { scan-assembler {\tvid\.v} } } */ +/* FIXME: Since we don't have VECT cost model yet, LOAD_LANES/STORE_LANES are chosen + instead of SLP when riscv-autovec-lmul=m1 or m2. */ +/* { dg-final { scan-tree-dump-times "\.VEC_PERM" 2 "optimized" { xfail { any-opts "--param riscv-autovec-lmul=m1" "--param riscv-autovec-lmul=m2" } } } } */ +/* { dg-final { scan-assembler {\tvid\.v} { xfail { any-opts "--param riscv-autovec-lmul=m1" "--param riscv-autovec-lmul=m2" } } } } */ /* { dg-final { scan-assembler-not {\tvmul} } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/partial/slp-19.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/partial/slp-19.c index 41ce0fc57675..309c30e47356 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/partial/slp-19.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/partial/slp-19.c @@ -21,6 +21,8 @@ f (float *restrict a, float *restrict b, } } -/* { dg-final { scan-tree-dump "\.VEC_PERM" "optimized" } } */ -/* { dg-final { scan-assembler {\tvid\.v} } } */ +/* FIXME: Since we don't have VECT cost model yet, LOAD_LANES/STORE_LANES are chosen + instead of SLP when riscv-autovec-lmul=m1 or m2. */ +/* { dg-final { scan-tree-dump "\.VEC_PERM" "optimized" { xfail { any-opts "--param riscv-autovec-lmul=m1" "--param riscv-autovec-lmul=m2" } } } } */ +/* { dg-final { scan-assembler {\tvid\.v} { xfail { any-opts "--param riscv-autovec-lmul=m1" "--param riscv-autovec-lmul=m2" } } } } */ /* { dg-final { scan-assembler-not {\tvmul} } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/partial/slp-2.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/partial/slp-2.c index ac817451295b..5605b1ba6846 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/partial/slp-2.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/partial/slp-2.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-additional-options "-march=rv32gcv -mabi=ilp32d --param riscv-autovec-preference=scalable -fdump-tree-optimized-details" } */ +/* { dg-additional-options "-march=rv32gcv -mabi=ilp32d --param riscv-autovec-preference=scalable -fno-vect-cost-model -fdump-tree-optimized-details" } */ #include @@ -19,4 +19,6 @@ f (int16_t *restrict a, int16_t *restrict b, int n) } } -/* { dg-final { scan-tree-dump-times "\.VEC_PERM" 1 "optimized" } } */ +/* FIXME: Since we don't have VECT cost model yet, LOAD_LANES/STORE_LANES are chosen + instead of SLP when riscv-autovec-lmul=m1. */ +/* { dg-final { scan-tree-dump-times "\.VEC_PERM" 1 "optimized" { xfail { any-opts "--param riscv-autovec-lmul=m1" } } } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/partial/slp-3.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/partial/slp-3.c index 73962055b032..fde54e1f059b 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/partial/slp-3.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/partial/slp-3.c @@ -19,4 +19,6 @@ f (int8_t *restrict a, int8_t *restrict b, int n) } } -/* { dg-final { scan-tree-dump-times "\.VEC_PERM" 1 "optimized" } } */ +/* FIXME: Since we don't have VECT cost model yet, LOAD_LANES/STORE_LANES are chosen + instead of SLP when riscv-autovec-lmul=m1 or m2. */ +/* { dg-final { scan-tree-dump-times "\.VEC_PERM" 1 "optimized" { xfail { any-opts "--param riscv-autovec-lmul=m1" "--param riscv-autovec-lmul=m2" } } } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/partial/slp-4.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/partial/slp-4.c index fa216fc8c400..e18ebd3ae2fb 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/partial/slp-4.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/partial/slp-4.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-additional-options "-march=rv32gcv -mabi=ilp32d --param riscv-autovec-preference=scalable -fdump-tree-optimized-details" } */ +/* { dg-additional-options "-march=rv32gcv -mabi=ilp32d --param riscv-autovec-preference=scalable -fno-vect-cost-model -fdump-tree-optimized-details" } */ #include @@ -19,4 +19,6 @@ f (int16_t *restrict a, int16_t *restrict b, int n) } } -/* { dg-final { scan-tree-dump-times "\.VEC_PERM" 1 "optimized" } } */ +/* FIXME: Since we don't have VECT cost model yet, LOAD_LANES/STORE_LANES are chosen + instead of SLP when riscv-autovec-lmul=m1. */ +/* { dg-final { scan-tree-dump-times "\.VEC_PERM" 1 "optimized" { xfail { any-opts "--param riscv-autovec-lmul=m1" } } } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/partial/slp-5.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/partial/slp-5.c index 899ed9e310be..600699be9d12 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/partial/slp-5.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/partial/slp-5.c @@ -19,4 +19,6 @@ f (int8_t *restrict a, int8_t *restrict b, int n) } } -/* { dg-final { scan-tree-dump-times "\.VEC_PERM" 1 "optimized" } } */ +/* FIXME: Since we don't have VECT cost model yet, LOAD_LANES/STORE_LANES are chosen + instead of SLP when riscv-autovec-lmul=m1 or m2. */ +/* { dg-final { scan-tree-dump-times "\.VEC_PERM" 1 "optimized" { xfail { any-opts "--param riscv-autovec-lmul=m1" "--param riscv-autovec-lmul=m2" } } } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/partial/slp-6.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/partial/slp-6.c index fb87cc00cead..9fca6bdf5d02 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/partial/slp-6.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/partial/slp-6.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-additional-options "-march=rv32gcv -mabi=ilp32d --param riscv-autovec-preference=scalable -fdump-tree-optimized-details" } */ +/* { dg-additional-options "-march=rv32gcv -mabi=ilp32d --param riscv-autovec-preference=scalable -fdump-tree-optimized-details -fno-vect-cost-model" } */ #include @@ -19,5 +19,7 @@ f (uint8_t *restrict a, uint8_t *restrict b, int n) } } -/* { dg-final { scan-tree-dump-times "\.VEC_PERM" 1 "optimized" } } */ +/* FIXME: Since we don't have VECT cost model yet, LOAD_LANES/STORE_LANES are chosen + instead of SLP when riscv-autovec-lmul=m1. */ +/* { dg-final { scan-tree-dump-times "\.VEC_PERM" 1 "optimized" { xfail { any-opts "--param riscv-autovec-lmul=m1" } } } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/pr110950.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/pr110950.c new file mode 100644 index 000000000000..9f276d06338b --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/pr110950.c @@ -0,0 +1,12 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gcv -mabi=lp64d --param=riscv-autovec-preference=scalable -Ofast" } */ + +int a; +void b() { + long *c = 0; + int *d; + for (; a; ++a) + c[a] = d[-a]; +} + +/* { dg-final { scan-assembler-times {vslide1up\.vx} 1 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/pr110964.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/pr110964.c new file mode 100644 index 000000000000..cf2d1fb5f1d2 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/pr110964.c @@ -0,0 +1,13 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gcv -mabi=lp64d --param=riscv-autovec-preference=scalable -Ofast" } */ + +int *a; +long b, c; + +int d () +{ + const int e; + for (; a < e; a++) /* { dg-warning "comparison between pointer and integer" } */ + c += *a * b; +} + diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/pr110989.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/pr110989.c new file mode 100644 index 000000000000..6e163a55c56a --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/pr110989.c @@ -0,0 +1,16 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gcv -mabi=lp64d --param=riscv-autovec-preference=scalable -Ofast -fno-schedule-insns -fno-schedule-insns2" } */ + +int a, b, c; +double *d; +void e() { + double f; + for (; c; c++, d--) + f = *d ?: *(&a + c); + b = f; +} + +/* { dg-final { scan-assembler-times {vsetvli} 3 } } */ +/* { dg-final { scan-assembler-times {vsetvli\s+[a-x0-9]+,\s*zero,\s*e64,\s*m1,\s*t[au],\s*m[au]} 1 } } */ +/* { dg-final { scan-assembler-times {vsetvli\s+zero,\s*zero,\s*e64,\s*m1,\s*t[au],\s*m[au]} 1 } } */ +/* { dg-final { scan-assembler-times {vsetvli\s+zero,\s*zero,\s*e32,\s*mf2,\s*t[au],\s*m[au]} 1 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/extract_last-1.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/extract_last-1.c new file mode 100644 index 000000000000..6c86f29e7d43 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/extract_last-1.c @@ -0,0 +1,20 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-march=rv32gcv_zvfh -mabi=ilp32d --param=riscv-autovec-preference=fixed-vlmax -fno-vect-cost-model -fdump-tree-optimized" } */ + +#define N 32 + +/* Simple condition reduction. */ + +int __attribute__ ((noinline, noclone)) +condition_reduction (int *a, int min_v) +{ + int last = 66; /* High start value. */ + + for (int i = 0; i < N; i++) + if (a[i] < min_v) + last = i; + + return last; +} + +/* { dg-final { scan-tree-dump "\.LEN_FOLD_EXTRACT_LAST" "optimized" } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/extract_last-10.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/extract_last-10.c new file mode 100644 index 000000000000..c5fe52047634 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/extract_last-10.c @@ -0,0 +1,6 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-march=rv32gcv_zvfh -mabi=ilp32d --param=riscv-autovec-preference=scalable -fno-vect-cost-model -fdump-tree-optimized" } */ + +#include "extract_last-9.c" + +/* { dg-final { scan-tree-dump "\.LEN_FOLD_EXTRACT_LAST" "optimized" } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/extract_last-11.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/extract_last-11.c new file mode 100644 index 000000000000..85547c8bd768 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/extract_last-11.c @@ -0,0 +1,24 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-march=rv32gcv_zvfh -mabi=ilp32d --param=riscv-autovec-preference=fixed-vlmax -fno-vect-cost-model -fdump-tree-optimized" } */ + +#define N 32 + +#ifndef TYPE +#define TYPE float +#endif + +/* Non-integer data types. */ + +TYPE __attribute__ ((noinline, noclone)) +condition_reduction (TYPE *a, TYPE min_v) +{ + TYPE last = 0; + + for (int i = 0; i < N; i++) + if (a[i] < min_v) + last = a[i]; + + return last; +} + +/* { dg-final { scan-tree-dump "\.LEN_FOLD_EXTRACT_LAST" "optimized" } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/extract_last-12.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/extract_last-12.c new file mode 100644 index 000000000000..c165cb33ce43 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/extract_last-12.c @@ -0,0 +1,6 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-march=rv32gcv_zvfh -mabi=ilp32d --param=riscv-autovec-preference=scalable -fno-vect-cost-model -fdump-tree-optimized" } */ + +#include "extract_last-11.c" + +/* { dg-final { scan-tree-dump "\.LEN_FOLD_EXTRACT_LAST" "optimized" } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/extract_last-13.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/extract_last-13.c new file mode 100644 index 000000000000..9a04af6c2667 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/extract_last-13.c @@ -0,0 +1,7 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-march=rv32gcv_zvfh -mabi=ilp32d --param=riscv-autovec-preference=fixed-vlmax -fno-vect-cost-model -fdump-tree-optimized" } */ + +#define TYPE double +#include "extract_last-11.c" + +/* { dg-final { scan-tree-dump "\.LEN_FOLD_EXTRACT_LAST" "optimized" } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/extract_last-14.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/extract_last-14.c new file mode 100644 index 000000000000..88f8a4c056a4 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/extract_last-14.c @@ -0,0 +1,6 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-march=rv32gcv_zvfh -mabi=ilp32d --param=riscv-autovec-preference=scalable -fno-vect-cost-model -fdump-tree-optimized" } */ + +#include "extract_last-13.c" + +/* { dg-final { scan-tree-dump "\.LEN_FOLD_EXTRACT_LAST" "optimized" } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/extract_last-2.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/extract_last-2.c new file mode 100644 index 000000000000..b1eea0db0cd7 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/extract_last-2.c @@ -0,0 +1,6 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-march=rv32gcv_zvfh -mabi=ilp32d --param=riscv-autovec-preference=scalable -fno-vect-cost-model -fdump-tree-optimized" } */ + +#include "extract_last-1.c" + +/* { dg-final { scan-tree-dump "\.LEN_FOLD_EXTRACT_LAST" "optimized" } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/extract_last-3.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/extract_last-3.c new file mode 100644 index 000000000000..2c94ef58a473 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/extract_last-3.c @@ -0,0 +1,26 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-march=rv32gcv_zvfh -mabi=ilp32d --param=riscv-autovec-preference=fixed-vlmax -fno-vect-cost-model -fdump-tree-optimized" } */ + +#include + +#if !defined(TYPE) +#define TYPE uint32_t +#endif + +#define N 254 + +/* Non-simple condition reduction. */ + +TYPE __attribute__ ((noinline, noclone)) +condition_reduction (TYPE *a, TYPE min_v) +{ + TYPE last = 65; + + for (TYPE i = 0; i < N; i++) + if (a[i] < min_v) + last = a[i]; + + return last; +} + +/* { dg-final { scan-tree-dump "\.LEN_FOLD_EXTRACT_LAST" "optimized" } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/extract_last-4.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/extract_last-4.c new file mode 100644 index 000000000000..a9ac667edd32 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/extract_last-4.c @@ -0,0 +1,6 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-march=rv32gcv_zvfh -mabi=ilp32d --param=riscv-autovec-preference=scalable -fno-vect-cost-model -fdump-tree-optimized" } */ + +#include "extract_last-3.c" + +/* { dg-final { scan-tree-dump "\.LEN_FOLD_EXTRACT_LAST" "optimized" } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/extract_last-5.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/extract_last-5.c new file mode 100644 index 000000000000..dc7fa6397864 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/extract_last-5.c @@ -0,0 +1,8 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-march=rv32gcv_zvfh -mabi=ilp32d --param=riscv-autovec-preference=fixed-vlmax -fno-vect-cost-model -fdump-tree-optimized" } */ + +#define TYPE uint8_t + +#include "extract_last-3.c" + +/* { dg-final { scan-tree-dump "\.LEN_FOLD_EXTRACT_LAST" "optimized" } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/extract_last-6.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/extract_last-6.c new file mode 100644 index 000000000000..4e434a1813d2 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/extract_last-6.c @@ -0,0 +1,6 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-march=rv32gcv_zvfh -mabi=ilp32d --param=riscv-autovec-preference=scalable -fno-vect-cost-model -fdump-tree-optimized" } */ + +#include "extract_last-5.c" + +/* { dg-final { scan-tree-dump "\.LEN_FOLD_EXTRACT_LAST" "optimized" } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/extract_last-7.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/extract_last-7.c new file mode 100644 index 000000000000..e75e9b21ed34 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/extract_last-7.c @@ -0,0 +1,8 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-march=rv32gcv_zvfh -mabi=ilp32d --param=riscv-autovec-preference=fixed-vlmax -fno-vect-cost-model -fdump-tree-optimized" } */ + +#define TYPE int16_t + +#include "extract_last-3.c" + +/* { dg-final { scan-tree-dump "\.LEN_FOLD_EXTRACT_LAST" "optimized" } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/extract_last-8.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/extract_last-8.c new file mode 100644 index 000000000000..a37eb26f5a45 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/extract_last-8.c @@ -0,0 +1,6 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-march=rv32gcv_zvfh -mabi=ilp32d --param=riscv-autovec-preference=scalable -fno-vect-cost-model -fdump-tree-optimized" } */ + +#include "extract_last-7.c" + +/* { dg-final { scan-tree-dump "\.LEN_FOLD_EXTRACT_LAST" "optimized" } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/extract_last-9.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/extract_last-9.c new file mode 100644 index 000000000000..c7ae0d747cc9 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/extract_last-9.c @@ -0,0 +1,8 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-march=rv32gcv_zvfh -mabi=ilp32d --param=riscv-autovec-preference=fixed-vlmax -fno-vect-cost-model -fdump-tree-optimized" } */ + +#define TYPE uint64_t + +#include "extract_last-3.c" + +/* { dg-final { scan-tree-dump "\.LEN_FOLD_EXTRACT_LAST" "optimized" } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/extract_last_run-1.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/extract_last_run-1.c new file mode 100644 index 000000000000..c2083455cde1 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/extract_last_run-1.c @@ -0,0 +1,22 @@ +/* { dg-do run { target { riscv_vector } } } */ +/* { dg-additional-options "--param=riscv-autovec-preference=fixed-vlmax -fno-vect-cost-model" } */ + +#include "extract_last-1.c" + +int __attribute__ ((optimize (1))) +main (void) +{ + int a[N] = { + 11, -12, 13, 14, 15, 16, 17, 18, 19, 20, + 1, 2, -3, 4, 5, 6, 7, -8, 9, 10, + 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, + 31, 32 + }; + + int ret = condition_reduction (a, 1); + + if (ret != 17) + __builtin_abort (); + + return 0; +} diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/extract_last_run-10.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/extract_last_run-10.c new file mode 100644 index 000000000000..7ff435df4f11 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/extract_last_run-10.c @@ -0,0 +1,4 @@ +/* { dg-do run { target { riscv_vector } } } */ +/* { dg-additional-options "--param=riscv-autovec-preference=scalable -fno-vect-cost-model" } */ + +#include "extract_last_run-9.c" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/extract_last_run-11.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/extract_last_run-11.c new file mode 100644 index 000000000000..99af6b3287e3 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/extract_last_run-11.c @@ -0,0 +1,22 @@ +/* { dg-do run { target { riscv_vector } } } */ +/* { dg-additional-options "--param=riscv-autovec-preference=fixed-vlmax -fno-vect-cost-model" } */ + +#include "extract_last-11.c" + +int __attribute__ ((optimize (1))) +main (void) +{ + float a[N] = { + 11.5, 12.2, 13.22, 14.1, 15.2, 16.3, 17, 18.7, 19, 20, + 1, 2, 3.3, 4.3333, 5.5, 6.23, 7, 8.63, 9, 10.6, + 21, 22.12, 23.55, 24.76, 25, 26, 27.34, 28.765, 29, 30, + 31.111, 32.322 + }; + + float ret = condition_reduction (a, 16.7); + + if (ret != (float) 10.6) + __builtin_abort (); + + return 0; +} diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/extract_last_run-12.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/extract_last_run-12.c new file mode 100644 index 000000000000..43d1c765bb57 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/extract_last_run-12.c @@ -0,0 +1,4 @@ +/* { dg-do run { target { riscv_vector } } } */ +/* { dg-additional-options "--param=riscv-autovec-preference=scalable -fno-vect-cost-model" } */ + +#include "extract_last_run-11.c" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/extract_last_run-13.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/extract_last_run-13.c new file mode 100644 index 000000000000..1e418964d689 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/extract_last_run-13.c @@ -0,0 +1,22 @@ +/* { dg-do run { target { riscv_vector } } } */ +/* { dg-additional-options "--param=riscv-autovec-preference=fixed-vlmax -fno-vect-cost-model" } */ + +#include "extract_last-13.c" + +int __attribute__ ((optimize (1))) +main (void) +{ + double a[N] = { + 11.5, 12.2, 13.22, 14.1, 15.2, 16.3, 17, 18.7, 19, 20, + 1, 2, 3.3, 4.3333, 5.5, 6.23, 7, 8.63, 9, 10.6, + 21, 22.12, 23.55, 24.76, 25, 26, 27.34, 28.765, 29, 30, + 31.111, 32.322 + }; + + double ret = condition_reduction (a, 16.7); + + if (ret != 10.6) + __builtin_abort (); + + return 0; +} diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/extract_last_run-14.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/extract_last_run-14.c new file mode 100644 index 000000000000..535b68f0f22e --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/extract_last_run-14.c @@ -0,0 +1,4 @@ +/* { dg-do run { target { riscv_vector } } } */ +/* { dg-additional-options "--param=riscv-autovec-preference=scalable -fno-vect-cost-model" } */ + +#include "extract_last_run-13.c" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/extract_last_run-2.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/extract_last_run-2.c new file mode 100644 index 000000000000..ee53bf9ccab3 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/extract_last_run-2.c @@ -0,0 +1,4 @@ +/* { dg-do run { target { riscv_vector } } } */ +/* { dg-additional-options "--param=riscv-autovec-preference=scalable -fno-vect-cost-model" } */ + +#include "extract_last_run-1.c" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/extract_last_run-3.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/extract_last_run-3.c new file mode 100644 index 000000000000..ff2b0258dc82 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/extract_last_run-3.c @@ -0,0 +1,23 @@ +/* { dg-do run { target { riscv_vector } } } */ +/* { dg-additional-options "--param=riscv-autovec-preference=fixed-vlmax -fno-vect-cost-model" } */ + +#include "extract_last-3.c" + +int __attribute__ ((optimize (1))) +main (void) +{ + TYPE a[N] = { + 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, + 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, + 31, 32 + }; + __builtin_memset (a + 32, 43, (N - 32) * sizeof (TYPE)); + + TYPE ret = condition_reduction (a, 16); + + if (ret != 10) + __builtin_abort (); + + return 0; +} diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/extract_last_run-4.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/extract_last_run-4.c new file mode 100644 index 000000000000..4b5b6332adfc --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/extract_last_run-4.c @@ -0,0 +1,4 @@ +/* { dg-do run { target { riscv_vector } } } */ +/* { dg-additional-options "--param=riscv-autovec-preference=scalable -fno-vect-cost-model" } */ + +#include "extract_last_run-3.c" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/extract_last_run-5.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/extract_last_run-5.c new file mode 100644 index 000000000000..7b66b24261f3 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/extract_last_run-5.c @@ -0,0 +1,23 @@ +/* { dg-do run { target { riscv_vector } } } */ +/* { dg-additional-options "--param=riscv-autovec-preference=fixed-vlmax -fno-vect-cost-model" } */ + +#include "extract_last-5.c" + +int __attribute__ ((optimize (1))) +main (void) +{ + TYPE a[N] = { + 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, + 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, + 31, 32 + }; + __builtin_memset (a + 32, 43, (N - 32) * sizeof (TYPE)); + + TYPE ret = condition_reduction (a, 16); + + if (ret != 10) + __builtin_abort (); + + return 0; +} diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/extract_last_run-6.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/extract_last_run-6.c new file mode 100644 index 000000000000..a52eac92487d --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/extract_last_run-6.c @@ -0,0 +1,4 @@ +/* { dg-do run { target { riscv_vector } } } */ +/* { dg-additional-options "--param=riscv-autovec-preference=scalable -fno-vect-cost-model" } */ + +#include "extract_last_run-5.c" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/extract_last_run-7.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/extract_last_run-7.c new file mode 100644 index 000000000000..a1ac4a5dfb75 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/extract_last_run-7.c @@ -0,0 +1,25 @@ +/* { dg-do run { target { riscv_vector } } } */ +/* { dg-additional-options "--param=riscv-autovec-preference=fixed-vlmax -fno-vect-cost-model" } */ + +#include "extract_last-7.c" + +extern void abort (void) __attribute__ ((noreturn)); + +int __attribute__ ((optimize (1))) +main (void) +{ + TYPE a[N] = { + 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, + 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, + 31, 32 + }; + __builtin_memset (a+32, 43, (N-32)*sizeof (TYPE)); + + TYPE ret = condition_reduction (a, 16); + + if (ret != 10) + abort (); + + return 0; +} diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/extract_last_run-8.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/extract_last_run-8.c new file mode 100644 index 000000000000..56858f999218 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/extract_last_run-8.c @@ -0,0 +1,4 @@ +/* { dg-do run { target { riscv_vector } } } */ +/* { dg-additional-options "--param=riscv-autovec-preference=scalable -fno-vect-cost-model" } */ + +#include "extract_last_run-7.c" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/extract_last_run-9.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/extract_last_run-9.c new file mode 100644 index 000000000000..67672bfb7056 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/extract_last_run-9.c @@ -0,0 +1,23 @@ +/* { dg-do run { target { riscv_vector } } } */ +/* { dg-additional-options "--param=riscv-autovec-preference=fixed-vlmax -fno-vect-cost-model" } */ + +#include "extract_last-9.c" + +int __attribute__ ((optimize (1))) +main (void) +{ + TYPE a[N] = { + 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, + 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, + 31, 32 + }; + __builtin_memset (a + 32, 43, (N - 32) * sizeof (TYPE)); + + TYPE ret = condition_reduction (a, 16); + + if (ret != 10) + __builtin_abort (); + + return 0; +} diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/reduc_call-1.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/reduc_call-1.c new file mode 100644 index 000000000000..1a3ca9cdf11c --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/reduc_call-1.c @@ -0,0 +1,12 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-march=rv32gcv_zvfh -mabi=ilp32d --param=riscv-autovec-preference=scalable -fno-vect-cost-model" } */ + +double foo (double *a, double *b, double *c) +{ + double result = 0.0; + for (int i = 0; i < 1024; ++i) + result += i & 1 ? __builtin_fma (a[i], b[i], c[i]) : 0.0; + return result; +} + +/* { dg-final { scan-assembler-times {vfmacc\.vv\s+v[0-9]+,v[0-9]+,v[0-9]+,v0.t} 1 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/reduc_call-2.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/reduc_call-2.c new file mode 100644 index 000000000000..cc07a047cd58 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/reduc_call-2.c @@ -0,0 +1,6 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-march=rv32gcv_zvfh -mabi=ilp32d --param=riscv-autovec-preference=scalable -fno-vect-cost-model -ffast-math" } */ + +#include "reduc_call-1.c" + +/* { dg-final { scan-assembler-times {vfmacc\.vv\s+v[0-9]+,v[0-9]+,v[0-9]+,v0.t} 1 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/reduc_call-3.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/reduc_call-3.c new file mode 100644 index 000000000000..91004e7760fb --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/reduc_call-3.c @@ -0,0 +1,6 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-march=rv32gcv_zvfh -mabi=ilp32d --param=riscv-autovec-preference=fixed-vlmax -fno-vect-cost-model" } */ + +#include "reduc_call-1.c" + +/* { dg-final { scan-assembler {vfmacc\.vv\s+v[0-9]+,v[0-9]+,v[0-9]+,v0.t} } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/reduc_call-4.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/reduc_call-4.c new file mode 100644 index 000000000000..6d00c404d2a8 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/reduc_call-4.c @@ -0,0 +1,6 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-march=rv32gcv_zvfh -mabi=ilp32d --param=riscv-autovec-preference=fixed-vlmax -fno-vect-cost-model -ffast-math" } */ + +#include "reduc_call-1.c" + +/* { dg-final { scan-assembler {vfmacc\.vv\s+v[0-9]+,v[0-9]+,v[0-9]+,v0.t} } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/reduc_call-5.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/reduc_call-5.c new file mode 100644 index 000000000000..3523c0f5cd5a --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/reduc_call-5.c @@ -0,0 +1,16 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-march=rv32gcv_zvfh -mabi=ilp32d --param=riscv-autovec-preference=scalable -fno-vect-cost-model" } */ + +double +foo (double *restrict r, const double *restrict a, const double *restrict b, + const double *restrict c, double res) +{ + for (int i = 0; i < 1024; i++) + { + double x = __builtin_fma (a[i], b[i], c[i]); + res += __builtin_fma (a[i], b[i], x); + } + return res; +} + +/* { dg-final { scan-assembler-times {vfredosum\.vs\s+v[0-9]+,v[0-9]+,v[0-9]+} 1 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/reduc_strict_run-1.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/reduc_strict_run-1.c index 516be97e9eb5..39c36ef6307b 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/reduc_strict_run-1.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/reduc_strict_run-1.c @@ -17,7 +17,8 @@ asm volatile ("" ::: "memory"); \ } \ TYPE res = reduc_plus_##TYPE (a, b); \ - if (res != r * q) \ + TYPE ref = r * q; \ + if (res != ref) \ __builtin_abort (); \ } diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/mask_struct_load-1.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/mask_struct_load-1.c new file mode 100644 index 000000000000..e5dc10aea881 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/mask_struct_load-1.c @@ -0,0 +1,42 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-std=c99 -march=rv32gcv_zvfh -mabi=ilp32d --param=riscv-autovec-preference=scalable -fno-vect-cost-model" } */ + +#include + +#define TEST_LOOP(NAME, OUTTYPE, INTYPE, MASKTYPE) \ + void __attribute__ ((noinline, noclone)) \ + NAME##_2 (OUTTYPE *__restrict dest, INTYPE *__restrict src, \ + MASKTYPE *__restrict cond, intptr_t n) \ + { \ + for (intptr_t i = 0; i < n; ++i) \ + if (cond[i]) \ + dest[i] = src[i * 2] + src[i * 2 + 1]; \ + } + +#define TEST2(NAME, OUTTYPE, INTYPE) \ + TEST_LOOP (NAME##_i8, OUTTYPE, INTYPE, int8_t) \ + TEST_LOOP (NAME##_i16, OUTTYPE, INTYPE, uint16_t) \ + TEST_LOOP (NAME##_f32, OUTTYPE, INTYPE, float) \ + TEST_LOOP (NAME##_f64, OUTTYPE, INTYPE, double) + +#define TEST1(NAME, OUTTYPE) \ + TEST2 (NAME##_i8, OUTTYPE, int8_t) \ + TEST2 (NAME##_i16, OUTTYPE, uint16_t) \ + TEST2 (NAME##_i32, OUTTYPE, int32_t) \ + TEST2 (NAME##_i64, OUTTYPE, uint64_t) + +#define TEST(NAME) \ + TEST1 (NAME##_i8, int8_t) \ + TEST1 (NAME##_i16, uint16_t) \ + TEST1 (NAME##_i32, int32_t) \ + TEST1 (NAME##_i64, uint64_t) \ + TEST2 (NAME##_f16_f16, _Float16, _Float16) \ + TEST2 (NAME##_f32_f32, float, float) \ + TEST2 (NAME##_f64_f64, double, double) + +TEST (test) + +/* { dg-final { scan-assembler-times {vlseg2e8\.v\s+v[0-9]+,\s*\([a-x0-9]+\),\s*v0.t} 16 } } */ +/* { dg-final { scan-assembler-times {vlseg2e16\.v\s+v[0-9]+,\s*\([a-x0-9]+\),\s*v0.t} 20 } } */ +/* { dg-final { scan-assembler-times {vlseg2e32\.v\s+v[0-9]+,\s*\([a-x0-9]+\),\s*v0.t} 20 } } */ +/* { dg-final { scan-assembler-times {vlseg2e64\.v\s+v[0-9]+,\s*\([a-x0-9]+\),\s*v0.t} 20 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/mask_struct_load-2.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/mask_struct_load-2.c new file mode 100644 index 000000000000..9d61a85267af --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/mask_struct_load-2.c @@ -0,0 +1,44 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-std=c99 -march=rv32gcv_zvfh -mabi=ilp32d --param=riscv-autovec-preference=scalable -fno-vect-cost-model" } */ + +#include + +#define TEST_LOOP(NAME, OUTTYPE, INTYPE, MASKTYPE) \ + void __attribute__ ((noinline, noclone)) \ + NAME##_3 (OUTTYPE *__restrict dest, INTYPE *__restrict src, \ + MASKTYPE *__restrict cond, intptr_t n) \ + { \ + for (intptr_t i = 0; i < n; ++i) \ + if (cond[i]) \ + dest[i] = (src[i * 3] \ + + src[i * 3 + 1] \ + + src[i * 3 + 2]); \ + } + +#define TEST2(NAME, OUTTYPE, INTYPE) \ + TEST_LOOP (NAME##_i8, OUTTYPE, INTYPE, int8_t) \ + TEST_LOOP (NAME##_i16, OUTTYPE, INTYPE, uint16_t) \ + TEST_LOOP (NAME##_f32, OUTTYPE, INTYPE, float) \ + TEST_LOOP (NAME##_f64, OUTTYPE, INTYPE, double) + +#define TEST1(NAME, OUTTYPE) \ + TEST2 (NAME##_i8, OUTTYPE, int8_t) \ + TEST2 (NAME##_i16, OUTTYPE, uint16_t) \ + TEST2 (NAME##_i32, OUTTYPE, int32_t) \ + TEST2 (NAME##_i64, OUTTYPE, uint64_t) + +#define TEST(NAME) \ + TEST1 (NAME##_i8, int8_t) \ + TEST1 (NAME##_i16, uint16_t) \ + TEST1 (NAME##_i32, int32_t) \ + TEST1 (NAME##_i64, uint64_t) \ + TEST2 (NAME##_f16_f16, _Float16, _Float16) \ + TEST2 (NAME##_f32_f32, float, float) \ + TEST2 (NAME##_f64_f64, double, double) + +TEST (test) + +/* { dg-final { scan-assembler-times {vlseg3e8\.v\s+v[0-9]+,\s*\([a-x0-9]+\),\s*v0.t} 16 } } */ +/* { dg-final { scan-assembler-times {vlseg3e16\.v\s+v[0-9]+,\s*\([a-x0-9]+\),\s*v0.t} 20 } } */ +/* { dg-final { scan-assembler-times {vlseg3e32\.v\s+v[0-9]+,\s*\([a-x0-9]+\),\s*v0.t} 20 } } */ +/* { dg-final { scan-assembler-times {vlseg3e64\.v\s+v[0-9]+,\s*\([a-x0-9]+\),\s*v0.t} 20 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/mask_struct_load-3.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/mask_struct_load-3.c new file mode 100644 index 000000000000..a686236793a3 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/mask_struct_load-3.c @@ -0,0 +1,45 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-std=c99 -march=rv32gcv_zvfh -mabi=ilp32d --param=riscv-autovec-preference=scalable -fno-vect-cost-model" } */ + +#include + +#define TEST_LOOP(NAME, OUTTYPE, INTYPE, MASKTYPE) \ + void __attribute__ ((noinline, noclone)) \ + NAME##_4 (OUTTYPE *__restrict dest, INTYPE *__restrict src, \ + MASKTYPE *__restrict cond, intptr_t n) \ + { \ + for (intptr_t i = 0; i < n; ++i) \ + if (cond[i]) \ + dest[i] = (src[i * 4] \ + + src[i * 4 + 1] \ + + src[i * 4 + 2] \ + + src[i * 4 + 3]); \ + } + +#define TEST2(NAME, OUTTYPE, INTYPE) \ + TEST_LOOP (NAME##_i8, OUTTYPE, INTYPE, int8_t) \ + TEST_LOOP (NAME##_i16, OUTTYPE, INTYPE, uint16_t) \ + TEST_LOOP (NAME##_f32, OUTTYPE, INTYPE, float) \ + TEST_LOOP (NAME##_f64, OUTTYPE, INTYPE, double) + +#define TEST1(NAME, OUTTYPE) \ + TEST2 (NAME##_i8, OUTTYPE, int8_t) \ + TEST2 (NAME##_i16, OUTTYPE, uint16_t) \ + TEST2 (NAME##_i32, OUTTYPE, int32_t) \ + TEST2 (NAME##_i64, OUTTYPE, uint64_t) + +#define TEST(NAME) \ + TEST1 (NAME##_i8, int8_t) \ + TEST1 (NAME##_i16, uint16_t) \ + TEST1 (NAME##_i32, int32_t) \ + TEST1 (NAME##_i64, uint64_t) \ + TEST2 (NAME##_f16_f16, _Float16, _Float16) \ + TEST2 (NAME##_f32_f32, float, float) \ + TEST2 (NAME##_f64_f64, double, double) + +TEST (test) + +/* { dg-final { scan-assembler-times {vlseg4e8\.v\s+v[0-9]+,\s*\([a-x0-9]+\),\s*v0.t} 16 } } */ +/* { dg-final { scan-assembler-times {vlseg4e16\.v\s+v[0-9]+,\s*\([a-x0-9]+\),\s*v0.t} 20 } } */ +/* { dg-final { scan-assembler-times {vlseg4e32\.v\s+v[0-9]+,\s*\([a-x0-9]+\),\s*v0.t} 20 } } */ +/* { dg-final { scan-assembler-times {vlseg4e64\.v\s+v[0-9]+,\s*\([a-x0-9]+\),\s*v0.t} 20 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/mask_struct_load-4.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/mask_struct_load-4.c new file mode 100644 index 000000000000..e3c48df5d3bb --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/mask_struct_load-4.c @@ -0,0 +1,43 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-std=c99 -march=rv32gcv_zvfh -mabi=ilp32d --param=riscv-autovec-preference=scalable -fno-vect-cost-model" } */ + +#include + +#define TEST_LOOP(NAME, OUTTYPE, INTYPE, MASKTYPE) \ + void __attribute__ ((noinline, noclone)) \ + NAME##_5 (OUTTYPE *__restrict dest, INTYPE *__restrict src, \ + MASKTYPE *__restrict cond, intptr_t n) \ + { \ + for (intptr_t i = 0; i < n; ++i) \ + if (cond[i]) \ + dest[i] = (src[i * 5] + src[i * 5 + 1] + src[i * 5 + 2] \ + + src[i * 5 + 3] + src[i * 5 + 4]); \ + } + +#define TEST2(NAME, OUTTYPE, INTYPE) \ + TEST_LOOP (NAME##_i8, OUTTYPE, INTYPE, int8_t) \ + TEST_LOOP (NAME##_i16, OUTTYPE, INTYPE, uint16_t) \ + TEST_LOOP (NAME##_f32, OUTTYPE, INTYPE, float) \ + TEST_LOOP (NAME##_f64, OUTTYPE, INTYPE, double) + +#define TEST1(NAME, OUTTYPE) \ + TEST2 (NAME##_i8, OUTTYPE, int8_t) \ + TEST2 (NAME##_i16, OUTTYPE, uint16_t) \ + TEST2 (NAME##_i32, OUTTYPE, int32_t) \ + TEST2 (NAME##_i64, OUTTYPE, uint64_t) + +#define TEST(NAME) \ + TEST1 (NAME##_i8, int8_t) \ + TEST1 (NAME##_i16, uint16_t) \ + TEST1 (NAME##_i32, int32_t) \ + TEST1 (NAME##_i64, uint64_t) \ + TEST2 (NAME##_f16_f16, _Float16, _Float16) \ + TEST2 (NAME##_f32_f32, float, float) \ + TEST2 (NAME##_f64_f64, double, double) + +TEST (test) + +/* { dg-final { scan-assembler-times {vlseg5e8\.v\s+v[0-9]+,\s*\([a-x0-9]+\),\s*v0.t} 16 } } */ +/* { dg-final { scan-assembler-times {vlseg5e16\.v\s+v[0-9]+,\s*\([a-x0-9]+\),\s*v0.t} 20 } } */ +/* { dg-final { scan-assembler-times {vlseg5e32\.v\s+v[0-9]+,\s*\([a-x0-9]+\),\s*v0.t} 20 } } */ +/* { dg-final { scan-assembler-times {vlseg5e64\.v\s+v[0-9]+,\s*\([a-x0-9]+\),\s*v0.t} 20 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/mask_struct_load-5.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/mask_struct_load-5.c new file mode 100644 index 000000000000..81f1a7a5ef4b --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/mask_struct_load-5.c @@ -0,0 +1,43 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-std=c99 -march=rv32gcv_zvfh -mabi=ilp32d --param=riscv-autovec-preference=scalable -fno-vect-cost-model" } */ + +#include + +#define TEST_LOOP(NAME, OUTTYPE, INTYPE, MASKTYPE) \ + void __attribute__ ((noinline, noclone)) \ + NAME##_6 (OUTTYPE *__restrict dest, INTYPE *__restrict src, \ + MASKTYPE *__restrict cond, intptr_t n) \ + { \ + for (intptr_t i = 0; i < n; ++i) \ + if (cond[i]) \ + dest[i] = (src[i * 6] + src[i * 6 + 1] + src[i * 6 + 2] \ + + src[i * 6 + 3] + src[i * 6 + 4] + src[i * 6 + 5]); \ + } + +#define TEST2(NAME, OUTTYPE, INTYPE) \ + TEST_LOOP (NAME##_i8, OUTTYPE, INTYPE, int8_t) \ + TEST_LOOP (NAME##_i16, OUTTYPE, INTYPE, uint16_t) \ + TEST_LOOP (NAME##_f32, OUTTYPE, INTYPE, float) \ + TEST_LOOP (NAME##_f64, OUTTYPE, INTYPE, double) + +#define TEST1(NAME, OUTTYPE) \ + TEST2 (NAME##_i8, OUTTYPE, int8_t) \ + TEST2 (NAME##_i16, OUTTYPE, uint16_t) \ + TEST2 (NAME##_i32, OUTTYPE, int32_t) \ + TEST2 (NAME##_i64, OUTTYPE, uint64_t) + +#define TEST(NAME) \ + TEST1 (NAME##_i8, int8_t) \ + TEST1 (NAME##_i16, uint16_t) \ + TEST1 (NAME##_i32, int32_t) \ + TEST1 (NAME##_i64, uint64_t) \ + TEST2 (NAME##_f16_f16, _Float16, _Float16) \ + TEST2 (NAME##_f32_f32, float, float) \ + TEST2 (NAME##_f64_f64, double, double) + +TEST (test) + +/* { dg-final { scan-assembler-times {vlseg6e8\.v\s+v[0-9]+,\s*\([a-x0-9]+\),\s*v0.t} 16 } } */ +/* { dg-final { scan-assembler-times {vlseg6e16\.v\s+v[0-9]+,\s*\([a-x0-9]+\),\s*v0.t} 20 } } */ +/* { dg-final { scan-assembler-times {vlseg6e32\.v\s+v[0-9]+,\s*\([a-x0-9]+\),\s*v0.t} 20 } } */ +/* { dg-final { scan-assembler-times {vlseg6e64\.v\s+v[0-9]+,\s*\([a-x0-9]+\),\s*v0.t} 20 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/mask_struct_load-6.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/mask_struct_load-6.c new file mode 100644 index 000000000000..911af2a853da --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/mask_struct_load-6.c @@ -0,0 +1,44 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-std=c99 -march=rv32gcv_zvfh -mabi=ilp32d --param=riscv-autovec-preference=scalable -fno-vect-cost-model" } */ + +#include + +#define TEST_LOOP(NAME, OUTTYPE, INTYPE, MASKTYPE) \ + void __attribute__ ((noinline, noclone)) \ + NAME##_7 (OUTTYPE *__restrict dest, INTYPE *__restrict src, \ + MASKTYPE *__restrict cond, intptr_t n) \ + { \ + for (intptr_t i = 0; i < n; ++i) \ + if (cond[i]) \ + dest[i] \ + = (src[i * 7] + src[i * 7 + 1] + src[i * 7 + 2] + src[i * 7 + 3] \ + + src[i * 7 + 4] + src[i * 7 + 5] + src[i * 7 + 6]); \ + } + +#define TEST2(NAME, OUTTYPE, INTYPE) \ + TEST_LOOP (NAME##_i8, OUTTYPE, INTYPE, int8_t) \ + TEST_LOOP (NAME##_i16, OUTTYPE, INTYPE, uint16_t) \ + TEST_LOOP (NAME##_f32, OUTTYPE, INTYPE, float) \ + TEST_LOOP (NAME##_f64, OUTTYPE, INTYPE, double) + +#define TEST1(NAME, OUTTYPE) \ + TEST2 (NAME##_i8, OUTTYPE, int8_t) \ + TEST2 (NAME##_i16, OUTTYPE, uint16_t) \ + TEST2 (NAME##_i32, OUTTYPE, int32_t) \ + TEST2 (NAME##_i64, OUTTYPE, uint64_t) + +#define TEST(NAME) \ + TEST1 (NAME##_i8, int8_t) \ + TEST1 (NAME##_i16, uint16_t) \ + TEST1 (NAME##_i32, int32_t) \ + TEST1 (NAME##_i64, uint64_t) \ + TEST2 (NAME##_f16_f16, _Float16, _Float16) \ + TEST2 (NAME##_f32_f32, float, float) \ + TEST2 (NAME##_f64_f64, double, double) + +TEST (test) + +/* { dg-final { scan-assembler-times {vlseg7e8\.v\s+v[0-9]+,\s*\([a-x0-9]+\),\s*v0.t} 16 } } */ +/* { dg-final { scan-assembler-times {vlseg7e16\.v\s+v[0-9]+,\s*\([a-x0-9]+\),\s*v0.t} 20 } } */ +/* { dg-final { scan-assembler-times {vlseg7e32\.v\s+v[0-9]+,\s*\([a-x0-9]+\),\s*v0.t} 20 } } */ +/* { dg-final { scan-assembler-times {vlseg7e64\.v\s+v[0-9]+,\s*\([a-x0-9]+\),\s*v0.t} 20 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/mask_struct_load-7.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/mask_struct_load-7.c new file mode 100644 index 000000000000..112facee5ad4 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/mask_struct_load-7.c @@ -0,0 +1,44 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-std=c99 -march=rv32gcv_zvfh -mabi=ilp32d --param=riscv-autovec-preference=scalable -fno-vect-cost-model" } */ + +#include + +#define TEST_LOOP(NAME, OUTTYPE, INTYPE, MASKTYPE) \ + void __attribute__ ((noinline, noclone)) \ + NAME##_8 (OUTTYPE *__restrict dest, INTYPE *__restrict src, \ + MASKTYPE *__restrict cond, intptr_t n) \ + { \ + for (intptr_t i = 0; i < n; ++i) \ + if (cond[i]) \ + dest[i] = (src[i * 8] + src[i * 8 + 1] + src[i * 8 + 2] \ + + src[i * 8 + 3] + src[i * 8 + 4] + src[i * 8 + 5] \ + + src[i * 8 + 6] + src[i * 8 + 7]); \ + } + +#define TEST2(NAME, OUTTYPE, INTYPE) \ + TEST_LOOP (NAME##_i8, OUTTYPE, INTYPE, int8_t) \ + TEST_LOOP (NAME##_i16, OUTTYPE, INTYPE, uint16_t) \ + TEST_LOOP (NAME##_f32, OUTTYPE, INTYPE, float) \ + TEST_LOOP (NAME##_f64, OUTTYPE, INTYPE, double) + +#define TEST1(NAME, OUTTYPE) \ + TEST2 (NAME##_i8, OUTTYPE, int8_t) \ + TEST2 (NAME##_i16, OUTTYPE, uint16_t) \ + TEST2 (NAME##_i32, OUTTYPE, int32_t) \ + TEST2 (NAME##_i64, OUTTYPE, uint64_t) + +#define TEST(NAME) \ + TEST1 (NAME##_i8, int8_t) \ + TEST1 (NAME##_i16, uint16_t) \ + TEST1 (NAME##_i32, int32_t) \ + TEST1 (NAME##_i64, uint64_t) \ + TEST2 (NAME##_f16_f16, _Float16, _Float16) \ + TEST2 (NAME##_f32_f32, float, float) \ + TEST2 (NAME##_f64_f64, double, double) + +TEST (test) + +/* { dg-final { scan-assembler-times {vlseg8e8\.v\s+v[0-9]+,\s*\([a-x0-9]+\),\s*v0.t} 16 } } */ +/* { dg-final { scan-assembler-times {vlseg8e16\.v\s+v[0-9]+,\s*\([a-x0-9]+\),\s*v0.t} 20 } } */ +/* { dg-final { scan-assembler-times {vlseg8e32\.v\s+v[0-9]+,\s*\([a-x0-9]+\),\s*v0.t} 20 } } */ +/* { dg-final { scan-assembler-times {vlseg8e64\.v\s+v[0-9]+,\s*\([a-x0-9]+\),\s*v0.t} 20 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/mask_struct_load_run-1.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/mask_struct_load_run-1.c new file mode 100644 index 000000000000..232ebceb9fc2 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/mask_struct_load_run-1.c @@ -0,0 +1,38 @@ +/* { dg-do run { target { riscv_vector } } } */ +/* { dg-additional-options "--param=riscv-autovec-preference=scalable -fno-vect-cost-model" } */ + +#include "mask_struct_load-1.c" + +#define N 100 + +#undef TEST_LOOP +#define TEST_LOOP(NAME, OUTTYPE, INTYPE, MASKTYPE) \ + { \ + OUTTYPE out[N]; \ + INTYPE in[N * 2]; \ + MASKTYPE mask[N]; \ + for (int i = 0; i < N; ++i) \ + { \ + out[i] = i * 7 / 2; \ + mask[i] = i % 5 <= i % 3; \ + asm volatile ("" ::: "memory"); \ + } \ + for (int i = 0; i < N * 2; ++i) \ + in[i] = i * 9 / 2; \ + NAME##_2 (out, in, mask, N); \ + for (int i = 0; i < N; ++i) \ + { \ + OUTTYPE if_true = in[i * 2] + in[i * 2 + 1]; \ + OUTTYPE if_false = i * 7 / 2; \ + if (out[i] != (mask[i] ? if_true : if_false)) \ + __builtin_abort (); \ + asm volatile ("" ::: "memory"); \ + } \ + } + +int __attribute__ ((optimize (1))) +main (void) +{ + TEST (test); + return 0; +} diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/mask_struct_load_run-2.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/mask_struct_load_run-2.c new file mode 100644 index 000000000000..309baf32bc9e --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/mask_struct_load_run-2.c @@ -0,0 +1,40 @@ +/* { dg-do run { target { riscv_vector } } } */ +/* { dg-additional-options "--param=riscv-autovec-preference=scalable -fno-vect-cost-model" } */ + +#include "mask_struct_load-2.c" + +#define N 100 + +#undef TEST_LOOP +#define TEST_LOOP(NAME, OUTTYPE, INTYPE, MASKTYPE) \ + { \ + OUTTYPE out[N]; \ + INTYPE in[N * 3]; \ + MASKTYPE mask[N]; \ + for (int i = 0; i < N; ++i) \ + { \ + out[i] = i * 7 / 2; \ + mask[i] = i % 5 <= i % 3; \ + asm volatile ("" ::: "memory"); \ + } \ + for (int i = 0; i < N * 3; ++i) \ + in[i] = i * 9 / 2; \ + NAME##_3 (out, in, mask, N); \ + for (int i = 0; i < N; ++i) \ + { \ + OUTTYPE if_true = (in[i * 3] \ + + in[i * 3 + 1] \ + + in[i * 3 + 2]); \ + OUTTYPE if_false = i * 7 / 2; \ + if (out[i] != (mask[i] ? if_true : if_false)) \ + __builtin_abort (); \ + asm volatile ("" ::: "memory"); \ + } \ + } + +int __attribute__ ((optimize (1))) +main (void) +{ + TEST (test); + return 0; +} diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/mask_struct_load_run-3.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/mask_struct_load_run-3.c new file mode 100644 index 000000000000..2c818bbc1175 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/mask_struct_load_run-3.c @@ -0,0 +1,41 @@ +/* { dg-do run { target { riscv_vector } } } */ +/* { dg-additional-options "--param=riscv-autovec-preference=scalable -fno-vect-cost-model" } */ + +#include "mask_struct_load-3.c" + +#define N 100 + +#undef TEST_LOOP +#define TEST_LOOP(NAME, OUTTYPE, INTYPE, MASKTYPE) \ + { \ + OUTTYPE out[N]; \ + INTYPE in[N * 4]; \ + MASKTYPE mask[N]; \ + for (int i = 0; i < N; ++i) \ + { \ + out[i] = i * 7 / 2; \ + mask[i] = i % 5 <= i % 3; \ + asm volatile ("" ::: "memory"); \ + } \ + for (int i = 0; i < N * 4; ++i) \ + in[i] = i * 9 / 2; \ + NAME##_4 (out, in, mask, N); \ + for (int i = 0; i < N; ++i) \ + { \ + OUTTYPE if_true = (in[i * 4] \ + + in[i * 4 + 1] \ + + in[i * 4 + 2] \ + + in[i * 4 + 3]); \ + OUTTYPE if_false = i * 7 / 2; \ + if (out[i] != (mask[i] ? if_true : if_false)) \ + __builtin_abort (); \ + asm volatile ("" ::: "memory"); \ + } \ + } + +int __attribute__ ((optimize (1))) +main (void) +{ + TEST (test); + return 0; +} diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/mask_struct_load_run-4.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/mask_struct_load_run-4.c new file mode 100644 index 000000000000..c2135b8c452e --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/mask_struct_load_run-4.c @@ -0,0 +1,42 @@ +/* { dg-do run { target { riscv_vector } } } */ +/* { dg-additional-options "--param=riscv-autovec-preference=scalable -fno-vect-cost-model" } */ + +#include "mask_struct_load-4.c" + +#define N 100 + +#undef TEST_LOOP +#define TEST_LOOP(NAME, OUTTYPE, INTYPE, MASKTYPE) \ + { \ + OUTTYPE out[N]; \ + INTYPE in[N * 5]; \ + MASKTYPE mask[N]; \ + for (int i = 0; i < N; ++i) \ + { \ + out[i] = i * 7 / 2; \ + mask[i] = i % 5 <= i % 3; \ + asm volatile ("" ::: "memory"); \ + } \ + for (int i = 0; i < N * 5; ++i) \ + in[i] = i * 9 / 2; \ + NAME##_5 (out, in, mask, N); \ + for (int i = 0; i < N; ++i) \ + { \ + OUTTYPE if_true = (in[i * 5] \ + + in[i * 5 + 1] \ + + in[i * 5 + 2] \ + + in[i * 5 + 3] \ + + in[i * 5 + 4]); \ + OUTTYPE if_false = i * 7 / 2; \ + if (out[i] != (mask[i] ? if_true : if_false)) \ + __builtin_abort (); \ + asm volatile ("" ::: "memory"); \ + } \ + } + +int __attribute__ ((optimize (1))) +main (void) +{ + TEST (test); + return 0; +} diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/mask_struct_load_run-5.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/mask_struct_load_run-5.c new file mode 100644 index 000000000000..029769994aa8 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/mask_struct_load_run-5.c @@ -0,0 +1,43 @@ +/* { dg-do run { target { riscv_vector } } } */ +/* { dg-additional-options "--param=riscv-autovec-preference=scalable -fno-vect-cost-model" } */ + +#include "mask_struct_load-5.c" + +#define N 100 + +#undef TEST_LOOP +#define TEST_LOOP(NAME, OUTTYPE, INTYPE, MASKTYPE) \ + { \ + OUTTYPE out[N]; \ + INTYPE in[N * 6]; \ + MASKTYPE mask[N]; \ + for (int i = 0; i < N; ++i) \ + { \ + out[i] = i * 7 / 2; \ + mask[i] = i % 5 <= i % 3; \ + asm volatile ("" ::: "memory"); \ + } \ + for (int i = 0; i < N * 6; ++i) \ + in[i] = i * 9 / 2; \ + NAME##_6 (out, in, mask, N); \ + for (int i = 0; i < N; ++i) \ + { \ + OUTTYPE if_true = (in[i * 6] \ + + in[i * 6 + 1] \ + + in[i * 6 + 2] \ + + in[i * 6 + 3] \ + + in[i * 6 + 4] \ + + in[i * 6 + 5]); \ + OUTTYPE if_false = i * 7 / 2; \ + if (out[i] != (mask[i] ? if_true : if_false)) \ + __builtin_abort (); \ + asm volatile ("" ::: "memory"); \ + } \ + } + +int __attribute__ ((optimize (1))) +main (void) +{ + TEST (test); + return 0; +} diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/mask_struct_load_run-6.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/mask_struct_load_run-6.c new file mode 100644 index 000000000000..c24c6411d5ce --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/mask_struct_load_run-6.c @@ -0,0 +1,44 @@ +/* { dg-do run { target { riscv_vector } } } */ +/* { dg-additional-options "--param=riscv-autovec-preference=scalable -fno-vect-cost-model" } */ + +#include "mask_struct_load-6.c" + +#define N 100 + +#undef TEST_LOOP +#define TEST_LOOP(NAME, OUTTYPE, INTYPE, MASKTYPE) \ + { \ + OUTTYPE out[N]; \ + INTYPE in[N * 7]; \ + MASKTYPE mask[N]; \ + for (int i = 0; i < N; ++i) \ + { \ + out[i] = i * 7 / 2; \ + mask[i] = i % 5 <= i % 3; \ + asm volatile ("" ::: "memory"); \ + } \ + for (int i = 0; i < N * 7; ++i) \ + in[i] = i * 9 / 2; \ + NAME##_7 (out, in, mask, N); \ + for (int i = 0; i < N; ++i) \ + { \ + OUTTYPE if_true = (in[i * 7] \ + + in[i * 7 + 1] \ + + in[i * 7 + 2] \ + + in[i * 7 + 3] \ + + in[i * 7 + 4] \ + + in[i * 7 + 5] \ + + in[i * 7 + 6]); \ + OUTTYPE if_false = i * 7 / 2; \ + if (out[i] != (mask[i] ? if_true : if_false)) \ + __builtin_abort (); \ + asm volatile ("" ::: "memory"); \ + } \ + } + +int __attribute__ ((optimize (1))) +main (void) +{ + TEST (test); + return 0; +} diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/mask_struct_load_run-7.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/mask_struct_load_run-7.c new file mode 100644 index 000000000000..be65d948da5e --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/mask_struct_load_run-7.c @@ -0,0 +1,45 @@ +/* { dg-do run { target { riscv_vector } } } */ +/* { dg-additional-options "--param=riscv-autovec-preference=scalable -fno-vect-cost-model" } */ + +#include "mask_struct_load-7.c" + +#define N 100 + +#undef TEST_LOOP +#define TEST_LOOP(NAME, OUTTYPE, INTYPE, MASKTYPE) \ + { \ + OUTTYPE out[N]; \ + INTYPE in[N * 8]; \ + MASKTYPE mask[N]; \ + for (int i = 0; i < N; ++i) \ + { \ + out[i] = i * 7 / 2; \ + mask[i] = i % 5 <= i % 3; \ + asm volatile ("" ::: "memory"); \ + } \ + for (int i = 0; i < N * 8; ++i) \ + in[i] = i * 9 / 2; \ + NAME##_8 (out, in, mask, N); \ + for (int i = 0; i < N; ++i) \ + { \ + OUTTYPE if_true = (in[i * 8] \ + + in[i * 8 + 1] \ + + in[i * 8 + 2] \ + + in[i * 8 + 3] \ + + in[i * 8 + 4] \ + + in[i * 8 + 5] \ + + in[i * 8 + 6] \ + + in[i * 8 + 7]); \ + OUTTYPE if_false = i * 7 / 2; \ + if (out[i] != (mask[i] ? if_true : if_false)) \ + __builtin_abort (); \ + asm volatile ("" ::: "memory"); \ + } \ + } + +int __attribute__ ((optimize (1))) +main (void) +{ + TEST (test); + return 0; +} diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/mask_struct_store-1.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/mask_struct_store-1.c new file mode 100644 index 000000000000..6df5f08dbc01 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/mask_struct_store-1.c @@ -0,0 +1,48 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-std=c99 -march=rv32gcv_zvfh -mabi=ilp32d --param=riscv-autovec-preference=scalable -fno-vect-cost-model" } */ + +#include + +#define TEST_LOOP(NAME, OUTTYPE, INTYPE, MASKTYPE) \ + void __attribute__ ((noinline, noclone)) \ + NAME##_2 (OUTTYPE *__restrict dest, INTYPE *__restrict src, \ + MASKTYPE *__restrict cond, INTYPE bias, intptr_t n) \ + { \ + for (intptr_t i = 0; i < n; ++i) \ + { \ + INTYPE value = src[i] + bias; \ + if (cond[i]) \ + { \ + dest[i * 2] = value; \ + dest[i * 2 + 1] = value; \ + } \ + } \ + } + +#define TEST2(NAME, OUTTYPE, INTYPE) \ + TEST_LOOP (NAME##_i8, OUTTYPE, INTYPE, int8_t) \ + TEST_LOOP (NAME##_i16, OUTTYPE, INTYPE, uint16_t) \ + TEST_LOOP (NAME##_f32, OUTTYPE, INTYPE, float) \ + TEST_LOOP (NAME##_f64, OUTTYPE, INTYPE, double) + +#define TEST1(NAME, OUTTYPE) \ + TEST2 (NAME##_i8, OUTTYPE, int8_t) \ + TEST2 (NAME##_i16, OUTTYPE, uint16_t) \ + TEST2 (NAME##_i32, OUTTYPE, int32_t) \ + TEST2 (NAME##_i64, OUTTYPE, uint64_t) + +#define TEST(NAME) \ + TEST1 (NAME##_i8, int8_t) \ + TEST1 (NAME##_i16, uint16_t) \ + TEST1 (NAME##_i32, int32_t) \ + TEST1 (NAME##_i64, uint64_t) \ + TEST2 (NAME##_f16_f16, _Float16, _Float16) \ + TEST2 (NAME##_f32_f32, float, float) \ + TEST2 (NAME##_f64_f64, double, double) + +TEST (test) + +/* { dg-final { scan-assembler-times {vsseg2e8\.v\s+v[0-9]+,\s*\([a-x0-9]+\),\s*v0.t} 16 } } */ +/* { dg-final { scan-assembler-times {vsseg2e16\.v\s+v[0-9]+,\s*\([a-x0-9]+\),\s*v0.t} 20 } } */ +/* { dg-final { scan-assembler-times {vsseg2e32\.v\s+v[0-9]+,\s*\([a-x0-9]+\),\s*v0.t} 20 } } */ +/* { dg-final { scan-assembler-times {vsseg2e64\.v\s+v[0-9]+,\s*\([a-x0-9]+\),\s*v0.t} 20 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/mask_struct_store-2.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/mask_struct_store-2.c new file mode 100644 index 000000000000..532b4580b200 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/mask_struct_store-2.c @@ -0,0 +1,49 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-std=c99 -march=rv32gcv_zvfh -mabi=ilp32d --param=riscv-autovec-preference=scalable -fno-vect-cost-model" } */ + +#include + +#define TEST_LOOP(NAME, OUTTYPE, INTYPE, MASKTYPE) \ + void __attribute__ ((noinline, noclone)) \ + NAME##_3 (OUTTYPE *__restrict dest, INTYPE *__restrict src, \ + MASKTYPE *__restrict cond, INTYPE bias, intptr_t n) \ + { \ + for (intptr_t i = 0; i < n; ++i) \ + { \ + INTYPE value = src[i] + bias; \ + if (cond[i]) \ + { \ + dest[i * 3] = value; \ + dest[i * 3 + 1] = value; \ + dest[i * 3 + 2] = value; \ + } \ + } \ + } + +#define TEST2(NAME, OUTTYPE, INTYPE) \ + TEST_LOOP (NAME##_i8, OUTTYPE, INTYPE, int8_t) \ + TEST_LOOP (NAME##_i16, OUTTYPE, INTYPE, uint16_t) \ + TEST_LOOP (NAME##_f32, OUTTYPE, INTYPE, float) \ + TEST_LOOP (NAME##_f64, OUTTYPE, INTYPE, double) + +#define TEST1(NAME, OUTTYPE) \ + TEST2 (NAME##_i8, OUTTYPE, int8_t) \ + TEST2 (NAME##_i16, OUTTYPE, uint16_t) \ + TEST2 (NAME##_i32, OUTTYPE, int32_t) \ + TEST2 (NAME##_i64, OUTTYPE, uint64_t) + +#define TEST(NAME) \ + TEST1 (NAME##_i8, int8_t) \ + TEST1 (NAME##_i16, uint16_t) \ + TEST1 (NAME##_i32, int32_t) \ + TEST1 (NAME##_i64, uint64_t) \ + TEST2 (NAME##_f16_f16, _Float16, _Float16) \ + TEST2 (NAME##_f32_f32, float, float) \ + TEST2 (NAME##_f64_f64, double, double) + +TEST (test) + +/* { dg-final { scan-assembler-times {vsseg3e8\.v\s+v[0-9]+,\s*\([a-x0-9]+\),\s*v0.t} 16 } } */ +/* { dg-final { scan-assembler-times {vsseg3e16\.v\s+v[0-9]+,\s*\([a-x0-9]+\),\s*v0.t} 20 } } */ +/* { dg-final { scan-assembler-times {vsseg3e32\.v\s+v[0-9]+,\s*\([a-x0-9]+\),\s*v0.t} 20 } } */ +/* { dg-final { scan-assembler-times {vsseg3e64\.v\s+v[0-9]+,\s*\([a-x0-9]+\),\s*v0.t} 20 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/mask_struct_store-3.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/mask_struct_store-3.c new file mode 100644 index 000000000000..92ed2361e37c --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/mask_struct_store-3.c @@ -0,0 +1,50 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-std=c99 -march=rv32gcv_zvfh -mabi=ilp32d --param=riscv-autovec-preference=scalable -fno-vect-cost-model" } */ + +#include + +#define TEST_LOOP(NAME, OUTTYPE, INTYPE, MASKTYPE) \ + void __attribute__ ((noinline, noclone)) \ + NAME##_4 (OUTTYPE *__restrict dest, INTYPE *__restrict src, \ + MASKTYPE *__restrict cond, INTYPE bias, intptr_t n) \ + { \ + for (intptr_t i = 0; i < n; ++i) \ + { \ + INTYPE value = src[i] + bias; \ + if (cond[i]) \ + { \ + dest[i * 4] = value; \ + dest[i * 4 + 1] = value; \ + dest[i * 4 + 2] = value; \ + dest[i * 4 + 3] = value; \ + } \ + } \ + } + +#define TEST2(NAME, OUTTYPE, INTYPE) \ + TEST_LOOP (NAME##_i8, OUTTYPE, INTYPE, int8_t) \ + TEST_LOOP (NAME##_i16, OUTTYPE, INTYPE, uint16_t) \ + TEST_LOOP (NAME##_f32, OUTTYPE, INTYPE, float) \ + TEST_LOOP (NAME##_f64, OUTTYPE, INTYPE, double) + +#define TEST1(NAME, OUTTYPE) \ + TEST2 (NAME##_i8, OUTTYPE, int8_t) \ + TEST2 (NAME##_i16, OUTTYPE, uint16_t) \ + TEST2 (NAME##_i32, OUTTYPE, int32_t) \ + TEST2 (NAME##_i64, OUTTYPE, uint64_t) + +#define TEST(NAME) \ + TEST1 (NAME##_i8, int8_t) \ + TEST1 (NAME##_i16, uint16_t) \ + TEST1 (NAME##_i32, int32_t) \ + TEST1 (NAME##_i64, uint64_t) \ + TEST2 (NAME##_f16_f16, _Float16, _Float16) \ + TEST2 (NAME##_f32_f32, float, float) \ + TEST2 (NAME##_f64_f64, double, double) + +TEST (test) + +/* { dg-final { scan-assembler-times {vsseg4e8\.v\s+v[0-9]+,\s*\([a-x0-9]+\),\s*v0.t} 16 } } */ +/* { dg-final { scan-assembler-times {vsseg4e16\.v\s+v[0-9]+,\s*\([a-x0-9]+\),\s*v0.t} 20 } } */ +/* { dg-final { scan-assembler-times {vsseg4e32\.v\s+v[0-9]+,\s*\([a-x0-9]+\),\s*v0.t} 20 } } */ +/* { dg-final { scan-assembler-times {vsseg4e64\.v\s+v[0-9]+,\s*\([a-x0-9]+\),\s*v0.t} 20 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/mask_struct_store-4.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/mask_struct_store-4.c new file mode 100644 index 000000000000..4a4048f6921c --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/mask_struct_store-4.c @@ -0,0 +1,51 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-std=c99 -march=rv32gcv_zvfh -mabi=ilp32d --param=riscv-autovec-preference=scalable -fno-vect-cost-model" } */ + +#include + +#define TEST_LOOP(NAME, OUTTYPE, INTYPE, MASKTYPE) \ + void __attribute__ ((noinline, noclone)) \ + NAME##_5 (OUTTYPE *__restrict dest, INTYPE *__restrict src, \ + MASKTYPE *__restrict cond, INTYPE bias, intptr_t n) \ + { \ + for (intptr_t i = 0; i < n; ++i) \ + { \ + INTYPE value = src[i] + bias; \ + if (cond[i]) \ + { \ + dest[i * 5] = value; \ + dest[i * 5 + 1] = value; \ + dest[i * 5 + 2] = value; \ + dest[i * 5 + 3] = value; \ + dest[i * 5 + 4] = value; \ + } \ + } \ + } + +#define TEST2(NAME, OUTTYPE, INTYPE) \ + TEST_LOOP (NAME##_i8, OUTTYPE, INTYPE, int8_t) \ + TEST_LOOP (NAME##_i16, OUTTYPE, INTYPE, uint16_t) \ + TEST_LOOP (NAME##_f32, OUTTYPE, INTYPE, float) \ + TEST_LOOP (NAME##_f64, OUTTYPE, INTYPE, double) + +#define TEST1(NAME, OUTTYPE) \ + TEST2 (NAME##_i8, OUTTYPE, int8_t) \ + TEST2 (NAME##_i16, OUTTYPE, uint16_t) \ + TEST2 (NAME##_i32, OUTTYPE, int32_t) \ + TEST2 (NAME##_i64, OUTTYPE, uint64_t) + +#define TEST(NAME) \ + TEST1 (NAME##_i8, int8_t) \ + TEST1 (NAME##_i16, uint16_t) \ + TEST1 (NAME##_i32, int32_t) \ + TEST1 (NAME##_i64, uint64_t) \ + TEST2 (NAME##_f16_f16, _Float16, _Float16) \ + TEST2 (NAME##_f32_f32, float, float) \ + TEST2 (NAME##_f64_f64, double, double) + +TEST (test) + +/* { dg-final { scan-assembler-times {vsseg5e8\.v\s+v[0-9]+,\s*\([a-x0-9]+\),\s*v0.t} 16 } } */ +/* { dg-final { scan-assembler-times {vsseg5e16\.v\s+v[0-9]+,\s*\([a-x0-9]+\),\s*v0.t} 20 } } */ +/* { dg-final { scan-assembler-times {vsseg5e32\.v\s+v[0-9]+,\s*\([a-x0-9]+\),\s*v0.t} 20 } } */ +/* { dg-final { scan-assembler-times {vsseg5e64\.v\s+v[0-9]+,\s*\([a-x0-9]+\),\s*v0.t} 20 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/mask_struct_store-5.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/mask_struct_store-5.c new file mode 100644 index 000000000000..eca8d5aa0030 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/mask_struct_store-5.c @@ -0,0 +1,52 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-std=c99 -march=rv32gcv_zvfh -mabi=ilp32d --param=riscv-autovec-preference=scalable -fno-vect-cost-model" } */ + +#include + +#define TEST_LOOP(NAME, OUTTYPE, INTYPE, MASKTYPE) \ + void __attribute__ ((noinline, noclone)) \ + NAME##_6 (OUTTYPE *__restrict dest, INTYPE *__restrict src, \ + MASKTYPE *__restrict cond, INTYPE bias, intptr_t n) \ + { \ + for (intptr_t i = 0; i < n; ++i) \ + { \ + INTYPE value = src[i] + bias; \ + if (cond[i]) \ + { \ + dest[i * 6] = value; \ + dest[i * 6 + 1] = value; \ + dest[i * 6 + 2] = value; \ + dest[i * 6 + 3] = value; \ + dest[i * 6 + 4] = value; \ + dest[i * 6 + 5] = value; \ + } \ + } \ + } + +#define TEST2(NAME, OUTTYPE, INTYPE) \ + TEST_LOOP (NAME##_i8, OUTTYPE, INTYPE, int8_t) \ + TEST_LOOP (NAME##_i16, OUTTYPE, INTYPE, uint16_t) \ + TEST_LOOP (NAME##_f32, OUTTYPE, INTYPE, float) \ + TEST_LOOP (NAME##_f64, OUTTYPE, INTYPE, double) + +#define TEST1(NAME, OUTTYPE) \ + TEST2 (NAME##_i8, OUTTYPE, int8_t) \ + TEST2 (NAME##_i16, OUTTYPE, uint16_t) \ + TEST2 (NAME##_i32, OUTTYPE, int32_t) \ + TEST2 (NAME##_i64, OUTTYPE, uint64_t) + +#define TEST(NAME) \ + TEST1 (NAME##_i8, int8_t) \ + TEST1 (NAME##_i16, uint16_t) \ + TEST1 (NAME##_i32, int32_t) \ + TEST1 (NAME##_i64, uint64_t) \ + TEST2 (NAME##_f16_f16, _Float16, _Float16) \ + TEST2 (NAME##_f32_f32, float, float) \ + TEST2 (NAME##_f64_f64, double, double) + +TEST (test) + +/* { dg-final { scan-assembler-times {vsseg6e8\.v\s+v[0-9]+,\s*\([a-x0-9]+\),\s*v0.t} 16 } } */ +/* { dg-final { scan-assembler-times {vsseg6e16\.v\s+v[0-9]+,\s*\([a-x0-9]+\),\s*v0.t} 20 } } */ +/* { dg-final { scan-assembler-times {vsseg6e32\.v\s+v[0-9]+,\s*\([a-x0-9]+\),\s*v0.t} 20 } } */ +/* { dg-final { scan-assembler-times {vsseg6e64\.v\s+v[0-9]+,\s*\([a-x0-9]+\),\s*v0.t} 20 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/mask_struct_store-6.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/mask_struct_store-6.c new file mode 100644 index 000000000000..3cce1620930d --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/mask_struct_store-6.c @@ -0,0 +1,53 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-std=c99 -march=rv32gcv_zvfh -mabi=ilp32d --param=riscv-autovec-preference=scalable -fno-vect-cost-model" } */ + +#include + +#define TEST_LOOP(NAME, OUTTYPE, INTYPE, MASKTYPE) \ + void __attribute__ ((noinline, noclone)) \ + NAME##_7 (OUTTYPE *__restrict dest, INTYPE *__restrict src, \ + MASKTYPE *__restrict cond, INTYPE bias, intptr_t n) \ + { \ + for (intptr_t i = 0; i < n; ++i) \ + { \ + INTYPE value = src[i] + bias; \ + if (cond[i]) \ + { \ + dest[i * 7] = value; \ + dest[i * 7 + 1] = value; \ + dest[i * 7 + 2] = value; \ + dest[i * 7 + 3] = value; \ + dest[i * 7 + 4] = value; \ + dest[i * 7 + 5] = value; \ + dest[i * 7 + 6] = value; \ + } \ + } \ + } + +#define TEST2(NAME, OUTTYPE, INTYPE) \ + TEST_LOOP (NAME##_i8, OUTTYPE, INTYPE, int8_t) \ + TEST_LOOP (NAME##_i16, OUTTYPE, INTYPE, uint16_t) \ + TEST_LOOP (NAME##_f32, OUTTYPE, INTYPE, float) \ + TEST_LOOP (NAME##_f64, OUTTYPE, INTYPE, double) + +#define TEST1(NAME, OUTTYPE) \ + TEST2 (NAME##_i8, OUTTYPE, int8_t) \ + TEST2 (NAME##_i16, OUTTYPE, uint16_t) \ + TEST2 (NAME##_i32, OUTTYPE, int32_t) \ + TEST2 (NAME##_i64, OUTTYPE, uint64_t) + +#define TEST(NAME) \ + TEST1 (NAME##_i8, int8_t) \ + TEST1 (NAME##_i16, uint16_t) \ + TEST1 (NAME##_i32, int32_t) \ + TEST1 (NAME##_i64, uint64_t) \ + TEST2 (NAME##_f16_f16, _Float16, _Float16) \ + TEST2 (NAME##_f32_f32, float, float) \ + TEST2 (NAME##_f64_f64, double, double) + +TEST (test) + +/* { dg-final { scan-assembler-times {vsseg7e8\.v\s+v[0-9]+,\s*\([a-x0-9]+\),\s*v0.t} 16 } } */ +/* { dg-final { scan-assembler-times {vsseg7e16\.v\s+v[0-9]+,\s*\([a-x0-9]+\),\s*v0.t} 20 } } */ +/* { dg-final { scan-assembler-times {vsseg7e32\.v\s+v[0-9]+,\s*\([a-x0-9]+\),\s*v0.t} 20 } } */ +/* { dg-final { scan-assembler-times {vsseg7e64\.v\s+v[0-9]+,\s*\([a-x0-9]+\),\s*v0.t} 20 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/mask_struct_store-7.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/mask_struct_store-7.c new file mode 100644 index 000000000000..9d0073bcf0ef --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/mask_struct_store-7.c @@ -0,0 +1,54 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-std=c99 -march=rv32gcv_zvfh -mabi=ilp32d --param=riscv-autovec-preference=scalable -fno-vect-cost-model" } */ + +#include + +#define TEST_LOOP(NAME, OUTTYPE, INTYPE, MASKTYPE) \ + void __attribute__ ((noinline, noclone)) \ + NAME##_8 (OUTTYPE *__restrict dest, INTYPE *__restrict src, \ + MASKTYPE *__restrict cond, INTYPE bias, intptr_t n) \ + { \ + for (intptr_t i = 0; i < n; ++i) \ + { \ + INTYPE value = src[i] + bias; \ + if (cond[i]) \ + { \ + dest[i * 8] = value; \ + dest[i * 8 + 1] = value; \ + dest[i * 8 + 2] = value; \ + dest[i * 8 + 3] = value; \ + dest[i * 8 + 4] = value; \ + dest[i * 8 + 5] = value; \ + dest[i * 8 + 6] = value; \ + dest[i * 8 + 7] = value; \ + } \ + } \ + } + +#define TEST2(NAME, OUTTYPE, INTYPE) \ + TEST_LOOP (NAME##_i8, OUTTYPE, INTYPE, int8_t) \ + TEST_LOOP (NAME##_i16, OUTTYPE, INTYPE, uint16_t) \ + TEST_LOOP (NAME##_f32, OUTTYPE, INTYPE, float) \ + TEST_LOOP (NAME##_f64, OUTTYPE, INTYPE, double) + +#define TEST1(NAME, OUTTYPE) \ + TEST2 (NAME##_i8, OUTTYPE, int8_t) \ + TEST2 (NAME##_i16, OUTTYPE, uint16_t) \ + TEST2 (NAME##_i32, OUTTYPE, int32_t) \ + TEST2 (NAME##_i64, OUTTYPE, uint64_t) + +#define TEST(NAME) \ + TEST1 (NAME##_i8, int8_t) \ + TEST1 (NAME##_i16, uint16_t) \ + TEST1 (NAME##_i32, int32_t) \ + TEST1 (NAME##_i64, uint64_t) \ + TEST2 (NAME##_f16_f16, _Float16, _Float16) \ + TEST2 (NAME##_f32_f32, float, float) \ + TEST2 (NAME##_f64_f64, double, double) + +TEST (test) + +/* { dg-final { scan-assembler-times {vsseg8e8\.v\s+v[0-9]+,\s*\([a-x0-9]+\),\s*v0.t} 16 } } */ +/* { dg-final { scan-assembler-times {vsseg8e16\.v\s+v[0-9]+,\s*\([a-x0-9]+\),\s*v0.t} 20 } } */ +/* { dg-final { scan-assembler-times {vsseg8e32\.v\s+v[0-9]+,\s*\([a-x0-9]+\),\s*v0.t} 20 } } */ +/* { dg-final { scan-assembler-times {vsseg8e64\.v\s+v[0-9]+,\s*\([a-x0-9]+\),\s*v0.t} 20 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/mask_struct_store_run-1.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/mask_struct_store_run-1.c new file mode 100644 index 000000000000..1208ea7ad588 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/mask_struct_store_run-1.c @@ -0,0 +1,38 @@ +/* { dg-do run { target { riscv_vector } } } */ +/* { dg-additional-options "--param=riscv-autovec-preference=scalable -fno-vect-cost-model" } */ + +#include "mask_struct_store-1.c" + +#define N 100 + +#undef TEST_LOOP +#define TEST_LOOP(NAME, OUTTYPE, INTYPE, MASKTYPE) \ + { \ + OUTTYPE out[N * 2]; \ + INTYPE in[N]; \ + MASKTYPE mask[N]; \ + for (int i = 0; i < N; ++i) \ + { \ + in[i] = i * 7 / 2; \ + mask[i] = i % 5 <= i % 3; \ + asm volatile ("" ::: "memory"); \ + } \ + for (int i = 0; i < N * 2; ++i) \ + out[i] = i * 9 / 2; \ + NAME##_2 (out, in, mask, 17, N); \ + for (int i = 0; i < N * 2; ++i) \ + { \ + OUTTYPE if_true = (INTYPE) (in[i / 2] + 17); \ + OUTTYPE if_false = i * 9 / 2; \ + if (out[i] != (mask[i / 2] ? if_true : if_false)) \ + __builtin_abort (); \ + asm volatile ("" ::: "memory"); \ + } \ + } + +int __attribute__ ((optimize (1))) +main (void) +{ + TEST (test); + return 0; +} diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/mask_struct_store_run-2.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/mask_struct_store_run-2.c new file mode 100644 index 000000000000..199402f596f1 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/mask_struct_store_run-2.c @@ -0,0 +1,38 @@ +/* { dg-do run { target { riscv_vector } } } */ +/* { dg-additional-options "--param=riscv-autovec-preference=scalable -fno-vect-cost-model" } */ + +#include "mask_struct_store-2.c" + +#define N 100 + +#undef TEST_LOOP +#define TEST_LOOP(NAME, OUTTYPE, INTYPE, MASKTYPE) \ + { \ + OUTTYPE out[N * 3]; \ + INTYPE in[N]; \ + MASKTYPE mask[N]; \ + for (int i = 0; i < N; ++i) \ + { \ + in[i] = i * 7 / 2; \ + mask[i] = i % 5 <= i % 3; \ + asm volatile ("" ::: "memory"); \ + } \ + for (int i = 0; i < N * 3; ++i) \ + out[i] = i * 9 / 2; \ + NAME##_3 (out, in, mask, 11, N); \ + for (int i = 0; i < N * 3; ++i) \ + { \ + OUTTYPE if_true = (INTYPE) (in[i / 3] + 11); \ + OUTTYPE if_false = i * 9 / 2; \ + if (out[i] != (mask[i / 3] ? if_true : if_false)) \ + __builtin_abort (); \ + asm volatile ("" ::: "memory"); \ + } \ + } + +int __attribute__ ((optimize (1))) +main (void) +{ + TEST (test); + return 0; +} diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/mask_struct_store_run-3.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/mask_struct_store_run-3.c new file mode 100644 index 000000000000..22fc0d5ac01f --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/mask_struct_store_run-3.c @@ -0,0 +1,38 @@ +/* { dg-do run { target { riscv_vector } } } */ +/* { dg-additional-options "--param=riscv-autovec-preference=scalable -fno-vect-cost-model" } */ + +#include "mask_struct_store-3.c" + +#define N 100 + +#undef TEST_LOOP +#define TEST_LOOP(NAME, OUTTYPE, INTYPE, MASKTYPE) \ + { \ + OUTTYPE out[N * 4]; \ + INTYPE in[N]; \ + MASKTYPE mask[N]; \ + for (int i = 0; i < N; ++i) \ + { \ + in[i] = i * 7 / 2; \ + mask[i] = i % 5 <= i % 3; \ + asm volatile ("" ::: "memory"); \ + } \ + for (int i = 0; i < N * 4; ++i) \ + out[i] = i * 9 / 2; \ + NAME##_4 (out, in, mask, 42, N); \ + for (int i = 0; i < N * 4; ++i) \ + { \ + OUTTYPE if_true = (INTYPE) (in[i / 4] + 42); \ + OUTTYPE if_false = i * 9 / 2; \ + if (out[i] != (mask[i / 4] ? if_true : if_false)) \ + __builtin_abort (); \ + asm volatile ("" ::: "memory"); \ + } \ + } + +int __attribute__ ((optimize (1))) +main (void) +{ + TEST (test); + return 0; +} diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/mask_struct_store_run-4.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/mask_struct_store_run-4.c new file mode 100644 index 000000000000..807e06e552cb --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/mask_struct_store_run-4.c @@ -0,0 +1,38 @@ +/* { dg-do run { target { riscv_vector } } } */ +/* { dg-additional-options "--param=riscv-autovec-preference=scalable -fno-vect-cost-model" } */ + +#include "mask_struct_store-4.c" + +#define N 100 + +#undef TEST_LOOP +#define TEST_LOOP(NAME, OUTTYPE, INTYPE, MASKTYPE) \ + { \ + OUTTYPE out[N * 5]; \ + INTYPE in[N]; \ + MASKTYPE mask[N]; \ + for (int i = 0; i < N; ++i) \ + { \ + in[i] = i * 7 / 2; \ + mask[i] = i % 5 <= i % 3; \ + asm volatile ("" ::: "memory"); \ + } \ + for (int i = 0; i < N * 5; ++i) \ + out[i] = i * 9 / 2; \ + NAME##_5 (out, in, mask, 42, N); \ + for (int i = 0; i < N * 5; ++i) \ + { \ + OUTTYPE if_true = (INTYPE) (in[i / 5] + 42); \ + OUTTYPE if_false = i * 9 / 2; \ + if (out[i] != (mask[i / 5] ? if_true : if_false)) \ + __builtin_abort (); \ + asm volatile ("" ::: "memory"); \ + } \ + } + +int __attribute__ ((optimize (1))) +main (void) +{ + TEST (test); + return 0; +} diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/mask_struct_store_run-5.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/mask_struct_store_run-5.c new file mode 100644 index 000000000000..3ce3774fcc5c --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/mask_struct_store_run-5.c @@ -0,0 +1,38 @@ +/* { dg-do run { target { riscv_vector } } } */ +/* { dg-additional-options "--param=riscv-autovec-preference=scalable -fno-vect-cost-model" } */ + +#include "mask_struct_store-5.c" + +#define N 100 + +#undef TEST_LOOP +#define TEST_LOOP(NAME, OUTTYPE, INTYPE, MASKTYPE) \ + { \ + OUTTYPE out[N * 6]; \ + INTYPE in[N]; \ + MASKTYPE mask[N]; \ + for (int i = 0; i < N; ++i) \ + { \ + in[i] = i * 7 / 2; \ + mask[i] = i % 5 <= i % 3; \ + asm volatile ("" ::: "memory"); \ + } \ + for (int i = 0; i < N * 6; ++i) \ + out[i] = i * 9 / 2; \ + NAME##_6 (out, in, mask, 42, N); \ + for (int i = 0; i < N * 6; ++i) \ + { \ + OUTTYPE if_true = (INTYPE) (in[i / 6] + 42); \ + OUTTYPE if_false = i * 9 / 2; \ + if (out[i] != (mask[i / 6] ? if_true : if_false)) \ + __builtin_abort (); \ + asm volatile ("" ::: "memory"); \ + } \ + } + +int __attribute__ ((optimize (1))) +main (void) +{ + TEST (test); + return 0; +} diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/mask_struct_store_run-6.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/mask_struct_store_run-6.c new file mode 100644 index 000000000000..8a22844bbeba --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/mask_struct_store_run-6.c @@ -0,0 +1,38 @@ +/* { dg-do run { target { riscv_vector } } } */ +/* { dg-additional-options "--param=riscv-autovec-preference=scalable -fno-vect-cost-model" } */ + +#include "mask_struct_store-6.c" + +#define N 100 + +#undef TEST_LOOP +#define TEST_LOOP(NAME, OUTTYPE, INTYPE, MASKTYPE) \ + { \ + OUTTYPE out[N * 7]; \ + INTYPE in[N]; \ + MASKTYPE mask[N]; \ + for (int i = 0; i < N; ++i) \ + { \ + in[i] = i * 7 / 2; \ + mask[i] = i % 5 <= i % 3; \ + asm volatile ("" ::: "memory"); \ + } \ + for (int i = 0; i < N * 7; ++i) \ + out[i] = i * 9 / 2; \ + NAME##_7 (out, in, mask, 42, N); \ + for (int i = 0; i < N * 7; ++i) \ + { \ + OUTTYPE if_true = (INTYPE) (in[i / 7] + 42); \ + OUTTYPE if_false = i * 9 / 2; \ + if (out[i] != (mask[i / 7] ? if_true : if_false)) \ + __builtin_abort (); \ + asm volatile ("" ::: "memory"); \ + } \ + } + +int __attribute__ ((optimize (1))) +main (void) +{ + TEST (test); + return 0; +} diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/mask_struct_store_run-7.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/mask_struct_store_run-7.c new file mode 100644 index 000000000000..af80f30ec4c4 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/mask_struct_store_run-7.c @@ -0,0 +1,38 @@ +/* { dg-do run { target { riscv_vector } } } */ +/* { dg-additional-options "--param=riscv-autovec-preference=scalable -fno-vect-cost-model" } */ + +#include "mask_struct_store-7.c" + +#define N 100 + +#undef TEST_LOOP +#define TEST_LOOP(NAME, OUTTYPE, INTYPE, MASKTYPE) \ + { \ + OUTTYPE out[N * 8]; \ + INTYPE in[N]; \ + MASKTYPE mask[N]; \ + for (int i = 0; i < N; ++i) \ + { \ + in[i] = i * 8 / 2; \ + mask[i] = i % 5 <= i % 3; \ + asm volatile ("" ::: "memory"); \ + } \ + for (int i = 0; i < N * 8; ++i) \ + out[i] = i * 9 / 2; \ + NAME##_8 (out, in, mask, 42, N); \ + for (int i = 0; i < N * 8; ++i) \ + { \ + OUTTYPE if_true = (INTYPE) (in[i / 8] + 42); \ + OUTTYPE if_false = i * 9 / 2; \ + if (out[i] != (mask[i / 8] ? if_true : if_false)) \ + __builtin_abort (); \ + asm volatile ("" ::: "memory"); \ + } \ + } + +int __attribute__ ((optimize (1))) +main (void) +{ + TEST (test); + return 0; +} diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/struct_vect-1.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/struct_vect-1.c new file mode 100644 index 000000000000..f49d92d74302 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/struct_vect-1.c @@ -0,0 +1,232 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-std=c99 -march=rv32gcv_zvfh -mabi=ilp32d --param=riscv-autovec-preference=fixed-vlmax -funroll-all-loops -fno-schedule-insns -fno-schedule-insns2" } */ + +#include +#ifndef TYPE +#define TYPE uint8_t +#endif + +#ifndef NAME +#define NAME(X) X +#endif + +#ifndef N +#define N 1024 +#endif + +void __attribute__ ((noinline, noclone)) +NAME(f2) (TYPE *__restrict a, TYPE *__restrict b, TYPE *__restrict c) +{ + for (int i = 0; i < N; ++i) + { + a[i] = c[i * 2]; + b[i] = c[i * 2 + 1]; + } +} + +void __attribute__ ((noinline, noclone)) +NAME(f3) (TYPE *__restrict a, TYPE *__restrict b, TYPE *__restrict c, + TYPE *__restrict d) +{ + for (int i = 0; i < N; ++i) + { + a[i] = d[i * 3]; + b[i] = d[i * 3 + 1]; + c[i] = d[i * 3 + 2]; + } +} + +void __attribute__ ((noinline, noclone)) +NAME(f4) (TYPE *__restrict a, TYPE *__restrict b, TYPE *__restrict c, + TYPE *__restrict d, TYPE *__restrict e) +{ + for (int i = 0; i < N; ++i) + { + a[i] = e[i * 4]; + b[i] = e[i * 4 + 1]; + c[i] = e[i * 4 + 2]; + d[i] = e[i * 4 + 3]; + } +} + +void __attribute__ ((noinline, noclone)) +NAME(f5) (TYPE *__restrict a, TYPE *__restrict b, TYPE *__restrict c, + TYPE *__restrict d, TYPE *__restrict e, TYPE *__restrict f) +{ + for (int i = 0; i < N; ++i) + { + a[i] = f[i * 5]; + b[i] = f[i * 5 + 1]; + c[i] = f[i * 5 + 2]; + d[i] = f[i * 5 + 3]; + e[i] = f[i * 5 + 4]; + } +} + +void __attribute__ ((noinline, noclone)) +NAME(f6) (TYPE *__restrict a, TYPE *__restrict b, TYPE *__restrict c, + TYPE *__restrict d, TYPE *__restrict e, TYPE *__restrict f, + TYPE *__restrict g) +{ + for (int i = 0; i < N; ++i) + { + a[i] = g[i * 6]; + b[i] = g[i * 6 + 1]; + c[i] = g[i * 6 + 2]; + d[i] = g[i * 6 + 3]; + e[i] = g[i * 6 + 4]; + f[i] = g[i * 6 + 5]; + } +} + +void __attribute__ ((noinline, noclone)) +NAME(f7) (TYPE *__restrict a, TYPE *__restrict b, TYPE *__restrict c, + TYPE *__restrict d, TYPE *__restrict e, TYPE *__restrict f, + TYPE *__restrict g, TYPE *__restrict h) +{ + for (int i = 0; i < N; ++i) + { + a[i] = h[i * 7]; + b[i] = h[i * 7 + 1]; + c[i] = h[i * 7 + 2]; + d[i] = h[i * 7 + 3]; + e[i] = h[i * 7 + 4]; + f[i] = h[i * 7 + 5]; + g[i] = h[i * 7 + 6]; + } +} + +void __attribute__ ((noinline, noclone)) +NAME(f8) (TYPE *__restrict a, TYPE *__restrict b, TYPE *__restrict c, + TYPE *__restrict d, TYPE *__restrict e, TYPE *__restrict f, + TYPE *__restrict g, TYPE *__restrict h, TYPE *__restrict j) +{ + for (int i = 0; i < N; ++i) + { + a[i] = j[i * 8]; + b[i] = j[i * 8 + 1]; + c[i] = j[i * 8 + 2]; + d[i] = j[i * 8 + 3]; + e[i] = j[i * 8 + 4]; + f[i] = j[i * 8 + 5]; + g[i] = j[i * 8 + 6]; + h[i] = j[i * 8 + 7]; + } +} + +void __attribute__ ((noinline, noclone)) +NAME(g2) (TYPE *__restrict a, TYPE *__restrict b, TYPE *__restrict c) +{ + for (int i = 0; i < N; ++i) + { + c[i * 2] = a[i]; + c[i * 2 + 1] = b[i]; + } +} + +void __attribute__ ((noinline, noclone)) +NAME(g3) (TYPE *__restrict a, TYPE *__restrict b, TYPE *__restrict c, + TYPE *__restrict d) +{ + for (int i = 0; i < N; ++i) + { + d[i * 3] = a[i]; + d[i * 3 + 1] = b[i]; + d[i * 3 + 2] = c[i]; + } +} + +void __attribute__ ((noinline, noclone)) +NAME(g4) (TYPE *__restrict a, TYPE *__restrict b, TYPE *__restrict c, + TYPE *__restrict d, TYPE *__restrict e) +{ + for (int i = 0; i < N; ++i) + { + e[i * 4] = a[i]; + e[i * 4 + 1] = b[i]; + e[i * 4 + 2] = c[i]; + e[i * 4 + 3] = d[i]; + } +} + +void __attribute__ ((noinline, noclone)) +NAME(g5) (TYPE *__restrict a, TYPE *__restrict b, TYPE *__restrict c, + TYPE *__restrict d, TYPE *__restrict e, TYPE *__restrict f) +{ + for (int i = 0; i < N; ++i) + { + f[i * 5] = a[i]; + f[i * 5 + 1] = b[i]; + f[i * 5 + 2] = c[i]; + f[i * 5 + 3] = d[i]; + f[i * 5 + 4] = e[i]; + } +} + +void __attribute__ ((noinline, noclone)) +NAME(g6) (TYPE *__restrict a, TYPE *__restrict b, TYPE *__restrict c, + TYPE *__restrict d, TYPE *__restrict e, TYPE *__restrict f, + TYPE *__restrict g) +{ + for (int i = 0; i < N; ++i) + { + g[i * 6] = a[i]; + g[i * 6 + 1] = b[i]; + g[i * 6 + 2] = c[i]; + g[i * 6 + 3] = d[i]; + g[i * 6 + 4] = e[i]; + g[i * 6 + 5] = f[i]; + } +} + +void __attribute__ ((noinline, noclone)) +NAME(g7) (TYPE *__restrict a, TYPE *__restrict b, TYPE *__restrict c, + TYPE *__restrict d, TYPE *__restrict e, TYPE *__restrict f, + TYPE *__restrict g, TYPE *__restrict h) +{ + for (int i = 0; i < N; ++i) + { + h[i * 7] = a[i]; + h[i * 7 + 1] = b[i]; + h[i * 7 + 2] = c[i]; + h[i * 7 + 3] = d[i]; + h[i * 7 + 4] = e[i]; + h[i * 7 + 5] = f[i]; + h[i * 7 + 6] = g[i]; + } +} + +void __attribute__ ((noinline, noclone)) +NAME(g8) (TYPE *__restrict a, TYPE *__restrict b, TYPE *__restrict c, + TYPE *__restrict d, TYPE *__restrict e, TYPE *__restrict f, + TYPE *__restrict g, TYPE *__restrict h, TYPE *__restrict j) +{ + for (int i = 0; i < N; ++i) + { + j[i * 8] = a[i]; + j[i * 8 + 1] = b[i]; + j[i * 8 + 2] = c[i]; + j[i * 8 + 3] = d[i]; + j[i * 8 + 4] = e[i]; + j[i * 8 + 5] = f[i]; + j[i * 8 + 6] = g[i]; + j[i * 8 + 7] = h[i]; + } +} + +/* { dg-final { scan-assembler-times {vlseg2e8\.v} 8 } } */ +/* { dg-final { scan-assembler-times {vlseg3e8\.v} 8 } } */ +/* { dg-final { scan-assembler-times {vlseg4e8\.v} 8 } } */ +/* { dg-final { scan-assembler-times {vlseg5e8\.v} 8 } } */ +/* { dg-final { scan-assembler-times {vlseg6e8\.v} 8 } } */ +/* { dg-final { scan-assembler-times {vlseg7e8\.v} 4 } } */ +/* { dg-final { scan-assembler-times {vlseg8e8\.v} 4 } } */ +/* { dg-final { scan-assembler-times {vsseg2e8\.v} 8 } } */ +/* { dg-final { scan-assembler-times {vsseg3e8\.v} 8 } } */ +/* { dg-final { scan-assembler-times {vsseg4e8\.v} 4 } } */ +/* { dg-final { scan-assembler-times {vsseg5e8\.v} 4 } } */ +/* { dg-final { scan-assembler-times {vsseg6e8\.v} 4 } } */ +/* { dg-final { scan-assembler-times {vsseg7e8\.v} 4 } } */ +/* { dg-final { scan-assembler-times {vsseg8e8\.v} 2 } } */ +/* { dg-final { scan-assembler-times {vsetivli\s+zero,\s*16,\s*e8,\s*m1,\s*t[au],\s*m[au]} 14 } } */ +/* { dg-final { scan-assembler-not {vsetvli} } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/struct_vect-10.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/struct_vect-10.c new file mode 100644 index 000000000000..dc4d6512f231 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/struct_vect-10.c @@ -0,0 +1,22 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-std=c99 -march=rv32gcv_zvfh -mabi=ilp32d --param=riscv-autovec-preference=scalable -fno-vect-cost-model" } */ + +#define TYPE _Float16 +#define ITYPE int16_t +#include "struct_vect-6.c" + +/* { dg-final { scan-assembler-times {vlseg2e16\.v} 1 } } */ +/* { dg-final { scan-assembler-times {vlseg3e16\.v} 1 } } */ +/* { dg-final { scan-assembler-times {vlseg4e16\.v} 1 } } */ +/* { dg-final { scan-assembler-times {vlseg5e16\.v} 1 } } */ +/* { dg-final { scan-assembler-times {vlseg6e16\.v} 1 } } */ +/* { dg-final { scan-assembler-times {vlseg7e16\.v} 1 } } */ +/* { dg-final { scan-assembler-times {vlseg8e16\.v} 1 } } */ +/* { dg-final { scan-assembler-times {vsseg2e16\.v} 1 } } */ +/* { dg-final { scan-assembler-times {vsseg3e16\.v} 1 } } */ +/* { dg-final { scan-assembler-times {vsseg4e16\.v} 1 } } */ +/* { dg-final { scan-assembler-times {vsseg5e16\.v} 1 } } */ +/* { dg-final { scan-assembler-times {vsseg6e16\.v} 1 } } */ +/* { dg-final { scan-assembler-times {vsseg7e16\.v} 1 } } */ +/* { dg-final { scan-assembler-times {vsseg8e16\.v} 1 } } */ +/* { dg-final { scan-assembler-times {vsetvli\s+[a-x0-9]+,\s*[a-x0-9]+} 14 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/struct_vect-11.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/struct_vect-11.c new file mode 100644 index 000000000000..36ade63dd9e4 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/struct_vect-11.c @@ -0,0 +1,22 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-std=c99 -march=rv32gcv_zvfh -mabi=ilp32d --param=riscv-autovec-preference=scalable -fno-vect-cost-model" } */ + +#define TYPE float +#define ITYPE int32_t +#include "struct_vect-6.c" + +/* { dg-final { scan-assembler-times {vlseg2e32\.v} 1 } } */ +/* { dg-final { scan-assembler-times {vlseg3e32\.v} 1 } } */ +/* { dg-final { scan-assembler-times {vlseg4e32\.v} 1 } } */ +/* { dg-final { scan-assembler-times {vlseg5e32\.v} 1 } } */ +/* { dg-final { scan-assembler-times {vlseg6e32\.v} 1 } } */ +/* { dg-final { scan-assembler-times {vlseg7e32\.v} 1 } } */ +/* { dg-final { scan-assembler-times {vlseg8e32\.v} 1 } } */ +/* { dg-final { scan-assembler-times {vsseg2e32\.v} 1 } } */ +/* { dg-final { scan-assembler-times {vsseg3e32\.v} 1 } } */ +/* { dg-final { scan-assembler-times {vsseg4e32\.v} 1 } } */ +/* { dg-final { scan-assembler-times {vsseg5e32\.v} 1 } } */ +/* { dg-final { scan-assembler-times {vsseg6e32\.v} 1 } } */ +/* { dg-final { scan-assembler-times {vsseg7e32\.v} 1 } } */ +/* { dg-final { scan-assembler-times {vsseg8e32\.v} 1 } } */ +/* { dg-final { scan-assembler-times {vsetvli\s+[a-x0-9]+,\s*[a-x0-9]+} 14 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/struct_vect-12.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/struct_vect-12.c new file mode 100644 index 000000000000..a2a93c432c64 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/struct_vect-12.c @@ -0,0 +1,22 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-std=c99 -march=rv64gcv_zvfh -mabi=lp64d --param=riscv-autovec-preference=scalable -fno-vect-cost-model" } */ + +#define TYPE double +#define ITYPE int64_t +#include "struct_vect-6.c" + +/* { dg-final { scan-assembler-times {vlseg2e64\.v} 1 } } */ +/* { dg-final { scan-assembler-times {vlseg3e64\.v} 1 } } */ +/* { dg-final { scan-assembler-times {vlseg4e64\.v} 1 } } */ +/* { dg-final { scan-assembler-times {vlseg5e64\.v} 1 } } */ +/* { dg-final { scan-assembler-times {vlseg6e64\.v} 1 } } */ +/* { dg-final { scan-assembler-times {vlseg7e64\.v} 1 } } */ +/* { dg-final { scan-assembler-times {vlseg8e64\.v} 1 } } */ +/* { dg-final { scan-assembler-times {vsseg2e64\.v} 1 } } */ +/* { dg-final { scan-assembler-times {vsseg3e64\.v} 1 } } */ +/* { dg-final { scan-assembler-times {vsseg4e64\.v} 1 } } */ +/* { dg-final { scan-assembler-times {vsseg5e64\.v} 1 } } */ +/* { dg-final { scan-assembler-times {vsseg6e64\.v} 1 } } */ +/* { dg-final { scan-assembler-times {vsseg7e64\.v} 1 } } */ +/* { dg-final { scan-assembler-times {vsseg8e64\.v} 1 } } */ +/* { dg-final { scan-assembler-times {vsetvli\s+[a-x0-9]+,\s*[a-x0-9]+} 14 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/struct_vect-13.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/struct_vect-13.c new file mode 100644 index 000000000000..4da1c4148bb6 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/struct_vect-13.c @@ -0,0 +1,27 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-std=c99 -march=rv64gcv_zvfh -mabi=lp64d --param=riscv-autovec-preference=scalable -fno-vect-cost-model" } */ + +#include + +#define N 2000 + +#define TEST_LOOP(NAME, TYPE) \ + void __attribute__ ((noinline, noclone)) \ + NAME (TYPE *restrict dest, TYPE *restrict src) \ + { \ + for (int i = 0; i < N; ++i) \ + dest[i] += src[i * 3]; \ + } + +#define TEST(NAME) \ + TEST_LOOP (NAME##_i8, int8_t) \ + TEST_LOOP (NAME##_i16, uint16_t) \ + TEST_LOOP (NAME##_f32, float) \ + TEST_LOOP (NAME##_f64, double) + +TEST (test) + +/* { dg-final { scan-assembler-times {vlseg3e8\.v} 1 } } */ +/* { dg-final { scan-assembler-times {vlseg3e16\.v} 1 } } */ +/* { dg-final { scan-assembler-times {vlseg3e32\.v} 1 } } */ +/* { dg-final { scan-assembler-times {vlseg3e64\.v} 1 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/struct_vect-14.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/struct_vect-14.c new file mode 100644 index 000000000000..f652a35bae45 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/struct_vect-14.c @@ -0,0 +1,25 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-std=c99 -march=rv64gcv_zvfh -mabi=lp64d --param=riscv-autovec-preference=scalable -fno-vect-cost-model" } */ + +#include + +#define TEST_LOOP(NAME, TYPE) \ + void __attribute__ ((noinline, noclone)) \ + NAME (TYPE *restrict dest, TYPE *restrict src, int n) \ + { \ + for (int i = 0; i < n; ++i) \ + dest[i] += src[i * 3]; \ + } + +#define TEST(NAME) \ + TEST_LOOP (NAME##_i8, int8_t) \ + TEST_LOOP (NAME##_i16, uint16_t) \ + TEST_LOOP (NAME##_f32, float) \ + TEST_LOOP (NAME##_f64, double) + +TEST (test) + +/* { dg-final { scan-assembler-times {vlseg3e8\.v} 1 } } */ +/* { dg-final { scan-assembler-times {vlseg3e16\.v} 1 } } */ +/* { dg-final { scan-assembler-times {vlseg3e32\.v} 1 } } */ +/* { dg-final { scan-assembler-times {vlseg3e64\.v} 1 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/struct_vect-15.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/struct_vect-15.c new file mode 100644 index 000000000000..29d32ab29dc2 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/struct_vect-15.c @@ -0,0 +1,27 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-std=c99 -march=rv64gcv_zvfh -mabi=lp64d --param=riscv-autovec-preference=scalable -fno-vect-cost-model" } */ + +#include + +#define N 2000 + +#define TEST_LOOP(NAME, TYPE) \ + void __attribute__ ((noinline, noclone)) \ + NAME (TYPE *restrict dest, TYPE *restrict src) \ + { \ + for (int i = 0; i < N; ++i) \ + dest[i] += src[i * 2]; \ + } + +#define TEST(NAME) \ + TEST_LOOP (NAME##_i8, int8_t) \ + TEST_LOOP (NAME##_i16, uint16_t) \ + TEST_LOOP (NAME##_f32, float) \ + TEST_LOOP (NAME##_f64, double) + +TEST (test) + +/* { dg-final { scan-assembler-times {vlseg2e8\.v} 1 } } */ +/* { dg-final { scan-assembler-times {vlseg2e16\.v} 1 } } */ +/* { dg-final { scan-assembler-times {vlseg2e32\.v} 1 } } */ +/* { dg-final { scan-assembler-times {vlseg2e64\.v} 1 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/struct_vect-16.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/struct_vect-16.c new file mode 100644 index 000000000000..15de93ec66f6 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/struct_vect-16.c @@ -0,0 +1,25 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-std=c99 -march=rv64gcv_zvfh -mabi=lp64d --param=riscv-autovec-preference=scalable -fno-vect-cost-model" } */ + +#include + +#define TEST_LOOP(NAME, TYPE) \ + void __attribute__ ((noinline, noclone)) \ + NAME (TYPE *restrict dest, TYPE *restrict src, int n) \ + { \ + for (int i = 0; i < n; ++i) \ + dest[i] += src[i * 2]; \ + } + +#define TEST(NAME) \ + TEST_LOOP (NAME##_i8, int8_t) \ + TEST_LOOP (NAME##_i16, uint16_t) \ + TEST_LOOP (NAME##_f32, float) \ + TEST_LOOP (NAME##_f64, double) + +TEST (test) + +/* { dg-final { scan-assembler-times {vlseg2e8\.v} 1 } } */ +/* { dg-final { scan-assembler-times {vlseg2e16\.v} 1 } } */ +/* { dg-final { scan-assembler-times {vlseg2e32\.v} 1 } } */ +/* { dg-final { scan-assembler-times {vlseg2e64\.v} 1 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/struct_vect-17.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/struct_vect-17.c new file mode 100644 index 000000000000..44eb0725a8e7 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/struct_vect-17.c @@ -0,0 +1,27 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-std=c99 -march=rv64gcv_zvfh -mabi=lp64d --param=riscv-autovec-preference=scalable -fno-vect-cost-model" } */ + +#include + +#define N 2000 + +#define TEST_LOOP(NAME, TYPE) \ + void __attribute__ ((noinline, noclone)) \ + NAME (TYPE *restrict dest, TYPE *restrict src) \ + { \ + for (int i = 0; i < N; ++i) \ + dest[i] += src[i * 4]; \ + } + +#define TEST(NAME) \ + TEST_LOOP (NAME##_i8, int8_t) \ + TEST_LOOP (NAME##_i16, uint16_t) \ + TEST_LOOP (NAME##_f32, float) \ + TEST_LOOP (NAME##_f64, double) + +TEST (test) + +/* { dg-final { scan-assembler-times {vlseg4e8\.v} 1 } } */ +/* { dg-final { scan-assembler-times {vlseg4e16\.v} 1 } } */ +/* { dg-final { scan-assembler-times {vlseg4e32\.v} 1 } } */ +/* { dg-final { scan-assembler-times {vlseg4e64\.v} 1 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/struct_vect-18.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/struct_vect-18.c new file mode 100644 index 000000000000..f6f559e4c2d2 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/struct_vect-18.c @@ -0,0 +1,25 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-std=c99 -march=rv64gcv_zvfh -mabi=lp64d --param=riscv-autovec-preference=scalable -fno-vect-cost-model" } */ + +#include + +#define TEST_LOOP(NAME, TYPE) \ + void __attribute__ ((noinline, noclone)) \ + NAME (TYPE *restrict dest, TYPE *restrict src, int n) \ + { \ + for (int i = 0; i < n; ++i) \ + dest[i] += src[i * 4]; \ + } + +#define TEST(NAME) \ + TEST_LOOP (NAME##_i8, int8_t) \ + TEST_LOOP (NAME##_i16, uint16_t) \ + TEST_LOOP (NAME##_f32, float) \ + TEST_LOOP (NAME##_f64, double) + +TEST (test) + +/* { dg-final { scan-assembler-times {vlseg4e8\.v} 1 } } */ +/* { dg-final { scan-assembler-times {vlseg4e16\.v} 1 } } */ +/* { dg-final { scan-assembler-times {vlseg4e32\.v} 1 } } */ +/* { dg-final { scan-assembler-times {vlseg4e64\.v} 1 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/struct_vect-2.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/struct_vect-2.c new file mode 100644 index 000000000000..2a61a79c620b --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/struct_vect-2.c @@ -0,0 +1,22 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-std=c99 -march=rv32gcv_zvfh -mabi=ilp32d --param=riscv-autovec-preference=fixed-vlmax -funroll-all-loops -fno-schedule-insns -fno-schedule-insns2" } */ + +#define TYPE uint16_t +#include "struct_vect-1.c" + +/* { dg-final { scan-assembler-times {vlseg2e16\.v} 8 } } */ +/* { dg-final { scan-assembler-times {vlseg3e16\.v} 8 } } */ +/* { dg-final { scan-assembler-times {vlseg4e16\.v} 8 } } */ +/* { dg-final { scan-assembler-times {vlseg5e16\.v} 8 } } */ +/* { dg-final { scan-assembler-times {vlseg6e16\.v} 4 } } */ +/* { dg-final { scan-assembler-times {vlseg7e16\.v} 4 } } */ +/* { dg-final { scan-assembler-times {vlseg8e16\.v} 4 } } */ +/* { dg-final { scan-assembler-times {vsseg2e16\.v} 8 } } */ +/* { dg-final { scan-assembler-times {vsseg3e16\.v} 8 } } */ +/* { dg-final { scan-assembler-times {vsseg4e16\.v} 4 } } */ +/* { dg-final { scan-assembler-times {vsseg5e16\.v} 4 } } */ +/* { dg-final { scan-assembler-times {vsseg6e16\.v} 4 } } */ +/* { dg-final { scan-assembler-times {vsseg7e16\.v} 2 } } */ +/* { dg-final { scan-assembler-times {vsseg8e16\.v} 2 } } */ +/* { dg-final { scan-assembler-times {vsetivli\s+zero,\s*8,\s*e16,\s*m1,\s*t[au],\s*m[au]} 14 } } */ +/* { dg-final { scan-assembler-not {vsetvli} } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/struct_vect-3.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/struct_vect-3.c new file mode 100644 index 000000000000..3d818dad10f9 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/struct_vect-3.c @@ -0,0 +1,22 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-std=c99 -march=rv32gcv_zvfh -mabi=ilp32d --param=riscv-autovec-preference=fixed-vlmax -funroll-all-loops -fno-schedule-insns -fno-schedule-insns2" } */ + +#define TYPE uint32_t +#include "struct_vect-1.c" + +/* { dg-final { scan-assembler-times {vlseg2e32\.v} 8 } } */ +/* { dg-final { scan-assembler-times {vlseg3e32\.v} 8 } } */ +/* { dg-final { scan-assembler-times {vlseg4e32\.v} 8 } } */ +/* { dg-final { scan-assembler-times {vlseg5e32\.v} 6 } } */ +/* { dg-final { scan-assembler-times {vlseg6e32\.v} 6 } } */ +/* { dg-final { scan-assembler-times {vlseg7e32\.v} 4 } } */ +/* { dg-final { scan-assembler-times {vlseg8e32\.v} 4 } } */ +/* { dg-final { scan-assembler-times {vsseg2e32\.v} 8 } } */ +/* { dg-final { scan-assembler-times {vsseg3e32\.v} 8 } } */ +/* { dg-final { scan-assembler-times {vsseg4e32\.v} 4 } } */ +/* { dg-final { scan-assembler-times {vsseg5e32\.v} 4 } } */ +/* { dg-final { scan-assembler-times {vsseg6e32\.v} 4 } } */ +/* { dg-final { scan-assembler-times {vsseg7e32\.v} 4 } } */ +/* { dg-final { scan-assembler-times {vsseg8e32\.v} 2 } } */ +/* { dg-final { scan-assembler-times {vsetivli\s+zero,\s*4,\s*e32,\s*m1,\s*t[au],\s*m[au]} 14 } } */ +/* { dg-final { scan-assembler-not {vsetvli} } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/struct_vect-4.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/struct_vect-4.c new file mode 100644 index 000000000000..b5ad45e8f82c --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/struct_vect-4.c @@ -0,0 +1,22 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-std=c99 -march=rv32gcv_zvfh -mabi=ilp32d --param=riscv-autovec-preference=fixed-vlmax -funroll-all-loops -fno-schedule-insns -fno-schedule-insns2" } */ + +#define TYPE uint64_t +#include "struct_vect-1.c" + +/* { dg-final { scan-assembler-times {vlseg2e64\.v} 8 } } */ +/* { dg-final { scan-assembler-times {vlseg3e64\.v} 8 } } */ +/* { dg-final { scan-assembler-times {vlseg4e64\.v} 8 } } */ +/* { dg-final { scan-assembler-times {vlseg5e64\.v} 7 } } */ +/* { dg-final { scan-assembler-times {vlseg6e64\.v} 7 } } */ +/* { dg-final { scan-assembler-times {vlseg7e64\.v} 4 } } */ +/* { dg-final { scan-assembler-times {vlseg8e64\.v} 4 } } */ +/* { dg-final { scan-assembler-times {vsseg2e64\.v} 8 } } */ +/* { dg-final { scan-assembler-times {vsseg3e64\.v} 8 } } */ +/* { dg-final { scan-assembler-times {vsseg4e64\.v} 4 } } */ +/* { dg-final { scan-assembler-times {vsseg5e64\.v} 4 } } */ +/* { dg-final { scan-assembler-times {vsseg6e64\.v} 4 } } */ +/* { dg-final { scan-assembler-times {vsseg7e64\.v} 4 } } */ +/* { dg-final { scan-assembler-times {vsseg8e64\.v} 2 } } */ +/* { dg-final { scan-assembler-times {vsetivli\s+zero,\s*2,\s*e64,\s*m1,\s*t[au],\s*m[au]} 14 } } */ +/* { dg-final { scan-assembler-not {vsetvli} } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/struct_vect-5.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/struct_vect-5.c new file mode 100644 index 000000000000..63b83dfab2ca --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/struct_vect-5.c @@ -0,0 +1,22 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-std=c99 -march=rv32gcv_zvfh -mabi=ilp32d --param=riscv-autovec-preference=fixed-vlmax -funroll-all-loops -fno-schedule-insns -fno-schedule-insns2" } */ + +#define TYPE float +#include "struct_vect-1.c" + +/* { dg-final { scan-assembler-times {vlseg2e32\.v} 8 } } */ +/* { dg-final { scan-assembler-times {vlseg3e32\.v} 8 } } */ +/* { dg-final { scan-assembler-times {vlseg4e32\.v} 8 } } */ +/* { dg-final { scan-assembler-times {vlseg5e32\.v} 6 } } */ +/* { dg-final { scan-assembler-times {vlseg6e32\.v} 6 } } */ +/* { dg-final { scan-assembler-times {vlseg7e32\.v} 4 } } */ +/* { dg-final { scan-assembler-times {vlseg8e32\.v} 4 } } */ +/* { dg-final { scan-assembler-times {vsseg2e32\.v} 8 } } */ +/* { dg-final { scan-assembler-times {vsseg3e32\.v} 8 } } */ +/* { dg-final { scan-assembler-times {vsseg4e32\.v} 4 } } */ +/* { dg-final { scan-assembler-times {vsseg5e32\.v} 4 } } */ +/* { dg-final { scan-assembler-times {vsseg6e32\.v} 4 } } */ +/* { dg-final { scan-assembler-times {vsseg7e32\.v} 4 } } */ +/* { dg-final { scan-assembler-times {vsseg8e32\.v} 2 } } */ +/* { dg-final { scan-assembler-times {vsetivli\s+zero,\s*4,\s*e32,\s*m1,\s*t[au],\s*m[au]} 14 } } */ +/* { dg-final { scan-assembler-not {vsetvli} } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/struct_vect-6.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/struct_vect-6.c new file mode 100644 index 000000000000..2494744d8b49 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/struct_vect-6.c @@ -0,0 +1,225 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-std=c99 -march=rv32gcv_zvfh -mabi=ilp32d --param=riscv-autovec-preference=scalable -fno-vect-cost-model" } */ + +#include + +#ifndef TYPE +#define TYPE uint8_t +#define ITYPE int8_t +#endif + +void __attribute__ ((noinline, noclone)) +f2 (TYPE *__restrict a, TYPE *__restrict b, TYPE *__restrict c, ITYPE n) +{ + for (ITYPE i = 0; i < n; ++i) + { + a[i] = c[i * 2]; + b[i] = c[i * 2 + 1]; + } +} + +void __attribute__ ((noinline, noclone)) +f3 (TYPE *__restrict a, TYPE *__restrict b, TYPE *__restrict c, + TYPE *__restrict d, ITYPE n) +{ + for (ITYPE i = 0; i < n; ++i) + { + a[i] = d[i * 3]; + b[i] = d[i * 3 + 1]; + c[i] = d[i * 3 + 2]; + } +} + +void __attribute__ ((noinline, noclone)) +f4 (TYPE *__restrict a, TYPE *__restrict b, TYPE *__restrict c, + TYPE *__restrict d, TYPE *__restrict e, ITYPE n) +{ + for (ITYPE i = 0; i < n; ++i) + { + a[i] = e[i * 4]; + b[i] = e[i * 4 + 1]; + c[i] = e[i * 4 + 2]; + d[i] = e[i * 4 + 3]; + } +} + +void __attribute__ ((noinline, noclone)) +f5 (TYPE *__restrict a, TYPE *__restrict b, TYPE *__restrict c, + TYPE *__restrict d, TYPE *__restrict e, TYPE *__restrict f, ITYPE n) +{ + for (ITYPE i = 0; i < n; ++i) + { + a[i] = f[i * 5]; + b[i] = f[i * 5 + 1]; + c[i] = f[i * 5 + 2]; + d[i] = f[i * 5 + 3]; + e[i] = f[i * 5 + 4]; + } +} + +void __attribute__ ((noinline, noclone)) +f6 (TYPE *__restrict a, TYPE *__restrict b, TYPE *__restrict c, + TYPE *__restrict d, TYPE *__restrict e, TYPE *__restrict f, + TYPE *__restrict g, ITYPE n) +{ + for (ITYPE i = 0; i < n; ++i) + { + a[i] = g[i * 6]; + b[i] = g[i * 6 + 1]; + c[i] = g[i * 6 + 2]; + d[i] = g[i * 6 + 3]; + e[i] = g[i * 6 + 4]; + f[i] = g[i * 6 + 5]; + } +} + +void __attribute__ ((noinline, noclone)) +f7 (TYPE *__restrict a, TYPE *__restrict b, TYPE *__restrict c, + TYPE *__restrict d, TYPE *__restrict e, TYPE *__restrict f, + TYPE *__restrict g, TYPE *__restrict h, ITYPE n) +{ + for (ITYPE i = 0; i < n; ++i) + { + a[i] = h[i * 7]; + b[i] = h[i * 7 + 1]; + c[i] = h[i * 7 + 2]; + d[i] = h[i * 7 + 3]; + e[i] = h[i * 7 + 4]; + f[i] = h[i * 7 + 5]; + g[i] = h[i * 7 + 6]; + } +} + +void __attribute__ ((noinline, noclone)) +f8 (TYPE *__restrict a, TYPE *__restrict b, TYPE *__restrict c, + TYPE *__restrict d, TYPE *__restrict e, TYPE *__restrict f, + TYPE *__restrict g, TYPE *__restrict h, TYPE *__restrict j, ITYPE n) +{ + for (ITYPE i = 0; i < n; ++i) + { + a[i] = j[i * 8]; + b[i] = j[i * 8 + 1]; + c[i] = j[i * 8 + 2]; + d[i] = j[i * 8 + 3]; + e[i] = j[i * 8 + 4]; + f[i] = j[i * 8 + 5]; + g[i] = j[i * 8 + 6]; + h[i] = j[i * 8 + 7]; + } +} + +void __attribute__ ((noinline, noclone)) +g2 (TYPE *__restrict a, TYPE *__restrict b, TYPE *__restrict c, ITYPE n) +{ + for (ITYPE i = 0; i < n; ++i) + { + c[i * 2] = a[i]; + c[i * 2 + 1] = b[i]; + } +} + +void __attribute__ ((noinline, noclone)) +g3 (TYPE *__restrict a, TYPE *__restrict b, TYPE *__restrict c, + TYPE *__restrict d, ITYPE n) +{ + for (ITYPE i = 0; i < n; ++i) + { + d[i * 3] = a[i]; + d[i * 3 + 1] = b[i]; + d[i * 3 + 2] = c[i]; + } +} + +void __attribute__ ((noinline, noclone)) +g4 (TYPE *__restrict a, TYPE *__restrict b, TYPE *__restrict c, + TYPE *__restrict d, TYPE *__restrict e, ITYPE n) +{ + for (ITYPE i = 0; i < n; ++i) + { + e[i * 4] = a[i]; + e[i * 4 + 1] = b[i]; + e[i * 4 + 2] = c[i]; + e[i * 4 + 3] = d[i]; + } +} + +void __attribute__ ((noinline, noclone)) +g5 (TYPE *__restrict a, TYPE *__restrict b, TYPE *__restrict c, + TYPE *__restrict d, TYPE *__restrict e, TYPE *__restrict f, ITYPE n) +{ + for (ITYPE i = 0; i < n; ++i) + { + f[i * 5] = a[i]; + f[i * 5 + 1] = b[i]; + f[i * 5 + 2] = c[i]; + f[i * 5 + 3] = d[i]; + f[i * 5 + 4] = e[i]; + } +} + +void __attribute__ ((noinline, noclone)) +g6 (TYPE *__restrict a, TYPE *__restrict b, TYPE *__restrict c, + TYPE *__restrict d, TYPE *__restrict e, TYPE *__restrict f, + TYPE *__restrict g, ITYPE n) +{ + for (ITYPE i = 0; i < n; ++i) + { + g[i * 6] = a[i]; + g[i * 6 + 1] = b[i]; + g[i * 6 + 2] = c[i]; + g[i * 6 + 3] = d[i]; + g[i * 6 + 4] = e[i]; + g[i * 6 + 5] = f[i]; + } +} + +void __attribute__ ((noinline, noclone)) +g7 (TYPE *__restrict a, TYPE *__restrict b, TYPE *__restrict c, + TYPE *__restrict d, TYPE *__restrict e, TYPE *__restrict f, + TYPE *__restrict g, TYPE *__restrict h, ITYPE n) +{ + for (ITYPE i = 0; i < n; ++i) + { + h[i * 7] = a[i]; + h[i * 7 + 1] = b[i]; + h[i * 7 + 2] = c[i]; + h[i * 7 + 3] = d[i]; + h[i * 7 + 4] = e[i]; + h[i * 7 + 5] = f[i]; + h[i * 7 + 6] = g[i]; + } +} + +void __attribute__ ((noinline, noclone)) +g8 (TYPE *__restrict a, TYPE *__restrict b, TYPE *__restrict c, + TYPE *__restrict d, TYPE *__restrict e, TYPE *__restrict f, + TYPE *__restrict g, TYPE *__restrict h, TYPE *__restrict j, ITYPE n) +{ + for (ITYPE i = 0; i < n; ++i) + { + j[i * 8] = a[i]; + j[i * 8 + 1] = b[i]; + j[i * 8 + 2] = c[i]; + j[i * 8 + 3] = d[i]; + j[i * 8 + 4] = e[i]; + j[i * 8 + 5] = f[i]; + j[i * 8 + 6] = g[i]; + j[i * 8 + 7] = h[i]; + } +} + +/* { dg-final { scan-assembler-times {vlseg2e8\.v} 1 } } */ +/* { dg-final { scan-assembler-times {vlseg3e8\.v} 1 } } */ +/* { dg-final { scan-assembler-times {vlseg4e8\.v} 1 } } */ +/* { dg-final { scan-assembler-times {vlseg5e8\.v} 1 } } */ +/* { dg-final { scan-assembler-times {vlseg6e8\.v} 1 } } */ +/* { dg-final { scan-assembler-times {vlseg7e8\.v} 1 } } */ +/* { dg-final { scan-assembler-times {vlseg8e8\.v} 1 } } */ +/* { dg-final { scan-assembler-times {vsseg2e8\.v} 1 } } */ +/* { dg-final { scan-assembler-times {vsseg3e8\.v} 1 } } */ +/* { dg-final { scan-assembler-times {vsseg4e8\.v} 1 } } */ +/* { dg-final { scan-assembler-times {vsseg5e8\.v} 1 } } */ +/* { dg-final { scan-assembler-times {vsseg6e8\.v} 1 } } */ +/* { dg-final { scan-assembler-times {vsseg7e8\.v} 1 } } */ +/* { dg-final { scan-assembler-times {vsseg8e8\.v} 1 } } */ +/* { dg-final { scan-assembler-times {vsetvli\s+[a-x0-9]+,\s*[a-x0-9]+,\s*e8,\s*m1,\s*t[au],\s*m[au]} 14 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/struct_vect-7.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/struct_vect-7.c new file mode 100644 index 000000000000..dd01769d98dd --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/struct_vect-7.c @@ -0,0 +1,22 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-std=c99 -march=rv32gcv_zvfh -mabi=ilp32d --param=riscv-autovec-preference=scalable -fno-vect-cost-model" } */ + +#define TYPE uint16_t +#define ITYPE int16_t +#include "struct_vect-6.c" + +/* { dg-final { scan-assembler-times {vlseg2e16\.v} 1 } } */ +/* { dg-final { scan-assembler-times {vlseg3e16\.v} 1 } } */ +/* { dg-final { scan-assembler-times {vlseg4e16\.v} 1 } } */ +/* { dg-final { scan-assembler-times {vlseg5e16\.v} 1 } } */ +/* { dg-final { scan-assembler-times {vlseg6e16\.v} 1 } } */ +/* { dg-final { scan-assembler-times {vlseg7e16\.v} 1 } } */ +/* { dg-final { scan-assembler-times {vlseg8e16\.v} 1 } } */ +/* { dg-final { scan-assembler-times {vsseg2e16\.v} 1 } } */ +/* { dg-final { scan-assembler-times {vsseg3e16\.v} 1 } } */ +/* { dg-final { scan-assembler-times {vsseg4e16\.v} 1 } } */ +/* { dg-final { scan-assembler-times {vsseg5e16\.v} 1 } } */ +/* { dg-final { scan-assembler-times {vsseg6e16\.v} 1 } } */ +/* { dg-final { scan-assembler-times {vsseg7e16\.v} 1 } } */ +/* { dg-final { scan-assembler-times {vsseg8e16\.v} 1 } } */ +/* { dg-final { scan-assembler-times {vsetvli\s+[a-x0-9]+,\s*[a-x0-9]+} 14 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/struct_vect-8.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/struct_vect-8.c new file mode 100644 index 000000000000..bedf17a6ee07 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/struct_vect-8.c @@ -0,0 +1,22 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-std=c99 -march=rv32gcv_zvfh -mabi=ilp32d --param=riscv-autovec-preference=scalable -fno-vect-cost-model" } */ + +#define TYPE uint32_t +#define ITYPE int32_t +#include "struct_vect-6.c" + +/* { dg-final { scan-assembler-times {vlseg2e32\.v} 1 } } */ +/* { dg-final { scan-assembler-times {vlseg3e32\.v} 1 } } */ +/* { dg-final { scan-assembler-times {vlseg4e32\.v} 1 } } */ +/* { dg-final { scan-assembler-times {vlseg5e32\.v} 1 } } */ +/* { dg-final { scan-assembler-times {vlseg6e32\.v} 1 } } */ +/* { dg-final { scan-assembler-times {vlseg7e32\.v} 1 } } */ +/* { dg-final { scan-assembler-times {vlseg8e32\.v} 1 } } */ +/* { dg-final { scan-assembler-times {vsseg2e32\.v} 1 } } */ +/* { dg-final { scan-assembler-times {vsseg3e32\.v} 1 } } */ +/* { dg-final { scan-assembler-times {vsseg4e32\.v} 1 } } */ +/* { dg-final { scan-assembler-times {vsseg5e32\.v} 1 } } */ +/* { dg-final { scan-assembler-times {vsseg6e32\.v} 1 } } */ +/* { dg-final { scan-assembler-times {vsseg7e32\.v} 1 } } */ +/* { dg-final { scan-assembler-times {vsseg8e32\.v} 1 } } */ +/* { dg-final { scan-assembler-times {vsetvli\s+[a-x0-9]+,\s*[a-x0-9]+} 14 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/struct_vect-9.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/struct_vect-9.c new file mode 100644 index 000000000000..8b608224a4fd --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/struct_vect-9.c @@ -0,0 +1,22 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-std=c99 -march=rv64gcv_zvfh -mabi=lp64d --param=riscv-autovec-preference=scalable -fno-vect-cost-model" } */ + +#define TYPE uint64_t +#define ITYPE int64_t +#include "struct_vect-6.c" + +/* { dg-final { scan-assembler-times {vlseg2e64\.v} 1 } } */ +/* { dg-final { scan-assembler-times {vlseg3e64\.v} 1 } } */ +/* { dg-final { scan-assembler-times {vlseg4e64\.v} 1 } } */ +/* { dg-final { scan-assembler-times {vlseg5e64\.v} 1 } } */ +/* { dg-final { scan-assembler-times {vlseg6e64\.v} 1 } } */ +/* { dg-final { scan-assembler-times {vlseg7e64\.v} 1 } } */ +/* { dg-final { scan-assembler-times {vlseg8e64\.v} 1 } } */ +/* { dg-final { scan-assembler-times {vsseg2e64\.v} 1 } } */ +/* { dg-final { scan-assembler-times {vsseg3e64\.v} 1 } } */ +/* { dg-final { scan-assembler-times {vsseg4e64\.v} 1 } } */ +/* { dg-final { scan-assembler-times {vsseg5e64\.v} 1 } } */ +/* { dg-final { scan-assembler-times {vsseg6e64\.v} 1 } } */ +/* { dg-final { scan-assembler-times {vsseg7e64\.v} 1 } } */ +/* { dg-final { scan-assembler-times {vsseg8e64\.v} 1 } } */ +/* { dg-final { scan-assembler-times {vsetvli\s+[a-x0-9]+,\s*[a-x0-9]+} 14 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/struct_vect_run-1.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/struct_vect_run-1.c new file mode 100644 index 000000000000..4807bebdd7e2 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/struct_vect_run-1.c @@ -0,0 +1,139 @@ +/* { dg-do run { target { riscv_vector } } } */ +/* { dg-additional-options "-std=c99 --param=riscv-autovec-preference=fixed-vlmax -funroll-all-loops -fno-schedule-insns -fno-schedule-insns2" } */ + +#include "struct_vect-1.c" + +TYPE a[N], b[N], c[N], d[N], a2[N], b2[N], c2[N], d2[N], e[N * 8]; + +void __attribute__ ((noinline, noclone)) +init_array (TYPE *array, int n, TYPE base, TYPE step) +{ + for (int i = 0; i < n; ++i) + array[i] = base + step * i; +} + +void __attribute__ ((noinline, noclone)) +check_array (TYPE *array, int n, TYPE base, TYPE step) +{ + for (int i = 0; i < n; ++i) + if (array[i] != (TYPE) (base + step * i)) + __builtin_abort (); +} + +int __attribute__ ((optimize (1))) +main (void) +{ + init_array (e, 2 * N, 11, 5); + f2 (a, b, e); + check_array (a, N, 11, 10); + check_array (b, N, 16, 10); + + init_array (e, 3 * N, 7, 6); + f3 (a, b, c, e); + check_array (a, N, 7, 18); + check_array (b, N, 13, 18); + check_array (c, N, 19, 18); + + init_array (e, 4 * N, 4, 11); + f4 (a, b, c, d, e); + check_array (a, N, 4, 44); + check_array (b, N, 15, 44); + check_array (c, N, 26, 44); + check_array (d, N, 37, 44); + + init_array (e, 5 * N, 3, 9); + f5 (a, b, c, d, a2, e); + check_array (a, N, 3, 45); + check_array (b, N, 12, 45); + check_array (c, N, 21, 45); + check_array (d, N, 30, 45); + check_array (a2, N, 39, 45); + + init_array (e, 6 * N, 5, 5); + f6 (a, b, c, d, a2, b2, e); + check_array (a, N, 5, 30); + check_array (b, N, 10, 30); + check_array (c, N, 15, 30); + check_array (d, N, 20, 30); + check_array (a2, N, 25, 30); + check_array (b2, N, 30, 30); + + init_array (e, 7 * N, 7, 3); + f7 (a, b, c, d, a2, b2, c2, e); + check_array (a, N, 7, 21); + check_array (b, N, 10, 21); + check_array (c, N, 13, 21); + check_array (d, N, 16, 21); + check_array (a2, N, 19, 21); + check_array (b2, N, 22, 21); + check_array (c2, N, 25, 21); + + init_array (e, 8 * N, 5, 8); + f8 (a, b, c, d, a2, b2, c2, d2, e); + check_array (a, N, 5, 64); + check_array (b, N, 13, 64); + check_array (c, N, 21, 64); + check_array (d, N, 29, 64); + check_array (a2, N, 37, 64); + check_array (b2, N, 45, 64); + check_array (c2, N, 53, 64); + check_array (d2, N, 61, 64); + + init_array (a, N, 2, 8); + init_array (b, N, 6, 8); + g2 (a, b, e); + check_array (e, 2 * N, 2, 4); + + init_array (a, N, 4, 15); + init_array (b, N, 9, 15); + init_array (c, N, 14, 15); + g3 (a, b, c, e); + check_array (e, 3 * N, 4, 5); + + init_array (a, N, 14, 36); + init_array (b, N, 23, 36); + init_array (c, N, 32, 36); + init_array (d, N, 41, 36); + g4 (a, b, c, d, e); + check_array (e, 4 * N, 14, 9); + + init_array (a, N, 3, 45); + init_array (b, N, 12, 45); + init_array (c, N, 21, 45); + init_array (d, N, 30, 45); + init_array (a2, N, 39, 45); + g5 (a, b, c, d, a2, e); + check_array (e, 5 * N, 3, 9); + + init_array (a, N, 5, 30); + init_array (b, N, 10, 30); + init_array (c, N, 15, 30); + init_array (d, N, 20, 30); + init_array (a2, N, 25, 30); + init_array (b2, N, 30, 30); + g6 (a, b, c, d, a2, b2, e); + check_array (e, 6 * N, 5, 5); + + init_array (a, N, 7, 21); + init_array (b, N, 10, 21); + init_array (c, N, 13, 21); + init_array (d, N, 16, 21); + init_array (a2, N, 19, 21); + init_array (b2, N, 22, 21); + init_array (c2, N, 25, 21); + g7 (a, b, c, d, a2, b2, c2, e); + check_array (e, 7 * N, 7, 3); + + init_array (a, N, 5, 64); + init_array (b, N, 13, 64); + init_array (c, N, 21, 64); + init_array (d, N, 29, 64); + init_array (a2, N, 37, 64); + init_array (b2, N, 45, 64); + init_array (c2, N, 53, 64); + init_array (d2, N, 61, 64); + g8 (a, b, c, d, a2, b2, c2, d2, e); + check_array (e, 8 * N, 5, 8); + + return 0; +} diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/struct_vect_run-10.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/struct_vect_run-10.c new file mode 100644 index 000000000000..afebde162d7f --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/struct_vect_run-10.c @@ -0,0 +1,6 @@ +/* { dg-do run { target { riscv_vector && riscv_zvfh_hw } } } */ +/* { dg-additional-options "-std=c99 --param=riscv-autovec-preference=scalable -fno-vect-cost-model" } */ + +#define TYPE _Float16 +#define ITYPE int16_t +#include "struct_vect_run-6.c" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/struct_vect_run-11.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/struct_vect_run-11.c new file mode 100644 index 000000000000..8d311b45eb4c --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/struct_vect_run-11.c @@ -0,0 +1,6 @@ +/* { dg-do run { target { riscv_vector } } } */ +/* { dg-additional-options "-std=c99 --param=riscv-autovec-preference=scalable -fno-vect-cost-model" } */ + +#define TYPE float +#define ITYPE int32_t +#include "struct_vect_run-6.c" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/struct_vect_run-12.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/struct_vect_run-12.c new file mode 100644 index 000000000000..763aa9e6f582 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/struct_vect_run-12.c @@ -0,0 +1,6 @@ +/* { dg-do run { target { riscv_vector } } } */ +/* { dg-additional-options "-std=c99 --param=riscv-autovec-preference=scalable -fno-vect-cost-model" } */ + +#define TYPE double +#define ITYPE int64_t +#include "struct_vect_run-6.c" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/struct_vect_run-13.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/struct_vect_run-13.c new file mode 100644 index 000000000000..e1824e912bf6 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/struct_vect_run-13.c @@ -0,0 +1,36 @@ +/* { dg-do run { target { riscv_vector } } } */ +/* { dg-additional-options "--param=riscv-autovec-preference=scalable -fno-vect-cost-model" } */ + +#include "struct_vect-13.c" + +#undef TEST_LOOP +#define TEST_LOOP(NAME, TYPE) \ + { \ + TYPE out[N]; \ + TYPE in[N * 3]; \ + for (int i = 0; i < N; ++i) \ + { \ + out[i] = i * 7 / 2; \ + asm volatile ("" ::: "memory"); \ + } \ + for (int i = 0; i < N * 3; ++i) \ + { \ + in[i] = i * 9 / 2; \ + asm volatile ("" ::: "memory"); \ + } \ + NAME (out, in); \ + for (int i = 0; i < N; ++i) \ + { \ + TYPE expected = i * 7 / 2 + in[i * 3]; \ + if (out[i] != expected) \ + __builtin_abort (); \ + asm volatile ("" ::: "memory"); \ + } \ + } + +int __attribute__ ((optimize (1))) +main (void) +{ + TEST (test); + return 0; +} diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/struct_vect_run-14.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/struct_vect_run-14.c new file mode 100644 index 000000000000..6b23023a918f --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/struct_vect_run-14.c @@ -0,0 +1,45 @@ +/* { dg-do run { target { riscv_vector } } } */ +/* { dg-additional-options "--param=riscv-autovec-preference=scalable -fno-vect-cost-model" } */ + +#include "struct_vect-14.c" + +#define N 1000 + +#undef TEST_LOOP +#define TEST_LOOP(NAME, TYPE) \ + { \ + TYPE out[N]; \ + TYPE in[N * 3]; \ + int counts[] = { 0, 1, N - 1 }; \ + for (int j = 0; j < 3; ++j) \ + { \ + int count = counts[j]; \ + for (int i = 0; i < N; ++i) \ + { \ + out[i] = i * 7 / 2; \ + asm volatile ("" ::: "memory"); \ + } \ + for (int i = 0; i < N * 3; ++i) \ + { \ + in[i] = i * 9 / 2; \ + asm volatile ("" ::: "memory"); \ + } \ + NAME (out, in, count); \ + for (int i = 0; i < N; ++i) \ + { \ + TYPE expected = i * 7 / 2; \ + if (i < count) \ + expected += in[i * 3]; \ + if (out[i] != expected) \ + __builtin_abort (); \ + asm volatile ("" ::: "memory"); \ + } \ + } \ + } + +int __attribute__ ((optimize (1))) +main (void) +{ + TEST (test); + return 0; +} diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/struct_vect_run-15.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/struct_vect_run-15.c new file mode 100644 index 000000000000..92eadd6fd459 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/struct_vect_run-15.c @@ -0,0 +1,36 @@ +/* { dg-do run { target { riscv_vector } } } */ +/* { dg-additional-options "--param=riscv-autovec-preference=scalable -fno-vect-cost-model" } */ + +#include "struct_vect-15.c" + +#undef TEST_LOOP +#define TEST_LOOP(NAME, TYPE) \ + { \ + TYPE out[N]; \ + TYPE in[N * 2]; \ + for (int i = 0; i < N; ++i) \ + { \ + out[i] = i * 7 / 2; \ + asm volatile ("" ::: "memory"); \ + } \ + for (int i = 0; i < N * 2; ++i) \ + { \ + in[i] = i * 9 / 2; \ + asm volatile ("" ::: "memory"); \ + } \ + NAME (out, in); \ + for (int i = 0; i < N; ++i) \ + { \ + TYPE expected = i * 7 / 2 + in[i * 2]; \ + if (out[i] != expected) \ + __builtin_abort (); \ + asm volatile ("" ::: "memory"); \ + } \ + } + +int __attribute__ ((optimize (1))) +main (void) +{ + TEST (test); + return 0; +} diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/struct_vect_run-16.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/struct_vect_run-16.c new file mode 100644 index 000000000000..f43e06c46fdc --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/struct_vect_run-16.c @@ -0,0 +1,45 @@ +/* { dg-do run { target { riscv_vector } } } */ +/* { dg-additional-options "--param=riscv-autovec-preference=scalable -fno-vect-cost-model" } */ + +#include "struct_vect-16.c" + +#define N 1000 + +#undef TEST_LOOP +#define TEST_LOOP(NAME, TYPE) \ + { \ + TYPE out[N]; \ + TYPE in[N * 2]; \ + int counts[] = { 0, 1, N - 1 }; \ + for (int j = 0; j < 3; ++j) \ + { \ + int count = counts[j]; \ + for (int i = 0; i < N; ++i) \ + { \ + out[i] = i * 7 / 2; \ + asm volatile ("" ::: "memory"); \ + } \ + for (int i = 0; i < N * 2; ++i) \ + { \ + in[i] = i * 9 / 2; \ + asm volatile ("" ::: "memory"); \ + } \ + NAME (out, in, count); \ + for (int i = 0; i < N; ++i) \ + { \ + TYPE expected = i * 7 / 2; \ + if (i < count) \ + expected += in[i * 2]; \ + if (out[i] != expected) \ + __builtin_abort (); \ + asm volatile ("" ::: "memory"); \ + } \ + } \ + } + +int __attribute__ ((optimize (1))) +main (void) +{ + TEST (test); + return 0; +} diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/struct_vect_run-17.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/struct_vect_run-17.c new file mode 100644 index 000000000000..b0bafb1cece3 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/struct_vect_run-17.c @@ -0,0 +1,36 @@ +/* { dg-do run { target { riscv_vector } } } */ +/* { dg-additional-options "--param=riscv-autovec-preference=scalable -fno-vect-cost-model" } */ + +#include "struct_vect-17.c" + +#undef TEST_LOOP +#define TEST_LOOP(NAME, TYPE) \ + { \ + TYPE out[N]; \ + TYPE in[N * 4]; \ + for (int i = 0; i < N; ++i) \ + { \ + out[i] = i * 7 / 2; \ + asm volatile ("" ::: "memory"); \ + } \ + for (int i = 0; i < N * 4; ++i) \ + { \ + in[i] = i * 9 / 2; \ + asm volatile ("" ::: "memory"); \ + } \ + NAME (out, in); \ + for (int i = 0; i < N; ++i) \ + { \ + TYPE expected = i * 7 / 2 + in[i * 4]; \ + if (out[i] != expected) \ + __builtin_abort (); \ + asm volatile ("" ::: "memory"); \ + } \ + } + +int __attribute__ ((optimize (1))) +main (void) +{ + TEST (test); + return 0; +} diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/struct_vect_run-18.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/struct_vect_run-18.c new file mode 100644 index 000000000000..169974cc0a9d --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/struct_vect_run-18.c @@ -0,0 +1,45 @@ +/* { dg-do run { target { riscv_vector } } } */ +/* { dg-additional-options "--param=riscv-autovec-preference=scalable -fno-vect-cost-model" } */ + +#include "struct_vect-18.c" + +#define N 1000 + +#undef TEST_LOOP +#define TEST_LOOP(NAME, TYPE) \ + { \ + TYPE out[N]; \ + TYPE in[N * 4]; \ + int counts[] = { 0, 1, N - 1 }; \ + for (int j = 0; j < 3; ++j) \ + { \ + int count = counts[j]; \ + for (int i = 0; i < N; ++i) \ + { \ + out[i] = i * 7 / 2; \ + asm volatile ("" ::: "memory"); \ + } \ + for (int i = 0; i < N * 4; ++i) \ + { \ + in[i] = i * 9 / 2; \ + asm volatile ("" ::: "memory"); \ + } \ + NAME (out, in, count); \ + for (int i = 0; i < N; ++i) \ + { \ + TYPE expected = i * 7 / 2; \ + if (i < count) \ + expected += in[i * 4]; \ + if (out[i] != expected) \ + __builtin_abort (); \ + asm volatile ("" ::: "memory"); \ + } \ + } \ + } + +int __attribute__ ((optimize (1))) +main (void) +{ + TEST (test); + return 0; +} diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/struct_vect_run-2.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/struct_vect_run-2.c new file mode 100644 index 000000000000..ab26245241ca --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/struct_vect_run-2.c @@ -0,0 +1,5 @@ +/* { dg-do run { target { riscv_vector } } } */ +/* { dg-additional-options "-std=c99 --param=riscv-autovec-preference=fixed-vlmax -funroll-all-loops -fno-schedule-insns -fno-schedule-insns2" } */ + +#define TYPE uint16_t +#include "struct_vect_run-1.c" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/struct_vect_run-3.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/struct_vect_run-3.c new file mode 100644 index 000000000000..a2b2e8183276 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/struct_vect_run-3.c @@ -0,0 +1,5 @@ +/* { dg-do run { target { riscv_vector } } } */ +/* { dg-additional-options "-std=c99 --param=riscv-autovec-preference=fixed-vlmax -funroll-all-loops -fno-schedule-insns -fno-schedule-insns2" } */ + +#define TYPE uint32_t +#include "struct_vect_run-1.c" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/struct_vect_run-4.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/struct_vect_run-4.c new file mode 100644 index 000000000000..4e4ddb3b39fe --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/struct_vect_run-4.c @@ -0,0 +1,5 @@ +/* { dg-do run { target { riscv_vector } } } */ +/* { dg-additional-options "-std=c99 --param=riscv-autovec-preference=fixed-vlmax -funroll-all-loops -fno-schedule-insns -fno-schedule-insns2" } */ + +#define TYPE uint64_t +#include "struct_vect_run-1.c" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/struct_vect_run-5.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/struct_vect_run-5.c new file mode 100644 index 000000000000..2fa48f1ce3ef --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/struct_vect_run-5.c @@ -0,0 +1,5 @@ +/* { dg-do run { target { riscv_vector } } } */ +/* { dg-additional-options "-std=c99 --param=riscv-autovec-preference=fixed-vlmax -funroll-all-loops -fno-schedule-insns -fno-schedule-insns2" } */ + +#define TYPE float +#include "struct_vect_run-1.c" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/struct_vect_run-6.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/struct_vect_run-6.c new file mode 100644 index 000000000000..7146042c4040 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/struct_vect_run-6.c @@ -0,0 +1,141 @@ +/* { dg-do run { target { riscv_vector } } } */ +/* { dg-additional-options "-std=c99 --param=riscv-autovec-preference=scalable -fno-vect-cost-model" } */ + +#include "struct_vect-6.c" + +#define N 93 + +TYPE a[N], b[N], c[N], d[N], a2[N], b2[N], c2[N], d2[N], e[N * 8]; + +void __attribute__ ((noinline, noclone)) +init_array (TYPE *array, int n, TYPE base, TYPE step) +{ + for (int i = 0; i < n; ++i) + array[i] = base + step * i; +} + +void __attribute__ ((noinline, noclone)) +check_array (TYPE *array, int n, TYPE base, TYPE step) +{ + for (int i = 0; i < n; ++i) + if (array[i] != (TYPE) (base + step * i)) + __builtin_abort (); +} + +int __attribute__ ((optimize (1))) +main (void) +{ + init_array (e, 2 * N, 11, 5); + f2 (a, b, e, N); + check_array (a, N, 11, 10); + check_array (b, N, 16, 10); + + init_array (e, 3 * N, 7, 6); + f3 (a, b, c, e, N); + check_array (a, N, 7, 18); + check_array (b, N, 13, 18); + check_array (c, N, 19, 18); + + init_array (e, 4 * N, 4, 11); + f4 (a, b, c, d, e, N); + check_array (a, N, 4, 44); + check_array (b, N, 15, 44); + check_array (c, N, 26, 44); + check_array (d, N, 37, 44); + + init_array (e, 5 * N, 3, 9); + f5 (a, b, c, d, a2, e, N); + check_array (a, N, 3, 45); + check_array (b, N, 12, 45); + check_array (c, N, 21, 45); + check_array (d, N, 30, 45); + check_array (a2, N, 39, 45); + + init_array (e, 6 * N, 5, 5); + f6 (a, b, c, d, a2, b2, e, N); + check_array (a, N, 5, 30); + check_array (b, N, 10, 30); + check_array (c, N, 15, 30); + check_array (d, N, 20, 30); + check_array (a2, N, 25, 30); + check_array (b2, N, 30, 30); + + init_array (e, 7 * N, 7, 3); + f7 (a, b, c, d, a2, b2, c2, e, N); + check_array (a, N, 7, 21); + check_array (b, N, 10, 21); + check_array (c, N, 13, 21); + check_array (d, N, 16, 21); + check_array (a2, N, 19, 21); + check_array (b2, N, 22, 21); + check_array (c2, N, 25, 21); + + init_array (e, 8 * N, 5, 8); + f8 (a, b, c, d, a2, b2, c2, d2, e, N); + check_array (a, N, 5, 64); + check_array (b, N, 13, 64); + check_array (c, N, 21, 64); + check_array (d, N, 29, 64); + check_array (a2, N, 37, 64); + check_array (b2, N, 45, 64); + check_array (c2, N, 53, 64); + check_array (d2, N, 61, 64); + + init_array (a, N, 2, 8); + init_array (b, N, 6, 8); + g2 (a, b, e, N); + check_array (e, 2 * N, 2, 4); + + init_array (a, N, 4, 15); + init_array (b, N, 9, 15); + init_array (c, N, 14, 15); + g3 (a, b, c, e, N); + check_array (e, 3 * N, 4, 5); + + init_array (a, N, 14, 36); + init_array (b, N, 23, 36); + init_array (c, N, 32, 36); + init_array (d, N, 41, 36); + g4 (a, b, c, d, e, N); + check_array (e, 4 * N, 14, 9); + + init_array (a, N, 3, 45); + init_array (b, N, 12, 45); + init_array (c, N, 21, 45); + init_array (d, N, 30, 45); + init_array (a2, N, 39, 45); + g5 (a, b, c, d, a2, e, N); + check_array (e, 5 * N, 3, 9); + + init_array (a, N, 5, 30); + init_array (b, N, 10, 30); + init_array (c, N, 15, 30); + init_array (d, N, 20, 30); + init_array (a2, N, 25, 30); + init_array (b2, N, 30, 30); + g6 (a, b, c, d, a2, b2, e, N); + check_array (e, 6 * N, 5, 5); + + init_array (a, N, 7, 21); + init_array (b, N, 10, 21); + init_array (c, N, 13, 21); + init_array (d, N, 16, 21); + init_array (a2, N, 19, 21); + init_array (b2, N, 22, 21); + init_array (c2, N, 25, 21); + g7 (a, b, c, d, a2, b2, c2, e, N); + check_array (e, 7 * N, 7, 3); + + init_array (a, N, 5, 64); + init_array (b, N, 13, 64); + init_array (c, N, 21, 64); + init_array (d, N, 29, 64); + init_array (a2, N, 37, 64); + init_array (b2, N, 45, 64); + init_array (c2, N, 53, 64); + init_array (d2, N, 61, 64); + g8 (a, b, c, d, a2, b2, c2, d2, e, N); + check_array (e, 8 * N, 5, 8); + + return 0; +} diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/struct_vect_run-7.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/struct_vect_run-7.c new file mode 100644 index 000000000000..73e74493bd2c --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/struct_vect_run-7.c @@ -0,0 +1,6 @@ +/* { dg-do run { target { riscv_vector } } } */ +/* { dg-additional-options "-std=c99 --param=riscv-autovec-preference=scalable -fno-vect-cost-model" } */ + +#define TYPE uint16_t +#define ITYPE int16_t +#include "struct_vect_run-6.c" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/struct_vect_run-8.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/struct_vect_run-8.c new file mode 100644 index 000000000000..383a6c686215 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/struct_vect_run-8.c @@ -0,0 +1,6 @@ +/* { dg-do run { target { riscv_vector } } } */ +/* { dg-additional-options "-std=c99 --param=riscv-autovec-preference=scalable -fno-vect-cost-model" } */ + +#define TYPE uint32_t +#define ITYPE int32_t +#include "struct_vect_run-6.c" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/struct_vect_run-9.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/struct_vect_run-9.c new file mode 100644 index 000000000000..79b5df73559c --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/struct/struct_vect_run-9.c @@ -0,0 +1,6 @@ +/* { dg-do run { target { riscv_vector } } } */ +/* { dg-additional-options "-std=c99 --param=riscv-autovec-preference=scalable -fno-vect-cost-model" } */ + +#define TYPE uint64_t +#define ITYPE int64_t +#include "struct_vect_run-6.c" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/ternop/ternop_nofm-1.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/ternop/ternop_nofm-1.c index d6085043af43..3f7febc4565b 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/ternop/ternop_nofm-1.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/ternop/ternop_nofm-1.c @@ -3,5 +3,7 @@ #include "ternop-1.c" -/* { dg-final { scan-assembler-not {\tvmv} } } */ +/* TODO: we don't have undefine IR for COND_LEN_* operations, + which will produce redundant move instructions here. + Will add assembler-not check of 'vmv' instructions in the future. */ /* { dg-final { scan-tree-dump-times "COND_LEN_FMA" 3 "optimized" } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/ternop/ternop_nofm-10.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/ternop/ternop_nofm-10.c new file mode 100644 index 000000000000..27981fc034ac --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/ternop/ternop_nofm-10.c @@ -0,0 +1,9 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-march=rv32gcv_zvfh -mabi=ilp32d --param=riscv-autovec-preference=scalable -fdump-tree-optimized-details" } */ + +#include "ternop-10.c" + +/* TODO: we don't have undefine IR for COND_LEN_* operations, + which will produce redundant move instructions here. + Will add assembler-not check of 'vmv' instructions in the future. */ +/* { dg-final { scan-tree-dump-times "COND_LEN_FNMS" 3 "optimized" } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/ternop/ternop_nofm-11.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/ternop/ternop_nofm-11.c new file mode 100644 index 000000000000..fcbed651be94 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/ternop/ternop_nofm-11.c @@ -0,0 +1,9 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-march=rv32gcv_zvfh -mabi=ilp32d --param=riscv-autovec-preference=scalable -fdump-tree-optimized-details" } */ + +#include "ternop-11.c" + +/* TODO: we don't have undefine IR for COND_LEN_* operations, + which will produce redundant move instructions here. + Will add assembler-not check of 'vmv' instructions in the future. */ +/* { dg-final { scan-tree-dump-times "COND_LEN_FNMS" 3 "optimized" } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/ternop/ternop_nofm-12.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/ternop/ternop_nofm-12.c new file mode 100644 index 000000000000..0ce468d60de2 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/ternop/ternop_nofm-12.c @@ -0,0 +1,6 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-march=rv32gcv_zvfh -mabi=ilp32d --param=riscv-autovec-preference=scalable -fdump-tree-optimized-details -fno-schedule-insns" } */ + +#include "ternop-12.c" + +/* { dg-final { scan-tree-dump-times "COND_LEN_FNMS" 3 "optimized" } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/ternop/ternop_nofm-3.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/ternop/ternop_nofm-3.c index 63cd4aeb7057..429cff9d4e92 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/ternop/ternop_nofm-3.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/ternop/ternop_nofm-3.c @@ -4,6 +4,5 @@ #include "ternop-3.c" /* { dg-final { scan-assembler-times {\tvmacc\.vv} 8 } } */ -/* { dg-final { scan-assembler-times {\tvfmacc\.vv} 6 } } */ -/* { dg-final { scan-assembler-times {\tvmv} 11 } } */ -/* { dg-final { scan-tree-dump-times "COND_LEN_FMA" 6 "optimized" } } */ +/* { dg-final { scan-assembler-times {\tvfmacc\.vv} 9 } } */ +/* { dg-final { scan-tree-dump-times "COND_LEN_FMA" 9 "optimized" } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/ternop/ternop_nofm-4.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/ternop/ternop_nofm-4.c new file mode 100644 index 000000000000..9ec7527553c2 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/ternop/ternop_nofm-4.c @@ -0,0 +1,9 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-march=rv32gcv_zvfh -mabi=ilp32d --param=riscv-autovec-preference=scalable -fdump-tree-optimized-details" } */ + +#include "ternop-4.c" + +/* TODO: we don't have undefine IR for COND_LEN_* operations, + which will produce redundant move instructions here. + Will add assembler-not check of 'vmv' instructions in the future. */ +/* { dg-final { scan-tree-dump-times "COND_LEN_FNMA" 3 "optimized" } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/ternop/ternop_nofm-5.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/ternop/ternop_nofm-5.c new file mode 100644 index 000000000000..9aa8e83f7a57 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/ternop/ternop_nofm-5.c @@ -0,0 +1,9 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-march=rv32gcv_zvfh -mabi=ilp32d --param=riscv-autovec-preference=scalable -fdump-tree-optimized-details" } */ + +#include "ternop-5.c" + +/* TODO: we don't have undefine IR for COND_LEN_* operations, + which will produce redundant move instructions here. + Will add assembler-not check of 'vmv' instructions in the future. */ +/* { dg-final { scan-tree-dump-times "COND_LEN_FNMA" 3 "optimized" } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/ternop/ternop_nofm-6.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/ternop/ternop_nofm-6.c new file mode 100644 index 000000000000..cc4f7f2c6e19 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/ternop/ternop_nofm-6.c @@ -0,0 +1,6 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-march=rv32gcv_zvfh -mabi=ilp32d --param=riscv-autovec-preference=scalable -fdump-tree-optimized-details -fno-schedule-insns" } */ + +#include "ternop-6.c" + +/* { dg-final { scan-tree-dump-times "COND_LEN_FNMA" 3 "optimized" } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/ternop/ternop_nofm-7.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/ternop/ternop_nofm-7.c new file mode 100644 index 000000000000..7100fe77767d --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/ternop/ternop_nofm-7.c @@ -0,0 +1,9 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-march=rv32gcv_zvfh -mabi=ilp32d --param=riscv-autovec-preference=scalable -fdump-tree-optimized-details" } */ + +#include "ternop-7.c" + +/* TODO: we don't have undefine IR for COND_LEN_* operations, + which will produce redundant move instructions here. + Will add assembler-not check of 'vmv' instructions in the future. */ +/* { dg-final { scan-tree-dump-times "COND_LEN_FMS" 3 "optimized" } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/ternop/ternop_nofm-8.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/ternop/ternop_nofm-8.c new file mode 100644 index 000000000000..228ada739351 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/ternop/ternop_nofm-8.c @@ -0,0 +1,9 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-march=rv32gcv_zvfh -mabi=ilp32d --param=riscv-autovec-preference=scalable -fdump-tree-optimized-details" } */ + +#include "ternop-8.c" + +/* TODO: we don't have undefine IR for COND_LEN_* operations, + which will produce redundant move instructions here. + Will add assembler-not check of 'vmv' instructions in the future. */ +/* { dg-final { scan-tree-dump-times "COND_LEN_FMS" 9 "optimized" } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/ternop/ternop_nofm-9.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/ternop/ternop_nofm-9.c new file mode 100644 index 000000000000..5ab222877417 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/ternop/ternop_nofm-9.c @@ -0,0 +1,6 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-march=rv32gcv_zvfh -mabi=ilp32d --param=riscv-autovec-preference=scalable -fdump-tree-optimized-details -fno-schedule-insns" } */ + +#include "ternop-9.c" + +/* { dg-final { scan-tree-dump-times "COND_LEN_FMS" 9 "optimized" } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/ternop/ternop_nofm_run-10.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/ternop/ternop_nofm_run-10.c new file mode 100644 index 000000000000..2e11144c0f42 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/ternop/ternop_nofm_run-10.c @@ -0,0 +1,4 @@ +/* { dg-do run { target { riscv_vector } } } */ +/* { dg-additional-options "--param=riscv-autovec-preference=scalable" } */ + +#include "ternop_run-10.c" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/ternop/ternop_nofm_run-11.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/ternop/ternop_nofm_run-11.c new file mode 100644 index 000000000000..bdbbb763d2d3 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/ternop/ternop_nofm_run-11.c @@ -0,0 +1,4 @@ +/* { dg-do run { target { riscv_vector } } } */ +/* { dg-additional-options "--param=riscv-autovec-preference=scalable" } */ + +#include "ternop_run-11.c" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/ternop/ternop_nofm_run-12.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/ternop/ternop_nofm_run-12.c new file mode 100644 index 000000000000..77d92ddb59c4 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/ternop/ternop_nofm_run-12.c @@ -0,0 +1,4 @@ +/* { dg-do run { target { riscv_vector } } } */ +/* { dg-additional-options "--param=riscv-autovec-preference=scalable" } */ + +#include "ternop_run-12.c" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/ternop/ternop_nofm_run-4.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/ternop/ternop_nofm_run-4.c new file mode 100644 index 000000000000..d595b60aeb79 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/ternop/ternop_nofm_run-4.c @@ -0,0 +1,4 @@ +/* { dg-do run { target { riscv_vector } } } */ +/* { dg-additional-options "--param=riscv-autovec-preference=scalable" } */ + +#include "ternop_run-4.c" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/ternop/ternop_nofm_run-5.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/ternop/ternop_nofm_run-5.c new file mode 100644 index 000000000000..a5373377db67 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/ternop/ternop_nofm_run-5.c @@ -0,0 +1,4 @@ +/* { dg-do run { target { riscv_vector } } } */ +/* { dg-additional-options "--param=riscv-autovec-preference=scalable" } */ + +#include "ternop_run-5.c" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/ternop/ternop_nofm_run-6.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/ternop/ternop_nofm_run-6.c new file mode 100644 index 000000000000..844b563d6d46 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/ternop/ternop_nofm_run-6.c @@ -0,0 +1,4 @@ +/* { dg-do run { target { riscv_vector } } } */ +/* { dg-additional-options "--param=riscv-autovec-preference=scalable" } */ + +#include "ternop_run-6.c" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/ternop/ternop_nofm_run-7.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/ternop/ternop_nofm_run-7.c new file mode 100644 index 000000000000..bd7fcfcce3b1 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/ternop/ternop_nofm_run-7.c @@ -0,0 +1,4 @@ +/* { dg-do run { target { riscv_vector } } } */ +/* { dg-additional-options "--param=riscv-autovec-preference=scalable" } */ + +#include "ternop_run-7.c" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/ternop/ternop_nofm_run-8.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/ternop/ternop_nofm_run-8.c new file mode 100644 index 000000000000..90300cce23bb --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/ternop/ternop_nofm_run-8.c @@ -0,0 +1,4 @@ +/* { dg-do run { target { riscv_vector } } } */ +/* { dg-additional-options "--param=riscv-autovec-preference=scalable" } */ + +#include "ternop_run-8.c" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/ternop/ternop_nofm_run-9.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/ternop/ternop_nofm_run-9.c new file mode 100644 index 000000000000..7e752afe367c --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/ternop/ternop_nofm_run-9.c @@ -0,0 +1,4 @@ +/* { dg-do run { target { riscv_vector } } } */ +/* { dg-additional-options "--param=riscv-autovec-preference=scalable" } */ + +#include "ternop_run-9.c" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls-vlmax/pr110985.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls-vlmax/pr110985.c new file mode 100644 index 000000000000..7710654c1bbd --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls-vlmax/pr110985.c @@ -0,0 +1,90 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gcv_zvl256b -mabi=lp64d -O3 --param=riscv-autovec-preference=fixed-vlmax -fno-schedule-insns -fno-schedule-insns2" } */ +/* { dg-final { check-function-bodies "**" "" } } */ + +#include + +typedef int16_t vnx16i __attribute__ ((vector_size (32))); + +/* +** foo1: +** vsetivli\s+zero,\s*16,\s*e16,\s*m1,\s*t[au],\s*m[au] +** vid\.v\s+v[0-9]+ +** vrsub\.vi\s+v[0-9]+,\s*v[0-9]+,\s*15 +** vs1r\.v\s+v[0-9]+,\s*0\([a-x0-9]+\) +** ret +*/ +void +foo1 (int16_t *__restrict out) +{ + vnx16i v = {15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0}; + *(vnx16i *) out = v; +} + +/* +** foo2: +** vsetivli\s+zero,\s*16,\s*e16,\s*m1,\s*t[au],\s*m[au] +** vid\.v\s+v[0-9]+ +** li\s+[a-x0-9]+,\s*7 +** vmul\.vx\s+v[0-9]+,\s*v[0-9]+,\s*[a-x0-9]+ +** vadd\.vi\s+v[0-9]+,\s*v[0-9]+,\s*3 +** vs1r\.v\s+v[0-9]+,\s*0\([a-x0-9]+\) +** ret +*/ +void +foo2 (int16_t *__restrict out) +{ + vnx16i v + = {3, 3 + 7 * 1, 3 + 7 * 2, 3 + 7 * 3, 3 + 7 * 4, 3 + 7 * 5, + 3 + 7 * 6, 3 + 7 * 7, 3 + 7 * 8, 3 + 7 * 9, 3 + 7 * 10, 3 + 7 * 11, + 3 + 7 * 12, 3 + 7 * 13, 3 + 7 * 14, 3 + 7 * 15}; + *(vnx16i *) out = v; +} + +/* +** foo3: +** vsetivli\s+zero,\s*16,\s*e16,\s*m1,\s*t[au],\s*m[au] +** vid\.v\s+v[0-9]+ +** vs1r\.v\s+v[0-9]+,\s*0\([a-x0-9]+\) +** ret +*/ +void +foo3 (int16_t *__restrict out) +{ + vnx16i v + = {0, 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15}; + *(vnx16i *) out = v; +} + +/* +** foo4: +** vsetivli\s+zero,\s*16,\s*e16,\s*m1,\s*t[au],\s*m[au] +** vid\.v\s+v[0-9]+ +** li\s+[a-x0-9]+,\s*6 +** vmul\.vx\s+v[0-9]+,\s*v[0-9]+,\s*[a-x0-9]+ +** vs1r\.v\s+v[0-9]+,\s*0\([a-x0-9]+\) +** ret +*/ +void +foo4 (int16_t *__restrict out) +{ + vnx16i v + = {0*6, 1*6,2*6,3*6,4*6,5*6,6*6,7*6,8*6,9*6,10*6,11*6,12*6,13*6,14*6,15*6}; + *(vnx16i *) out = v; +} + +/* +** foo5: +** vsetivli\s+zero,\s*16,\s*e16,\s*m1,\s*t[au],\s*m[au] +** vid\.v\s+v[0-9]+ +** vadd\.vi\s+v[0-9]+,\s*v[0-9]+,\s*-16 +** vs1r\.v\s+v[0-9]+,\s*0\([a-x0-9]+\) +** ret +*/ +void +foo5 (int16_t *__restrict out) +{ + vnx16i v + = {0-16, 1-16,2-16,3-16,4-16,5-16,6-16,7-16,8-16,9-16,10-16,11-16,12-16,13-16,14-16,15-16}; + *(vnx16i *) out = v; +} diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls-vlmax/vec_extract-1u.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls-vlmax/vec_extract-1u.c new file mode 100644 index 000000000000..98f6c7dc17eb --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls-vlmax/vec_extract-1u.c @@ -0,0 +1,63 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-march=rv64gcv -mabi=lp64d -Wno-pedantic -Wno-psabi" } */ + +#include + +typedef uint64_t vnx2di __attribute__((vector_size (16))); +typedef uint32_t vnx4si __attribute__((vector_size (16))); +typedef uint16_t vnx8hi __attribute__((vector_size (16))); +typedef uint8_t vnx16qi __attribute__((vector_size (16))); + +#define VEC_EXTRACT(S,V,IDX) \ + S \ + __attribute__((noipa)) \ + vec_extract_##V##_##IDX (V v) \ + { \ + return v[IDX]; \ + } + +#define VEC_EXTRACT_VAR1(S,V) \ + S \ + __attribute__((noipa)) \ + vec_extract_var_##V (V v, int8_t idx) \ + { \ + return v[idx]; \ + } + +#define TEST_ALL1(T) \ + T (uint64_t, vnx2di, 0) \ + T (uint64_t, vnx2di, 1) \ + T (uint32_t, vnx4si, 0) \ + T (uint32_t, vnx4si, 1) \ + T (uint32_t, vnx4si, 3) \ + T (uint16_t, vnx8hi, 0) \ + T (uint16_t, vnx8hi, 2) \ + T (uint16_t, vnx8hi, 6) \ + T (uint8_t, vnx16qi, 0) \ + T (uint8_t, vnx16qi, 1) \ + T (uint8_t, vnx16qi, 7) \ + T (uint8_t, vnx16qi, 11) \ + T (uint8_t, vnx16qi, 15) \ + +#define TEST_ALL_VAR1(T) \ + T (uint64_t, vnx2di) \ + T (uint32_t, vnx4si) \ + T (uint16_t, vnx8hi) \ + T (uint8_t, vnx16qi) \ + +TEST_ALL1 (VEC_EXTRACT) +TEST_ALL_VAR1 (VEC_EXTRACT_VAR1) + +/* { dg-final { scan-assembler-times {vset[i]*vli\s+[a-z0-9,]+,\s*e8,\s*m1,\s*ta,\s*ma} 6 } } */ +/* { dg-final { scan-assembler-times {vset[i]*vli\s+[a-z0-9,]+,\s*e16,\s*m1,\s*ta,\s*ma} 4 } } */ +/* { dg-final { scan-assembler-times {vset[i]*vli\s+[a-z0-9,]+,\s*e32,\s*m1,\s*ta,\s*ma} 4 } } */ +/* { dg-final { scan-assembler-times {vset[i]*vli\s+[a-z0-9,]+,\s*e64,\s*m1,\s*ta,\s*ma} 3 } } */ + +/* { dg-final { scan-assembler-times {\tvslidedown.vi} 9 } } */ +/* { dg-final { scan-assembler-times {\tvslidedown.vx} 4 } } */ + +/* { dg-final { scan-assembler-times {\tvmv.x.s} 17 } } */ + +/* { dg-final { scan-assembler-times {\tandi\ta0,a0,0xff} 6 } } */ +/* { dg-final { scan-assembler-times {\tslli\ta0,a0,48} 4 } } */ +/* { dg-final { scan-assembler-times {\tsrli\ta0,a0,48} 4 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls-vlmax/vec_extract-2u.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls-vlmax/vec_extract-2u.c new file mode 100644 index 000000000000..9223bc56f911 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls-vlmax/vec_extract-2u.c @@ -0,0 +1,69 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-march=rv64gcv -mabi=lp64d -Wno-pedantic -Wno-psabi" } */ + +#include + +typedef uint64_t vnx4di __attribute__((vector_size (32))); +typedef uint32_t vnx8si __attribute__((vector_size (32))); +typedef uint16_t vnx16hi __attribute__((vector_size (32))); +typedef uint8_t vnx32qi __attribute__((vector_size (32))); + +#define VEC_EXTRACT(S,V,IDX) \ + S \ + __attribute__((noipa)) \ + vec_extract_##V##_##IDX (V v) \ + { \ + return v[IDX]; \ + } + +#define VEC_EXTRACT_VAR2(S,V) \ + S \ + __attribute__((noipa)) \ + vec_extract_var_##V (V v, int16_t idx) \ + { \ + return v[idx]; \ + } + +#define TEST_ALL2(T) \ + T (uint64_t, vnx4di, 0) \ + T (uint64_t, vnx4di, 1) \ + T (uint64_t, vnx4di, 2) \ + T (uint64_t, vnx4di, 3) \ + T (uint32_t, vnx8si, 0) \ + T (uint32_t, vnx8si, 1) \ + T (uint32_t, vnx8si, 3) \ + T (uint32_t, vnx8si, 4) \ + T (uint32_t, vnx8si, 7) \ + T (uint16_t, vnx16hi, 0) \ + T (uint16_t, vnx16hi, 1) \ + T (uint16_t, vnx16hi, 7) \ + T (uint16_t, vnx16hi, 8) \ + T (uint16_t, vnx16hi, 15) \ + T (uint8_t, vnx32qi, 0) \ + T (uint8_t, vnx32qi, 1) \ + T (uint8_t, vnx32qi, 15) \ + T (uint8_t, vnx32qi, 16) \ + T (uint8_t, vnx32qi, 31) \ + +#define TEST_ALL_VAR2(T) \ + T (uint64_t, vnx4di) \ + T (uint32_t, vnx8si) \ + T (uint16_t, vnx16hi) \ + T (uint8_t, vnx32qi) \ + +TEST_ALL2 (VEC_EXTRACT) +TEST_ALL_VAR2 (VEC_EXTRACT_VAR2) + +/* { dg-final { scan-assembler-times {vset[i]*vli\s+[a-z0-9,]+,\s*e8,\s*m2,\s*ta,\s*ma} 6 } } */ +/* { dg-final { scan-assembler-times {vset[i]*vli\s+[a-z0-9,]+,\s*e16,\s*m2,\s*ta,\s*ma} 6 } } */ +/* { dg-final { scan-assembler-times {vset[i]*vli\s+[a-z0-9,]+,\s*e32,\s*m2,\s*ta,\s*ma} 6 } } */ +/* { dg-final { scan-assembler-times {vset[i]*vli\s+[a-z0-9,]+,\s*e64,\s*m2,\s*ta,\s*ma} 5 } } */ + +/* { dg-final { scan-assembler-times {\tvslidedown.vi} 15 } } */ +/* { dg-final { scan-assembler-times {\tvslidedown.vx} 4 } } */ + +/* { dg-final { scan-assembler-times {\tvmv.x.s} 23 } } */ + +/* { dg-final { scan-assembler-times {\tandi\ta0,a0,0xff} 6 } } */ +/* { dg-final { scan-assembler-times {\tslli\ta0,a0,48} 6 } } */ +/* { dg-final { scan-assembler-times {\tsrli\ta0,a0,48} 6 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls-vlmax/vec_extract-3u.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls-vlmax/vec_extract-3u.c new file mode 100644 index 000000000000..c4047b6eba5f --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls-vlmax/vec_extract-3u.c @@ -0,0 +1,69 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-march=rv64gcv -mabi=lp64d -Wno-pedantic -Wno-psabi" } */ + +#include + +typedef uint64_t vnx8di __attribute__((vector_size (64))); +typedef uint32_t vnx16si __attribute__((vector_size (64))); +typedef uint16_t vnx32hi __attribute__((vector_size (64))); +typedef uint8_t vnx64qi __attribute__((vector_size (64))); + +#define VEC_EXTRACT(S,V,IDX) \ + S \ + __attribute__((noipa)) \ + vec_extract_##V##_##IDX (V v) \ + { \ + return v[IDX]; \ + } + +#define VEC_EXTRACT_VAR3(S,V) \ + S \ + __attribute__((noipa)) \ + vec_extract_var_##V (V v, int32_t idx) \ + { \ + return v[idx]; \ + } + +#define TEST_ALL3(T) \ + T (uint64_t, vnx8di, 0) \ + T (uint64_t, vnx8di, 2) \ + T (uint64_t, vnx8di, 4) \ + T (uint64_t, vnx8di, 6) \ + T (uint32_t, vnx16si, 0) \ + T (uint32_t, vnx16si, 2) \ + T (uint32_t, vnx16si, 6) \ + T (uint32_t, vnx16si, 8) \ + T (uint32_t, vnx16si, 14) \ + T (uint16_t, vnx32hi, 0) \ + T (uint16_t, vnx32hi, 2) \ + T (uint16_t, vnx32hi, 14) \ + T (uint16_t, vnx32hi, 16) \ + T (uint16_t, vnx32hi, 30) \ + T (uint8_t, vnx64qi, 0) \ + T (uint8_t, vnx64qi, 2) \ + T (uint8_t, vnx64qi, 30) \ + T (uint8_t, vnx64qi, 32) \ + T (uint8_t, vnx64qi, 63) \ + +#define TEST_ALL_VAR3(T) \ + T (uint64_t, vnx8di) \ + T (uint32_t, vnx16si) \ + T (uint16_t, vnx32hi) \ + T (uint8_t, vnx64qi) \ + +TEST_ALL3 (VEC_EXTRACT) +TEST_ALL_VAR3 (VEC_EXTRACT_VAR3) + +/* { dg-final { scan-assembler-times {vset[i]*vli\s+[a-z0-9,]+,\s*e8,\s*m4,\s*ta,\s*ma} 6 } } */ +/* { dg-final { scan-assembler-times {vset[i]*vli\s+[a-z0-9,]+,\s*e16,\s*m4,\s*ta,\s*ma} 6 } } */ +/* { dg-final { scan-assembler-times {vset[i]*vli\s+[a-z0-9,]+,\s*e32,\s*m4,\s*ta,\s*ma} 6 } } */ +/* { dg-final { scan-assembler-times {vset[i]*vli\s+[a-z0-9,]+,\s*e64,\s*m4,\s*ta,\s*ma} 5 } } */ + +/* { dg-final { scan-assembler-times {\tvslidedown.vi} 13 } } */ +/* { dg-final { scan-assembler-times {\tvslidedown.vx} 6 } } */ + +/* { dg-final { scan-assembler-times {\tvmv.x.s} 23 } } */ + +/* { dg-final { scan-assembler-times {\tandi\ta0,a0,0xff} 6 } } */ +/* { dg-final { scan-assembler-times {\tslli\ta0,a0,48} 6 } } */ +/* { dg-final { scan-assembler-times {\tsrli\ta0,a0,48} 6 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls-vlmax/vec_extract-4u.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls-vlmax/vec_extract-4u.c new file mode 100644 index 000000000000..a276700cd94b --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls-vlmax/vec_extract-4u.c @@ -0,0 +1,70 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-march=rv64gcv -mabi=lp64d -Wno-pedantic -Wno-psabi" } */ + +#include + +typedef uint64_t vnx16di __attribute__((vector_size (128))); +typedef uint32_t vnx32si __attribute__((vector_size (128))); +typedef uint16_t vnx64hi __attribute__((vector_size (128))); +typedef uint8_t vnx128qi __attribute__((vector_size (128))); + +#define VEC_EXTRACT(S,V,IDX) \ + S \ + __attribute__((noipa)) \ + vec_extract_##V##_##IDX (V v) \ + { \ + return v[IDX]; \ + } + +#define VEC_EXTRACT_VAR4(S,V) \ + S \ + __attribute__((noipa)) \ + vec_extract_var_##V (V v, int64_t idx) \ + { \ + return v[idx]; \ + } + +#define TEST_ALL4(T) \ + T (uint64_t, vnx16di, 0) \ + T (uint64_t, vnx16di, 4) \ + T (uint64_t, vnx16di, 8) \ + T (uint64_t, vnx16di, 12) \ + T (uint32_t, vnx32si, 0) \ + T (uint32_t, vnx32si, 4) \ + T (uint32_t, vnx32si, 12) \ + T (uint32_t, vnx32si, 16) \ + T (uint32_t, vnx32si, 28) \ + T (uint16_t, vnx64hi, 0) \ + T (uint16_t, vnx64hi, 4) \ + T (uint16_t, vnx64hi, 28) \ + T (uint16_t, vnx64hi, 32) \ + T (uint16_t, vnx64hi, 60) \ + T (uint8_t, vnx128qi, 0) \ + T (uint8_t, vnx128qi, 4) \ + T (uint8_t, vnx128qi, 30) \ + T (uint8_t, vnx128qi, 60) \ + T (uint8_t, vnx128qi, 64) \ + T (uint8_t, vnx128qi, 127) \ + +#define TEST_ALL_VAR4(T) \ + T (uint64_t, vnx16di) \ + T (uint32_t, vnx32si) \ + T (uint16_t, vnx64hi) \ + T (uint8_t, vnx128qi) \ + +TEST_ALL4 (VEC_EXTRACT) +TEST_ALL_VAR4 (VEC_EXTRACT_VAR4) + +/* { dg-final { scan-assembler-times {vset[i]*vli\s+[a-z0-9,]+,\s*e8,\s*m8,\s*ta,\s*ma} 7 } } */ +/* { dg-final { scan-assembler-times {vset[i]*vli\s+[a-z0-9,]+,\s*e16,\s*m8,\s*ta,\s*ma} 6 } } */ +/* { dg-final { scan-assembler-times {vset[i]*vli\s+[a-z0-9,]+,\s*e32,\s*m8,\s*ta,\s*ma} 6 } } */ +/* { dg-final { scan-assembler-times {vset[i]*vli\s+[a-z0-9,]+,\s*e64,\s*m8,\s*ta,\s*ma} 5 } } */ + +/* { dg-final { scan-assembler-times {\tvslidedown.vi} 11 } } */ +/* { dg-final { scan-assembler-times {\tvslidedown.vx} 9 } } */ + +/* { dg-final { scan-assembler-times {\tvmv.x.s} 24 } } */ + +/* { dg-final { scan-assembler-times {\tandi\ta0,a0,0xff} 7 } } */ +/* { dg-final { scan-assembler-times {\tslli\ta0,a0,48} 6 } } */ +/* { dg-final { scan-assembler-times {\tsrli\ta0,a0,48} 6 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls-vlmax/vec_extract-runu.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls-vlmax/vec_extract-runu.c new file mode 100644 index 000000000000..924e40c9dbb8 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls-vlmax/vec_extract-runu.c @@ -0,0 +1,137 @@ +/* { dg-do run { target { riscv_vector } } } */ +/* { dg-additional-options "-std=c99 -Wno-pedantic -Wno-psabi" } */ + +#include +#include + +#include "vec_extract-1u.c" +#include "vec_extract-2u.c" +#include "vec_extract-3u.c" +#include "vec_extract-4u.c" + +#define CHECK(S, V, IDX) \ + __attribute__ ((noipa, optimize ("0"))) void check_##V##_##IDX () \ + { \ + V v; \ + for (int i = 0; i < sizeof (V) / sizeof (S); i++) \ + v[i] = (S) (INT_MAX - i); \ + S res = vec_extract_##V##_##IDX (v); \ + assert (res == (S) (INT_MAX - IDX)); \ + } + +#define CHECK_VAR(S, V) \ + __attribute__ ((noipa, optimize ("0"))) void check_var_##V (int32_t idx) \ + { \ + V v; \ + for (int i = 0; i < sizeof (V) / sizeof (S); i++) \ + v[i] = (S) (INT_MAX - i); \ + S res = vec_extract_var_##V (v, idx); \ + assert (res == (S) (INT_MAX - idx)); \ + } + +#define RUN(S, V, IDX) check_##V##_##IDX (); + +#define RUN_VAR(S, V) \ + for (int i = 0; i < sizeof (V) / sizeof (S); i++) \ + check_var_##V (i); + +#define RUN_ALL(T) \ + T (uint64_t, vnx2di, 0) \ + T (uint64_t, vnx2di, 1) \ + T (uint32_t, vnx4si, 0) \ + T (uint32_t, vnx4si, 1) \ + T (uint32_t, vnx4si, 3) \ + T (uint16_t, vnx8hi, 0) \ + T (uint16_t, vnx8hi, 2) \ + T (uint16_t, vnx8hi, 6) \ + T (uint8_t, vnx16qi, 0) \ + T (uint8_t, vnx16qi, 1) \ + T (uint8_t, vnx16qi, 7) \ + T (uint8_t, vnx16qi, 11) \ + T (uint8_t, vnx16qi, 15) \ + T (uint64_t, vnx4di, 0) \ + T (uint64_t, vnx4di, 1) \ + T (uint64_t, vnx4di, 2) \ + T (uint64_t, vnx4di, 3) \ + T (uint32_t, vnx8si, 0) \ + T (uint32_t, vnx8si, 1) \ + T (uint32_t, vnx8si, 3) \ + T (uint32_t, vnx8si, 4) \ + T (uint32_t, vnx8si, 7) \ + T (uint16_t, vnx16hi, 0) \ + T (uint16_t, vnx16hi, 1) \ + T (uint16_t, vnx16hi, 7) \ + T (uint16_t, vnx16hi, 8) \ + T (uint16_t, vnx16hi, 15) \ + T (uint8_t, vnx32qi, 0) \ + T (uint8_t, vnx32qi, 1) \ + T (uint8_t, vnx32qi, 15) \ + T (uint8_t, vnx32qi, 16) \ + T (uint8_t, vnx32qi, 31) \ + T (uint64_t, vnx8di, 0) \ + T (uint64_t, vnx8di, 2) \ + T (uint64_t, vnx8di, 4) \ + T (uint64_t, vnx8di, 6) \ + T (uint32_t, vnx16si, 0) \ + T (uint32_t, vnx16si, 2) \ + T (uint32_t, vnx16si, 6) \ + T (uint32_t, vnx16si, 8) \ + T (uint32_t, vnx16si, 14) \ + T (uint16_t, vnx32hi, 0) \ + T (uint16_t, vnx32hi, 2) \ + T (uint16_t, vnx32hi, 14) \ + T (uint16_t, vnx32hi, 16) \ + T (uint16_t, vnx32hi, 30) \ + T (uint8_t, vnx64qi, 0) \ + T (uint8_t, vnx64qi, 2) \ + T (uint8_t, vnx64qi, 30) \ + T (uint8_t, vnx64qi, 32) \ + T (uint8_t, vnx64qi, 63) \ + T (uint64_t, vnx16di, 0) \ + T (uint64_t, vnx16di, 4) \ + T (uint64_t, vnx16di, 8) \ + T (uint64_t, vnx16di, 12) \ + T (uint32_t, vnx32si, 0) \ + T (uint32_t, vnx32si, 4) \ + T (uint32_t, vnx32si, 12) \ + T (uint32_t, vnx32si, 16) \ + T (uint32_t, vnx32si, 28) \ + T (uint16_t, vnx64hi, 0) \ + T (uint16_t, vnx64hi, 4) \ + T (uint16_t, vnx64hi, 28) \ + T (uint16_t, vnx64hi, 32) \ + T (uint16_t, vnx64hi, 60) \ + T (uint8_t, vnx128qi, 0) \ + T (uint8_t, vnx128qi, 4) \ + T (uint8_t, vnx128qi, 30) \ + T (uint8_t, vnx128qi, 60) \ + T (uint8_t, vnx128qi, 64) \ + T (uint8_t, vnx128qi, 127) + +#define RUN_ALL_VAR(T) \ + T (uint64_t, vnx2di) \ + T (uint32_t, vnx4si) \ + T (uint16_t, vnx8hi) \ + T (uint8_t, vnx16qi) \ + T (uint64_t, vnx4di) \ + T (uint32_t, vnx8si) \ + T (uint16_t, vnx16hi) \ + T (uint8_t, vnx32qi) \ + T (uint64_t, vnx8di) \ + T (uint32_t, vnx16si) \ + T (uint16_t, vnx32hi) \ + T (uint8_t, vnx64qi) \ + T (uint64_t, vnx16di) \ + T (uint32_t, vnx32si) \ + T (uint16_t, vnx64hi) \ + T (uint8_t, vnx128qi) + +RUN_ALL (CHECK) +RUN_ALL_VAR (CHECK_VAR) + +int +main () +{ + RUN_ALL (RUN); + RUN_ALL_VAR (RUN_VAR); +} diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/and-1.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/and-1.c new file mode 100644 index 000000000000..15ffdf68de7b --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/and-1.c @@ -0,0 +1,57 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gcv_zvfh_zvl4096b -mabi=lp64d -O3 -fno-schedule-insns -fno-schedule-insns2 --param=riscv-autovec-lmul=m8" } */ + +#include "def.h" + +DEF_OP_VV (and, 1, int8_t, &) +DEF_OP_VV (and, 2, int8_t, &) +DEF_OP_VV (and, 4, int8_t, &) +DEF_OP_VV (and, 8, int8_t, &) +DEF_OP_VV (and, 16, int8_t, &) +DEF_OP_VV (and, 32, int8_t, &) +DEF_OP_VV (and, 64, int8_t, &) +DEF_OP_VV (and, 128, int8_t, &) +DEF_OP_VV (and, 256, int8_t, &) +DEF_OP_VV (and, 512, int8_t, &) +DEF_OP_VV (and, 1024, int8_t, &) +DEF_OP_VV (and, 2048, int8_t, &) +DEF_OP_VV (and, 4096, int8_t, &) + +DEF_OP_VV (and, 1, int16_t, &) +DEF_OP_VV (and, 2, int16_t, &) +DEF_OP_VV (and, 4, int16_t, &) +DEF_OP_VV (and, 8, int16_t, &) +DEF_OP_VV (and, 16, int16_t, &) +DEF_OP_VV (and, 32, int16_t, &) +DEF_OP_VV (and, 64, int16_t, &) +DEF_OP_VV (and, 128, int16_t, &) +DEF_OP_VV (and, 256, int16_t, &) +DEF_OP_VV (and, 512, int16_t, &) +DEF_OP_VV (and, 1024, int16_t, &) +DEF_OP_VV (and, 2048, int16_t, &) + +DEF_OP_VV (and, 1, int32_t, &) +DEF_OP_VV (and, 2, int32_t, &) +DEF_OP_VV (and, 4, int32_t, &) +DEF_OP_VV (and, 8, int32_t, &) +DEF_OP_VV (and, 16, int32_t, &) +DEF_OP_VV (and, 32, int32_t, &) +DEF_OP_VV (and, 64, int32_t, &) +DEF_OP_VV (and, 128, int32_t, &) +DEF_OP_VV (and, 256, int32_t, &) +DEF_OP_VV (and, 512, int32_t, &) +DEF_OP_VV (and, 1024, int32_t, &) + +DEF_OP_VV (and, 1, int64_t, &) +DEF_OP_VV (and, 2, int64_t, &) +DEF_OP_VV (and, 4, int64_t, &) +DEF_OP_VV (and, 8, int64_t, &) +DEF_OP_VV (and, 16, int64_t, &) +DEF_OP_VV (and, 32, int64_t, &) +DEF_OP_VV (and, 64, int64_t, &) +DEF_OP_VV (and, 128, int64_t, &) +DEF_OP_VV (and, 256, int64_t, &) +DEF_OP_VV (and, 512, int64_t, &) + +/* { dg-final { scan-assembler-times {vand\.vv\s+v[0-9]+,\s*v[0-9]+,\s*v[0-9]+} 42 } } */ +/* { dg-final { scan-assembler-not {csrr} } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/and-2.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/and-2.c new file mode 100644 index 000000000000..d0e68b1b47c3 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/and-2.c @@ -0,0 +1,57 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gcv_zvfh_zvl4096b -mabi=lp64d -O3 -fno-schedule-insns -fno-schedule-insns2 --param=riscv-autovec-lmul=m8" } */ + +#include "def.h" + +DEF_OP_VI_M16 (and, 1, int8_t, &) +DEF_OP_VI_M16 (and, 2, int8_t, &) +DEF_OP_VI_M16 (and, 4, int8_t, &) +DEF_OP_VI_M16 (and, 8, int8_t, &) +DEF_OP_VI_M16 (and, 16, int8_t, &) +DEF_OP_VI_M16 (and, 32, int8_t, &) +DEF_OP_VI_M16 (and, 64, int8_t, &) +DEF_OP_VI_M16 (and, 128, int8_t, &) +DEF_OP_VI_M16 (and, 256, int8_t, &) +DEF_OP_VI_M16 (and, 512, int8_t, &) +DEF_OP_VI_M16 (and, 1024, int8_t, &) +DEF_OP_VI_M16 (and, 2048, int8_t, &) +DEF_OP_VI_M16 (and, 4096, int8_t, &) + +DEF_OP_VI_M16 (and, 1, int16_t, &) +DEF_OP_VI_M16 (and, 2, int16_t, &) +DEF_OP_VI_M16 (and, 4, int16_t, &) +DEF_OP_VI_M16 (and, 8, int16_t, &) +DEF_OP_VI_M16 (and, 16, int16_t, &) +DEF_OP_VI_M16 (and, 32, int16_t, &) +DEF_OP_VI_M16 (and, 64, int16_t, &) +DEF_OP_VI_M16 (and, 128, int16_t, &) +DEF_OP_VI_M16 (and, 256, int16_t, &) +DEF_OP_VI_M16 (and, 512, int16_t, &) +DEF_OP_VI_M16 (and, 1024, int16_t, &) +DEF_OP_VI_M16 (and, 2048, int16_t, &) + +DEF_OP_VI_M16 (and, 1, int32_t, &) +DEF_OP_VI_M16 (and, 2, int32_t, &) +DEF_OP_VI_M16 (and, 4, int32_t, &) +DEF_OP_VI_M16 (and, 8, int32_t, &) +DEF_OP_VI_M16 (and, 16, int32_t, &) +DEF_OP_VI_M16 (and, 32, int32_t, &) +DEF_OP_VI_M16 (and, 64, int32_t, &) +DEF_OP_VI_M16 (and, 128, int32_t, &) +DEF_OP_VI_M16 (and, 256, int32_t, &) +DEF_OP_VI_M16 (and, 512, int32_t, &) +DEF_OP_VI_M16 (and, 1024, int32_t, &) + +DEF_OP_VI_M16 (and, 1, int64_t, &) +DEF_OP_VI_M16 (and, 2, int64_t, &) +DEF_OP_VI_M16 (and, 4, int64_t, &) +DEF_OP_VI_M16 (and, 8, int64_t, &) +DEF_OP_VI_M16 (and, 16, int64_t, &) +DEF_OP_VI_M16 (and, 32, int64_t, &) +DEF_OP_VI_M16 (and, 64, int64_t, &) +DEF_OP_VI_M16 (and, 128, int64_t, &) +DEF_OP_VI_M16 (and, 256, int64_t, &) +DEF_OP_VI_M16 (and, 512, int64_t, &) + +/* { dg-final { scan-assembler-times {vand\.vi\s+v[0-9]+,\s*v[0-9]+,\s*-16} 42 } } */ +/* { dg-final { scan-assembler-not {csrr} } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/and-3.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/and-3.c new file mode 100644 index 000000000000..5b697dd88185 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/and-3.c @@ -0,0 +1,57 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gcv_zvfh_zvl4096b -mabi=lp64d -O3 -fno-schedule-insns -fno-schedule-insns2 --param=riscv-autovec-lmul=m8" } */ + +#include "def.h" + +DEF_OP_VI_15 (and, 1, int8_t, &) +DEF_OP_VI_15 (and, 2, int8_t, &) +DEF_OP_VI_15 (and, 4, int8_t, &) +DEF_OP_VI_15 (and, 8, int8_t, &) +DEF_OP_VI_15 (and, 16, int8_t, &) +DEF_OP_VI_15 (and, 32, int8_t, &) +DEF_OP_VI_15 (and, 64, int8_t, &) +DEF_OP_VI_15 (and, 128, int8_t, &) +DEF_OP_VI_15 (and, 256, int8_t, &) +DEF_OP_VI_15 (and, 512, int8_t, &) +DEF_OP_VI_15 (and, 1024, int8_t, &) +DEF_OP_VI_15 (and, 2048, int8_t, &) +DEF_OP_VI_15 (and, 4096, int8_t, &) + +DEF_OP_VI_15 (and, 1, int16_t, &) +DEF_OP_VI_15 (and, 2, int16_t, &) +DEF_OP_VI_15 (and, 4, int16_t, &) +DEF_OP_VI_15 (and, 8, int16_t, &) +DEF_OP_VI_15 (and, 16, int16_t, &) +DEF_OP_VI_15 (and, 32, int16_t, &) +DEF_OP_VI_15 (and, 64, int16_t, &) +DEF_OP_VI_15 (and, 128, int16_t, &) +DEF_OP_VI_15 (and, 256, int16_t, &) +DEF_OP_VI_15 (and, 512, int16_t, &) +DEF_OP_VI_15 (and, 1024, int16_t, &) +DEF_OP_VI_15 (and, 2048, int16_t, &) + +DEF_OP_VI_15 (and, 1, int32_t, &) +DEF_OP_VI_15 (and, 2, int32_t, &) +DEF_OP_VI_15 (and, 4, int32_t, &) +DEF_OP_VI_15 (and, 8, int32_t, &) +DEF_OP_VI_15 (and, 16, int32_t, &) +DEF_OP_VI_15 (and, 32, int32_t, &) +DEF_OP_VI_15 (and, 64, int32_t, &) +DEF_OP_VI_15 (and, 128, int32_t, &) +DEF_OP_VI_15 (and, 256, int32_t, &) +DEF_OP_VI_15 (and, 512, int32_t, &) +DEF_OP_VI_15 (and, 1024, int32_t, &) + +DEF_OP_VI_15 (and, 1, int64_t, &) +DEF_OP_VI_15 (and, 2, int64_t, &) +DEF_OP_VI_15 (and, 4, int64_t, &) +DEF_OP_VI_15 (and, 8, int64_t, &) +DEF_OP_VI_15 (and, 16, int64_t, &) +DEF_OP_VI_15 (and, 32, int64_t, &) +DEF_OP_VI_15 (and, 64, int64_t, &) +DEF_OP_VI_15 (and, 128, int64_t, &) +DEF_OP_VI_15 (and, 256, int64_t, &) +DEF_OP_VI_15 (and, 512, int64_t, &) + +/* { dg-final { scan-assembler-times {vand\.vi\s+v[0-9]+,\s*v[0-9]+,\s*15} 42 } } */ +/* { dg-final { scan-assembler-not {csrr} } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/const-1.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/const-1.c new file mode 100644 index 000000000000..f3217e6063e8 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/const-1.c @@ -0,0 +1,40 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gcv_zvfh_zvl4096b -mabi=lp64d -O3 -fno-schedule-insns -fno-schedule-insns2 --param=riscv-autovec-lmul=m8 -fno-builtin" } */ + +#include "def.h" + +DEF_CONST (int16_t, -16, 2) +DEF_CONST (int16_t, -16, 4) +DEF_CONST (int16_t, -16, 8) +DEF_CONST (int16_t, -16, 16) +DEF_CONST (int16_t, -16, 32) +DEF_CONST (int16_t, -16, 64) +DEF_CONST (int16_t, -16, 128) +DEF_CONST (int16_t, -16, 256) +DEF_CONST (int16_t, -16, 512) +DEF_CONST (int16_t, -16, 1024) +DEF_CONST (int16_t, -16, 2048) + +DEF_CONST (int32_t, -16, 2) +DEF_CONST (int32_t, -16, 4) +DEF_CONST (int32_t, -16, 8) +DEF_CONST (int32_t, -16, 16) +DEF_CONST (int32_t, -16, 32) +DEF_CONST (int32_t, -16, 64) +DEF_CONST (int32_t, -16, 128) +DEF_CONST (int32_t, -16, 256) +DEF_CONST (int32_t, -16, 512) +DEF_CONST (int32_t, -16, 1024) + +DEF_CONST (int64_t, -16, 2) +DEF_CONST (int64_t, -16, 4) +DEF_CONST (int64_t, -16, 8) +DEF_CONST (int64_t, -16, 16) +DEF_CONST (int64_t, -16, 32) +DEF_CONST (int64_t, -16, 64) +DEF_CONST (int64_t, -16, 128) +DEF_CONST (int64_t, -16, 256) +DEF_CONST (int64_t, -16, 512) + +/* { dg-final { scan-assembler-times {vmv\.v\.i\s+v[0-9]+,\s*-16} 30 } } */ +/* { dg-final { scan-assembler-not {csrr} } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/const-2.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/const-2.c new file mode 100644 index 000000000000..99255ec5aa69 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/const-2.c @@ -0,0 +1,40 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gcv_zvfh_zvl4096b -mabi=lp64d -O3 -fno-schedule-insns -fno-schedule-insns2 --param=riscv-autovec-lmul=m8 -fno-builtin" } */ + +#include "def.h" + +DEF_CONST (int16_t, 15, 2) +DEF_CONST (int16_t, 15, 4) +DEF_CONST (int16_t, 15, 8) +DEF_CONST (int16_t, 15, 16) +DEF_CONST (int16_t, 15, 32) +DEF_CONST (int16_t, 15, 64) +DEF_CONST (int16_t, 15, 128) +DEF_CONST (int16_t, 15, 256) +DEF_CONST (int16_t, 15, 512) +DEF_CONST (int16_t, 15, 1024) +DEF_CONST (int16_t, 15, 2048) + +DEF_CONST (int32_t, 15, 2) +DEF_CONST (int32_t, 15, 4) +DEF_CONST (int32_t, 15, 8) +DEF_CONST (int32_t, 15, 16) +DEF_CONST (int32_t, 15, 32) +DEF_CONST (int32_t, 15, 64) +DEF_CONST (int32_t, 15, 128) +DEF_CONST (int32_t, 15, 256) +DEF_CONST (int32_t, 15, 512) +DEF_CONST (int32_t, 15, 1024) + +DEF_CONST (int64_t, 15, 2) +DEF_CONST (int64_t, 15, 4) +DEF_CONST (int64_t, 15, 8) +DEF_CONST (int64_t, 15, 16) +DEF_CONST (int64_t, 15, 32) +DEF_CONST (int64_t, 15, 64) +DEF_CONST (int64_t, 15, 128) +DEF_CONST (int64_t, 15, 256) +DEF_CONST (int64_t, 15, 512) + +/* { dg-final { scan-assembler-times {vmv\.v\.i\s+v[0-9]+,\s*15} 30 } } */ +/* { dg-final { scan-assembler-not {csrr} } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/const-3.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/const-3.c new file mode 100644 index 000000000000..a9c8ae34ba77 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/const-3.c @@ -0,0 +1,40 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gcv_zvfh_zvl4096b -mabi=lp64d -O3 -fno-schedule-insns -fno-schedule-insns2 --param=riscv-autovec-lmul=m8 -fno-builtin" } */ + +#include "def.h" + +DEF_CONST (_Float16, 0, 2) +DEF_CONST (_Float16, 0, 4) +DEF_CONST (_Float16, 0, 8) +DEF_CONST (_Float16, 0, 16) +DEF_CONST (_Float16, 0, 32) +DEF_CONST (_Float16, 0, 64) +DEF_CONST (_Float16, 0, 128) +DEF_CONST (_Float16, 0, 256) +DEF_CONST (_Float16, 0, 512) +DEF_CONST (_Float16, 0, 1024) +DEF_CONST (_Float16, 0, 2048) + +DEF_CONST (float, 0, 2) +DEF_CONST (float, 0, 4) +DEF_CONST (float, 0, 8) +DEF_CONST (float, 0, 16) +DEF_CONST (float, 0, 32) +DEF_CONST (float, 0, 64) +DEF_CONST (float, 0, 128) +DEF_CONST (float, 0, 256) +DEF_CONST (float, 0, 512) +DEF_CONST (float, 0, 1024) + +DEF_CONST (double, 0, 2) +DEF_CONST (double, 0, 4) +DEF_CONST (double, 0, 8) +DEF_CONST (double, 0, 16) +DEF_CONST (double, 0, 32) +DEF_CONST (double, 0, 64) +DEF_CONST (double, 0, 128) +DEF_CONST (double, 0, 256) +DEF_CONST (double, 0, 512) + +/* { dg-final { scan-assembler-times {vmv\.v\.i\s+v[0-9]+,\s*0} 30 } } */ +/* { dg-final { scan-assembler-not {csrr} } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/const-4.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/const-4.c new file mode 100644 index 000000000000..50d1515aff6d --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/const-4.c @@ -0,0 +1,40 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gcv_zvfh_zvl4096b -mabi=lp64d -O3 -fno-schedule-insns -fno-schedule-insns2 --param=riscv-autovec-lmul=m8 -fno-builtin" } */ + +#include "def.h" + +DEF_CONST (_Float16, 8.88, 2) +DEF_CONST (_Float16, 8.88, 4) +DEF_CONST (_Float16, 8.88, 8) +DEF_CONST (_Float16, 8.88, 16) +DEF_CONST (_Float16, 8.88, 32) +DEF_CONST (_Float16, 8.88, 64) +DEF_CONST (_Float16, 8.88, 128) +DEF_CONST (_Float16, 8.88, 256) +DEF_CONST (_Float16, 8.88, 512) +DEF_CONST (_Float16, 8.88, 1024) +DEF_CONST (_Float16, 8.88, 2048) + +DEF_CONST (float, 8.88, 2) +DEF_CONST (float, 8.88, 4) +DEF_CONST (float, 8.88, 8) +DEF_CONST (float, 8.88, 16) +DEF_CONST (float, 8.88, 32) +DEF_CONST (float, 8.88, 64) +DEF_CONST (float, 8.88, 128) +DEF_CONST (float, 8.88, 256) +DEF_CONST (float, 8.88, 512) +DEF_CONST (float, 8.88, 1024) + +DEF_CONST (double, 8.88, 2) +DEF_CONST (double, 8.88, 4) +DEF_CONST (double, 8.88, 8) +DEF_CONST (double, 8.88, 16) +DEF_CONST (double, 8.88, 32) +DEF_CONST (double, 8.88, 64) +DEF_CONST (double, 8.88, 128) +DEF_CONST (double, 8.88, 256) +DEF_CONST (double, 8.88, 512) + +/* { dg-final { scan-assembler-times {vfmv\.v\.f\s+v[0-9]+,\s*[a-x0-9]+} 30 } } */ +/* { dg-final { scan-assembler-not {csrr} } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/const-5.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/const-5.c new file mode 100644 index 000000000000..afc2a8777185 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/const-5.c @@ -0,0 +1,40 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gcv_zvfh_zvl4096b -mabi=lp64d -O3 -fno-schedule-insns -fno-schedule-insns2 --param=riscv-autovec-lmul=m8 -fno-builtin" } */ + +#include "def.h" + +DEF_CONST (int16_t, 116, 2) +DEF_CONST (int16_t, 116, 4) +DEF_CONST (int16_t, 116, 8) +DEF_CONST (int16_t, 116, 16) +DEF_CONST (int16_t, 116, 32) +DEF_CONST (int16_t, 116, 64) +DEF_CONST (int16_t, 116, 128) +DEF_CONST (int16_t, 116, 256) +DEF_CONST (int16_t, 116, 512) +DEF_CONST (int16_t, 116, 1024) +DEF_CONST (int16_t, 116, 2048) + +DEF_CONST (int32_t, 116, 2) +DEF_CONST (int32_t, 116, 4) +DEF_CONST (int32_t, 116, 8) +DEF_CONST (int32_t, 116, 16) +DEF_CONST (int32_t, 116, 32) +DEF_CONST (int32_t, 116, 64) +DEF_CONST (int32_t, 116, 128) +DEF_CONST (int32_t, 116, 256) +DEF_CONST (int32_t, 116, 512) +DEF_CONST (int32_t, 116, 1024) + +DEF_CONST (int64_t, 116, 2) +DEF_CONST (int64_t, 116, 4) +DEF_CONST (int64_t, 116, 8) +DEF_CONST (int64_t, 116, 16) +DEF_CONST (int64_t, 116, 32) +DEF_CONST (int64_t, 116, 64) +DEF_CONST (int64_t, 116, 128) +DEF_CONST (int64_t, 116, 256) +DEF_CONST (int64_t, 116, 512) + +/* { dg-final { scan-assembler-times {vmv\.v\.x\s+v[0-9]+,\s*[a-x0-9]+} 30 } } */ +/* { dg-final { scan-assembler-not {csrr} } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/def.h b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/def.h index d03108ad771c..2e07e9087365 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/def.h +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/def.h @@ -86,3 +86,105 @@ typedef double v512df __attribute__ ((vector_size (4096))); "v10", "v11", "v12", "v13", "v14", "v15", "v16", "v17", \ "v18", "v19", "v20", "v21", "v22", "v23", "v24", "v25", \ "v26", "v27", "v28", "v29", "v30", "v31"); + +#define DEF_OP_VV(PREFIX, NUM, TYPE, OP) \ + void __attribute__ ((noinline, noclone)) \ + PREFIX##_##TYPE##NUM (TYPE *restrict a, TYPE *restrict b, TYPE *restrict c) \ + { \ + for (int i = 0; i < NUM; ++i) \ + a[i] = b[i] OP c[i]; \ + } + +#define DEF_OP_VX(PREFIX, NUM, TYPE, OP) \ + void __attribute__ ((noinline, noclone)) \ + PREFIX##_##TYPE##NUM (TYPE *restrict a, TYPE *restrict b, TYPE c) \ + { \ + for (int i = 0; i < NUM; ++i) \ + a[i] = b[i] OP c; \ + } + +#define DEF_OP_VI_M16(PREFIX, NUM, TYPE, OP) \ + void __attribute__ ((noinline, noclone)) \ + PREFIX##_##TYPE##NUM (TYPE *restrict a, TYPE *restrict b, TYPE *restrict c) \ + { \ + for (int i = 0; i < NUM; ++i) \ + a[i] = b[i] OP -16; \ + } + +#define DEF_OP_VI_15(PREFIX, NUM, TYPE, OP) \ + void __attribute__ ((noinline, noclone)) \ + PREFIX##_##TYPE##NUM (TYPE *restrict a, TYPE *restrict b, TYPE *restrict c) \ + { \ + for (int i = 0; i < NUM; ++i) \ + a[i] = b[i] OP 15; \ + } + +#define DEF_OP_IV_M16(PREFIX, NUM, TYPE, OP) \ + void __attribute__ ((noinline, noclone)) \ + PREFIX##_##TYPE##NUM (TYPE *restrict a, TYPE *restrict b, TYPE *restrict c) \ + { \ + for (int i = 0; i < NUM; ++i) \ + a[i] = -16 OP b[i]; \ + } + +#define DEF_OP_IV_15(PREFIX, NUM, TYPE, OP) \ + void __attribute__ ((noinline, noclone)) \ + PREFIX##_##TYPE##NUM (TYPE *restrict a, TYPE *restrict b, TYPE *restrict c) \ + { \ + for (int i = 0; i < NUM; ++i) \ + a[i] = 15 OP b[i]; \ + } + +#define DEF_MINMAX_VV(PREFIX, NUM, TYPE, OP) \ + void __attribute__ ((noinline, noclone)) \ + PREFIX##_##TYPE##NUM (TYPE *restrict a, TYPE *restrict b, TYPE *restrict c) \ + { \ + for (int i = 0; i < NUM; ++i) \ + a[i] = b[i] OP c[i] ? b[i] : c[i]; \ + } + +#define DEF_MINMAX_VX(PREFIX, NUM, TYPE, OP) \ + void __attribute__ ((noinline, noclone)) \ + PREFIX##_##TYPE##NUM (TYPE *restrict a, TYPE *restrict b, TYPE c) \ + { \ + for (int i = 0; i < NUM; ++i) \ + a[i] = b[i] OP c ? b[i] : c; \ + } + +#define DEF_OP_VI_7(PREFIX, NUM, TYPE, OP) \ + void __attribute__ ((noinline, noclone)) \ + PREFIX##_##TYPE##NUM (TYPE *restrict a, TYPE *restrict b, TYPE *restrict c) \ + { \ + for (int i = 0; i < NUM; ++i) \ + a[i] = b[i] OP 7; \ + } + +#define DEF_OP_V(PREFIX, NUM, TYPE, OP) \ + void __attribute__ ((noinline, noclone)) \ + PREFIX##_##TYPE##NUM (TYPE *restrict a, TYPE *restrict b) \ + { \ + for (int i = 0; i < NUM; ++i) \ + a[i] = OP b[i]; \ + } + +#define DEF_CALL_VV(PREFIX, NUM, TYPE, CALL) \ + void __attribute__ ((noinline, noclone)) \ + PREFIX##_##TYPE##NUM (TYPE *restrict a, TYPE *restrict b, TYPE *restrict c) \ + { \ + for (int i = 0; i < NUM; ++i) \ + a[i] = CALL (b[i], c[i]); \ + } + +#define DEF_CONST(TYPE, VAL, NUM) \ + void const_##TYPE##_##NUM (TYPE *restrict a) \ + { \ + for (int i = 0; i < NUM; ++i) \ + a[i] = VAL; \ + } + +#define DEF_SERIES(TYPE, BASE, STEP, NUM, SUFFIX) \ + void series_##TYPE##_##SUFFIX (TYPE *restrict a) \ + { \ + for (TYPE i = 0; i < NUM; ++i) \ + a[i] = (BASE) + i * (STEP); \ + } diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/div-1.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/div-1.c new file mode 100644 index 000000000000..f3388a86e389 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/div-1.c @@ -0,0 +1,58 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gcv_zvfh_zvl4096b -mabi=lp64d -O3 -fno-schedule-insns -fno-schedule-insns2 --param=riscv-autovec-lmul=m8" } */ + +#include "def.h" + +DEF_OP_VV (div, 1, int8_t, /) +DEF_OP_VV (div, 2, int8_t, /) +DEF_OP_VV (div, 4, int8_t, /) +DEF_OP_VV (div, 8, int8_t, /) +DEF_OP_VV (div, 16, int8_t, /) +DEF_OP_VV (div, 32, int8_t, /) +DEF_OP_VV (div, 64, int8_t, /) +DEF_OP_VV (div, 128, int8_t, /) +DEF_OP_VV (div, 256, int8_t, /) +DEF_OP_VV (div, 512, int8_t, /) +DEF_OP_VV (div, 1024, int8_t, /) +DEF_OP_VV (div, 2048, int8_t, /) +DEF_OP_VV (div, 4096, int8_t, /) + +DEF_OP_VV (div, 1, int16_t, /) +DEF_OP_VV (div, 2, int16_t, /) +DEF_OP_VV (div, 4, int16_t, /) +DEF_OP_VV (div, 8, int16_t, /) +DEF_OP_VV (div, 16, int16_t, /) +DEF_OP_VV (div, 32, int16_t, /) +DEF_OP_VV (div, 64, int16_t, /) +DEF_OP_VV (div, 128, int16_t, /) +DEF_OP_VV (div, 256, int16_t, /) +DEF_OP_VV (div, 512, int16_t, /) +DEF_OP_VV (div, 1024, int16_t, /) +DEF_OP_VV (div, 2048, int16_t, /) + +DEF_OP_VV (div, 1, int32_t, /) +DEF_OP_VV (div, 2, int32_t, /) +DEF_OP_VV (div, 4, int32_t, /) +DEF_OP_VV (div, 8, int32_t, /) +DEF_OP_VV (div, 16, int32_t, /) +DEF_OP_VV (div, 32, int32_t, /) +DEF_OP_VV (div, 64, int32_t, /) +DEF_OP_VV (div, 128, int32_t, /) +DEF_OP_VV (div, 256, int32_t, /) +DEF_OP_VV (div, 512, int32_t, /) +DEF_OP_VV (div, 1024, int32_t, /) + +DEF_OP_VV (div, 1, int64_t, /) +DEF_OP_VV (div, 2, int64_t, /) +DEF_OP_VV (div, 4, int64_t, /) +DEF_OP_VV (div, 8, int64_t, /) +DEF_OP_VV (div, 16, int64_t, /) +DEF_OP_VV (div, 32, int64_t, /) +DEF_OP_VV (div, 64, int64_t, /) +DEF_OP_VV (div, 128, int64_t, /) +DEF_OP_VV (div, 256, int64_t, /) +DEF_OP_VV (div, 512, int64_t, /) + +/* { dg-final { scan-assembler-times {vdivu?\.vv\s+v[0-9]+,\s*v[0-9]+,\s*v[0-9]+} 42 } } */ +/* TODO: Ideally, we should make sure there is no "csrr vlenb". However, we still have 'csrr vlenb' for some cases since we don't support VLS mode conversion which are needed by division. */ +/* { dg-final { scan-assembler-times {csrr} 19 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/floating-point-add-1.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/floating-point-add-1.c new file mode 100644 index 000000000000..5c2da4df24e7 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/floating-point-add-1.c @@ -0,0 +1,43 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gcv_zvfh_zvl4096b -mabi=lp64d -O3 -fno-schedule-insns -fno-schedule-insns2 --param=riscv-autovec-lmul=m8" } */ + +#include "def.h" + +DEF_OP_VV (add, 1, _Float16, +) +DEF_OP_VV (add, 2, _Float16, +) +DEF_OP_VV (add, 4, _Float16, +) +DEF_OP_VV (add, 8, _Float16, +) +DEF_OP_VV (add, 16, _Float16, +) +DEF_OP_VV (add, 32, _Float16, +) +DEF_OP_VV (add, 64, _Float16, +) +DEF_OP_VV (add, 128, _Float16, +) +DEF_OP_VV (add, 256, _Float16, +) +DEF_OP_VV (add, 512, _Float16, +) +DEF_OP_VV (add, 1024, _Float16, +) +DEF_OP_VV (add, 2048, _Float16, +) + +DEF_OP_VV (add, 1, float, +) +DEF_OP_VV (add, 2, float, +) +DEF_OP_VV (add, 4, float, +) +DEF_OP_VV (add, 8, float, +) +DEF_OP_VV (add, 16, float, +) +DEF_OP_VV (add, 32, float, +) +DEF_OP_VV (add, 64, float, +) +DEF_OP_VV (add, 128, float, +) +DEF_OP_VV (add, 256, float, +) +DEF_OP_VV (add, 512, float, +) +DEF_OP_VV (add, 1024, float, +) + +DEF_OP_VV (add, 1, double, +) +DEF_OP_VV (add, 2, double, +) +DEF_OP_VV (add, 4, double, +) +DEF_OP_VV (add, 8, double, +) +DEF_OP_VV (add, 16, double, +) +DEF_OP_VV (add, 32, double, +) +DEF_OP_VV (add, 64, double, +) +DEF_OP_VV (add, 128, double, +) +DEF_OP_VV (add, 256, double, +) +DEF_OP_VV (add, 512, double, +) + +/* { dg-final { scan-assembler-times {vfadd\.vv\s+v[0-9]+,\s*v[0-9]+,\s*v[0-9]+} 30 } } */ +/* { dg-final { scan-assembler-not {csrr} } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/floating-point-add-2.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/floating-point-add-2.c new file mode 100644 index 000000000000..73a355bc0859 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/floating-point-add-2.c @@ -0,0 +1,43 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gcv_zvfh_zvl4096b -mabi=lp64d -O3 -fno-schedule-insns -fno-schedule-insns2 --param=riscv-autovec-lmul=m8" } */ + +#include "def.h" + +DEF_OP_VX (add, 1, _Float16, +) +DEF_OP_VX (add, 2, _Float16, +) +DEF_OP_VX (add, 4, _Float16, +) +DEF_OP_VX (add, 8, _Float16, +) +DEF_OP_VX (add, 16, _Float16, +) +DEF_OP_VX (add, 32, _Float16, +) +DEF_OP_VX (add, 64, _Float16, +) +DEF_OP_VX (add, 128, _Float16, +) +DEF_OP_VX (add, 256, _Float16, +) +DEF_OP_VX (add, 512, _Float16, +) +DEF_OP_VX (add, 1024, _Float16, +) +DEF_OP_VX (add, 2048, _Float16, +) + +DEF_OP_VX (add, 1, float, +) +DEF_OP_VX (add, 2, float, +) +DEF_OP_VX (add, 4, float, +) +DEF_OP_VX (add, 8, float, +) +DEF_OP_VX (add, 16, float, +) +DEF_OP_VX (add, 32, float, +) +DEF_OP_VX (add, 64, float, +) +DEF_OP_VX (add, 128, float, +) +DEF_OP_VX (add, 256, float, +) +DEF_OP_VX (add, 512, float, +) +DEF_OP_VX (add, 1024, float, +) + +DEF_OP_VX (add, 1, double, +) +DEF_OP_VX (add, 2, double, +) +DEF_OP_VX (add, 4, double, +) +DEF_OP_VX (add, 8, double, +) +DEF_OP_VX (add, 16, double, +) +DEF_OP_VX (add, 32, double, +) +DEF_OP_VX (add, 64, double, +) +DEF_OP_VX (add, 128, double, +) +DEF_OP_VX (add, 256, double, +) +DEF_OP_VX (add, 512, double, +) + +/* { dg-final { scan-assembler-times {vfadd\.vv\s+v[0-9]+,\s*v[0-9]+,\s*v[0-9]+} 30 } } */ +/* { dg-final { scan-assembler-not {csrr} } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/floating-point-add-3.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/floating-point-add-3.c new file mode 100644 index 000000000000..42925e5143a7 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/floating-point-add-3.c @@ -0,0 +1,43 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gcv_zvfh_zvl4096b -mabi=lp64d -O3 -fno-schedule-insns -fno-schedule-insns2 --param=riscv-autovec-lmul=m8" } */ + +#include "def.h" + +DEF_OP_VI_15 (add, 1, _Float16, +) +DEF_OP_VI_15 (add, 2, _Float16, +) +DEF_OP_VI_15 (add, 4, _Float16, +) +DEF_OP_VI_15 (add, 8, _Float16, +) +DEF_OP_VI_15 (add, 16, _Float16, +) +DEF_OP_VI_15 (add, 32, _Float16, +) +DEF_OP_VI_15 (add, 64, _Float16, +) +DEF_OP_VI_15 (add, 128, _Float16, +) +DEF_OP_VI_15 (add, 256, _Float16, +) +DEF_OP_VI_15 (add, 512, _Float16, +) +DEF_OP_VI_15 (add, 1024, _Float16, +) +DEF_OP_VI_15 (add, 2048, _Float16, +) + +DEF_OP_VI_15 (add, 1, float, +) +DEF_OP_VI_15 (add, 2, float, +) +DEF_OP_VI_15 (add, 4, float, +) +DEF_OP_VI_15 (add, 8, float, +) +DEF_OP_VI_15 (add, 16, float, +) +DEF_OP_VI_15 (add, 32, float, +) +DEF_OP_VI_15 (add, 64, float, +) +DEF_OP_VI_15 (add, 128, float, +) +DEF_OP_VI_15 (add, 256, float, +) +DEF_OP_VI_15 (add, 512, float, +) +DEF_OP_VI_15 (add, 1024, float, +) + +DEF_OP_VI_15 (add, 1, double, +) +DEF_OP_VI_15 (add, 2, double, +) +DEF_OP_VI_15 (add, 4, double, +) +DEF_OP_VI_15 (add, 8, double, +) +DEF_OP_VI_15 (add, 16, double, +) +DEF_OP_VI_15 (add, 32, double, +) +DEF_OP_VI_15 (add, 64, double, +) +DEF_OP_VI_15 (add, 128, double, +) +DEF_OP_VI_15 (add, 256, double, +) +DEF_OP_VI_15 (add, 512, double, +) + +/* { dg-final { scan-assembler-times {vfadd\.vv\s+v[0-9]+,\s*v[0-9]+,\s*v[0-9]+} 30 } } */ +/* { dg-final { scan-assembler-not {csrr} } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/floating-point-div-1.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/floating-point-div-1.c new file mode 100644 index 000000000000..93a9e39d00ca --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/floating-point-div-1.c @@ -0,0 +1,43 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gcv_zvfh_zvl4096b -mabi=lp64d -O3 -fno-schedule-insns -fno-schedule-insns2 --param=riscv-autovec-lmul=m8" } */ + +#include "def.h" + +DEF_OP_VV (div, 1, _Float16, /) +DEF_OP_VV (div, 2, _Float16, /) +DEF_OP_VV (div, 4, _Float16, /) +DEF_OP_VV (div, 8, _Float16, /) +DEF_OP_VV (div, 16, _Float16, /) +DEF_OP_VV (div, 32, _Float16, /) +DEF_OP_VV (div, 64, _Float16, /) +DEF_OP_VV (div, 128, _Float16, /) +DEF_OP_VV (div, 256, _Float16, /) +DEF_OP_VV (div, 512, _Float16, /) +DEF_OP_VV (div, 1024, _Float16, /) +DEF_OP_VV (div, 2048, _Float16, /) + +DEF_OP_VV (div, 1, float, /) +DEF_OP_VV (div, 2, float, /) +DEF_OP_VV (div, 4, float, /) +DEF_OP_VV (div, 8, float, /) +DEF_OP_VV (div, 16, float, /) +DEF_OP_VV (div, 32, float, /) +DEF_OP_VV (div, 64, float, /) +DEF_OP_VV (div, 128, float, /) +DEF_OP_VV (div, 256, float, /) +DEF_OP_VV (div, 512, float, /) +DEF_OP_VV (div, 1024, float, /) + +DEF_OP_VV (div, 1, double, /) +DEF_OP_VV (div, 2, double, /) +DEF_OP_VV (div, 4, double, /) +DEF_OP_VV (div, 8, double, /) +DEF_OP_VV (div, 16, double, /) +DEF_OP_VV (div, 32, double, /) +DEF_OP_VV (div, 64, double, /) +DEF_OP_VV (div, 128, double, /) +DEF_OP_VV (div, 256, double, /) +DEF_OP_VV (div, 512, double, /) + +/* { dg-final { scan-assembler-times {vfdiv\.vv\s+v[0-9]+,\s*v[0-9]+,\s*v[0-9]+} 30 } } */ +/* { dg-final { scan-assembler-not {csrr} } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/floating-point-div-2.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/floating-point-div-2.c new file mode 100644 index 000000000000..a5bc2a0e970f --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/floating-point-div-2.c @@ -0,0 +1,43 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gcv_zvfh_zvl4096b -mabi=lp64d -O3 -fno-schedule-insns -fno-schedule-insns2 --param=riscv-autovec-lmul=m8" } */ + +#include "def.h" + +DEF_OP_VX (div, 1, _Float16, /) +DEF_OP_VX (div, 2, _Float16, /) +DEF_OP_VX (div, 4, _Float16, /) +DEF_OP_VX (div, 8, _Float16, /) +DEF_OP_VX (div, 16, _Float16, /) +DEF_OP_VX (div, 32, _Float16, /) +DEF_OP_VX (div, 64, _Float16, /) +DEF_OP_VX (div, 128, _Float16, /) +DEF_OP_VX (div, 256, _Float16, /) +DEF_OP_VX (div, 512, _Float16, /) +DEF_OP_VX (div, 1024, _Float16, /) +DEF_OP_VX (div, 2048, _Float16, /) + +DEF_OP_VX (div, 1, float, /) +DEF_OP_VX (div, 2, float, /) +DEF_OP_VX (div, 4, float, /) +DEF_OP_VX (div, 8, float, /) +DEF_OP_VX (div, 16, float, /) +DEF_OP_VX (div, 32, float, /) +DEF_OP_VX (div, 64, float, /) +DEF_OP_VX (div, 128, float, /) +DEF_OP_VX (div, 256, float, /) +DEF_OP_VX (div, 512, float, /) +DEF_OP_VX (div, 1024, float, /) + +DEF_OP_VX (div, 1, double, /) +DEF_OP_VX (div, 2, double, /) +DEF_OP_VX (div, 4, double, /) +DEF_OP_VX (div, 8, double, /) +DEF_OP_VX (div, 16, double, /) +DEF_OP_VX (div, 32, double, /) +DEF_OP_VX (div, 64, double, /) +DEF_OP_VX (div, 128, double, /) +DEF_OP_VX (div, 256, double, /) +DEF_OP_VX (div, 512, double, /) + +/* { dg-final { scan-assembler-times {vfdiv\.vv\s+v[0-9]+,\s*v[0-9]+,\s*v[0-9]+} 30 } } */ +/* { dg-final { scan-assembler-not {csrr} } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/floating-point-div-3.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/floating-point-div-3.c new file mode 100644 index 000000000000..f1fb7ed2c9d1 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/floating-point-div-3.c @@ -0,0 +1,43 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gcv_zvfh_zvl4096b -mabi=lp64d -O3 -fno-schedule-insns -fno-schedule-insns2 --param=riscv-autovec-lmul=m8" } */ + +#include "def.h" + +DEF_OP_VI_15 (div, 1, _Float16, /) +DEF_OP_VI_15 (div, 2, _Float16, /) +DEF_OP_VI_15 (div, 4, _Float16, /) +DEF_OP_VI_15 (div, 8, _Float16, /) +DEF_OP_VI_15 (div, 16, _Float16, /) +DEF_OP_VI_15 (div, 32, _Float16, /) +DEF_OP_VI_15 (div, 64, _Float16, /) +DEF_OP_VI_15 (div, 128, _Float16, /) +DEF_OP_VI_15 (div, 256, _Float16, /) +DEF_OP_VI_15 (div, 512, _Float16, /) +DEF_OP_VI_15 (div, 1024, _Float16, /) +DEF_OP_VI_15 (div, 2048, _Float16, /) + +DEF_OP_VI_15 (div, 1, float, /) +DEF_OP_VI_15 (div, 2, float, /) +DEF_OP_VI_15 (div, 4, float, /) +DEF_OP_VI_15 (div, 8, float, /) +DEF_OP_VI_15 (div, 16, float, /) +DEF_OP_VI_15 (div, 32, float, /) +DEF_OP_VI_15 (div, 64, float, /) +DEF_OP_VI_15 (div, 128, float, /) +DEF_OP_VI_15 (div, 256, float, /) +DEF_OP_VI_15 (div, 512, float, /) +DEF_OP_VI_15 (div, 1024, float, /) + +DEF_OP_VI_15 (div, 1, double, /) +DEF_OP_VI_15 (div, 2, double, /) +DEF_OP_VI_15 (div, 4, double, /) +DEF_OP_VI_15 (div, 8, double, /) +DEF_OP_VI_15 (div, 16, double, /) +DEF_OP_VI_15 (div, 32, double, /) +DEF_OP_VI_15 (div, 64, double, /) +DEF_OP_VI_15 (div, 128, double, /) +DEF_OP_VI_15 (div, 256, double, /) +DEF_OP_VI_15 (div, 512, double, /) + +/* { dg-final { scan-assembler-times {vfdiv\.vv\s+v[0-9]+,\s*v[0-9]+,\s*v[0-9]+} 30 } } */ +/* { dg-final { scan-assembler-not {csrr} } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/floating-point-max-1.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/floating-point-max-1.c new file mode 100644 index 000000000000..8d3cd2aa5384 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/floating-point-max-1.c @@ -0,0 +1,43 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gcv_zvfh_zvl4096b -mabi=lp64d -O3 -fno-schedule-insns -fno-schedule-insns2 --param=riscv-autovec-lmul=m8 -ffast-math" } */ + +#include "def.h" + +DEF_MINMAX_VV (max, 1, _Float16, >) +DEF_MINMAX_VV (max, 2, _Float16, >) +DEF_MINMAX_VV (max, 4, _Float16, >) +DEF_MINMAX_VV (max, 8, _Float16, >) +DEF_MINMAX_VV (max, 16, _Float16, >) +DEF_MINMAX_VV (max, 32, _Float16, >) +DEF_MINMAX_VV (max, 64, _Float16, >) +DEF_MINMAX_VV (max, 128, _Float16, >) +DEF_MINMAX_VV (max, 256, _Float16, >) +DEF_MINMAX_VV (max, 512, _Float16, >) +DEF_MINMAX_VV (max, 1024, _Float16, >) +DEF_MINMAX_VV (max, 2048, _Float16, >) + +DEF_MINMAX_VV (max, 1, float, >) +DEF_MINMAX_VV (max, 2, float, >) +DEF_MINMAX_VV (max, 4, float, >) +DEF_MINMAX_VV (max, 8, float, >) +DEF_MINMAX_VV (max, 16, float, >) +DEF_MINMAX_VV (max, 32, float, >) +DEF_MINMAX_VV (max, 64, float, >) +DEF_MINMAX_VV (max, 128, float, >) +DEF_MINMAX_VV (max, 256, float, >) +DEF_MINMAX_VV (max, 512, float, >) +DEF_MINMAX_VV (max, 1024, float, >) + +DEF_MINMAX_VV (max, 1, double, >) +DEF_MINMAX_VV (max, 2, double, >) +DEF_MINMAX_VV (max, 4, double, >) +DEF_MINMAX_VV (max, 8, double, >) +DEF_MINMAX_VV (max, 16, double, >) +DEF_MINMAX_VV (max, 32, double, >) +DEF_MINMAX_VV (max, 64, double, >) +DEF_MINMAX_VV (max, 128, double, >) +DEF_MINMAX_VV (max, 256, double, >) +DEF_MINMAX_VV (max, 512, double, >) + +/* { dg-final { scan-assembler-times {vfmax\.vv\s+v[0-9]+,\s*v[0-9]+,\s*v[0-9]+} 30 } } */ +/* { dg-final { scan-assembler-not {csrr} } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/floating-point-max-2.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/floating-point-max-2.c new file mode 100644 index 000000000000..a13de042041f --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/floating-point-max-2.c @@ -0,0 +1,43 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gcv_zvfh_zvl4096b -mabi=lp64d -O3 -fno-schedule-insns -fno-schedule-insns2 --param=riscv-autovec-lmul=m8 -ffast-math" } */ + +#include "def.h" + +DEF_MINMAX_VX (max, 1, _Float16, >) +DEF_MINMAX_VX (max, 2, _Float16, >) +DEF_MINMAX_VX (max, 4, _Float16, >) +DEF_MINMAX_VX (max, 8, _Float16, >) +DEF_MINMAX_VX (max, 16, _Float16, >) +DEF_MINMAX_VX (max, 32, _Float16, >) +DEF_MINMAX_VX (max, 64, _Float16, >) +DEF_MINMAX_VX (max, 128, _Float16, >) +DEF_MINMAX_VX (max, 256, _Float16, >) +DEF_MINMAX_VX (max, 512, _Float16, >) +DEF_MINMAX_VX (max, 1024, _Float16, >) +DEF_MINMAX_VX (max, 2048, _Float16, >) + +DEF_MINMAX_VX (max, 1, float, >) +DEF_MINMAX_VX (max, 2, float, >) +DEF_MINMAX_VX (max, 4, float, >) +DEF_MINMAX_VX (max, 8, float, >) +DEF_MINMAX_VX (max, 16, float, >) +DEF_MINMAX_VX (max, 32, float, >) +DEF_MINMAX_VX (max, 64, float, >) +DEF_MINMAX_VX (max, 128, float, >) +DEF_MINMAX_VX (max, 256, float, >) +DEF_MINMAX_VX (max, 512, float, >) +DEF_MINMAX_VX (max, 1024, float, >) + +DEF_MINMAX_VX (max, 1, double, >) +DEF_MINMAX_VX (max, 2, double, >) +DEF_MINMAX_VX (max, 4, double, >) +DEF_MINMAX_VX (max, 8, double, >) +DEF_MINMAX_VX (max, 16, double, >) +DEF_MINMAX_VX (max, 32, double, >) +DEF_MINMAX_VX (max, 64, double, >) +DEF_MINMAX_VX (max, 128, double, >) +DEF_MINMAX_VX (max, 256, double, >) +DEF_MINMAX_VX (max, 512, double, >) + +/* { dg-final { scan-assembler-times {vfmax\.vv\s+v[0-9]+,\s*v[0-9]+,\s*v[0-9]+} 30 } } */ +/* { dg-final { scan-assembler-not {csrr} } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/floating-point-max-3.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/floating-point-max-3.c new file mode 100644 index 000000000000..108a883bba55 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/floating-point-max-3.c @@ -0,0 +1,43 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gcv_zvfh_zvl4096b -mabi=lp64d -O3 -fno-schedule-insns -fno-schedule-insns2 --param=riscv-autovec-lmul=m8 -ffast-math" } */ + +#include "def.h" + +DEF_MINMAX_VV (max, 1, _Float16, >=) +DEF_MINMAX_VV (max, 2, _Float16, >=) +DEF_MINMAX_VV (max, 4, _Float16, >=) +DEF_MINMAX_VV (max, 8, _Float16, >=) +DEF_MINMAX_VV (max, 16, _Float16, >=) +DEF_MINMAX_VV (max, 32, _Float16, >=) +DEF_MINMAX_VV (max, 64, _Float16, >=) +DEF_MINMAX_VV (max, 128, _Float16, >=) +DEF_MINMAX_VV (max, 256, _Float16, >=) +DEF_MINMAX_VV (max, 512, _Float16, >=) +DEF_MINMAX_VV (max, 1024, _Float16, >=) +DEF_MINMAX_VV (max, 2048, _Float16, >=) + +DEF_MINMAX_VV (max, 1, float, >=) +DEF_MINMAX_VV (max, 2, float, >=) +DEF_MINMAX_VV (max, 4, float, >=) +DEF_MINMAX_VV (max, 8, float, >=) +DEF_MINMAX_VV (max, 16, float, >=) +DEF_MINMAX_VV (max, 32, float, >=) +DEF_MINMAX_VV (max, 64, float, >=) +DEF_MINMAX_VV (max, 128, float, >=) +DEF_MINMAX_VV (max, 256, float, >=) +DEF_MINMAX_VV (max, 512, float, >=) +DEF_MINMAX_VV (max, 1024, float, >=) + +DEF_MINMAX_VV (max, 1, double, >=) +DEF_MINMAX_VV (max, 2, double, >=) +DEF_MINMAX_VV (max, 4, double, >=) +DEF_MINMAX_VV (max, 8, double, >=) +DEF_MINMAX_VV (max, 16, double, >=) +DEF_MINMAX_VV (max, 32, double, >=) +DEF_MINMAX_VV (max, 64, double, >=) +DEF_MINMAX_VV (max, 128, double, >=) +DEF_MINMAX_VV (max, 256, double, >=) +DEF_MINMAX_VV (max, 512, double, >=) + +/* { dg-final { scan-assembler-times {vfmax\.vv\s+v[0-9]+,\s*v[0-9]+,\s*v[0-9]+} 30 } } */ +/* { dg-final { scan-assembler-not {csrr} } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/floating-point-max-4.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/floating-point-max-4.c new file mode 100644 index 000000000000..d74801887b6c --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/floating-point-max-4.c @@ -0,0 +1,43 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gcv_zvfh_zvl4096b -mabi=lp64d -O3 -fno-schedule-insns -fno-schedule-insns2 --param=riscv-autovec-lmul=m8 -ffast-math" } */ + +#include "def.h" + +DEF_MINMAX_VX (max, 1, _Float16, >=) +DEF_MINMAX_VX (max, 2, _Float16, >=) +DEF_MINMAX_VX (max, 4, _Float16, >=) +DEF_MINMAX_VX (max, 8, _Float16, >=) +DEF_MINMAX_VX (max, 16, _Float16, >=) +DEF_MINMAX_VX (max, 32, _Float16, >=) +DEF_MINMAX_VX (max, 64, _Float16, >=) +DEF_MINMAX_VX (max, 128, _Float16, >=) +DEF_MINMAX_VX (max, 256, _Float16, >=) +DEF_MINMAX_VX (max, 512, _Float16, >=) +DEF_MINMAX_VX (max, 1024, _Float16, >=) +DEF_MINMAX_VX (max, 2048, _Float16, >=) + +DEF_MINMAX_VX (max, 1, float, >=) +DEF_MINMAX_VX (max, 2, float, >=) +DEF_MINMAX_VX (max, 4, float, >=) +DEF_MINMAX_VX (max, 8, float, >=) +DEF_MINMAX_VX (max, 16, float, >=) +DEF_MINMAX_VX (max, 32, float, >=) +DEF_MINMAX_VX (max, 64, float, >=) +DEF_MINMAX_VX (max, 128, float, >=) +DEF_MINMAX_VX (max, 256, float, >=) +DEF_MINMAX_VX (max, 512, float, >=) +DEF_MINMAX_VX (max, 1024, float, >=) + +DEF_MINMAX_VX (max, 1, double, >=) +DEF_MINMAX_VX (max, 2, double, >=) +DEF_MINMAX_VX (max, 4, double, >=) +DEF_MINMAX_VX (max, 8, double, >=) +DEF_MINMAX_VX (max, 16, double, >=) +DEF_MINMAX_VX (max, 32, double, >=) +DEF_MINMAX_VX (max, 64, double, >=) +DEF_MINMAX_VX (max, 128, double, >=) +DEF_MINMAX_VX (max, 256, double, >=) +DEF_MINMAX_VX (max, 512, double, >=) + +/* { dg-final { scan-assembler-times {vfmax\.vv\s+v[0-9]+,\s*v[0-9]+,\s*v[0-9]+} 30 } } */ +/* { dg-final { scan-assembler-not {csrr} } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/floating-point-max-5.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/floating-point-max-5.c new file mode 100644 index 000000000000..775ddb1d25e2 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/floating-point-max-5.c @@ -0,0 +1,31 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gcv_zvfh_zvl4096b -mabi=lp64d -O3 -fno-schedule-insns -fno-schedule-insns2 --param=riscv-autovec-lmul=m8 -ffast-math" } */ + +#include "def.h" +#include "math.h" + +DEF_CALL_VV (max, 1, float, fmaxf) +DEF_CALL_VV (max, 2, float, fmaxf) +DEF_CALL_VV (max, 4, float, fmaxf) +DEF_CALL_VV (max, 8, float, fmaxf) +DEF_CALL_VV (max, 16, float, fmaxf) +DEF_CALL_VV (max, 32, float, fmaxf) +DEF_CALL_VV (max, 64, float, fmaxf) +DEF_CALL_VV (max, 128, float, fmaxf) +DEF_CALL_VV (max, 256, float, fmaxf) +DEF_CALL_VV (max, 512, float, fmaxf) +DEF_CALL_VV (max, 1024, float, fmaxf) + +DEF_CALL_VV (max, 1, double, fmax) +DEF_CALL_VV (max, 2, double, fmax) +DEF_CALL_VV (max, 4, double, fmax) +DEF_CALL_VV (max, 8, double, fmax) +DEF_CALL_VV (max, 16, double, fmax) +DEF_CALL_VV (max, 32, double, fmax) +DEF_CALL_VV (max, 64, double, fmax) +DEF_CALL_VV (max, 128, double, fmax) +DEF_CALL_VV (max, 256, double, fmax) +DEF_CALL_VV (max, 512, double, fmax) + +/* { dg-final { scan-assembler-times {vfmax\.vv\s+v[0-9]+,\s*v[0-9]+,\s*v[0-9]+} 19 } } */ +/* { dg-final { scan-assembler-not {csrr} } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/floating-point-min-1.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/floating-point-min-1.c new file mode 100644 index 000000000000..e082c47b0442 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/floating-point-min-1.c @@ -0,0 +1,43 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gcv_zvfh_zvl4096b -mabi=lp64d -O3 -fno-schedule-insns -fno-schedule-insns2 --param=riscv-autovec-lmul=m8 -ffast-math" } */ + +#include "def.h" + +DEF_MINMAX_VV (min, 1, _Float16, <) +DEF_MINMAX_VV (min, 2, _Float16, <) +DEF_MINMAX_VV (min, 4, _Float16, <) +DEF_MINMAX_VV (min, 8, _Float16, <) +DEF_MINMAX_VV (min, 16, _Float16, <) +DEF_MINMAX_VV (min, 32, _Float16, <) +DEF_MINMAX_VV (min, 64, _Float16, <) +DEF_MINMAX_VV (min, 128, _Float16, <) +DEF_MINMAX_VV (min, 256, _Float16, <) +DEF_MINMAX_VV (min, 512, _Float16, <) +DEF_MINMAX_VV (min, 1024, _Float16, <) +DEF_MINMAX_VV (min, 2048, _Float16, <) + +DEF_MINMAX_VV (min, 1, float, <) +DEF_MINMAX_VV (min, 2, float, <) +DEF_MINMAX_VV (min, 4, float, <) +DEF_MINMAX_VV (min, 8, float, <) +DEF_MINMAX_VV (min, 16, float, <) +DEF_MINMAX_VV (min, 32, float, <) +DEF_MINMAX_VV (min, 64, float, <) +DEF_MINMAX_VV (min, 128, float, <) +DEF_MINMAX_VV (min, 256, float, <) +DEF_MINMAX_VV (min, 512, float, <) +DEF_MINMAX_VV (min, 1024, float, <) + +DEF_MINMAX_VV (min, 1, double, <) +DEF_MINMAX_VV (min, 2, double, <) +DEF_MINMAX_VV (min, 4, double, <) +DEF_MINMAX_VV (min, 8, double, <) +DEF_MINMAX_VV (min, 16, double, <) +DEF_MINMAX_VV (min, 32, double, <) +DEF_MINMAX_VV (min, 64, double, <) +DEF_MINMAX_VV (min, 128, double, <) +DEF_MINMAX_VV (min, 256, double, <) +DEF_MINMAX_VV (min, 512, double, <) + +/* { dg-final { scan-assembler-times {vfmin\.vv\s+v[0-9]+,\s*v[0-9]+,\s*v[0-9]+} 30 } } */ +/* { dg-final { scan-assembler-not {csrr} } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/floating-point-min-2.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/floating-point-min-2.c new file mode 100644 index 000000000000..1b900522750a --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/floating-point-min-2.c @@ -0,0 +1,43 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gcv_zvfh_zvl4096b -mabi=lp64d -O3 -fno-schedule-insns -fno-schedule-insns2 --param=riscv-autovec-lmul=m8 -ffast-math" } */ + +#include "def.h" + +DEF_MINMAX_VX (min, 1, _Float16, <) +DEF_MINMAX_VX (min, 2, _Float16, <) +DEF_MINMAX_VX (min, 4, _Float16, <) +DEF_MINMAX_VX (min, 8, _Float16, <) +DEF_MINMAX_VX (min, 16, _Float16, <) +DEF_MINMAX_VX (min, 32, _Float16, <) +DEF_MINMAX_VX (min, 64, _Float16, <) +DEF_MINMAX_VX (min, 128, _Float16, <) +DEF_MINMAX_VX (min, 256, _Float16, <) +DEF_MINMAX_VX (min, 512, _Float16, <) +DEF_MINMAX_VX (min, 1024, _Float16, <) +DEF_MINMAX_VX (min, 2048, _Float16, <) + +DEF_MINMAX_VX (min, 1, float, <) +DEF_MINMAX_VX (min, 2, float, <) +DEF_MINMAX_VX (min, 4, float, <) +DEF_MINMAX_VX (min, 8, float, <) +DEF_MINMAX_VX (min, 16, float, <) +DEF_MINMAX_VX (min, 32, float, <) +DEF_MINMAX_VX (min, 64, float, <) +DEF_MINMAX_VX (min, 128, float, <) +DEF_MINMAX_VX (min, 256, float, <) +DEF_MINMAX_VX (min, 512, float, <) +DEF_MINMAX_VX (min, 1024, float, <) + +DEF_MINMAX_VX (min, 1, double, <) +DEF_MINMAX_VX (min, 2, double, <) +DEF_MINMAX_VX (min, 4, double, <) +DEF_MINMAX_VX (min, 8, double, <) +DEF_MINMAX_VX (min, 16, double, <) +DEF_MINMAX_VX (min, 32, double, <) +DEF_MINMAX_VX (min, 64, double, <) +DEF_MINMAX_VX (min, 128, double, <) +DEF_MINMAX_VX (min, 256, double, <) +DEF_MINMAX_VX (min, 512, double, <) + +/* { dg-final { scan-assembler-times {vfmin\.vv\s+v[0-9]+,\s*v[0-9]+,\s*v[0-9]+} 30 } } */ +/* { dg-final { scan-assembler-not {csrr} } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/floating-point-min-3.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/floating-point-min-3.c new file mode 100644 index 000000000000..ad05800572f2 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/floating-point-min-3.c @@ -0,0 +1,43 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gcv_zvfh_zvl4096b -mabi=lp64d -O3 -fno-schedule-insns -fno-schedule-insns2 --param=riscv-autovec-lmul=m8 -ffast-math" } */ + +#include "def.h" + +DEF_MINMAX_VV (min, 1, _Float16, <=) +DEF_MINMAX_VV (min, 2, _Float16, <=) +DEF_MINMAX_VV (min, 4, _Float16, <=) +DEF_MINMAX_VV (min, 8, _Float16, <=) +DEF_MINMAX_VV (min, 16, _Float16, <=) +DEF_MINMAX_VV (min, 32, _Float16, <=) +DEF_MINMAX_VV (min, 64, _Float16, <=) +DEF_MINMAX_VV (min, 128, _Float16, <=) +DEF_MINMAX_VV (min, 256, _Float16, <=) +DEF_MINMAX_VV (min, 512, _Float16, <=) +DEF_MINMAX_VV (min, 1024, _Float16, <=) +DEF_MINMAX_VV (min, 2048, _Float16, <=) + +DEF_MINMAX_VV (min, 1, float, <=) +DEF_MINMAX_VV (min, 2, float, <=) +DEF_MINMAX_VV (min, 4, float, <=) +DEF_MINMAX_VV (min, 8, float, <=) +DEF_MINMAX_VV (min, 16, float, <=) +DEF_MINMAX_VV (min, 32, float, <=) +DEF_MINMAX_VV (min, 64, float, <=) +DEF_MINMAX_VV (min, 128, float, <=) +DEF_MINMAX_VV (min, 256, float, <=) +DEF_MINMAX_VV (min, 512, float, <=) +DEF_MINMAX_VV (min, 1024, float, <=) + +DEF_MINMAX_VV (min, 1, double, <=) +DEF_MINMAX_VV (min, 2, double, <=) +DEF_MINMAX_VV (min, 4, double, <=) +DEF_MINMAX_VV (min, 8, double, <=) +DEF_MINMAX_VV (min, 16, double, <=) +DEF_MINMAX_VV (min, 32, double, <=) +DEF_MINMAX_VV (min, 64, double, <=) +DEF_MINMAX_VV (min, 128, double, <=) +DEF_MINMAX_VV (min, 256, double, <=) +DEF_MINMAX_VV (min, 512, double, <=) + +/* { dg-final { scan-assembler-times {vfmin\.vv\s+v[0-9]+,\s*v[0-9]+,\s*v[0-9]+} 30 } } */ +/* { dg-final { scan-assembler-not {csrr} } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/floating-point-min-4.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/floating-point-min-4.c new file mode 100644 index 000000000000..5d4109aa3c26 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/floating-point-min-4.c @@ -0,0 +1,43 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gcv_zvfh_zvl4096b -mabi=lp64d -O3 -fno-schedule-insns -fno-schedule-insns2 --param=riscv-autovec-lmul=m8 -ffast-math" } */ + +#include "def.h" + +DEF_MINMAX_VX (min, 1, _Float16, <=) +DEF_MINMAX_VX (min, 2, _Float16, <=) +DEF_MINMAX_VX (min, 4, _Float16, <=) +DEF_MINMAX_VX (min, 8, _Float16, <=) +DEF_MINMAX_VX (min, 16, _Float16, <=) +DEF_MINMAX_VX (min, 32, _Float16, <=) +DEF_MINMAX_VX (min, 64, _Float16, <=) +DEF_MINMAX_VX (min, 128, _Float16, <=) +DEF_MINMAX_VX (min, 256, _Float16, <=) +DEF_MINMAX_VX (min, 512, _Float16, <=) +DEF_MINMAX_VX (min, 1024, _Float16, <=) +DEF_MINMAX_VX (min, 2048, _Float16, <=) + +DEF_MINMAX_VX (min, 1, float, <=) +DEF_MINMAX_VX (min, 2, float, <=) +DEF_MINMAX_VX (min, 4, float, <=) +DEF_MINMAX_VX (min, 8, float, <=) +DEF_MINMAX_VX (min, 16, float, <=) +DEF_MINMAX_VX (min, 32, float, <=) +DEF_MINMAX_VX (min, 64, float, <=) +DEF_MINMAX_VX (min, 128, float, <=) +DEF_MINMAX_VX (min, 256, float, <=) +DEF_MINMAX_VX (min, 512, float, <=) +DEF_MINMAX_VX (min, 1024, float, <=) + +DEF_MINMAX_VX (min, 1, double, <=) +DEF_MINMAX_VX (min, 2, double, <=) +DEF_MINMAX_VX (min, 4, double, <=) +DEF_MINMAX_VX (min, 8, double, <=) +DEF_MINMAX_VX (min, 16, double, <=) +DEF_MINMAX_VX (min, 32, double, <=) +DEF_MINMAX_VX (min, 64, double, <=) +DEF_MINMAX_VX (min, 128, double, <=) +DEF_MINMAX_VX (min, 256, double, <=) +DEF_MINMAX_VX (min, 512, double, <=) + +/* { dg-final { scan-assembler-times {vfmin\.vv\s+v[0-9]+,\s*v[0-9]+,\s*v[0-9]+} 30 } } */ +/* { dg-final { scan-assembler-not {csrr} } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/floating-point-min-5.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/floating-point-min-5.c new file mode 100644 index 000000000000..1e9ff7d5054b --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/floating-point-min-5.c @@ -0,0 +1,31 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gcv_zvfh_zvl4096b -mabi=lp64d -O3 -fno-schedule-insns -fno-schedule-insns2 --param=riscv-autovec-lmul=m8 -ffast-math" } */ + +#include "def.h" +#include "math.h" + +DEF_CALL_VV (min, 1, float, fminf) +DEF_CALL_VV (min, 2, float, fminf) +DEF_CALL_VV (min, 4, float, fminf) +DEF_CALL_VV (min, 8, float, fminf) +DEF_CALL_VV (min, 16, float, fminf) +DEF_CALL_VV (min, 32, float, fminf) +DEF_CALL_VV (min, 64, float, fminf) +DEF_CALL_VV (min, 128, float, fminf) +DEF_CALL_VV (min, 256, float, fminf) +DEF_CALL_VV (min, 512, float, fminf) +DEF_CALL_VV (min, 1024, float, fminf) + +DEF_CALL_VV (min, 1, double, fmin) +DEF_CALL_VV (min, 2, double, fmin) +DEF_CALL_VV (min, 4, double, fmin) +DEF_CALL_VV (min, 8, double, fmin) +DEF_CALL_VV (min, 16, double, fmin) +DEF_CALL_VV (min, 32, double, fmin) +DEF_CALL_VV (min, 64, double, fmin) +DEF_CALL_VV (min, 128, double, fmin) +DEF_CALL_VV (min, 256, double, fmin) +DEF_CALL_VV (min, 512, double, fmin) + +/* { dg-final { scan-assembler-times {vfmin\.vv\s+v[0-9]+,\s*v[0-9]+,\s*v[0-9]+} 19 } } */ +/* { dg-final { scan-assembler-not {csrr} } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/floating-point-mul-1.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/floating-point-mul-1.c new file mode 100644 index 000000000000..3beccb275ab5 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/floating-point-mul-1.c @@ -0,0 +1,43 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gcv_zvfh_zvl4096b -mabi=lp64d -O3 -fno-schedule-insns -fno-schedule-insns2 --param=riscv-autovec-lmul=m8" } */ + +#include "def.h" + +DEF_OP_VV (mul, 1, _Float16, *) +DEF_OP_VV (mul, 2, _Float16, *) +DEF_OP_VV (mul, 4, _Float16, *) +DEF_OP_VV (mul, 8, _Float16, *) +DEF_OP_VV (mul, 16, _Float16, *) +DEF_OP_VV (mul, 32, _Float16, *) +DEF_OP_VV (mul, 64, _Float16, *) +DEF_OP_VV (mul, 128, _Float16, *) +DEF_OP_VV (mul, 256, _Float16, *) +DEF_OP_VV (mul, 512, _Float16, *) +DEF_OP_VV (mul, 1024, _Float16, *) +DEF_OP_VV (mul, 2048, _Float16, *) + +DEF_OP_VV (mul, 1, float, *) +DEF_OP_VV (mul, 2, float, *) +DEF_OP_VV (mul, 4, float, *) +DEF_OP_VV (mul, 8, float, *) +DEF_OP_VV (mul, 16, float, *) +DEF_OP_VV (mul, 32, float, *) +DEF_OP_VV (mul, 64, float, *) +DEF_OP_VV (mul, 128, float, *) +DEF_OP_VV (mul, 256, float, *) +DEF_OP_VV (mul, 512, float, *) +DEF_OP_VV (mul, 1024, float, *) + +DEF_OP_VV (mul, 1, double, *) +DEF_OP_VV (mul, 2, double, *) +DEF_OP_VV (mul, 4, double, *) +DEF_OP_VV (mul, 8, double, *) +DEF_OP_VV (mul, 16, double, *) +DEF_OP_VV (mul, 32, double, *) +DEF_OP_VV (mul, 64, double, *) +DEF_OP_VV (mul, 128, double, *) +DEF_OP_VV (mul, 256, double, *) +DEF_OP_VV (mul, 512, double, *) + +/* { dg-final { scan-assembler-times {vfmul\.vv\s+v[0-9]+,\s*v[0-9]+,\s*v[0-9]+} 30 } } */ +/* { dg-final { scan-assembler-not {csrr} } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/floating-point-mul-2.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/floating-point-mul-2.c new file mode 100644 index 000000000000..b96163861779 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/floating-point-mul-2.c @@ -0,0 +1,43 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gcv_zvfh_zvl4096b -mabi=lp64d -O3 -fno-schedule-insns -fno-schedule-insns2 --param=riscv-autovec-lmul=m8" } */ + +#include "def.h" + +DEF_OP_VX (mul, 1, _Float16, *) +DEF_OP_VX (mul, 2, _Float16, *) +DEF_OP_VX (mul, 4, _Float16, *) +DEF_OP_VX (mul, 8, _Float16, *) +DEF_OP_VX (mul, 16, _Float16, *) +DEF_OP_VX (mul, 32, _Float16, *) +DEF_OP_VX (mul, 64, _Float16, *) +DEF_OP_VX (mul, 128, _Float16, *) +DEF_OP_VX (mul, 256, _Float16, *) +DEF_OP_VX (mul, 512, _Float16, *) +DEF_OP_VX (mul, 1024, _Float16, *) +DEF_OP_VX (mul, 2048, _Float16, *) + +DEF_OP_VX (mul, 1, float, *) +DEF_OP_VX (mul, 2, float, *) +DEF_OP_VX (mul, 4, float, *) +DEF_OP_VX (mul, 8, float, *) +DEF_OP_VX (mul, 16, float, *) +DEF_OP_VX (mul, 32, float, *) +DEF_OP_VX (mul, 64, float, *) +DEF_OP_VX (mul, 128, float, *) +DEF_OP_VX (mul, 256, float, *) +DEF_OP_VX (mul, 512, float, *) +DEF_OP_VX (mul, 1024, float, *) + +DEF_OP_VX (mul, 1, double, *) +DEF_OP_VX (mul, 2, double, *) +DEF_OP_VX (mul, 4, double, *) +DEF_OP_VX (mul, 8, double, *) +DEF_OP_VX (mul, 16, double, *) +DEF_OP_VX (mul, 32, double, *) +DEF_OP_VX (mul, 64, double, *) +DEF_OP_VX (mul, 128, double, *) +DEF_OP_VX (mul, 256, double, *) +DEF_OP_VX (mul, 512, double, *) + +/* { dg-final { scan-assembler-times {vfmul\.vv\s+v[0-9]+,\s*v[0-9]+,\s*v[0-9]+} 30 } } */ +/* { dg-final { scan-assembler-not {csrr} } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/floating-point-mul-3.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/floating-point-mul-3.c new file mode 100644 index 000000000000..d8e4e26bc00d --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/floating-point-mul-3.c @@ -0,0 +1,43 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gcv_zvfh_zvl4096b -mabi=lp64d -O3 -fno-schedule-insns -fno-schedule-insns2 --param=riscv-autovec-lmul=m8" } */ + +#include "def.h" + +DEF_OP_VI_15 (mul, 1, _Float16, *) +DEF_OP_VI_15 (mul, 2, _Float16, *) +DEF_OP_VI_15 (mul, 4, _Float16, *) +DEF_OP_VI_15 (mul, 8, _Float16, *) +DEF_OP_VI_15 (mul, 16, _Float16, *) +DEF_OP_VI_15 (mul, 32, _Float16, *) +DEF_OP_VI_15 (mul, 64, _Float16, *) +DEF_OP_VI_15 (mul, 128, _Float16, *) +DEF_OP_VI_15 (mul, 256, _Float16, *) +DEF_OP_VI_15 (mul, 512, _Float16, *) +DEF_OP_VI_15 (mul, 1024, _Float16, *) +DEF_OP_VI_15 (mul, 2048, _Float16, *) + +DEF_OP_VI_15 (mul, 1, float, *) +DEF_OP_VI_15 (mul, 2, float, *) +DEF_OP_VI_15 (mul, 4, float, *) +DEF_OP_VI_15 (mul, 8, float, *) +DEF_OP_VI_15 (mul, 16, float, *) +DEF_OP_VI_15 (mul, 32, float, *) +DEF_OP_VI_15 (mul, 64, float, *) +DEF_OP_VI_15 (mul, 128, float, *) +DEF_OP_VI_15 (mul, 256, float, *) +DEF_OP_VI_15 (mul, 512, float, *) +DEF_OP_VI_15 (mul, 1024, float, *) + +DEF_OP_VI_15 (mul, 1, double, *) +DEF_OP_VI_15 (mul, 2, double, *) +DEF_OP_VI_15 (mul, 4, double, *) +DEF_OP_VI_15 (mul, 8, double, *) +DEF_OP_VI_15 (mul, 16, double, *) +DEF_OP_VI_15 (mul, 32, double, *) +DEF_OP_VI_15 (mul, 64, double, *) +DEF_OP_VI_15 (mul, 128, double, *) +DEF_OP_VI_15 (mul, 256, double, *) +DEF_OP_VI_15 (mul, 512, double, *) + +/* { dg-final { scan-assembler-times {vfmul\.vv\s+v[0-9]+,\s*v[0-9]+,\s*v[0-9]+} 30 } } */ +/* { dg-final { scan-assembler-not {csrr} } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/floating-point-sub-1.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/floating-point-sub-1.c new file mode 100644 index 000000000000..75fe340935cd --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/floating-point-sub-1.c @@ -0,0 +1,43 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gcv_zvfh_zvl4096b -mabi=lp64d -O3 -fno-schedule-insns -fno-schedule-insns2 --param=riscv-autovec-lmul=m8" } */ + +#include "def.h" + +DEF_OP_VV (sub, 1, _Float16, -) +DEF_OP_VV (sub, 2, _Float16, -) +DEF_OP_VV (sub, 4, _Float16, -) +DEF_OP_VV (sub, 8, _Float16, -) +DEF_OP_VV (sub, 16, _Float16, -) +DEF_OP_VV (sub, 32, _Float16, -) +DEF_OP_VV (sub, 64, _Float16, -) +DEF_OP_VV (sub, 128, _Float16, -) +DEF_OP_VV (sub, 256, _Float16, -) +DEF_OP_VV (sub, 512, _Float16, -) +DEF_OP_VV (sub, 1024, _Float16, -) +DEF_OP_VV (sub, 2048, _Float16, -) + +DEF_OP_VV (sub, 1, float, -) +DEF_OP_VV (sub, 2, float, -) +DEF_OP_VV (sub, 4, float, -) +DEF_OP_VV (sub, 8, float, -) +DEF_OP_VV (sub, 16, float, -) +DEF_OP_VV (sub, 32, float, -) +DEF_OP_VV (sub, 64, float, -) +DEF_OP_VV (sub, 128, float, -) +DEF_OP_VV (sub, 256, float, -) +DEF_OP_VV (sub, 512, float, -) +DEF_OP_VV (sub, 1024, float, -) + +DEF_OP_VV (sub, 1, double, -) +DEF_OP_VV (sub, 2, double, -) +DEF_OP_VV (sub, 4, double, -) +DEF_OP_VV (sub, 8, double, -) +DEF_OP_VV (sub, 16, double, -) +DEF_OP_VV (sub, 32, double, -) +DEF_OP_VV (sub, 64, double, -) +DEF_OP_VV (sub, 128, double, -) +DEF_OP_VV (sub, 256, double, -) +DEF_OP_VV (sub, 512, double, -) + +/* { dg-final { scan-assembler-times {vfsub\.vv\s+v[0-9]+,\s*v[0-9]+,\s*v[0-9]+} 30 } } */ +/* { dg-final { scan-assembler-not {csrr} } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/floating-point-sub-2.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/floating-point-sub-2.c new file mode 100644 index 000000000000..96a6fe6df2c0 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/floating-point-sub-2.c @@ -0,0 +1,43 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gcv_zvfh_zvl4096b -mabi=lp64d -O3 -fno-schedule-insns -fno-schedule-insns2 --param=riscv-autovec-lmul=m8" } */ + +#include "def.h" + +DEF_OP_VX (sub, 1, _Float16, -) +DEF_OP_VX (sub, 2, _Float16, -) +DEF_OP_VX (sub, 4, _Float16, -) +DEF_OP_VX (sub, 8, _Float16, -) +DEF_OP_VX (sub, 16, _Float16, -) +DEF_OP_VX (sub, 32, _Float16, -) +DEF_OP_VX (sub, 64, _Float16, -) +DEF_OP_VX (sub, 128, _Float16, -) +DEF_OP_VX (sub, 256, _Float16, -) +DEF_OP_VX (sub, 512, _Float16, -) +DEF_OP_VX (sub, 1024, _Float16, -) +DEF_OP_VX (sub, 2048, _Float16, -) + +DEF_OP_VX (sub, 1, float, -) +DEF_OP_VX (sub, 2, float, -) +DEF_OP_VX (sub, 4, float, -) +DEF_OP_VX (sub, 8, float, -) +DEF_OP_VX (sub, 16, float, -) +DEF_OP_VX (sub, 32, float, -) +DEF_OP_VX (sub, 64, float, -) +DEF_OP_VX (sub, 128, float, -) +DEF_OP_VX (sub, 256, float, -) +DEF_OP_VX (sub, 512, float, -) +DEF_OP_VX (sub, 1024, float, -) + +DEF_OP_VX (sub, 1, double, -) +DEF_OP_VX (sub, 2, double, -) +DEF_OP_VX (sub, 4, double, -) +DEF_OP_VX (sub, 8, double, -) +DEF_OP_VX (sub, 16, double, -) +DEF_OP_VX (sub, 32, double, -) +DEF_OP_VX (sub, 64, double, -) +DEF_OP_VX (sub, 128, double, -) +DEF_OP_VX (sub, 256, double, -) +DEF_OP_VX (sub, 512, double, -) + +/* { dg-final { scan-assembler-times {vfsub\.vv\s+v[0-9]+,\s*v[0-9]+,\s*v[0-9]+} 30 } } */ +/* { dg-final { scan-assembler-not {csrr} } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/floating-point-sub-3.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/floating-point-sub-3.c new file mode 100644 index 000000000000..0094e2cbf4b3 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/floating-point-sub-3.c @@ -0,0 +1,43 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gcv_zvfh_zvl4096b -mabi=lp64d -O3 -fno-schedule-insns -fno-schedule-insns2 --param=riscv-autovec-lmul=m8" } */ + +#include "def.h" + +DEF_OP_VI_15 (sub, 1, _Float16, -) +DEF_OP_VI_15 (sub, 2, _Float16, -) +DEF_OP_VI_15 (sub, 4, _Float16, -) +DEF_OP_VI_15 (sub, 8, _Float16, -) +DEF_OP_VI_15 (sub, 16, _Float16, -) +DEF_OP_VI_15 (sub, 32, _Float16, -) +DEF_OP_VI_15 (sub, 64, _Float16, -) +DEF_OP_VI_15 (sub, 128, _Float16, -) +DEF_OP_VI_15 (sub, 256, _Float16, -) +DEF_OP_VI_15 (sub, 512, _Float16, -) +DEF_OP_VI_15 (sub, 1024, _Float16, -) +DEF_OP_VI_15 (sub, 2048, _Float16, -) + +DEF_OP_VI_15 (sub, 1, float, -) +DEF_OP_VI_15 (sub, 2, float, -) +DEF_OP_VI_15 (sub, 4, float, -) +DEF_OP_VI_15 (sub, 8, float, -) +DEF_OP_VI_15 (sub, 16, float, -) +DEF_OP_VI_15 (sub, 32, float, -) +DEF_OP_VI_15 (sub, 64, float, -) +DEF_OP_VI_15 (sub, 128, float, -) +DEF_OP_VI_15 (sub, 256, float, -) +DEF_OP_VI_15 (sub, 512, float, -) +DEF_OP_VI_15 (sub, 1024, float, -) + +DEF_OP_VI_15 (sub, 1, double, -) +DEF_OP_VI_15 (sub, 2, double, -) +DEF_OP_VI_15 (sub, 4, double, -) +DEF_OP_VI_15 (sub, 8, double, -) +DEF_OP_VI_15 (sub, 16, double, -) +DEF_OP_VI_15 (sub, 32, double, -) +DEF_OP_VI_15 (sub, 64, double, -) +DEF_OP_VI_15 (sub, 128, double, -) +DEF_OP_VI_15 (sub, 256, double, -) +DEF_OP_VI_15 (sub, 512, double, -) + +/* { dg-final { scan-assembler-times {vfadd\.vv\s+v[0-9]+,\s*v[0-9]+,\s*v[0-9]+} 30 } } */ +/* { dg-final { scan-assembler-not {csrr} } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/ior-1.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/ior-1.c new file mode 100644 index 000000000000..dcee81a9bc08 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/ior-1.c @@ -0,0 +1,57 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gcv_zvfh_zvl4096b -mabi=lp64d -O3 -fno-schedule-insns -fno-schedule-insns2 --param=riscv-autovec-lmul=m8" } */ + +#include "def.h" + +DEF_OP_VV (ior, 1, int8_t, |) +DEF_OP_VV (ior, 2, int8_t, |) +DEF_OP_VV (ior, 4, int8_t, |) +DEF_OP_VV (ior, 8, int8_t, |) +DEF_OP_VV (ior, 16, int8_t, |) +DEF_OP_VV (ior, 32, int8_t, |) +DEF_OP_VV (ior, 64, int8_t, |) +DEF_OP_VV (ior, 128, int8_t, |) +DEF_OP_VV (ior, 256, int8_t, |) +DEF_OP_VV (ior, 512, int8_t, |) +DEF_OP_VV (ior, 1024, int8_t, |) +DEF_OP_VV (ior, 2048, int8_t, |) +DEF_OP_VV (ior, 4096, int8_t, |) + +DEF_OP_VV (ior, 1, int16_t, |) +DEF_OP_VV (ior, 2, int16_t, |) +DEF_OP_VV (ior, 4, int16_t, |) +DEF_OP_VV (ior, 8, int16_t, |) +DEF_OP_VV (ior, 16, int16_t, |) +DEF_OP_VV (ior, 32, int16_t, |) +DEF_OP_VV (ior, 64, int16_t, |) +DEF_OP_VV (ior, 128, int16_t, |) +DEF_OP_VV (ior, 256, int16_t, |) +DEF_OP_VV (ior, 512, int16_t, |) +DEF_OP_VV (ior, 1024, int16_t, |) +DEF_OP_VV (ior, 2048, int16_t, |) + +DEF_OP_VV (ior, 1, int32_t, |) +DEF_OP_VV (ior, 2, int32_t, |) +DEF_OP_VV (ior, 4, int32_t, |) +DEF_OP_VV (ior, 8, int32_t, |) +DEF_OP_VV (ior, 16, int32_t, |) +DEF_OP_VV (ior, 32, int32_t, |) +DEF_OP_VV (ior, 64, int32_t, |) +DEF_OP_VV (ior, 128, int32_t, |) +DEF_OP_VV (ior, 256, int32_t, |) +DEF_OP_VV (ior, 512, int32_t, |) +DEF_OP_VV (ior, 1024, int32_t, |) + +DEF_OP_VV (ior, 1, int64_t, |) +DEF_OP_VV (ior, 2, int64_t, |) +DEF_OP_VV (ior, 4, int64_t, |) +DEF_OP_VV (ior, 8, int64_t, |) +DEF_OP_VV (ior, 16, int64_t, |) +DEF_OP_VV (ior, 32, int64_t, |) +DEF_OP_VV (ior, 64, int64_t, |) +DEF_OP_VV (ior, 128, int64_t, |) +DEF_OP_VV (ior, 256, int64_t, |) +DEF_OP_VV (ior, 512, int64_t, |) + +/* { dg-final { scan-assembler-times {vor\.vv\s+v[0-9]+,\s*v[0-9]+,\s*v[0-9]+} 42 } } */ +/* { dg-final { scan-assembler-not {csrr} } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/ior-2.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/ior-2.c new file mode 100644 index 000000000000..adcba29197a8 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/ior-2.c @@ -0,0 +1,57 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gcv_zvfh_zvl4096b -mabi=lp64d -O3 -fno-schedule-insns -fno-schedule-insns2 --param=riscv-autovec-lmul=m8" } */ + +#include "def.h" + +DEF_OP_VI_M16 (ior, 1, int8_t, |) +DEF_OP_VI_M16 (ior, 2, int8_t, |) +DEF_OP_VI_M16 (ior, 4, int8_t, |) +DEF_OP_VI_M16 (ior, 8, int8_t, |) +DEF_OP_VI_M16 (ior, 16, int8_t, |) +DEF_OP_VI_M16 (ior, 32, int8_t, |) +DEF_OP_VI_M16 (ior, 64, int8_t, |) +DEF_OP_VI_M16 (ior, 128, int8_t, |) +DEF_OP_VI_M16 (ior, 256, int8_t, |) +DEF_OP_VI_M16 (ior, 512, int8_t, |) +DEF_OP_VI_M16 (ior, 1024, int8_t, |) +DEF_OP_VI_M16 (ior, 2048, int8_t, |) +DEF_OP_VI_M16 (ior, 4096, int8_t, |) + +DEF_OP_VI_M16 (ior, 1, int16_t, |) +DEF_OP_VI_M16 (ior, 2, int16_t, |) +DEF_OP_VI_M16 (ior, 4, int16_t, |) +DEF_OP_VI_M16 (ior, 8, int16_t, |) +DEF_OP_VI_M16 (ior, 16, int16_t, |) +DEF_OP_VI_M16 (ior, 32, int16_t, |) +DEF_OP_VI_M16 (ior, 64, int16_t, |) +DEF_OP_VI_M16 (ior, 128, int16_t, |) +DEF_OP_VI_M16 (ior, 256, int16_t, |) +DEF_OP_VI_M16 (ior, 512, int16_t, |) +DEF_OP_VI_M16 (ior, 1024, int16_t, |) +DEF_OP_VI_M16 (ior, 2048, int16_t, |) + +DEF_OP_VI_M16 (ior, 1, int32_t, |) +DEF_OP_VI_M16 (ior, 2, int32_t, |) +DEF_OP_VI_M16 (ior, 4, int32_t, |) +DEF_OP_VI_M16 (ior, 8, int32_t, |) +DEF_OP_VI_M16 (ior, 16, int32_t, |) +DEF_OP_VI_M16 (ior, 32, int32_t, |) +DEF_OP_VI_M16 (ior, 64, int32_t, |) +DEF_OP_VI_M16 (ior, 128, int32_t, |) +DEF_OP_VI_M16 (ior, 256, int32_t, |) +DEF_OP_VI_M16 (ior, 512, int32_t, |) +DEF_OP_VI_M16 (ior, 1024, int32_t, |) + +DEF_OP_VI_M16 (ior, 1, int64_t, |) +DEF_OP_VI_M16 (ior, 2, int64_t, |) +DEF_OP_VI_M16 (ior, 4, int64_t, |) +DEF_OP_VI_M16 (ior, 8, int64_t, |) +DEF_OP_VI_M16 (ior, 16, int64_t, |) +DEF_OP_VI_M16 (ior, 32, int64_t, |) +DEF_OP_VI_M16 (ior, 64, int64_t, |) +DEF_OP_VI_M16 (ior, 128, int64_t, |) +DEF_OP_VI_M16 (ior, 256, int64_t, |) +DEF_OP_VI_M16 (ior, 512, int64_t, |) + +/* { dg-final { scan-assembler-times {vor\.vi\s+v[0-9]+,\s*v[0-9]+,\s*-16} 42 } } */ +/* { dg-final { scan-assembler-not {csrr} } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/ior-3.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/ior-3.c new file mode 100644 index 000000000000..ed142d58489c --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/ior-3.c @@ -0,0 +1,57 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gcv_zvfh_zvl4096b -mabi=lp64d -O3 -fno-schedule-insns -fno-schedule-insns2 --param=riscv-autovec-lmul=m8" } */ + +#include "def.h" + +DEF_OP_VI_15 (ior, 1, int8_t, |) +DEF_OP_VI_15 (ior, 2, int8_t, |) +DEF_OP_VI_15 (ior, 4, int8_t, |) +DEF_OP_VI_15 (ior, 8, int8_t, |) +DEF_OP_VI_15 (ior, 16, int8_t, |) +DEF_OP_VI_15 (ior, 32, int8_t, |) +DEF_OP_VI_15 (ior, 64, int8_t, |) +DEF_OP_VI_15 (ior, 128, int8_t, |) +DEF_OP_VI_15 (ior, 256, int8_t, |) +DEF_OP_VI_15 (ior, 512, int8_t, |) +DEF_OP_VI_15 (ior, 1024, int8_t, |) +DEF_OP_VI_15 (ior, 2048, int8_t, |) +DEF_OP_VI_15 (ior, 4096, int8_t, |) + +DEF_OP_VI_15 (ior, 1, int16_t, |) +DEF_OP_VI_15 (ior, 2, int16_t, |) +DEF_OP_VI_15 (ior, 4, int16_t, |) +DEF_OP_VI_15 (ior, 8, int16_t, |) +DEF_OP_VI_15 (ior, 16, int16_t, |) +DEF_OP_VI_15 (ior, 32, int16_t, |) +DEF_OP_VI_15 (ior, 64, int16_t, |) +DEF_OP_VI_15 (ior, 128, int16_t, |) +DEF_OP_VI_15 (ior, 256, int16_t, |) +DEF_OP_VI_15 (ior, 512, int16_t, |) +DEF_OP_VI_15 (ior, 1024, int16_t, |) +DEF_OP_VI_15 (ior, 2048, int16_t, |) + +DEF_OP_VI_15 (ior, 1, int32_t, |) +DEF_OP_VI_15 (ior, 2, int32_t, |) +DEF_OP_VI_15 (ior, 4, int32_t, |) +DEF_OP_VI_15 (ior, 8, int32_t, |) +DEF_OP_VI_15 (ior, 16, int32_t, |) +DEF_OP_VI_15 (ior, 32, int32_t, |) +DEF_OP_VI_15 (ior, 64, int32_t, |) +DEF_OP_VI_15 (ior, 128, int32_t, |) +DEF_OP_VI_15 (ior, 256, int32_t, |) +DEF_OP_VI_15 (ior, 512, int32_t, |) +DEF_OP_VI_15 (ior, 1024, int32_t, |) + +DEF_OP_VI_15 (ior, 1, int64_t, |) +DEF_OP_VI_15 (ior, 2, int64_t, |) +DEF_OP_VI_15 (ior, 4, int64_t, |) +DEF_OP_VI_15 (ior, 8, int64_t, |) +DEF_OP_VI_15 (ior, 16, int64_t, |) +DEF_OP_VI_15 (ior, 32, int64_t, |) +DEF_OP_VI_15 (ior, 64, int64_t, |) +DEF_OP_VI_15 (ior, 128, int64_t, |) +DEF_OP_VI_15 (ior, 256, int64_t, |) +DEF_OP_VI_15 (ior, 512, int64_t, |) + +/* { dg-final { scan-assembler-times {vor\.vi\s+v[0-9]+,\s*v[0-9]+,\s*15} 42 } } */ +/* { dg-final { scan-assembler-not {csrr} } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/max-1.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/max-1.c new file mode 100644 index 000000000000..e4400c20733c --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/max-1.c @@ -0,0 +1,57 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gcv_zvfh_zvl4096b -mabi=lp64d -O3 -fno-schedule-insns -fno-schedule-insns2 --param=riscv-autovec-lmul=m8" } */ + +#include "def.h" + +DEF_MINMAX_VV (max, 1, int8_t, >) +DEF_MINMAX_VV (max, 2, int8_t, >) +DEF_MINMAX_VV (max, 4, int8_t, >) +DEF_MINMAX_VV (max, 8, int8_t, >) +DEF_MINMAX_VV (max, 16, int8_t, >) +DEF_MINMAX_VV (max, 32, int8_t, >) +DEF_MINMAX_VV (max, 64, int8_t, >) +DEF_MINMAX_VV (max, 128, int8_t, >) +DEF_MINMAX_VV (max, 256, int8_t, >) +DEF_MINMAX_VV (max, 512, int8_t, >) +DEF_MINMAX_VV (max, 1024, int8_t, >) +DEF_MINMAX_VV (max, 2048, int8_t, >) +DEF_MINMAX_VV (max, 4096, int8_t, >) + +DEF_MINMAX_VV (max, 1, int16_t, >) +DEF_MINMAX_VV (max, 2, int16_t, >) +DEF_MINMAX_VV (max, 4, int16_t, >) +DEF_MINMAX_VV (max, 8, int16_t, >) +DEF_MINMAX_VV (max, 16, int16_t, >) +DEF_MINMAX_VV (max, 32, int16_t, >) +DEF_MINMAX_VV (max, 64, int16_t, >) +DEF_MINMAX_VV (max, 128, int16_t, >) +DEF_MINMAX_VV (max, 256, int16_t, >) +DEF_MINMAX_VV (max, 512, int16_t, >) +DEF_MINMAX_VV (max, 1024, int16_t, >) +DEF_MINMAX_VV (max, 2048, int16_t, >) + +DEF_MINMAX_VV (max, 1, int32_t, >) +DEF_MINMAX_VV (max, 2, int32_t, >) +DEF_MINMAX_VV (max, 4, int32_t, >) +DEF_MINMAX_VV (max, 8, int32_t, >) +DEF_MINMAX_VV (max, 16, int32_t, >) +DEF_MINMAX_VV (max, 32, int32_t, >) +DEF_MINMAX_VV (max, 64, int32_t, >) +DEF_MINMAX_VV (max, 128, int32_t, >) +DEF_MINMAX_VV (max, 256, int32_t, >) +DEF_MINMAX_VV (max, 512, int32_t, >) +DEF_MINMAX_VV (max, 1024, int32_t, >) + +DEF_MINMAX_VV (max, 1, int64_t, >) +DEF_MINMAX_VV (max, 2, int64_t, >) +DEF_MINMAX_VV (max, 4, int64_t, >) +DEF_MINMAX_VV (max, 8, int64_t, >) +DEF_MINMAX_VV (max, 16, int64_t, >) +DEF_MINMAX_VV (max, 32, int64_t, >) +DEF_MINMAX_VV (max, 64, int64_t, >) +DEF_MINMAX_VV (max, 128, int64_t, >) +DEF_MINMAX_VV (max, 256, int64_t, >) +DEF_MINMAX_VV (max, 512, int64_t, >) + +/* { dg-final { scan-assembler-times {vmax\.vv\s+v[0-9]+,\s*v[0-9]+,\s*v[0-9]+} 42 } } */ +/* { dg-final { scan-assembler-not {csrr} } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/min-1.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/min-1.c new file mode 100644 index 000000000000..41e2d26e1588 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/min-1.c @@ -0,0 +1,57 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gcv_zvfh_zvl4096b -mabi=lp64d -O3 -fno-schedule-insns -fno-schedule-insns2 --param=riscv-autovec-lmul=m8" } */ + +#include "def.h" + +DEF_MINMAX_VV (min, 1, int8_t, <) +DEF_MINMAX_VV (min, 2, int8_t, <) +DEF_MINMAX_VV (min, 4, int8_t, <) +DEF_MINMAX_VV (min, 8, int8_t, <) +DEF_MINMAX_VV (min, 16, int8_t, <) +DEF_MINMAX_VV (min, 32, int8_t, <) +DEF_MINMAX_VV (min, 64, int8_t, <) +DEF_MINMAX_VV (min, 128, int8_t, <) +DEF_MINMAX_VV (min, 256, int8_t, <) +DEF_MINMAX_VV (min, 512, int8_t, <) +DEF_MINMAX_VV (min, 1024, int8_t, <) +DEF_MINMAX_VV (min, 2048, int8_t, <) +DEF_MINMAX_VV (min, 4096, int8_t, <) + +DEF_MINMAX_VV (min, 1, int16_t, <) +DEF_MINMAX_VV (min, 2, int16_t, <) +DEF_MINMAX_VV (min, 4, int16_t, <) +DEF_MINMAX_VV (min, 8, int16_t, <) +DEF_MINMAX_VV (min, 16, int16_t, <) +DEF_MINMAX_VV (min, 32, int16_t, <) +DEF_MINMAX_VV (min, 64, int16_t, <) +DEF_MINMAX_VV (min, 128, int16_t, <) +DEF_MINMAX_VV (min, 256, int16_t, <) +DEF_MINMAX_VV (min, 512, int16_t, <) +DEF_MINMAX_VV (min, 1024, int16_t, <) +DEF_MINMAX_VV (min, 2048, int16_t, <) + +DEF_MINMAX_VV (min, 1, int32_t, <) +DEF_MINMAX_VV (min, 2, int32_t, <) +DEF_MINMAX_VV (min, 4, int32_t, <) +DEF_MINMAX_VV (min, 8, int32_t, <) +DEF_MINMAX_VV (min, 16, int32_t, <) +DEF_MINMAX_VV (min, 32, int32_t, <) +DEF_MINMAX_VV (min, 64, int32_t, <) +DEF_MINMAX_VV (min, 128, int32_t, <) +DEF_MINMAX_VV (min, 256, int32_t, <) +DEF_MINMAX_VV (min, 512, int32_t, <) +DEF_MINMAX_VV (min, 1024, int32_t, <) + +DEF_MINMAX_VV (min, 1, int64_t, <) +DEF_MINMAX_VV (min, 2, int64_t, <) +DEF_MINMAX_VV (min, 4, int64_t, <) +DEF_MINMAX_VV (min, 8, int64_t, <) +DEF_MINMAX_VV (min, 16, int64_t, <) +DEF_MINMAX_VV (min, 32, int64_t, <) +DEF_MINMAX_VV (min, 64, int64_t, <) +DEF_MINMAX_VV (min, 128, int64_t, <) +DEF_MINMAX_VV (min, 256, int64_t, <) +DEF_MINMAX_VV (min, 512, int64_t, <) + +/* { dg-final { scan-assembler-times {vmin\.vv\s+v[0-9]+,\s*v[0-9]+,\s*v[0-9]+} 42 } } */ +/* { dg-final { scan-assembler-not {csrr} } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/minus-1.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/minus-1.c new file mode 100644 index 000000000000..4d698ba3c890 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/minus-1.c @@ -0,0 +1,57 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gcv_zvfh_zvl4096b -mabi=lp64d -O3 -fno-schedule-insns -fno-schedule-insns2 --param=riscv-autovec-lmul=m8" } */ + +#include "def.h" + +DEF_OP_VV (minus, 1, int8_t, -) +DEF_OP_VV (minus, 2, int8_t, -) +DEF_OP_VV (minus, 4, int8_t, -) +DEF_OP_VV (minus, 8, int8_t, -) +DEF_OP_VV (minus, 16, int8_t, -) +DEF_OP_VV (minus, 32, int8_t, -) +DEF_OP_VV (minus, 64, int8_t, -) +DEF_OP_VV (minus, 128, int8_t, -) +DEF_OP_VV (minus, 256, int8_t, -) +DEF_OP_VV (minus, 512, int8_t, -) +DEF_OP_VV (minus, 1024, int8_t, -) +DEF_OP_VV (minus, 2048, int8_t, -) +DEF_OP_VV (minus, 4096, int8_t, -) + +DEF_OP_VV (minus, 1, int16_t, -) +DEF_OP_VV (minus, 2, int16_t, -) +DEF_OP_VV (minus, 4, int16_t, -) +DEF_OP_VV (minus, 8, int16_t, -) +DEF_OP_VV (minus, 16, int16_t, -) +DEF_OP_VV (minus, 32, int16_t, -) +DEF_OP_VV (minus, 64, int16_t, -) +DEF_OP_VV (minus, 128, int16_t, -) +DEF_OP_VV (minus, 256, int16_t, -) +DEF_OP_VV (minus, 512, int16_t, -) +DEF_OP_VV (minus, 1024, int16_t, -) +DEF_OP_VV (minus, 2048, int16_t, -) + +DEF_OP_VV (minus, 1, int32_t, -) +DEF_OP_VV (minus, 2, int32_t, -) +DEF_OP_VV (minus, 4, int32_t, -) +DEF_OP_VV (minus, 8, int32_t, -) +DEF_OP_VV (minus, 16, int32_t, -) +DEF_OP_VV (minus, 32, int32_t, -) +DEF_OP_VV (minus, 64, int32_t, -) +DEF_OP_VV (minus, 128, int32_t, -) +DEF_OP_VV (minus, 256, int32_t, -) +DEF_OP_VV (minus, 512, int32_t, -) +DEF_OP_VV (minus, 1024, int32_t, -) + +DEF_OP_VV (minus, 1, int64_t, -) +DEF_OP_VV (minus, 2, int64_t, -) +DEF_OP_VV (minus, 4, int64_t, -) +DEF_OP_VV (minus, 8, int64_t, -) +DEF_OP_VV (minus, 16, int64_t, -) +DEF_OP_VV (minus, 32, int64_t, -) +DEF_OP_VV (minus, 64, int64_t, -) +DEF_OP_VV (minus, 128, int64_t, -) +DEF_OP_VV (minus, 256, int64_t, -) +DEF_OP_VV (minus, 512, int64_t, -) + +/* { dg-final { scan-assembler-times {vsub\.vv\s+v[0-9]+,\s*v[0-9]+,\s*v[0-9]+} 42 } } */ +/* { dg-final { scan-assembler-not {csrr} } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/minus-2.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/minus-2.c new file mode 100644 index 000000000000..2d9dd6290f5e --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/minus-2.c @@ -0,0 +1,57 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gcv_zvfh_zvl4096b -mabi=lp64d -O3 -fno-schedule-insns -fno-schedule-insns2 --param=riscv-autovec-lmul=m8" } */ + +#include "def.h" + +DEF_OP_IV_M16 (minus, 1, int8_t, -) +DEF_OP_IV_M16 (minus, 2, int8_t, -) +DEF_OP_IV_M16 (minus, 4, int8_t, -) +DEF_OP_IV_M16 (minus, 8, int8_t, -) +DEF_OP_IV_M16 (minus, 16, int8_t, -) +DEF_OP_IV_M16 (minus, 32, int8_t, -) +DEF_OP_IV_M16 (minus, 64, int8_t, -) +DEF_OP_IV_M16 (minus, 128, int8_t, -) +DEF_OP_IV_M16 (minus, 256, int8_t, -) +DEF_OP_IV_M16 (minus, 512, int8_t, -) +DEF_OP_IV_M16 (minus, 1024, int8_t, -) +DEF_OP_IV_M16 (minus, 2048, int8_t, -) +DEF_OP_IV_M16 (minus, 4096, int8_t, -) + +DEF_OP_IV_M16 (minus, 1, int16_t, -) +DEF_OP_IV_M16 (minus, 2, int16_t, -) +DEF_OP_IV_M16 (minus, 4, int16_t, -) +DEF_OP_IV_M16 (minus, 8, int16_t, -) +DEF_OP_IV_M16 (minus, 16, int16_t, -) +DEF_OP_IV_M16 (minus, 32, int16_t, -) +DEF_OP_IV_M16 (minus, 64, int16_t, -) +DEF_OP_IV_M16 (minus, 128, int16_t, -) +DEF_OP_IV_M16 (minus, 256, int16_t, -) +DEF_OP_IV_M16 (minus, 512, int16_t, -) +DEF_OP_IV_M16 (minus, 1024, int16_t, -) +DEF_OP_IV_M16 (minus, 2048, int16_t, -) + +DEF_OP_IV_M16 (minus, 1, int32_t, -) +DEF_OP_IV_M16 (minus, 2, int32_t, -) +DEF_OP_IV_M16 (minus, 4, int32_t, -) +DEF_OP_IV_M16 (minus, 8, int32_t, -) +DEF_OP_IV_M16 (minus, 16, int32_t, -) +DEF_OP_IV_M16 (minus, 32, int32_t, -) +DEF_OP_IV_M16 (minus, 64, int32_t, -) +DEF_OP_IV_M16 (minus, 128, int32_t, -) +DEF_OP_IV_M16 (minus, 256, int32_t, -) +DEF_OP_IV_M16 (minus, 512, int32_t, -) +DEF_OP_IV_M16 (minus, 1024, int32_t, -) + +DEF_OP_IV_M16 (minus, 1, int64_t, -) +DEF_OP_IV_M16 (minus, 2, int64_t, -) +DEF_OP_IV_M16 (minus, 4, int64_t, -) +DEF_OP_IV_M16 (minus, 8, int64_t, -) +DEF_OP_IV_M16 (minus, 16, int64_t, -) +DEF_OP_IV_M16 (minus, 32, int64_t, -) +DEF_OP_IV_M16 (minus, 64, int64_t, -) +DEF_OP_IV_M16 (minus, 128, int64_t, -) +DEF_OP_IV_M16 (minus, 256, int64_t, -) +DEF_OP_IV_M16 (minus, 512, int64_t, -) + +/* { dg-final { scan-assembler-times {vrsub\.vi\s+v[0-9]+,\s*v[0-9]+,\s*-16} 42 } } */ +/* { dg-final { scan-assembler-not {csrr} } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/minus-3.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/minus-3.c new file mode 100644 index 000000000000..2625c164e41b --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/minus-3.c @@ -0,0 +1,57 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gcv_zvfh_zvl4096b -mabi=lp64d -O3 -fno-schedule-insns -fno-schedule-insns2 --param=riscv-autovec-lmul=m8" } */ + +#include "def.h" + +DEF_OP_IV_15 (minus, 1, int8_t, -) +DEF_OP_IV_15 (minus, 2, int8_t, -) +DEF_OP_IV_15 (minus, 4, int8_t, -) +DEF_OP_IV_15 (minus, 8, int8_t, -) +DEF_OP_IV_15 (minus, 16, int8_t, -) +DEF_OP_IV_15 (minus, 32, int8_t, -) +DEF_OP_IV_15 (minus, 64, int8_t, -) +DEF_OP_IV_15 (minus, 128, int8_t, -) +DEF_OP_IV_15 (minus, 256, int8_t, -) +DEF_OP_IV_15 (minus, 512, int8_t, -) +DEF_OP_IV_15 (minus, 1024, int8_t, -) +DEF_OP_IV_15 (minus, 2048, int8_t, -) +DEF_OP_IV_15 (minus, 4096, int8_t, -) + +DEF_OP_IV_15 (minus, 1, int16_t, -) +DEF_OP_IV_15 (minus, 2, int16_t, -) +DEF_OP_IV_15 (minus, 4, int16_t, -) +DEF_OP_IV_15 (minus, 8, int16_t, -) +DEF_OP_IV_15 (minus, 16, int16_t, -) +DEF_OP_IV_15 (minus, 32, int16_t, -) +DEF_OP_IV_15 (minus, 64, int16_t, -) +DEF_OP_IV_15 (minus, 128, int16_t, -) +DEF_OP_IV_15 (minus, 256, int16_t, -) +DEF_OP_IV_15 (minus, 512, int16_t, -) +DEF_OP_IV_15 (minus, 1024, int16_t, -) +DEF_OP_IV_15 (minus, 2048, int16_t, -) + +DEF_OP_IV_15 (minus, 1, int32_t, -) +DEF_OP_IV_15 (minus, 2, int32_t, -) +DEF_OP_IV_15 (minus, 4, int32_t, -) +DEF_OP_IV_15 (minus, 8, int32_t, -) +DEF_OP_IV_15 (minus, 16, int32_t, -) +DEF_OP_IV_15 (minus, 32, int32_t, -) +DEF_OP_IV_15 (minus, 64, int32_t, -) +DEF_OP_IV_15 (minus, 128, int32_t, -) +DEF_OP_IV_15 (minus, 256, int32_t, -) +DEF_OP_IV_15 (minus, 512, int32_t, -) +DEF_OP_IV_15 (minus, 1024, int32_t, -) + +DEF_OP_IV_15 (minus, 1, int64_t, -) +DEF_OP_IV_15 (minus, 2, int64_t, -) +DEF_OP_IV_15 (minus, 4, int64_t, -) +DEF_OP_IV_15 (minus, 8, int64_t, -) +DEF_OP_IV_15 (minus, 16, int64_t, -) +DEF_OP_IV_15 (minus, 32, int64_t, -) +DEF_OP_IV_15 (minus, 64, int64_t, -) +DEF_OP_IV_15 (minus, 128, int64_t, -) +DEF_OP_IV_15 (minus, 256, int64_t, -) +DEF_OP_IV_15 (minus, 512, int64_t, -) + +/* { dg-final { scan-assembler-times {vrsub\.vi\s+v[0-9]+,\s*v[0-9]+,\s*15} 42 } } */ +/* { dg-final { scan-assembler-not {csrr} } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/misalign-1.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/misalign-1.c new file mode 100644 index 000000000000..b602ffd69bbc --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/misalign-1.c @@ -0,0 +1,27 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gcv -mabi=lp64d -O3 -fno-schedule-insns -fno-schedule-insns2 --param=riscv-autovec-lmul=m4 -fno-tree-loop-distribute-patterns" } */ + +#include + +typedef union U { unsigned short s; unsigned char c; } __attribute__((packed)) U; +struct S { char e __attribute__((aligned (64))); U s[32]; }; +struct S t = {0, {{1}, {2}, {3}, {4}, {5}, {6}, {7}, {8}, + {9}, {10}, {11}, {12}, {13}, {14}, {15}, {16}, + {17}, {18}, {19}, {20}, {21}, {22}, {23}, {24}, + {25}, {26}, {27}, {28}, {29}, {30}, {31}, {32}}}; +unsigned short d[32] = { 1 }; + +__attribute__((noinline, noclone)) void +foo () +{ + int i; + for (i = 0; i < 32; i++) + d[i] = t.s[i].s; + if (__builtin_memcmp (d, t.s, sizeof d)) + abort (); +} + +/* { dg-final { scan-assembler-times {vle8\.v} 1 } } */ +/* { dg-final { scan-assembler-times {vle8\.v} 1 } } */ +/* { dg-final { scan-assembler-not {vle16\.v} } } */ +/* { dg-final { scan-assembler-not {vle16\.v} } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/mod-1.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/mod-1.c new file mode 100644 index 000000000000..c8caf3535536 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/mod-1.c @@ -0,0 +1,57 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gcv_zvfh_zvl4096b -mabi=lp64d -O3 -fno-schedule-insns -fno-schedule-insns2 --param=riscv-autovec-lmul=m8" } */ + +#include "def.h" + +DEF_OP_VV (mod, 1, int8_t, %) +DEF_OP_VV (mod, 2, int8_t, %) +DEF_OP_VV (mod, 4, int8_t, %) +DEF_OP_VV (mod, 8, int8_t, %) +DEF_OP_VV (mod, 16, int8_t, %) +DEF_OP_VV (mod, 32, int8_t, %) +DEF_OP_VV (mod, 64, int8_t, %) +DEF_OP_VV (mod, 128, int8_t, %) +DEF_OP_VV (mod, 256, int8_t, %) +DEF_OP_VV (mod, 512, int8_t, %) +DEF_OP_VV (mod, 1024, int8_t, %) +DEF_OP_VV (mod, 2048, int8_t, %) +DEF_OP_VV (mod, 4096, int8_t, %) + +DEF_OP_VV (mod, 1, int16_t, %) +DEF_OP_VV (mod, 2, int16_t, %) +DEF_OP_VV (mod, 4, int16_t, %) +DEF_OP_VV (mod, 8, int16_t, %) +DEF_OP_VV (mod, 16, int16_t, %) +DEF_OP_VV (mod, 32, int16_t, %) +DEF_OP_VV (mod, 64, int16_t, %) +DEF_OP_VV (mod, 128, int16_t, %) +DEF_OP_VV (mod, 256, int16_t, %) +DEF_OP_VV (mod, 512, int16_t, %) +DEF_OP_VV (mod, 1024, int16_t, %) +DEF_OP_VV (mod, 2048, int16_t, %) + +DEF_OP_VV (mod, 1, int32_t, %) +DEF_OP_VV (mod, 2, int32_t, %) +DEF_OP_VV (mod, 4, int32_t, %) +DEF_OP_VV (mod, 8, int32_t, %) +DEF_OP_VV (mod, 16, int32_t, %) +DEF_OP_VV (mod, 32, int32_t, %) +DEF_OP_VV (mod, 64, int32_t, %) +DEF_OP_VV (mod, 128, int32_t, %) +DEF_OP_VV (mod, 256, int32_t, %) +DEF_OP_VV (mod, 512, int32_t, %) +DEF_OP_VV (mod, 1024, int32_t, %) + +DEF_OP_VV (mod, 1, int64_t, %) +DEF_OP_VV (mod, 2, int64_t, %) +DEF_OP_VV (mod, 4, int64_t, %) +DEF_OP_VV (mod, 8, int64_t, %) +DEF_OP_VV (mod, 16, int64_t, %) +DEF_OP_VV (mod, 32, int64_t, %) +DEF_OP_VV (mod, 64, int64_t, %) +DEF_OP_VV (mod, 128, int64_t, %) +DEF_OP_VV (mod, 256, int64_t, %) +DEF_OP_VV (mod, 512, int64_t, %) + +/* { dg-final { scan-assembler-times {vremu?\.vv\s+v[0-9]+,\s*v[0-9]+,\s*v[0-9]+} 42 } } */ +/* { dg-final { scan-assembler-not {csrr} } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/mult-1.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/mult-1.c new file mode 100644 index 000000000000..0d1b5a45e9c9 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/mult-1.c @@ -0,0 +1,57 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gcv_zvfh_zvl4096b -mabi=lp64d -O3 -fno-schedule-insns -fno-schedule-insns2 --param=riscv-autovec-lmul=m8" } */ + +#include "def.h" + +DEF_OP_VV (mult, 1, int8_t, *) +DEF_OP_VV (mult, 2, int8_t, *) +DEF_OP_VV (mult, 4, int8_t, *) +DEF_OP_VV (mult, 8, int8_t, *) +DEF_OP_VV (mult, 16, int8_t, *) +DEF_OP_VV (mult, 32, int8_t, *) +DEF_OP_VV (mult, 64, int8_t, *) +DEF_OP_VV (mult, 128, int8_t, *) +DEF_OP_VV (mult, 256, int8_t, *) +DEF_OP_VV (mult, 512, int8_t, *) +DEF_OP_VV (mult, 1024, int8_t, *) +DEF_OP_VV (mult, 2048, int8_t, *) +DEF_OP_VV (mult, 4096, int8_t, *) + +DEF_OP_VV (mult, 1, int16_t, *) +DEF_OP_VV (mult, 2, int16_t, *) +DEF_OP_VV (mult, 4, int16_t, *) +DEF_OP_VV (mult, 8, int16_t, *) +DEF_OP_VV (mult, 16, int16_t, *) +DEF_OP_VV (mult, 32, int16_t, *) +DEF_OP_VV (mult, 64, int16_t, *) +DEF_OP_VV (mult, 128, int16_t, *) +DEF_OP_VV (mult, 256, int16_t, *) +DEF_OP_VV (mult, 512, int16_t, *) +DEF_OP_VV (mult, 1024, int16_t, *) +DEF_OP_VV (mult, 2048, int16_t, *) + +DEF_OP_VV (mult, 1, int32_t, *) +DEF_OP_VV (mult, 2, int32_t, *) +DEF_OP_VV (mult, 4, int32_t, *) +DEF_OP_VV (mult, 8, int32_t, *) +DEF_OP_VV (mult, 16, int32_t, *) +DEF_OP_VV (mult, 32, int32_t, *) +DEF_OP_VV (mult, 64, int32_t, *) +DEF_OP_VV (mult, 128, int32_t, *) +DEF_OP_VV (mult, 256, int32_t, *) +DEF_OP_VV (mult, 512, int32_t, *) +DEF_OP_VV (mult, 1024, int32_t, *) + +DEF_OP_VV (mult, 1, int64_t, *) +DEF_OP_VV (mult, 2, int64_t, *) +DEF_OP_VV (mult, 4, int64_t, *) +DEF_OP_VV (mult, 8, int64_t, *) +DEF_OP_VV (mult, 16, int64_t, *) +DEF_OP_VV (mult, 32, int64_t, *) +DEF_OP_VV (mult, 64, int64_t, *) +DEF_OP_VV (mult, 128, int64_t, *) +DEF_OP_VV (mult, 256, int64_t, *) +DEF_OP_VV (mult, 512, int64_t, *) + +/* { dg-final { scan-assembler-times {vmul\.vv\s+v[0-9]+,\s*v[0-9]+,\s*v[0-9]+} 42 } } */ +/* { dg-final { scan-assembler-not {csrr} } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/neg-1.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/neg-1.c new file mode 100644 index 000000000000..0d723d70e8c2 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/neg-1.c @@ -0,0 +1,57 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gcv_zvfh_zvl4096b -mabi=lp64d -O3 -fno-schedule-insns -fno-schedule-insns2 --param=riscv-autovec-lmul=m8" } */ + +#include "def.h" + +DEF_OP_V (neg, 1, int8_t, -) +DEF_OP_V (neg, 2, int8_t, -) +DEF_OP_V (neg, 4, int8_t, -) +DEF_OP_V (neg, 8, int8_t, -) +DEF_OP_V (neg, 16, int8_t, -) +DEF_OP_V (neg, 32, int8_t, -) +DEF_OP_V (neg, 64, int8_t, -) +DEF_OP_V (neg, 128, int8_t, -) +DEF_OP_V (neg, 256, int8_t, -) +DEF_OP_V (neg, 512, int8_t, -) +DEF_OP_V (neg, 1024, int8_t, -) +DEF_OP_V (neg, 2048, int8_t, -) +DEF_OP_V (neg, 4096, int8_t, -) + +DEF_OP_V (neg, 1, int16_t, -) +DEF_OP_V (neg, 2, int16_t, -) +DEF_OP_V (neg, 4, int16_t, -) +DEF_OP_V (neg, 8, int16_t, -) +DEF_OP_V (neg, 16, int16_t, -) +DEF_OP_V (neg, 32, int16_t, -) +DEF_OP_V (neg, 64, int16_t, -) +DEF_OP_V (neg, 128, int16_t, -) +DEF_OP_V (neg, 256, int16_t, -) +DEF_OP_V (neg, 512, int16_t, -) +DEF_OP_V (neg, 1024, int16_t, -) +DEF_OP_V (neg, 2048, int16_t, -) + +DEF_OP_V (neg, 1, int32_t, -) +DEF_OP_V (neg, 2, int32_t, -) +DEF_OP_V (neg, 4, int32_t, -) +DEF_OP_V (neg, 8, int32_t, -) +DEF_OP_V (neg, 16, int32_t, -) +DEF_OP_V (neg, 32, int32_t, -) +DEF_OP_V (neg, 64, int32_t, -) +DEF_OP_V (neg, 128, int32_t, -) +DEF_OP_V (neg, 256, int32_t, -) +DEF_OP_V (neg, 512, int32_t, -) +DEF_OP_V (neg, 1024, int32_t, -) + +DEF_OP_V (neg, 1, int64_t, -) +DEF_OP_V (neg, 2, int64_t, -) +DEF_OP_V (neg, 4, int64_t, -) +DEF_OP_V (neg, 8, int64_t, -) +DEF_OP_V (neg, 16, int64_t, -) +DEF_OP_V (neg, 32, int64_t, -) +DEF_OP_V (neg, 64, int64_t, -) +DEF_OP_V (neg, 128, int64_t, -) +DEF_OP_V (neg, 256, int64_t, -) +DEF_OP_V (neg, 512, int64_t, -) + +/* { dg-final { scan-assembler-times {vneg\.v\s+v[0-9]+,\s*v[0-9]+} 42 } } */ +/* { dg-final { scan-assembler-not {csrr} } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/plus-1.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/plus-1.c new file mode 100644 index 000000000000..146b4dd2cace --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/plus-1.c @@ -0,0 +1,57 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gcv_zvfh_zvl4096b -mabi=lp64d -O3 -fno-schedule-insns -fno-schedule-insns2 --param=riscv-autovec-lmul=m8" } */ + +#include "def.h" + +DEF_OP_VV (plus, 1, int8_t, +) +DEF_OP_VV (plus, 2, int8_t, +) +DEF_OP_VV (plus, 4, int8_t, +) +DEF_OP_VV (plus, 8, int8_t, +) +DEF_OP_VV (plus, 16, int8_t, +) +DEF_OP_VV (plus, 32, int8_t, +) +DEF_OP_VV (plus, 64, int8_t, +) +DEF_OP_VV (plus, 128, int8_t, +) +DEF_OP_VV (plus, 256, int8_t, +) +DEF_OP_VV (plus, 512, int8_t, +) +DEF_OP_VV (plus, 1024, int8_t, +) +DEF_OP_VV (plus, 2048, int8_t, +) +DEF_OP_VV (plus, 4096, int8_t, +) + +DEF_OP_VV (plus, 1, int16_t, +) +DEF_OP_VV (plus, 2, int16_t, +) +DEF_OP_VV (plus, 4, int16_t, +) +DEF_OP_VV (plus, 8, int16_t, +) +DEF_OP_VV (plus, 16, int16_t, +) +DEF_OP_VV (plus, 32, int16_t, +) +DEF_OP_VV (plus, 64, int16_t, +) +DEF_OP_VV (plus, 128, int16_t, +) +DEF_OP_VV (plus, 256, int16_t, +) +DEF_OP_VV (plus, 512, int16_t, +) +DEF_OP_VV (plus, 1024, int16_t, +) +DEF_OP_VV (plus, 2048, int16_t, +) + +DEF_OP_VV (plus, 1, int32_t, +) +DEF_OP_VV (plus, 2, int32_t, +) +DEF_OP_VV (plus, 4, int32_t, +) +DEF_OP_VV (plus, 8, int32_t, +) +DEF_OP_VV (plus, 16, int32_t, +) +DEF_OP_VV (plus, 32, int32_t, +) +DEF_OP_VV (plus, 64, int32_t, +) +DEF_OP_VV (plus, 128, int32_t, +) +DEF_OP_VV (plus, 256, int32_t, +) +DEF_OP_VV (plus, 512, int32_t, +) +DEF_OP_VV (plus, 1024, int32_t, +) + +DEF_OP_VV (plus, 1, int64_t, +) +DEF_OP_VV (plus, 2, int64_t, +) +DEF_OP_VV (plus, 4, int64_t, +) +DEF_OP_VV (plus, 8, int64_t, +) +DEF_OP_VV (plus, 16, int64_t, +) +DEF_OP_VV (plus, 32, int64_t, +) +DEF_OP_VV (plus, 64, int64_t, +) +DEF_OP_VV (plus, 128, int64_t, +) +DEF_OP_VV (plus, 256, int64_t, +) +DEF_OP_VV (plus, 512, int64_t, +) + +/* { dg-final { scan-assembler-times {vadd\.vv\s+v[0-9]+,\s*v[0-9]+,\s*v[0-9]+} 42 } } */ +/* { dg-final { scan-assembler-not {csrr} } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/plus-2.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/plus-2.c new file mode 100644 index 000000000000..6ce07194d144 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/plus-2.c @@ -0,0 +1,57 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gcv_zvfh_zvl4096b -mabi=lp64d -O3 -fno-schedule-insns -fno-schedule-insns2 --param=riscv-autovec-lmul=m8" } */ + +#include "def.h" + +DEF_OP_VI_M16 (plus, 1, int8_t, +) +DEF_OP_VI_M16 (plus, 2, int8_t, +) +DEF_OP_VI_M16 (plus, 4, int8_t, +) +DEF_OP_VI_M16 (plus, 8, int8_t, +) +DEF_OP_VI_M16 (plus, 16, int8_t, +) +DEF_OP_VI_M16 (plus, 32, int8_t, +) +DEF_OP_VI_M16 (plus, 64, int8_t, +) +DEF_OP_VI_M16 (plus, 128, int8_t, +) +DEF_OP_VI_M16 (plus, 256, int8_t, +) +DEF_OP_VI_M16 (plus, 512, int8_t, +) +DEF_OP_VI_M16 (plus, 1024, int8_t, +) +DEF_OP_VI_M16 (plus, 2048, int8_t, +) +DEF_OP_VI_M16 (plus, 4096, int8_t, +) + +DEF_OP_VI_M16 (plus, 1, int16_t, +) +DEF_OP_VI_M16 (plus, 2, int16_t, +) +DEF_OP_VI_M16 (plus, 4, int16_t, +) +DEF_OP_VI_M16 (plus, 8, int16_t, +) +DEF_OP_VI_M16 (plus, 16, int16_t, +) +DEF_OP_VI_M16 (plus, 32, int16_t, +) +DEF_OP_VI_M16 (plus, 64, int16_t, +) +DEF_OP_VI_M16 (plus, 128, int16_t, +) +DEF_OP_VI_M16 (plus, 256, int16_t, +) +DEF_OP_VI_M16 (plus, 512, int16_t, +) +DEF_OP_VI_M16 (plus, 1024, int16_t, +) +DEF_OP_VI_M16 (plus, 2048, int16_t, +) + +DEF_OP_VI_M16 (plus, 1, int32_t, +) +DEF_OP_VI_M16 (plus, 2, int32_t, +) +DEF_OP_VI_M16 (plus, 4, int32_t, +) +DEF_OP_VI_M16 (plus, 8, int32_t, +) +DEF_OP_VI_M16 (plus, 16, int32_t, +) +DEF_OP_VI_M16 (plus, 32, int32_t, +) +DEF_OP_VI_M16 (plus, 64, int32_t, +) +DEF_OP_VI_M16 (plus, 128, int32_t, +) +DEF_OP_VI_M16 (plus, 256, int32_t, +) +DEF_OP_VI_M16 (plus, 512, int32_t, +) +DEF_OP_VI_M16 (plus, 1024, int32_t, +) + +DEF_OP_VI_M16 (plus, 1, int64_t, +) +DEF_OP_VI_M16 (plus, 2, int64_t, +) +DEF_OP_VI_M16 (plus, 4, int64_t, +) +DEF_OP_VI_M16 (plus, 8, int64_t, +) +DEF_OP_VI_M16 (plus, 16, int64_t, +) +DEF_OP_VI_M16 (plus, 32, int64_t, +) +DEF_OP_VI_M16 (plus, 64, int64_t, +) +DEF_OP_VI_M16 (plus, 128, int64_t, +) +DEF_OP_VI_M16 (plus, 256, int64_t, +) +DEF_OP_VI_M16 (plus, 512, int64_t, +) + +/* { dg-final { scan-assembler-times {vadd\.vi\s+v[0-9]+,\s*v[0-9]+,\s*-16} 42 } } */ +/* { dg-final { scan-assembler-not {csrr} } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/plus-3.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/plus-3.c new file mode 100644 index 000000000000..c68b2bc7755d --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/plus-3.c @@ -0,0 +1,57 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gcv_zvfh_zvl4096b -mabi=lp64d -O3 -fno-schedule-insns -fno-schedule-insns2 --param=riscv-autovec-lmul=m8" } */ + +#include "def.h" + +DEF_OP_VI_15 (plus, 1, int8_t, +) +DEF_OP_VI_15 (plus, 2, int8_t, +) +DEF_OP_VI_15 (plus, 4, int8_t, +) +DEF_OP_VI_15 (plus, 8, int8_t, +) +DEF_OP_VI_15 (plus, 16, int8_t, +) +DEF_OP_VI_15 (plus, 32, int8_t, +) +DEF_OP_VI_15 (plus, 64, int8_t, +) +DEF_OP_VI_15 (plus, 128, int8_t, +) +DEF_OP_VI_15 (plus, 256, int8_t, +) +DEF_OP_VI_15 (plus, 512, int8_t, +) +DEF_OP_VI_15 (plus, 1024, int8_t, +) +DEF_OP_VI_15 (plus, 2048, int8_t, +) +DEF_OP_VI_15 (plus, 4096, int8_t, +) + +DEF_OP_VI_15 (plus, 1, int16_t, +) +DEF_OP_VI_15 (plus, 2, int16_t, +) +DEF_OP_VI_15 (plus, 4, int16_t, +) +DEF_OP_VI_15 (plus, 8, int16_t, +) +DEF_OP_VI_15 (plus, 16, int16_t, +) +DEF_OP_VI_15 (plus, 32, int16_t, +) +DEF_OP_VI_15 (plus, 64, int16_t, +) +DEF_OP_VI_15 (plus, 128, int16_t, +) +DEF_OP_VI_15 (plus, 256, int16_t, +) +DEF_OP_VI_15 (plus, 512, int16_t, +) +DEF_OP_VI_15 (plus, 1024, int16_t, +) +DEF_OP_VI_15 (plus, 2048, int16_t, +) + +DEF_OP_VI_15 (plus, 1, int32_t, +) +DEF_OP_VI_15 (plus, 2, int32_t, +) +DEF_OP_VI_15 (plus, 4, int32_t, +) +DEF_OP_VI_15 (plus, 8, int32_t, +) +DEF_OP_VI_15 (plus, 16, int32_t, +) +DEF_OP_VI_15 (plus, 32, int32_t, +) +DEF_OP_VI_15 (plus, 64, int32_t, +) +DEF_OP_VI_15 (plus, 128, int32_t, +) +DEF_OP_VI_15 (plus, 256, int32_t, +) +DEF_OP_VI_15 (plus, 512, int32_t, +) +DEF_OP_VI_15 (plus, 1024, int32_t, +) + +DEF_OP_VI_15 (plus, 1, int64_t, +) +DEF_OP_VI_15 (plus, 2, int64_t, +) +DEF_OP_VI_15 (plus, 4, int64_t, +) +DEF_OP_VI_15 (plus, 8, int64_t, +) +DEF_OP_VI_15 (plus, 16, int64_t, +) +DEF_OP_VI_15 (plus, 32, int64_t, +) +DEF_OP_VI_15 (plus, 64, int64_t, +) +DEF_OP_VI_15 (plus, 128, int64_t, +) +DEF_OP_VI_15 (plus, 256, int64_t, +) +DEF_OP_VI_15 (plus, 512, int64_t, +) + +/* { dg-final { scan-assembler-times {vadd\.vi\s+v[0-9]+,\s*v[0-9]+,\s*15} 42 } } */ +/* { dg-final { scan-assembler-not {csrr} } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/pr110994.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/pr110994.c new file mode 100644 index 000000000000..fcacc78b7a0a --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/pr110994.c @@ -0,0 +1,10 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gc -mabi=lp64d --param=riscv-autovec-preference=scalable -O2" } */ + +#include "def.h" + +void foo (int8_t *in, int8_t *out) +{ + v4qi v = *(v4qi*)in; + *(v4qi*)out = v; +} diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/series-1.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/series-1.c new file mode 100644 index 000000000000..b575bb9e60bf --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/series-1.c @@ -0,0 +1,40 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gcv_zvfh_zvl4096b -mabi=lp64d -O3 -fno-schedule-insns -fno-schedule-insns2 --param=riscv-autovec-lmul=m8 -fno-builtin" } */ + +#include "def.h" + +DEF_SERIES (int16_t, 0, 1, 2, b0s1n2) +DEF_SERIES (int16_t, 0, 1, 4, b0s1n4) +DEF_SERIES (int16_t, 0, 1, 8, b0s1n8) +DEF_SERIES (int16_t, 0, 1, 16, b0s1n16) +DEF_SERIES (int16_t, 0, 1, 32, b0s1n32) +DEF_SERIES (int16_t, 0, 1, 64, b0s1n64) +DEF_SERIES (int16_t, 0, 1, 128, b0s1n128) +DEF_SERIES (int16_t, 0, 1, 256, b0s1n256) +DEF_SERIES (int16_t, 0, 1, 512, b0s1n512) +DEF_SERIES (int16_t, 0, 1, 1024, b0s1n1024) +DEF_SERIES (int16_t, 0, 1, 2048, b0s1n2048) + +DEF_SERIES (int32_t, 0, 1, 2, b0s1n2) +DEF_SERIES (int32_t, 0, 1, 4, b0s1n4) +DEF_SERIES (int32_t, 0, 1, 8, b0s1n8) +DEF_SERIES (int32_t, 0, 1, 16, b0s1n16) +DEF_SERIES (int32_t, 0, 1, 32, b0s1n32) +DEF_SERIES (int32_t, 0, 1, 64, b0s1n64) +DEF_SERIES (int32_t, 0, 1, 128, b0s1n128) +DEF_SERIES (int32_t, 0, 1, 256, b0s1n256) +DEF_SERIES (int32_t, 0, 1, 512, b0s1n512) +DEF_SERIES (int32_t, 0, 1, 1024, b0s1n1024) + +DEF_SERIES (int64_t, 0, 1, 2, b0s1n2) +DEF_SERIES (int64_t, 0, 1, 4, b0s1n4) +DEF_SERIES (int64_t, 0, 1, 8, b0s1n8) +DEF_SERIES (int64_t, 0, 1, 16, b0s1n16) +DEF_SERIES (int64_t, 0, 1, 32, b0s1n32) +DEF_SERIES (int64_t, 0, 1, 64, b0s1n64) +DEF_SERIES (int64_t, 0, 1, 128, b0s1n128) +DEF_SERIES (int64_t, 0, 1, 256, b0s1n256) +DEF_SERIES (int64_t, 0, 1, 512, b0s1n512) + +/* { dg-final { scan-assembler-times {vid\.v\s+v[0-9]+} 30 } } */ +/* { dg-final { scan-assembler-not {csrr} } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/series-2.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/series-2.c new file mode 100644 index 000000000000..c84eed158e55 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/series-2.c @@ -0,0 +1,40 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gcv_zvfh_zvl4096b -mabi=lp64d -O3 -fno-schedule-insns -fno-schedule-insns2 --param=riscv-autovec-lmul=m8 -fno-builtin" } */ + +#include "def.h" + +DEF_SERIES (int16_t, 1, -1, 2, b1sm1n2) +DEF_SERIES (int16_t, 3, -1, 4, b3sm1n4) +DEF_SERIES (int16_t, 7, -1, 8, b7sm1n8) +DEF_SERIES (int16_t, 15, -1, 16, b15sm1n16) +DEF_SERIES (int16_t, 31, -1, 32, b31sm1n32) +DEF_SERIES (int16_t, 63, -1, 64, b63sm1n64) +DEF_SERIES (int16_t, 127, -1, 128, b127sm1n128) +DEF_SERIES (int16_t, 255, -1, 256, b255sm1n256) +DEF_SERIES (int16_t, 511, -1, 512, b511sm1n512) +DEF_SERIES (int16_t, 1023, -1, 1024, b1023sm1n1024) +DEF_SERIES (int16_t, 2047, -1, 2048, b2047sm1n2048) + +DEF_SERIES (int32_t, 1, -1, 2, b0sm1n2) +DEF_SERIES (int32_t, 3, -1, 4, b0sm1n4) +DEF_SERIES (int32_t, 7, -1, 8, b0sm1n8) +DEF_SERIES (int32_t, 15, -1, 16, b0sm1n16) +DEF_SERIES (int32_t, 31, -1, 32, b0sm1n32) +DEF_SERIES (int32_t, 63, -1, 64, b0sm1n64) +DEF_SERIES (int32_t, 127, -1, 128, b0sm1n128) +DEF_SERIES (int32_t, 255, -1, 256, b0sm1n256) +DEF_SERIES (int32_t, 511, -1, 512, b0sm1n512) +DEF_SERIES (int32_t, 1023, -1, 1024, b0sm1n1024) + +DEF_SERIES (int64_t, 1, -1, 2, b0sm1n2) +DEF_SERIES (int64_t, 3, -1, 4, b0sm1n4) +DEF_SERIES (int64_t, 7, -1, 8, b0sm1n8) +DEF_SERIES (int64_t, 15, -1, 16, b0sm1n16) +DEF_SERIES (int64_t, 31, -1, 32, b0sm1n32) +DEF_SERIES (int64_t, 63, -1, 64, b0sm1n64) +DEF_SERIES (int64_t, 127, -1, 128, b0sm1n128) +DEF_SERIES (int64_t, 255, -1, 256, b0sm1n256) +DEF_SERIES (int64_t, 511, -1, 512, b0sm1n512) + +/* { dg-final { scan-assembler-times {vid\.v\s+v[0-9]+} 30 } } */ +/* { dg-final { scan-assembler-not {csrr} } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/series-3.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/series-3.c new file mode 100644 index 000000000000..16cce76dcf46 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/series-3.c @@ -0,0 +1,40 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gcv_zvfh_zvl4096b -mabi=lp64d -O3 -fno-schedule-insns -fno-schedule-insns2 --param=riscv-autovec-lmul=m8 -fno-builtin" } */ + +#include "def.h" + +DEF_SERIES (int16_t, 0, 8, 2, b0s8n2) +DEF_SERIES (int16_t, 0, 8, 4, b0s8n4) +DEF_SERIES (int16_t, 0, 8, 8, b0s8n8) +DEF_SERIES (int16_t, 0, 8, 16, b0s8n16) +DEF_SERIES (int16_t, 0, 8, 32, b0s8n32) +DEF_SERIES (int16_t, 0, 8, 64, b0s8n64) +DEF_SERIES (int16_t, 0, 8, 128, b0s8n128) +DEF_SERIES (int16_t, 0, 8, 256, b0s8n256) +DEF_SERIES (int16_t, 0, 8, 512, b0s8n512) +DEF_SERIES (int16_t, 0, 8, 1024, b0s8n1024) +DEF_SERIES (int16_t, 0, 8, 2048, b0s8n2048) + +DEF_SERIES (int32_t, 0, 8, 2, b0s8n2) +DEF_SERIES (int32_t, 0, 8, 4, b0s8n4) +DEF_SERIES (int32_t, 0, 8, 8, b0s8n8) +DEF_SERIES (int32_t, 0, 8, 16, b0s8n16) +DEF_SERIES (int32_t, 0, 8, 32, b0s8n32) +DEF_SERIES (int32_t, 0, 8, 64, b0s8n64) +DEF_SERIES (int32_t, 0, 8, 128, b0s8n128) +DEF_SERIES (int32_t, 0, 8, 256, b0s8n256) +DEF_SERIES (int32_t, 0, 8, 512, b0s8n512) +DEF_SERIES (int32_t, 0, 8, 1024, b0s8n1024) + +DEF_SERIES (int64_t, 0, 8, 2, b0s8n2) +DEF_SERIES (int64_t, 0, 8, 4, b0s8n4) +DEF_SERIES (int64_t, 0, 8, 8, b0s8n8) +DEF_SERIES (int64_t, 0, 8, 16, b0s8n16) +DEF_SERIES (int64_t, 0, 8, 32, b0s8n32) +DEF_SERIES (int64_t, 0, 8, 64, b0s8n64) +DEF_SERIES (int64_t, 0, 8, 128, b0s8n128) +DEF_SERIES (int64_t, 0, 8, 256, b0s8n256) +DEF_SERIES (int64_t, 0, 8, 512, b0s8n512) + +/* { dg-final { scan-assembler-times {vid\.v\s+v[0-9]+} 30 } } */ +/* { dg-final { scan-assembler-not {csrr} } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/series-4.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/series-4.c new file mode 100644 index 000000000000..966391e1f5c3 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/series-4.c @@ -0,0 +1,40 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gcv_zvfh_zvl4096b -mabi=lp64d -O3 -fno-schedule-insns -fno-schedule-insns2 --param=riscv-autovec-lmul=m8 -fno-builtin" } */ + +#include "def.h" + +DEF_SERIES (int16_t, 67, 7, 2, b99s7n2) +DEF_SERIES (int16_t, 67, 7, 4, b99s7n4) +DEF_SERIES (int16_t, 67, 7, 8, b99s7n8) +DEF_SERIES (int16_t, 67, 7, 16, b99s7n16) +DEF_SERIES (int16_t, 67, 7, 32, b99s7n32) +DEF_SERIES (int16_t, 67, 7, 64, b99s7n64) +DEF_SERIES (int16_t, 67, 7, 128, b99s7n128) +DEF_SERIES (int16_t, 67, 7, 256, b99s7n256) +DEF_SERIES (int16_t, 67, 7, 512, b99s7n512) +DEF_SERIES (int16_t, 67, 7, 1024, b99s7n1024) +DEF_SERIES (int16_t, 67, 7, 2048, b99s7n2048) + +DEF_SERIES (int32_t, 76, 7, 2, b99s7n2) +DEF_SERIES (int32_t, 76, 7, 4, b99s7n4) +DEF_SERIES (int32_t, 76, 7, 8, b99s7n8) +DEF_SERIES (int32_t, 76, 7, 16, b99s7n16) +DEF_SERIES (int32_t, 76, 7, 32, b99s7n32) +DEF_SERIES (int32_t, 76, 7, 64, b99s7n64) +DEF_SERIES (int32_t, 76, 7, 128, b99s7n128) +DEF_SERIES (int32_t, 76, 7, 256, b99s7n256) +DEF_SERIES (int32_t, 76, 7, 512, b99s7n512) +DEF_SERIES (int32_t, 76, 7, 1024, b99s7n1024) + +DEF_SERIES (int64_t, 99, 7, 2, b99s7n2) +DEF_SERIES (int64_t, 99, 7, 4, b99s7n4) +DEF_SERIES (int64_t, 99, 7, 8, b99s7n8) +DEF_SERIES (int64_t, 99, 7, 16, b99s7n16) +DEF_SERIES (int64_t, 99, 7, 32, b99s7n32) +DEF_SERIES (int64_t, 99, 7, 64, b99s7n64) +DEF_SERIES (int64_t, 99, 7, 128, b99s7n128) +DEF_SERIES (int64_t, 99, 7, 256, b99s7n256) +DEF_SERIES (int64_t, 99, 7, 512, b99s7n512) + +/* { dg-final { scan-assembler-times {vid\.v\s+v[0-9]+} 30 } } */ +/* { dg-final { scan-assembler-not {csrr} } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/shift-1.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/shift-1.c new file mode 100644 index 000000000000..e57a0b6bdf37 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/shift-1.c @@ -0,0 +1,57 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gcv_zvfh_zvl4096b -mabi=lp64d -O3 -fno-schedule-insns -fno-schedule-insns2 --param=riscv-autovec-lmul=m8" } */ + +#include "def.h" + +DEF_OP_VV (shift, 1, int8_t, >>) +DEF_OP_VV (shift, 2, int8_t, >>) +DEF_OP_VV (shift, 4, int8_t, >>) +DEF_OP_VV (shift, 8, int8_t, >>) +DEF_OP_VV (shift, 16, int8_t, >>) +DEF_OP_VV (shift, 32, int8_t, >>) +DEF_OP_VV (shift, 64, int8_t, >>) +DEF_OP_VV (shift, 128, int8_t, >>) +DEF_OP_VV (shift, 256, int8_t, >>) +DEF_OP_VV (shift, 512, int8_t, >>) +DEF_OP_VV (shift, 1024, int8_t, >>) +DEF_OP_VV (shift, 2048, int8_t, >>) +DEF_OP_VV (shift, 4096, int8_t, >>) + +DEF_OP_VV (shift, 1, int16_t, >>) +DEF_OP_VV (shift, 2, int16_t, >>) +DEF_OP_VV (shift, 4, int16_t, >>) +DEF_OP_VV (shift, 8, int16_t, >>) +DEF_OP_VV (shift, 16, int16_t, >>) +DEF_OP_VV (shift, 32, int16_t, >>) +DEF_OP_VV (shift, 64, int16_t, >>) +DEF_OP_VV (shift, 128, int16_t, >>) +DEF_OP_VV (shift, 256, int16_t, >>) +DEF_OP_VV (shift, 512, int16_t, >>) +DEF_OP_VV (shift, 1024, int16_t, >>) +DEF_OP_VV (shift, 2048, int16_t, >>) + +DEF_OP_VV (shift, 1, int32_t, >>) +DEF_OP_VV (shift, 2, int32_t, >>) +DEF_OP_VV (shift, 4, int32_t, >>) +DEF_OP_VV (shift, 8, int32_t, >>) +DEF_OP_VV (shift, 16, int32_t, >>) +DEF_OP_VV (shift, 32, int32_t, >>) +DEF_OP_VV (shift, 64, int32_t, >>) +DEF_OP_VV (shift, 128, int32_t, >>) +DEF_OP_VV (shift, 256, int32_t, >>) +DEF_OP_VV (shift, 512, int32_t, >>) +DEF_OP_VV (shift, 1024, int32_t, >>) + +DEF_OP_VV (shift, 1, int64_t, >>) +DEF_OP_VV (shift, 2, int64_t, >>) +DEF_OP_VV (shift, 4, int64_t, >>) +DEF_OP_VV (shift, 8, int64_t, >>) +DEF_OP_VV (shift, 16, int64_t, >>) +DEF_OP_VV (shift, 32, int64_t, >>) +DEF_OP_VV (shift, 64, int64_t, >>) +DEF_OP_VV (shift, 128, int64_t, >>) +DEF_OP_VV (shift, 256, int64_t, >>) +DEF_OP_VV (shift, 512, int64_t, >>) + +/* { dg-final { scan-assembler-times {vsra\.vv\s+v[0-9]+,\s*v[0-9]+,\s*v[0-9]+} 39 } } */ +/* { dg-final { scan-assembler-not {csrr} } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/shift-2.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/shift-2.c new file mode 100644 index 000000000000..9d1fa64232c9 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/shift-2.c @@ -0,0 +1,57 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gcv_zvfh_zvl4096b -mabi=lp64d -O3 -fno-schedule-insns -fno-schedule-insns2 --param=riscv-autovec-lmul=m8" } */ + +#include "def.h" + +DEF_OP_VV (shift, 1, uint8_t, >>) +DEF_OP_VV (shift, 2, uint8_t, >>) +DEF_OP_VV (shift, 4, uint8_t, >>) +DEF_OP_VV (shift, 8, uint8_t, >>) +DEF_OP_VV (shift, 16, uint8_t, >>) +DEF_OP_VV (shift, 32, uint8_t, >>) +DEF_OP_VV (shift, 64, uint8_t, >>) +DEF_OP_VV (shift, 128, uint8_t, >>) +DEF_OP_VV (shift, 256, uint8_t, >>) +DEF_OP_VV (shift, 512, uint8_t, >>) +DEF_OP_VV (shift, 1024, uint8_t, >>) +DEF_OP_VV (shift, 2048, uint8_t, >>) +DEF_OP_VV (shift, 4096, uint8_t, >>) + +DEF_OP_VV (shift, 1, uint16_t, >>) +DEF_OP_VV (shift, 2, uint16_t, >>) +DEF_OP_VV (shift, 4, uint16_t, >>) +DEF_OP_VV (shift, 8, uint16_t, >>) +DEF_OP_VV (shift, 16, uint16_t, >>) +DEF_OP_VV (shift, 32, uint16_t, >>) +DEF_OP_VV (shift, 64, uint16_t, >>) +DEF_OP_VV (shift, 128, uint16_t, >>) +DEF_OP_VV (shift, 256, uint16_t, >>) +DEF_OP_VV (shift, 512, uint16_t, >>) +DEF_OP_VV (shift, 1024, uint16_t, >>) +DEF_OP_VV (shift, 2048, uint16_t, >>) + +DEF_OP_VV (shift, 1, uint32_t, >>) +DEF_OP_VV (shift, 2, uint32_t, >>) +DEF_OP_VV (shift, 4, uint32_t, >>) +DEF_OP_VV (shift, 8, uint32_t, >>) +DEF_OP_VV (shift, 16, uint32_t, >>) +DEF_OP_VV (shift, 32, uint32_t, >>) +DEF_OP_VV (shift, 64, uint32_t, >>) +DEF_OP_VV (shift, 128, uint32_t, >>) +DEF_OP_VV (shift, 256, uint32_t, >>) +DEF_OP_VV (shift, 512, uint32_t, >>) +DEF_OP_VV (shift, 1024, uint32_t, >>) + +DEF_OP_VV (shift, 1, uint64_t, >>) +DEF_OP_VV (shift, 2, uint64_t, >>) +DEF_OP_VV (shift, 4, uint64_t, >>) +DEF_OP_VV (shift, 8, uint64_t, >>) +DEF_OP_VV (shift, 16, uint64_t, >>) +DEF_OP_VV (shift, 32, uint64_t, >>) +DEF_OP_VV (shift, 64, uint64_t, >>) +DEF_OP_VV (shift, 128, uint64_t, >>) +DEF_OP_VV (shift, 256, uint64_t, >>) +DEF_OP_VV (shift, 512, uint64_t, >>) + +/* { dg-final { scan-assembler-times {vsrl\.vv\s+v[0-9]+,\s*v[0-9]+,\s*v[0-9]+} 39 } } */ +/* { dg-final { scan-assembler-not {csrr} } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/shift-3.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/shift-3.c new file mode 100644 index 000000000000..98822b156571 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/shift-3.c @@ -0,0 +1,58 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gcv_zvfh_zvl4096b -mabi=lp64d -O3 -fno-schedule-insns -fno-schedule-insns2 --param=riscv-autovec-lmul=m8" } */ + +#include "def.h" + +DEF_OP_VV (shift, 1, int8_t, <<) +DEF_OP_VV (shift, 2, int8_t, <<) +DEF_OP_VV (shift, 4, int8_t, <<) +DEF_OP_VV (shift, 8, int8_t, <<) +DEF_OP_VV (shift, 16, int8_t, <<) +DEF_OP_VV (shift, 32, int8_t, <<) +DEF_OP_VV (shift, 64, int8_t, <<) +DEF_OP_VV (shift, 128, int8_t, <<) +DEF_OP_VV (shift, 256, int8_t, <<) +DEF_OP_VV (shift, 512, int8_t, <<) +DEF_OP_VV (shift, 1024, int8_t, <<) +DEF_OP_VV (shift, 2048, int8_t, <<) +DEF_OP_VV (shift, 4096, int8_t, <<) + +DEF_OP_VV (shift, 1, int16_t, <<) +DEF_OP_VV (shift, 2, int16_t, <<) +DEF_OP_VV (shift, 4, int16_t, <<) +DEF_OP_VV (shift, 8, int16_t, <<) +DEF_OP_VV (shift, 16, int16_t, <<) +DEF_OP_VV (shift, 32, int16_t, <<) +DEF_OP_VV (shift, 64, int16_t, <<) +DEF_OP_VV (shift, 128, int16_t, <<) +DEF_OP_VV (shift, 256, int16_t, <<) +DEF_OP_VV (shift, 512, int16_t, <<) +DEF_OP_VV (shift, 1024, int16_t, <<) +DEF_OP_VV (shift, 2048, int16_t, <<) + +DEF_OP_VV (shift, 1, int32_t, <<) +DEF_OP_VV (shift, 2, int32_t, <<) +DEF_OP_VV (shift, 4, int32_t, <<) +DEF_OP_VV (shift, 8, int32_t, <<) +DEF_OP_VV (shift, 16, int32_t, <<) +DEF_OP_VV (shift, 32, int32_t, <<) +DEF_OP_VV (shift, 64, int32_t, <<) +DEF_OP_VV (shift, 128, int32_t, <<) +DEF_OP_VV (shift, 256, int32_t, <<) +DEF_OP_VV (shift, 512, int32_t, <<) +DEF_OP_VV (shift, 1024, int32_t, <<) + +DEF_OP_VV (shift, 1, int64_t, <<) +DEF_OP_VV (shift, 2, int64_t, <<) +DEF_OP_VV (shift, 4, int64_t, <<) +DEF_OP_VV (shift, 8, int64_t, <<) +DEF_OP_VV (shift, 16, int64_t, <<) +DEF_OP_VV (shift, 32, int64_t, <<) +DEF_OP_VV (shift, 64, int64_t, <<) +DEF_OP_VV (shift, 128, int64_t, <<) +DEF_OP_VV (shift, 256, int64_t, <<) +DEF_OP_VV (shift, 512, int64_t, <<) + +/* { dg-final { scan-assembler-times {vsll\.vv\s+v[0-9]+,\s*v[0-9]+,\s*v[0-9]+} 41 } } */ +/* TODO: Ideally, we should make sure there is no "csrr vlenb". However, we still have 'csrr vlenb' for some cases since we don't support VLS mode conversion which are needed by division. */ +/* { dg-final { scan-assembler-times {csrr} 18 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/shift-4.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/shift-4.c new file mode 100644 index 000000000000..56b6ef92c836 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/shift-4.c @@ -0,0 +1,57 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gcv_zvfh_zvl4096b -mabi=lp64d -O3 -fno-schedule-insns -fno-schedule-insns2 --param=riscv-autovec-lmul=m8" } */ + +#include "def.h" + +DEF_OP_VI_7 (shift, 1, int8_t, >>) +DEF_OP_VI_7 (shift, 2, int8_t, >>) +DEF_OP_VI_7 (shift, 4, int8_t, >>) +DEF_OP_VI_7 (shift, 8, int8_t, >>) +DEF_OP_VI_7 (shift, 16, int8_t, >>) +DEF_OP_VI_7 (shift, 32, int8_t, >>) +DEF_OP_VI_7 (shift, 64, int8_t, >>) +DEF_OP_VI_7 (shift, 128, int8_t, >>) +DEF_OP_VI_7 (shift, 256, int8_t, >>) +DEF_OP_VI_7 (shift, 512, int8_t, >>) +DEF_OP_VI_7 (shift, 1024, int8_t, >>) +DEF_OP_VI_7 (shift, 2048, int8_t, >>) +DEF_OP_VI_7 (shift, 4096, int8_t, >>) + +DEF_OP_VI_7 (shift, 1, int16_t, >>) +DEF_OP_VI_7 (shift, 2, int16_t, >>) +DEF_OP_VI_7 (shift, 4, int16_t, >>) +DEF_OP_VI_7 (shift, 8, int16_t, >>) +DEF_OP_VI_7 (shift, 16, int16_t, >>) +DEF_OP_VI_7 (shift, 32, int16_t, >>) +DEF_OP_VI_7 (shift, 64, int16_t, >>) +DEF_OP_VI_7 (shift, 128, int16_t, >>) +DEF_OP_VI_7 (shift, 256, int16_t, >>) +DEF_OP_VI_7 (shift, 512, int16_t, >>) +DEF_OP_VI_7 (shift, 1024, int16_t, >>) +DEF_OP_VI_7 (shift, 2048, int16_t, >>) + +DEF_OP_VI_7 (shift, 1, int32_t, >>) +DEF_OP_VI_7 (shift, 2, int32_t, >>) +DEF_OP_VI_7 (shift, 4, int32_t, >>) +DEF_OP_VI_7 (shift, 8, int32_t, >>) +DEF_OP_VI_7 (shift, 16, int32_t, >>) +DEF_OP_VI_7 (shift, 32, int32_t, >>) +DEF_OP_VI_7 (shift, 64, int32_t, >>) +DEF_OP_VI_7 (shift, 128, int32_t, >>) +DEF_OP_VI_7 (shift, 256, int32_t, >>) +DEF_OP_VI_7 (shift, 512, int32_t, >>) +DEF_OP_VI_7 (shift, 1024, int32_t, >>) + +DEF_OP_VI_7 (shift, 1, int64_t, >>) +DEF_OP_VI_7 (shift, 2, int64_t, >>) +DEF_OP_VI_7 (shift, 4, int64_t, >>) +DEF_OP_VI_7 (shift, 8, int64_t, >>) +DEF_OP_VI_7 (shift, 16, int64_t, >>) +DEF_OP_VI_7 (shift, 32, int64_t, >>) +DEF_OP_VI_7 (shift, 64, int64_t, >>) +DEF_OP_VI_7 (shift, 128, int64_t, >>) +DEF_OP_VI_7 (shift, 256, int64_t, >>) +DEF_OP_VI_7 (shift, 512, int64_t, >>) + +/* { dg-final { scan-assembler-times {vsra\.vi\s+v[0-9]+,\s*v[0-9]+,\s*7} 42 } } */ +/* { dg-final { scan-assembler-not {csrr} } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/shift-5.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/shift-5.c new file mode 100644 index 000000000000..c909cb1a75a8 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/shift-5.c @@ -0,0 +1,57 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gcv_zvfh_zvl4096b -mabi=lp64d -O3 -fno-schedule-insns -fno-schedule-insns2 --param=riscv-autovec-lmul=m8" } */ + +#include "def.h" + +DEF_OP_VI_7 (shift, 1, uint8_t, >>) +DEF_OP_VI_7 (shift, 2, uint8_t, >>) +DEF_OP_VI_7 (shift, 4, uint8_t, >>) +DEF_OP_VI_7 (shift, 8, uint8_t, >>) +DEF_OP_VI_7 (shift, 16, uint8_t, >>) +DEF_OP_VI_7 (shift, 32, uint8_t, >>) +DEF_OP_VI_7 (shift, 64, uint8_t, >>) +DEF_OP_VI_7 (shift, 128, uint8_t, >>) +DEF_OP_VI_7 (shift, 256, uint8_t, >>) +DEF_OP_VI_7 (shift, 512, uint8_t, >>) +DEF_OP_VI_7 (shift, 1024, uint8_t, >>) +DEF_OP_VI_7 (shift, 2048, uint8_t, >>) +DEF_OP_VI_7 (shift, 4096, uint8_t, >>) + +DEF_OP_VI_7 (shift, 1, uint16_t, >>) +DEF_OP_VI_7 (shift, 2, uint16_t, >>) +DEF_OP_VI_7 (shift, 4, uint16_t, >>) +DEF_OP_VI_7 (shift, 8, uint16_t, >>) +DEF_OP_VI_7 (shift, 16, uint16_t, >>) +DEF_OP_VI_7 (shift, 32, uint16_t, >>) +DEF_OP_VI_7 (shift, 64, uint16_t, >>) +DEF_OP_VI_7 (shift, 128, uint16_t, >>) +DEF_OP_VI_7 (shift, 256, uint16_t, >>) +DEF_OP_VI_7 (shift, 512, uint16_t, >>) +DEF_OP_VI_7 (shift, 1024, uint16_t, >>) +DEF_OP_VI_7 (shift, 2048, uint16_t, >>) + +DEF_OP_VI_7 (shift, 1, uint32_t, >>) +DEF_OP_VI_7 (shift, 2, uint32_t, >>) +DEF_OP_VI_7 (shift, 4, uint32_t, >>) +DEF_OP_VI_7 (shift, 8, uint32_t, >>) +DEF_OP_VI_7 (shift, 16, uint32_t, >>) +DEF_OP_VI_7 (shift, 32, uint32_t, >>) +DEF_OP_VI_7 (shift, 64, uint32_t, >>) +DEF_OP_VI_7 (shift, 128, uint32_t, >>) +DEF_OP_VI_7 (shift, 256, uint32_t, >>) +DEF_OP_VI_7 (shift, 512, uint32_t, >>) +DEF_OP_VI_7 (shift, 1024, uint32_t, >>) + +DEF_OP_VI_7 (shift, 1, uint64_t, >>) +DEF_OP_VI_7 (shift, 2, uint64_t, >>) +DEF_OP_VI_7 (shift, 4, uint64_t, >>) +DEF_OP_VI_7 (shift, 8, uint64_t, >>) +DEF_OP_VI_7 (shift, 16, uint64_t, >>) +DEF_OP_VI_7 (shift, 32, uint64_t, >>) +DEF_OP_VI_7 (shift, 64, uint64_t, >>) +DEF_OP_VI_7 (shift, 128, uint64_t, >>) +DEF_OP_VI_7 (shift, 256, uint64_t, >>) +DEF_OP_VI_7 (shift, 512, uint64_t, >>) + +/* { dg-final { scan-assembler-times {vsrl\.vi\s+v[0-9]+,\s*v[0-9]+,\s*7} 42 } } */ +/* { dg-final { scan-assembler-not {csrr} } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/shift-6.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/shift-6.c new file mode 100644 index 000000000000..fdea84c39d8d --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/shift-6.c @@ -0,0 +1,57 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gcv_zvfh_zvl4096b -mabi=lp64d -O3 -fno-schedule-insns -fno-schedule-insns2 --param=riscv-autovec-lmul=m8" } */ + +#include "def.h" + +DEF_OP_VI_7 (shift, 1, int8_t, <<) +DEF_OP_VI_7 (shift, 2, int8_t, <<) +DEF_OP_VI_7 (shift, 4, int8_t, <<) +DEF_OP_VI_7 (shift, 8, int8_t, <<) +DEF_OP_VI_7 (shift, 16, int8_t, <<) +DEF_OP_VI_7 (shift, 32, int8_t, <<) +DEF_OP_VI_7 (shift, 64, int8_t, <<) +DEF_OP_VI_7 (shift, 128, int8_t, <<) +DEF_OP_VI_7 (shift, 256, int8_t, <<) +DEF_OP_VI_7 (shift, 512, int8_t, <<) +DEF_OP_VI_7 (shift, 1024, int8_t, <<) +DEF_OP_VI_7 (shift, 2048, int8_t, <<) +DEF_OP_VI_7 (shift, 4096, int8_t, <<) + +DEF_OP_VI_7 (shift, 1, int16_t, <<) +DEF_OP_VI_7 (shift, 2, int16_t, <<) +DEF_OP_VI_7 (shift, 4, int16_t, <<) +DEF_OP_VI_7 (shift, 8, int16_t, <<) +DEF_OP_VI_7 (shift, 16, int16_t, <<) +DEF_OP_VI_7 (shift, 32, int16_t, <<) +DEF_OP_VI_7 (shift, 64, int16_t, <<) +DEF_OP_VI_7 (shift, 128, int16_t, <<) +DEF_OP_VI_7 (shift, 256, int16_t, <<) +DEF_OP_VI_7 (shift, 512, int16_t, <<) +DEF_OP_VI_7 (shift, 1024, int16_t, <<) +DEF_OP_VI_7 (shift, 2048, int16_t, <<) + +DEF_OP_VI_7 (shift, 1, int32_t, <<) +DEF_OP_VI_7 (shift, 2, int32_t, <<) +DEF_OP_VI_7 (shift, 4, int32_t, <<) +DEF_OP_VI_7 (shift, 8, int32_t, <<) +DEF_OP_VI_7 (shift, 16, int32_t, <<) +DEF_OP_VI_7 (shift, 32, int32_t, <<) +DEF_OP_VI_7 (shift, 64, int32_t, <<) +DEF_OP_VI_7 (shift, 128, int32_t, <<) +DEF_OP_VI_7 (shift, 256, int32_t, <<) +DEF_OP_VI_7 (shift, 512, int32_t, <<) +DEF_OP_VI_7 (shift, 1024, int32_t, <<) + +DEF_OP_VI_7 (shift, 1, int64_t, <<) +DEF_OP_VI_7 (shift, 2, int64_t, <<) +DEF_OP_VI_7 (shift, 4, int64_t, <<) +DEF_OP_VI_7 (shift, 8, int64_t, <<) +DEF_OP_VI_7 (shift, 16, int64_t, <<) +DEF_OP_VI_7 (shift, 32, int64_t, <<) +DEF_OP_VI_7 (shift, 64, int64_t, <<) +DEF_OP_VI_7 (shift, 128, int64_t, <<) +DEF_OP_VI_7 (shift, 256, int64_t, <<) +DEF_OP_VI_7 (shift, 512, int64_t, <<) + +/* { dg-final { scan-assembler-times {vsll\.vi\s+v[0-9]+,\s*v[0-9]+,\s*7} 42 } } */ +/* { dg-final { scan-assembler-not {csrr} } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/widen/vec-avg-run.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/widen/vec-avg-run.c new file mode 100644 index 000000000000..7ca193ec2f2d --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/widen/vec-avg-run.c @@ -0,0 +1,85 @@ +/* { dg-do run { target { riscv_vector } } } */ +/* { dg-additional-options "-std=c99 -fno-vect-cost-model --param=riscv-autovec-preference=scalable -lm" } */ + +#include +#include +#include + +#include "vec-avg-template.h" + +#define SZ 256 + +#define RUNS1(TYPE, SCALE) \ + TYPE a##TYPE[SZ + 1]; \ + TYPE b##TYPE[SZ + 1]; \ + TYPE dst##TYPE[SZ + 1]; \ + for (int cnt = 0, i = -(SZ * SCALE) / 2; i < (SZ * SCALE) / 2; i += SCALE) \ + { \ + a##TYPE[cnt] = i; \ + b##TYPE[cnt] = i + 1; \ + dst##TYPE[cnt++] = 0; \ + } \ + vavg_##TYPE (dst##TYPE, a##TYPE, b##TYPE, SZ); \ + for (int i = 0; i < SZ; i += SCALE) \ + assert (dst##TYPE[i] == floor ((a##TYPE[i] + b##TYPE[i]) / 2.0)); + +#define RUNU1(TYPE, SCALE) \ + TYPE a##TYPE[SZ + 1]; \ + TYPE b##TYPE[SZ + 1]; \ + TYPE dst##TYPE[SZ + 1]; \ + for (int cnt = 0, i = 0; i < (SZ * SCALE); i += SCALE) \ + { \ + a##TYPE[cnt] = i; \ + b##TYPE[cnt] = i + 1; \ + dst##TYPE[cnt++] = 0; \ + } \ + vavg_##TYPE (dst##TYPE, a##TYPE, b##TYPE, SZ); \ + for (int i = 0; i < SZ; i += SCALE) \ + assert (dst##TYPE[i] == floor ((a##TYPE[i] + b##TYPE[i]) / 2.0)); + +#define RUNS2(TYPE, SCALE) \ + TYPE a2##TYPE[SZ + 1]; \ + TYPE b2##TYPE[SZ + 1]; \ + TYPE dst2##TYPE[SZ + 1]; \ + for (int cnt = 0, i = -(SZ * SCALE) / 2; i < (SZ * SCALE) / 2; i += SCALE) \ + { \ + a2##TYPE[cnt] = i; \ + b2##TYPE[cnt] = i + 1; \ + dst2##TYPE[cnt++] = 0; \ + } \ + vavg2_##TYPE (dst2##TYPE, a2##TYPE, b2##TYPE, SZ); \ + for (int i = 0; i < SZ; i += SCALE) \ + assert (dst2##TYPE[i] == ceil ((a2##TYPE[i] + b2##TYPE[i]) / 2.0)); + +#define RUNU2(TYPE, SCALE) \ + TYPE a2##TYPE[SZ + 1]; \ + TYPE b2##TYPE[SZ + 1]; \ + TYPE dst2##TYPE[SZ + 1]; \ + for (int cnt = 0, i = 0; i < (SZ * SCALE); i += SCALE) \ + { \ + a2##TYPE[cnt] = i; \ + b2##TYPE[cnt] = i + 1; \ + dst2##TYPE[cnt++] = 0; \ + } \ + vavg2_##TYPE (dst2##TYPE, a2##TYPE, b2##TYPE, SZ); \ + for (int i = 0; i < SZ; i += SCALE) \ + assert (dst2##TYPE[i] == ceil ((a2##TYPE[i] + b2##TYPE[i]) / 2.0)); + +#define RUN_ALL() \ + RUNS1 (int8_t, 1) \ + RUNS1 (int16_t, 256) \ + RUNS1 (int32_t, 65536) \ + RUNU1 (uint8_t, 1) \ + RUNU1 (uint16_t, 256) \ + RUNU1 (uint32_t, 65536) \ + RUNS2 (int8_t, 1) \ + RUNS2 (int16_t, 256) \ + RUNS2 (int32_t, 65536) \ + RUNU2 (uint8_t, 1) \ + RUNU2 (uint16_t, 256) \ + RUNU2 (uint32_t, 65536)\ + +int main () +{ + RUN_ALL () +} diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/widen/vec-avg-rv32gcv.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/widen/vec-avg-rv32gcv.c new file mode 100644 index 000000000000..e2754339d942 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/widen/vec-avg-rv32gcv.c @@ -0,0 +1,10 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-std=c99 -fno-vect-cost-model -march=rv32gcv -mabi=ilp32d --param=riscv-autovec-preference=scalable" } */ + +#include "vec-avg-template.h" + +/* { dg-final { scan-assembler-times {\tvwadd\.vv} 6 } } */ +/* { dg-final { scan-assembler-times {\tvwaddu\.vv} 6 } } */ +/* { dg-final { scan-assembler-times {\tvadd\.vi} 6 } } */ +/* { dg-final { scan-assembler-times {\tvnsrl.wi} 6 } } */ +/* { dg-final { scan-assembler-times {\tvnsra.wi} 6 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/widen/vec-avg-rv64gcv.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/widen/vec-avg-rv64gcv.c new file mode 100644 index 000000000000..1f0ef29566dd --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/widen/vec-avg-rv64gcv.c @@ -0,0 +1,10 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-std=c99 -fno-vect-cost-model -march=rv64gcv -mabi=lp64d --param=riscv-autovec-preference=scalable" } */ + +#include "vec-avg-template.h" + +/* { dg-final { scan-assembler-times {\tvwadd\.vv} 6 } } */ +/* { dg-final { scan-assembler-times {\tvwaddu\.vv} 6 } } */ +/* { dg-final { scan-assembler-times {\tvadd\.vi} 6 } } */ +/* { dg-final { scan-assembler-times {\tvnsrl\.wi} 6 } } */ +/* { dg-final { scan-assembler-times {\tvnsra\.wi} 6 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/widen/vec-avg-template.h b/gcc/testsuite/gcc.target/riscv/rvv/autovec/widen/vec-avg-template.h new file mode 100644 index 000000000000..9c2a6f1b9cb8 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/widen/vec-avg-template.h @@ -0,0 +1,33 @@ +#include + +#define TEST_TYPE(TYPE, TYPE2) \ + __attribute__ ((noipa)) void vavg_##TYPE (TYPE *dst, TYPE *a, TYPE *b, \ + int n) \ + { \ + for (int i = 0; i < n; i++) \ + dst[i] = ((TYPE2) a[i] + b[i]) >> 1; \ + } + +#define TEST_TYPE2(TYPE, TYPE2) \ + __attribute__ ((noipa)) void vavg2_##TYPE (TYPE *dst, TYPE *a, TYPE *b, \ + int n) \ + { \ + for (int i = 0; i < n; i++) \ + dst[i] = ((TYPE2) a[i] + b[i] + 1) >> 1; \ + } + +#define TEST_ALL() \ + TEST_TYPE (int8_t, int16_t) \ + TEST_TYPE (uint8_t, uint16_t) \ + TEST_TYPE (int16_t, int32_t) \ + TEST_TYPE (uint16_t, uint32_t) \ + TEST_TYPE (int32_t, int64_t) \ + TEST_TYPE (uint32_t, uint64_t) \ + TEST_TYPE2 (int8_t, int16_t) \ + TEST_TYPE2 (uint8_t, uint16_t) \ + TEST_TYPE2 (int16_t, int32_t) \ + TEST_TYPE2 (uint16_t, uint32_t) \ + TEST_TYPE2 (int32_t, int64_t) \ + TEST_TYPE2 (uint32_t, uint64_t) + +TEST_ALL() diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-171.c b/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-171.c index dae5eff42ce1..6e8669ae59ec 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-171.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-171.c @@ -7,7 +7,7 @@ /* ** f1: ** ... -** vsetivli\t[a-x0-9]+,\s*4,e64,m1,tu,m[au] +** vsetivli\t[a-x0-9]+,\s*4,e64,m1,t[au],m[au] ** ... ** vsetvli\tzero,\s*[a-x0-9]+,e32,m1,tu,m[au] ** ... @@ -41,7 +41,7 @@ void f1 (void * in, void *out, int64_t x, int n) /* ** f2: ** ... -** vsetivli\t[a-x0-9]+,\s*4,e64,m1,tu,m[au] +** vsetivli\t[a-x0-9]+,\s*4,e64,m1,t[au],m[au] ** ... ** vsetvli\tzero,\s*[a-x0-9]+,e32,m1,tu,m[au] ** ... diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-173.c b/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-173.c index 0d5a2603856a..af9c45e942b4 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-173.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/binop_vx_constraint-173.c @@ -7,7 +7,7 @@ /* ** f1: ** ... -** vsetvli\t[a-x0-9]+,\s*[a-x0-9]+,e64,m1,tu,m[au] +** vsetvli\t[a-x0-9]+,\s*[a-x0-9]+,e64,m1,t[au],m[au] ** ... ** vsetvli\tzero,\s*[a-x0-9]+,e32,m1,tu,m[au] ** ... @@ -41,7 +41,7 @@ void f1 (void * in, void *out, int64_t x, int vl) /* ** f2: ** ... -** vsetvli\t[a-x0-9]+,\s*[a-x0-9]+,e64,m1,tu,m[au] +** vsetvli\t[a-x0-9]+,\s*[a-x0-9]+,e64,m1,t[au],m[au] ** ... ** vsetvli\tzero,\s*[a-x0-9]+,e32,m1,tu,m[au] ** ... diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-cvt-f.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-cvt-f.c new file mode 100644 index 000000000000..424a38ede13d --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-cvt-f.c @@ -0,0 +1,50 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */ + +#include "riscv_vector.h" + +vfloat32m1_t +test_riscv_vfcvt_f_x_v_f32m1_rm (vint32m1_t op1, size_t vl) { + return __riscv_vfcvt_f_x_v_f32m1_rm (op1, 0, vl); +} + +vfloat32m1_t +test_riscv_vfcvt_f_x_v_f32m1_rm_m (vbool32_t mask, vint32m1_t op1, size_t vl) { + return __riscv_vfcvt_f_x_v_f32m1_rm_m (mask, op1, 0, vl); +} + +vfloat32m1_t +test_riscv_vfcvt_f_xu_v_f32m1_rm (vuint32m1_t op1, size_t vl) { + return __riscv_vfcvt_f_xu_v_f32m1_rm (op1, 0, vl); +} + +vfloat32m1_t +test_riscv_vfcvt_f_xu_v_f32m1_rm_m (vbool32_t mask, vuint32m1_t op1, + size_t vl) { + return __riscv_vfcvt_f_xu_v_f32m1_rm_m (mask, op1, 0, vl); +} + +vfloat32m1_t +test_riscv_vfcvt_f_x_v_f32m1 (vint32m1_t op1, size_t vl) { + return __riscv_vfcvt_f_x_v_f32m1 (op1, vl); +} + +vfloat32m1_t +test_vfcvt_f_x_v_f32m1_m (vbool32_t mask, vint32m1_t op1, size_t vl) { + return __riscv_vfcvt_f_x_v_f32m1_m (mask, op1, vl); +} + +vfloat32m1_t +test_riscv_vfcvt_f_xu_v_f32m1 (vuint32m1_t op1, size_t vl) { + return __riscv_vfcvt_f_xu_v_f32m1 (op1, vl); +} + +vfloat32m1_t +test_vfcvt_f_x_vu_f32m1_m (vbool32_t mask, vuint32m1_t op1, size_t vl) { + return __riscv_vfcvt_f_xu_v_f32m1_m (mask, op1, vl); +} + +/* { dg-final { scan-assembler-times {vfcvt\.f\.x[u]?\.v\s+v[0-9]+,\s*v[0-9]+} 8 } } */ +/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 4 } } */ +/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 4 } } */ +/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 4 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-cvt-x.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-cvt-x.c new file mode 100644 index 000000000000..e090f0f97e9a --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-cvt-x.c @@ -0,0 +1,29 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */ + +#include "riscv_vector.h" + +vint32m1_t +test_riscv_vfcvt_x_f_vv_i32m1_rm (vfloat32m1_t op1, size_t vl) { + return __riscv_vfcvt_x_f_v_i32m1_rm (op1, 0, vl); +} + +vint32m1_t +test_vfcvt_x_f_vv_i32m1_rm_m (vbool32_t mask, vfloat32m1_t op1, size_t vl) { + return __riscv_vfcvt_x_f_v_i32m1_rm_m (mask, op1, 1, vl); +} + +vint32m1_t +test_riscv_vfcvt_x_f_vv_i32m1 (vfloat32m1_t op1, size_t vl) { + return __riscv_vfcvt_x_f_v_i32m1 (op1, vl); +} + +vint32m1_t +test_vfcvt_x_f_vv_i32m1_m (vbool32_t mask, vfloat32m1_t op1, size_t vl) { + return __riscv_vfcvt_x_f_v_i32m1_m (mask, op1, vl); +} + +/* { dg-final { scan-assembler-times {vfcvt\.x\.f\.v\s+v[0-9]+,\s*v[0-9]+} 4 } } */ +/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */ +/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 2 } } */ +/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-cvt-xu.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-cvt-xu.c new file mode 100644 index 000000000000..bb164b2b0014 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-cvt-xu.c @@ -0,0 +1,29 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */ + +#include "riscv_vector.h" + +vuint32m1_t +test_riscv_vfcvt_xu_f_v_u32m1_rm (vfloat32m1_t op1, size_t vl) { + return __riscv_vfcvt_xu_f_v_u32m1_rm (op1, 0, vl); +} + +vuint32m1_t +test_vfcvt_xu_f_v_u32m1_rm_m (vbool32_t mask, vfloat32m1_t op1, size_t vl) { + return __riscv_vfcvt_xu_f_v_u32m1_rm_m (mask, op1, 1, vl); +} + +vuint32m1_t +test_riscv_vfcvt_xu_f_vv_u32m1 (vfloat32m1_t op1, size_t vl) { + return __riscv_vfcvt_xu_f_v_u32m1 (op1, vl); +} + +vuint32m1_t +test_vfcvt_xu_f_v_u32m1_m (vbool32_t mask, vfloat32m1_t op1, size_t vl) { + return __riscv_vfcvt_xu_f_v_u32m1_m (mask, op1, vl); +} + +/* { dg-final { scan-assembler-times {vfcvt\.xu\.f\.v\s+v[0-9]+,\s*v[0-9]+} 4 } } */ +/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */ +/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 2 } } */ +/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-autovec-1.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-autovec-1.c new file mode 100644 index 000000000000..f4f17a306d5f --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-autovec-1.c @@ -0,0 +1,88 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gcv --param=riscv-autovec-preference=fixed-vlmax -ffast-math -mabi=lp64 -O3 -Wno-psabi" } */ +/* { dg-final { check-function-bodies "**" "" } } */ + +#include "riscv_vector.h" + +/* +**test_1: +** ... +** frrm\t[axt][0-9]+ +** ... +** fsrmi\t1 +** ... +** vfsub\.vv\tv[0-9]+,v[0-9]+,v[0-9]+ +** ... +** fsrm\t[axt][0-9]+ +** ... +** vfmadd\.vv\tv[0-9]+,v[0-9]+,v[0-9]+ +** ... +** ret +*/ +void +test_1 (vfloat32m1_t op1, vfloat32m1_t op2, vfloat32m1_t *op_out, size_t vl, + double *in1, double *in2, double *out) +{ + *op_out = __riscv_vfsub_vv_f32m1_rm (op1, op2, 1, vl); + + for (int i = 0; i < 4; ++i) + out[i] += in1[i] * in2[i]; +} + +/* +**test_2: +** ... +** frrm\t[axt][0-9]+ +** ... +** fsrmi\t1 +** ... +** vfsub\.vv\tv[0-9]+,v[0-9]+,v[0-9]+ +** ... +** fsrm\t[axt][0-9]+ +** ... +** vfmadd\.vv\tv[0-9]+,v[0-9]+,v[0-9]+ +** ... +** fsrmi\t4 +** ... +** vfsub\.vv\tv[0-9]+,v[0-9]+,v[0-9]+ +** ... +** fsrm\t[axt][0-9]+ +** ... +** ret +*/ +void +test_2 (vfloat32m1_t op1, vfloat32m1_t op2, vfloat32m1_t *op_out, size_t vl, + double *in1, double *in2, double *out) +{ + op2 = __riscv_vfsub_vv_f32m1_rm (op1, op2, 1, vl); + + for (int i = 0; i < 4; ++i) + out[i] = out[i] * in1[i] + in2[i]; + + *op_out = __riscv_vfsub_vv_f32m1_rm (op1, op2, 4, vl); +} + +/* +**test_3: +** ... +** frrm\t[axt][0-9]+ +** ... +** vfmadd\.vv\tv[0-9]+,v[0-9]+,v[0-9]+ +** ... +** fsrmi\t4 +** ... +** vfsub\.vv\tv[0-9]+,v[0-9]+,v[0-9]+ +** ... +** fsrm\t[axt][0-9]+ +** ... +** ret +*/ +void +test_3 (vfloat32m1_t op1, vfloat32m1_t op2, vfloat32m1_t *op_out, size_t vl, + double *in1, double *in2, double *in3, double *out) +{ + for (int i = 0; i < 4; ++i) + out[i] = in1[i] + in2[i] * out[i]; + + *op_out = __riscv_vfsub_vv_f32m1_rm (op1, op2, 4, vl); +} diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-autovec-2.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-autovec-2.c new file mode 100644 index 000000000000..77d0f5ef773d --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-autovec-2.c @@ -0,0 +1,88 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gcv --param=riscv-autovec-preference=fixed-vlmax -ffast-math -mabi=lp64 -O3 -Wno-psabi" } */ +/* { dg-final { check-function-bodies "**" "" } } */ + +#include "riscv_vector.h" + +/* +**test_1: +** ... +** frrm\t[axt][0-9]+ +** ... +** fsrmi\t1 +** ... +** vfadd\.vv\tv[0-9]+,v[0-9]+,v[0-9]+ +** ... +** fsrm\t[axt][0-9]+ +** ... +** vfmsub\.vv\tv[0-9]+,v[0-9]+,v[0-9]+ +** ... +** ret +*/ +void +test_1 (vfloat32m1_t op1, vfloat32m1_t op2, vfloat32m1_t *op_out, size_t vl, + double *in1, double *in2, double *out) +{ + *op_out = __riscv_vfadd_vv_f32m1_rm (op1, op2, 1, vl); + + for (int i = 0; i < vl; ++i) + out[i] = in1[i] * in2[i] - out[i]; +} + +/* +**test_2: +** ... +** frrm\t[axt][0-9]+ +** ... +** fsrmi\t1 +** ... +** vfadd\.vv\tv[0-9]+,v[0-9]+,v[0-9]+ +** ... +** fsrm\t[axt][0-9]+ +** ... +** vfmsub\.vv\tv[0-9]+,v[0-9]+,v[0-9]+ +** ... +** fsrmi\t4 +** ... +** vfadd\.vv\tv[0-9]+,v[0-9]+,v[0-9]+ +** ... +** fsrm\t[axt][0-9]+ +** ... +** ret +*/ +void +test_2 (vfloat32m1_t op1, vfloat32m1_t op2, vfloat32m1_t *op_out, size_t vl, + double *in1, double *in2, double *out) +{ + op2 = __riscv_vfadd_vv_f32m1_rm (op1, op2, 1, vl); + + for (int i = 0; i < vl; ++i) + out[i] = out[i] * in1[i] - in2[i]; + + *op_out = __riscv_vfadd_vv_f32m1_rm (op1, op2, 4, vl); +} + +/* +**test_3: +** ... +** frrm\t[axt][0-9]+ +** ... +** vfmsub\.vv\tv[0-9]+,v[0-9]+,v[0-9]+ +** ... +** fsrmi\t4 +** ... +** vfadd\.vv\tv[0-9]+,v[0-9]+,v[0-9]+ +** ... +** fsrm\t[axt][0-9]+ +** ... +** ret +*/ +void +test_3 (vfloat32m1_t op1, vfloat32m1_t op2, vfloat32m1_t *op_out, size_t vl, + double *in1, double *in2, double *in3, double *out) +{ + for (int i = 0; i < vl; ++i) + out[i] = in2[i] * out[i] - in1[i]; + + *op_out = __riscv_vfadd_vv_f32m1_rm (op1, op2, 4, vl); +} diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-autovec-3.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-autovec-3.c new file mode 100644 index 000000000000..abedfc1b8fb0 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-autovec-3.c @@ -0,0 +1,88 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gcv --param=riscv-autovec-preference=fixed-vlmax -ffast-math -mabi=lp64 -O3 -Wno-psabi" } */ +/* { dg-final { check-function-bodies "**" "" } } */ + +#include "riscv_vector.h" + +/* +**test_1: +** ... +** frrm\t[axt][0-9]+ +** ... +** fsrmi\t1 +** ... +** vfadd\.vv\tv[0-9]+,v[0-9]+,v[0-9]+ +** ... +** fsrm\t[axt][0-9]+ +** ... +** vfnmsub\.vv\tv[0-9]+,v[0-9]+,v[0-9]+ +** ... +** ret +*/ +void +test_1 (vfloat32m1_t op1, vfloat32m1_t op2, vfloat32m1_t *op_out, size_t vl, + double *in1, double *in2, double *out) +{ + *op_out = __riscv_vfadd_vv_f32m1_rm (op1, op2, 1, vl); + + for (int i = 0; i < vl; ++i) + out[i] = - in1[i] * in2[i] + out[i]; +} + +/* +**test_2: +** ... +** frrm\t[axt][0-9]+ +** ... +** fsrmi\t1 +** ... +** vfadd\.vv\tv[0-9]+,v[0-9]+,v[0-9]+ +** ... +** fsrm\t[axt][0-9]+ +** ... +** vfnmsub\.vv\tv[0-9]+,v[0-9]+,v[0-9]+ +** ... +** fsrmi\t4 +** ... +** vfadd\.vv\tv[0-9]+,v[0-9]+,v[0-9]+ +** ... +** fsrm\t[axt][0-9]+ +** ... +** ret +*/ +void +test_2 (vfloat32m1_t op1, vfloat32m1_t op2, vfloat32m1_t *op_out, size_t vl, + double *in1, double *in2, double *out) +{ + op2 = __riscv_vfadd_vv_f32m1_rm (op1, op2, 1, vl); + + for (int i = 0; i < vl; ++i) + out[i] = - out[i] * in1[i] + in2[i]; + + *op_out = __riscv_vfadd_vv_f32m1_rm (op1, op2, 4, vl); +} + +/* +**test_3: +** ... +** frrm\t[axt][0-9]+ +** ... +** vfnmsub\.vv\tv[0-9]+,v[0-9]+,v[0-9]+ +** ... +** fsrmi\t4 +** ... +** vfadd\.vv\tv[0-9]+,v[0-9]+,v[0-9]+ +** ... +** fsrm\t[axt][0-9]+ +** ... +** ret +*/ +void +test_3 (vfloat32m1_t op1, vfloat32m1_t op2, vfloat32m1_t *op_out, size_t vl, + double *in1, double *in2, double *in3, double *out) +{ + for (int i = 0; i < vl; ++i) + out[i] = - in2[i] * out[i] + in1[i]; + + *op_out = __riscv_vfadd_vv_f32m1_rm (op1, op2, 4, vl); +} diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-autovec-4.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-autovec-4.c new file mode 100644 index 000000000000..2cc4e0ae38e2 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-autovec-4.c @@ -0,0 +1,88 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gcv --param=riscv-autovec-preference=fixed-vlmax -ffast-math -mabi=lp64 -O3 -Wno-psabi" } */ +/* { dg-final { check-function-bodies "**" "" } } */ + +#include "riscv_vector.h" + +/* +**test_1: +** ... +** frrm\t[axt][0-9]+ +** ... +** fsrmi\t1 +** ... +** vfadd\.vv\tv[0-9]+,v[0-9]+,v[0-9]+ +** ... +** fsrm\t[axt][0-9]+ +** ... +** vfnmadd\.vv\tv[0-9]+,v[0-9]+,v[0-9]+ +** ... +** ret +*/ +void +test_1 (vfloat32m1_t op1, vfloat32m1_t op2, vfloat32m1_t *op_out, size_t vl, + double *in1, double *in2, double *out) +{ + *op_out = __riscv_vfadd_vv_f32m1_rm (op1, op2, 1, vl); + + for (int i = 0; i < vl; ++i) + out[i] = - in1[i] * in2[i] - out[i]; +} + +/* +**test_2: +** ... +** frrm\t[axt][0-9]+ +** ... +** fsrmi\t1 +** ... +** vfadd\.vv\tv[0-9]+,v[0-9]+,v[0-9]+ +** ... +** fsrm\t[axt][0-9]+ +** ... +** vfnmadd\.vv\tv[0-9]+,v[0-9]+,v[0-9]+ +** ... +** fsrmi\t4 +** ... +** vfadd\.vv\tv[0-9]+,v[0-9]+,v[0-9]+ +** ... +** fsrm\t[axt][0-9]+ +** ... +** ret +*/ +void +test_2 (vfloat32m1_t op1, vfloat32m1_t op2, vfloat32m1_t *op_out, size_t vl, + double *in1, double *in2, double *out) +{ + op2 = __riscv_vfadd_vv_f32m1_rm (op1, op2, 1, vl); + + for (int i = 0; i < vl; ++i) + out[i] = - out[i] * in1[i] - in2[i]; + + *op_out = __riscv_vfadd_vv_f32m1_rm (op1, op2, 4, vl); +} + +/* +**test_3: +** ... +** frrm\t[axt][0-9]+ +** ... +** vfnmadd\.vv\tv[0-9]+,v[0-9]+,v[0-9]+ +** ... +** fsrmi\t4 +** ... +** vfadd\.vv\tv[0-9]+,v[0-9]+,v[0-9]+ +** ... +** fsrm\t[axt][0-9]+ +** ... +** ret +*/ +void +test_3 (vfloat32m1_t op1, vfloat32m1_t op2, vfloat32m1_t *op_out, size_t vl, + double *in1, double *in2, double *in3, double *out) +{ + for (int i = 0; i < vl; ++i) + out[i] = - in2[i] * out[i] - in1[i]; + + *op_out = __riscv_vfadd_vv_f32m1_rm (op1, op2, 4, vl); +} diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-fwmacc.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-fwmacc.c new file mode 100644 index 000000000000..45bb628fa7be --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-fwmacc.c @@ -0,0 +1,47 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */ + +#include "riscv_vector.h" + +typedef float float32_t; + +vfloat64m2_t +test_vfwmacc_vv_f32m1_rm (vfloat64m2_t vd, vfloat32m1_t op1, vfloat32m1_t op2, + size_t vl) { + return __riscv_vfwmacc_vv_f64m2_rm (vd, op1, op2, 0, vl); +} + +vfloat64m2_t +test_vfwmacc_vv_f32m1_rm_m (vbool32_t mask, vfloat64m2_t vd, vfloat32m1_t op1, + vfloat32m1_t op2, size_t vl) { + return __riscv_vfwmacc_vv_f64m2_rm_m (mask, vd, op1, op2, 1, vl); +} + +vfloat64m2_t +test_vfwmacc_vf_f32m1_rm (vfloat64m2_t vd, float32_t op1, vfloat32m1_t op2, + size_t vl) { + return __riscv_vfwmacc_vf_f64m2_rm (vd, op1, op2, 2, vl); +} + +vfloat64m2_t +test_vfwmacc_vf_f32m1_rm_m (vbool32_t mask, vfloat64m2_t vd, float32_t op1, + vfloat32m1_t op2, size_t vl) { + return __riscv_vfwmacc_vf_f64m2_rm_m (mask, vd, op1, op2, 3, vl); +} + +vfloat64m2_t +test_vfwmacc_vv_f32m1 (vfloat64m2_t vd, vfloat32m1_t op1, vfloat32m1_t op2, + size_t vl) { + return __riscv_vfwmacc_vv_f64m2 (vd, op1, op2, vl); +} + +vfloat64m2_t +test_vfwmacc_vv_f32m1_m (vbool32_t mask, vfloat64m2_t vd, vfloat32m1_t op1, + vfloat32m1_t op2, size_t vl) { + return __riscv_vfwmacc_vv_f64m2_m (mask, vd, op1, op2, vl); +} + +/* { dg-final { scan-assembler-times {vfwmacc\.[vw][vf]\s+v[0-9]+,\s*[fav]+[0-9]+,\s*[fav]+[0-9]+} 6 } } */ +/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 4 } } */ +/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 4 } } */ +/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 4 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-macc.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-macc.c new file mode 100644 index 000000000000..df29f4d240f8 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-macc.c @@ -0,0 +1,47 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */ + +#include "riscv_vector.h" + +typedef float float32_t; + +vfloat32m1_t +test_riscv_vfmacc_vv_f32m1_rm (vfloat32m1_t vd, vfloat32m1_t op1, + vfloat32m1_t op2, size_t vl) { + return __riscv_vfmacc_vv_f32m1_rm (vd, op1, op2, 0, vl); +} + +vfloat32m1_t +test_vfmacc_vv_f32m1_rm_m (vbool32_t mask, vfloat32m1_t vd, vfloat32m1_t op1, + vfloat32m1_t op2, size_t vl) { + return __riscv_vfmacc_vv_f32m1_rm_m (mask, vd, op1, op2, 1, vl); +} + +vfloat32m1_t +test_vfmacc_vf_f32m1_rm (vfloat32m1_t vd, float32_t op1, vfloat32m1_t op2, + size_t vl) { + return __riscv_vfmacc_vf_f32m1_rm (vd, op1, op2, 2, vl); +} + +vfloat32m1_t +test_vfmacc_vf_f32m1_rm_m (vfloat32m1_t vd, vbool32_t mask, float32_t op1, + vfloat32m1_t op2, size_t vl) { + return __riscv_vfmacc_vf_f32m1_rm_m (mask, vd, op1, op2, 3, vl); +} + +vfloat32m1_t +test_riscv_vfmacc_vv_f32m1 (vfloat32m1_t vd, vfloat32m1_t op1, vfloat32m1_t op2, + size_t vl) { + return __riscv_vfmacc_vv_f32m1 (vd, op1, op2, vl); +} + +vfloat32m1_t +test_vfmacc_vv_f32m1_m (vbool32_t mask, vfloat32m1_t vd, vfloat32m1_t op1, + vfloat32m1_t op2, size_t vl) { + return __riscv_vfmacc_vv_f32m1_m (mask, vd, op1, op2, vl); +} + +/* { dg-final { scan-assembler-times {vfmacc\.v[vf]\s+v[0-9]+,\s*[fav]+[0-9]+,\s*v[0-9]+} 6 } } */ +/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 4 } } */ +/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 4 } } */ +/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 4 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-madd.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-madd.c new file mode 100644 index 000000000000..00c9d0029987 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-madd.c @@ -0,0 +1,47 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */ + +#include "riscv_vector.h" + +typedef float float32_t; + +vfloat32m1_t +test_riscv_vfmadd_vv_f32m1_rm (vfloat32m1_t vd, vfloat32m1_t op1, + vfloat32m1_t op2, size_t vl) { + return __riscv_vfmadd_vv_f32m1_rm (vd, op1, op2, 0, vl); +} + +vfloat32m1_t +test_vfmadd_vv_f32m1_rm_m (vbool32_t mask, vfloat32m1_t vd, vfloat32m1_t op1, + vfloat32m1_t op2, size_t vl) { + return __riscv_vfmadd_vv_f32m1_rm_m (mask, vd, op1, op2, 1, vl); +} + +vfloat32m1_t +test_vfmadd_vf_f32m1_rm (vfloat32m1_t vd, float32_t op1, vfloat32m1_t op2, + size_t vl) { + return __riscv_vfmadd_vf_f32m1_rm (vd, op1, op2, 2, vl); +} + +vfloat32m1_t +test_vfmadd_vf_f32m1_rm_m (vfloat32m1_t vd, vbool32_t mask, float32_t op1, + vfloat32m1_t op2, size_t vl) { + return __riscv_vfmadd_vf_f32m1_rm_m (mask, vd, op1, op2, 3, vl); +} + +vfloat32m1_t +test_riscv_vfmadd_vv_f32m1 (vfloat32m1_t vd, vfloat32m1_t op1, + vfloat32m1_t op2, size_t vl) { + return __riscv_vfmadd_vv_f32m1 (vd, op1, op2, vl); +} + +vfloat32m1_t +test_vfmadd_vv_f32m1_m (vbool32_t mask, vfloat32m1_t vd, vfloat32m1_t op1, + vfloat32m1_t op2, size_t vl) { + return __riscv_vfmadd_vv_f32m1_m (mask, vd, op1, op2, vl); +} + +/* { dg-final { scan-assembler-times {vfmadd\.v[vf]\s+v[0-9]+,\s*[fav]+[0-9]+,\s*v[0-9]+} 6 } } */ +/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 4 } } */ +/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 4 } } */ +/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 4 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-msac.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-msac.c new file mode 100644 index 000000000000..8fee552dd300 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-msac.c @@ -0,0 +1,47 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */ + +#include "riscv_vector.h" + +typedef float float32_t; + +vfloat32m1_t +test_riscv_vfmsac_vv_f32m1_rm (vfloat32m1_t vd, vfloat32m1_t op1, + vfloat32m1_t op2, size_t vl) { + return __riscv_vfmsac_vv_f32m1_rm (vd, op1, op2, 0, vl); +} + +vfloat32m1_t +test_vfmsac_vv_f32m1_rm_m (vbool32_t mask, vfloat32m1_t vd, vfloat32m1_t op1, + vfloat32m1_t op2, size_t vl) { + return __riscv_vfmsac_vv_f32m1_rm_m (mask, vd, op1, op2, 1, vl); +} + +vfloat32m1_t +test_vfmsac_vf_f32m1_rm (vfloat32m1_t vd, float32_t op1, vfloat32m1_t op2, + size_t vl) { + return __riscv_vfmsac_vf_f32m1_rm (vd, op1, op2, 2, vl); +} + +vfloat32m1_t +test_vfmsac_vf_f32m1_rm_m (vfloat32m1_t vd, vbool32_t mask, float32_t op1, + vfloat32m1_t op2, size_t vl) { + return __riscv_vfmsac_vf_f32m1_rm_m (mask, vd, op1, op2, 3, vl); +} + +vfloat32m1_t +test_riscv_vfmsac_vv_f32m1 (vfloat32m1_t vd, vfloat32m1_t op1, + vfloat32m1_t op2, size_t vl) { + return __riscv_vfmsac_vv_f32m1 (vd, op1, op2, vl); +} + +vfloat32m1_t +test_vfmsac_vv_f32m1_m (vbool32_t mask, vfloat32m1_t vd, vfloat32m1_t op1, + vfloat32m1_t op2, size_t vl) { + return __riscv_vfmsac_vv_f32m1_m (mask, vd, op1, op2, vl); +} + +/* { dg-final { scan-assembler-times {vfmsac\.v[vf]\s+v[0-9]+,\s*[fav]+[0-9]+,\s*v[0-9]+} 6 } } */ +/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 4 } } */ +/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 4 } } */ +/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 4 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-msub.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-msub.c new file mode 100644 index 000000000000..e58519d0742a --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-msub.c @@ -0,0 +1,47 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */ + +#include "riscv_vector.h" + +typedef float float32_t; + +vfloat32m1_t +test_riscv_vfmsub_vv_f32m1_rm (vfloat32m1_t vd, vfloat32m1_t op1, + vfloat32m1_t op2, size_t vl) { + return __riscv_vfmsub_vv_f32m1_rm (vd, op1, op2, 0, vl); +} + +vfloat32m1_t +test_vfmsub_vv_f32m1_rm_m (vbool32_t mask, vfloat32m1_t vd, vfloat32m1_t op1, + vfloat32m1_t op2, size_t vl) { + return __riscv_vfmsub_vv_f32m1_rm_m (mask, vd, op1, op2, 1, vl); +} + +vfloat32m1_t +test_vfmsub_vf_f32m1_rm (vfloat32m1_t vd, float32_t op1, vfloat32m1_t op2, + size_t vl) { + return __riscv_vfmsub_vf_f32m1_rm (vd, op1, op2, 2, vl); +} + +vfloat32m1_t +test_vfmsub_vf_f32m1_rm_m (vfloat32m1_t vd, vbool32_t mask, float32_t op1, + vfloat32m1_t op2, size_t vl) { + return __riscv_vfmsub_vf_f32m1_rm_m (mask, vd, op1, op2, 3, vl); +} + +vfloat32m1_t +test_riscv_vfmsub_vv_f32m1 (vfloat32m1_t vd, vfloat32m1_t op1, + vfloat32m1_t op2, size_t vl) { + return __riscv_vfmsub_vv_f32m1 (vd, op1, op2, vl); +} + +vfloat32m1_t +test_vfmsub_vv_f32m1_m (vbool32_t mask, vfloat32m1_t vd, vfloat32m1_t op1, + vfloat32m1_t op2, size_t vl) { + return __riscv_vfmsub_vv_f32m1_m (mask, vd, op1, op2, vl); +} + +/* { dg-final { scan-assembler-times {vfmsub\.v[vf]\s+v[0-9]+,\s*[fav]+[0-9]+,\s*v[0-9]+} 6 } } */ +/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 4 } } */ +/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 4 } } */ +/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 4 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-ncvt-f.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-ncvt-f.c new file mode 100644 index 000000000000..d6d4be5e98ea --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-ncvt-f.c @@ -0,0 +1,69 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */ + +#include "riscv_vector.h" + +vfloat32m1_t +test_riscv_vfncvt_f_x_w_f32m1_rm (vint64m2_t op1, size_t vl) { + return __riscv_vfncvt_f_x_w_f32m1_rm (op1, 0, vl); +} + +vfloat32m1_t +test_vfncvt_f_x_w_f32m1_rm_m (vbool32_t mask, vint64m2_t op1, size_t vl) { + return __riscv_vfncvt_f_x_w_f32m1_rm_m (mask, op1, 1, vl); +} + +vfloat32m1_t +test_riscv_vfncvt_f_xu_w_f32m1_rm (vuint64m2_t op1, size_t vl) { + return __riscv_vfncvt_f_xu_w_f32m1_rm (op1, 0, vl); +} + +vfloat32m1_t +test_vfncvt_f_xu_w_f32m1_rm_m (vbool32_t mask, vuint64m2_t op1, size_t vl) { + return __riscv_vfncvt_f_xu_w_f32m1_rm_m (mask, op1, 1, vl); +} + +vfloat32m1_t +test_riscv_vfncvt_f_f_w_f32m1_rm (vfloat64m2_t op1, size_t vl) { + return __riscv_vfncvt_f_f_w_f32m1_rm (op1, 0, vl); +} + +vfloat32m1_t +test_vfncvt_f_f_w_f32m1_rm_m (vbool32_t mask, vfloat64m2_t op1, size_t vl) { + return __riscv_vfncvt_f_f_w_f32m1_rm_m (mask, op1, 1, vl); +} + +vfloat32m1_t +test_riscv_vfncvt_f_x_w_f32m1 (vint64m2_t op1, size_t vl) { + return __riscv_vfncvt_f_x_w_f32m1 (op1, vl); +} + +vfloat32m1_t +test_vfncvt_f_x_w_f32m1_m (vbool32_t mask, vint64m2_t op1, size_t vl) { + return __riscv_vfncvt_f_x_w_f32m1_m (mask, op1, vl); +} + +vfloat32m1_t +test_riscv_vfncvt_f_xu_w_f32m1 (vuint64m2_t op1, size_t vl) { + return __riscv_vfncvt_f_xu_w_f32m1 (op1, vl); +} + +vfloat32m1_t +test_vfncvt_f_xu_w_f32m1_m (vbool32_t mask, vuint64m2_t op1, size_t vl) { + return __riscv_vfncvt_f_xu_w_f32m1_m (mask, op1, vl); +} + +vfloat32m1_t +test_riscv_vfncvt_f_f_w_f32m1 (vfloat64m2_t op1, size_t vl) { + return __riscv_vfncvt_f_f_w_f32m1 (op1, vl); +} + +vfloat32m1_t +test_vfncvt_f_f_w_f32m1_m (vbool32_t mask, vfloat64m2_t op1, size_t vl) { + return __riscv_vfncvt_f_f_w_f32m1_m (mask, op1, vl); +} + +/* { dg-final { scan-assembler-times {vfncvt\.f\.[xuf]+\.w\s+v[0-9]+,\s*v[0-9]+} 12 } } */ +/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 6 } } */ +/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 6 } } */ +/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 6 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-ncvt-x.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-ncvt-x.c new file mode 100644 index 000000000000..1630b7e7ccf2 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-ncvt-x.c @@ -0,0 +1,29 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */ + +#include "riscv_vector.h" + +vint16mf2_t +test_riscv_vfncvt_x_f_w_i16mf2_rm (vfloat32m1_t op1, size_t vl) { + return __riscv_vfncvt_x_f_w_i16mf2_rm (op1, 0, vl); +} + +vint16mf2_t +test_vfncvt_x_f_w_i16mf2_rm_m (vbool32_t mask, vfloat32m1_t op1, size_t vl) { + return __riscv_vfncvt_x_f_w_i16mf2_rm_m (mask, op1, 1, vl); +} + +vint16mf2_t +test_riscv_vfncvt_x_f_w_i16mf2 (vfloat32m1_t op1, size_t vl) { + return __riscv_vfncvt_x_f_w_i16mf2 (op1, vl); +} + +vint16mf2_t +test_vfncvt_x_f_w_i16mf2_m (vbool32_t mask, vfloat32m1_t op1, size_t vl) { + return __riscv_vfncvt_x_f_w_i16mf2_m (mask, op1, vl); +} + +/* { dg-final { scan-assembler-times {vfncvt\.x\.f\.w\s+v[0-9]+,\s*v[0-9]+} 4 } } */ +/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */ +/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 2 } } */ +/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-ncvt-xu.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-ncvt-xu.c new file mode 100644 index 000000000000..82c3e1364bf4 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-ncvt-xu.c @@ -0,0 +1,29 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */ + +#include "riscv_vector.h" + +vuint16mf2_t +test_riscv_vfncvt_xu_f_w_u16mf2_rm (vfloat32m1_t op1, size_t vl) { + return __riscv_vfncvt_xu_f_w_u16mf2_rm (op1, 0, vl); +} + +vuint16mf2_t +test_vfncvt_xu_f_w_u16mf2_rm_m (vbool32_t mask, vfloat32m1_t op1, size_t vl) { + return __riscv_vfncvt_xu_f_w_u16mf2_rm_m (mask, op1, 1, vl); +} + +vuint16mf2_t +test_riscv_vfncvt_xu_f_w_u16mf2 (vfloat32m1_t op1, size_t vl) { + return __riscv_vfncvt_xu_f_w_u16mf2 (op1, vl); +} + +vuint16mf2_t +test_vfncvt_xu_f_w_u16mf2_m (vbool32_t mask, vfloat32m1_t op1, size_t vl) { + return __riscv_vfncvt_xu_f_w_u16mf2_m (mask, op1, vl); +} + +/* { dg-final { scan-assembler-times {vfncvt\.xu\.f\.w\s+v[0-9]+,\s*v[0-9]+} 4 } } */ +/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */ +/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 2 } } */ +/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-nmacc.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-nmacc.c new file mode 100644 index 000000000000..fca378b7a8fd --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-nmacc.c @@ -0,0 +1,47 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */ + +#include "riscv_vector.h" + +typedef float float32_t; + +vfloat32m1_t +test_riscv_vfnmacc_vv_f32m1_rm (vfloat32m1_t vd, vfloat32m1_t op1, + vfloat32m1_t op2, size_t vl) { + return __riscv_vfnmacc_vv_f32m1_rm (vd, op1, op2, 0, vl); +} + +vfloat32m1_t +test_vfnmacc_vv_f32m1_rm_m (vbool32_t mask, vfloat32m1_t vd, vfloat32m1_t op1, + vfloat32m1_t op2, size_t vl) { + return __riscv_vfnmacc_vv_f32m1_rm_m (mask, vd, op1, op2, 1, vl); +} + +vfloat32m1_t +test_vfnmacc_vf_f32m1_rm (vfloat32m1_t vd, float32_t op1, vfloat32m1_t op2, + size_t vl) { + return __riscv_vfnmacc_vf_f32m1_rm (vd, op1, op2, 2, vl); +} + +vfloat32m1_t +test_vfnmacc_vf_f32m1_rm_m (vfloat32m1_t vd, vbool32_t mask, float32_t op1, + vfloat32m1_t op2, size_t vl) { + return __riscv_vfnmacc_vf_f32m1_rm_m (mask, vd, op1, op2, 3, vl); +} + +vfloat32m1_t +test_riscv_vfnmacc_vv_f32m1 (vfloat32m1_t vd, vfloat32m1_t op1, + vfloat32m1_t op2, size_t vl) { + return __riscv_vfnmacc_vv_f32m1 (vd, op1, op2, vl); +} + +vfloat32m1_t +test_vfnmacc_vv_f32m1_m (vbool32_t mask, vfloat32m1_t vd, vfloat32m1_t op1, + vfloat32m1_t op2, size_t vl) { + return __riscv_vfnmacc_vv_f32m1_m (mask, vd, op1, op2, vl); +} + +/* { dg-final { scan-assembler-times {vfnmacc\.v[vf]\s+v[0-9]+,\s*[fav]+[0-9]+,\s*v[0-9]+} 6 } } */ +/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 4 } } */ +/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 4 } } */ +/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 4 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-nmadd.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-nmadd.c new file mode 100644 index 000000000000..9332617641b4 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-nmadd.c @@ -0,0 +1,47 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */ + +#include "riscv_vector.h" + +typedef float float32_t; + +vfloat32m1_t +test_riscv_vfnmadd_vv_f32m1_rm (vfloat32m1_t vd, vfloat32m1_t op1, + vfloat32m1_t op2, size_t vl) { + return __riscv_vfnmadd_vv_f32m1_rm (vd, op1, op2, 0, vl); +} + +vfloat32m1_t +test_vfnmadd_vv_f32m1_rm_m (vbool32_t mask, vfloat32m1_t vd, vfloat32m1_t op1, + vfloat32m1_t op2, size_t vl) { + return __riscv_vfnmadd_vv_f32m1_rm_m (mask, vd, op1, op2, 1, vl); +} + +vfloat32m1_t +test_vfnmadd_vf_f32m1_rm (vfloat32m1_t vd, float32_t op1, vfloat32m1_t op2, + size_t vl) { + return __riscv_vfnmadd_vf_f32m1_rm (vd, op1, op2, 2, vl); +} + +vfloat32m1_t +test_vfnmadd_vf_f32m1_rm_m (vfloat32m1_t vd, vbool32_t mask, float32_t op1, + vfloat32m1_t op2, size_t vl) { + return __riscv_vfnmadd_vf_f32m1_rm_m (mask, vd, op1, op2, 3, vl); +} + +vfloat32m1_t +test_riscv_vfnmadd_vv_f32m1 (vfloat32m1_t vd, vfloat32m1_t op1, + vfloat32m1_t op2, size_t vl) { + return __riscv_vfnmadd_vv_f32m1 (vd, op1, op2, vl); +} + +vfloat32m1_t +test_vfnmadd_vv_f32m1_m (vbool32_t mask, vfloat32m1_t vd, vfloat32m1_t op1, + vfloat32m1_t op2, size_t vl) { + return __riscv_vfnmadd_vv_f32m1_m (mask, vd, op1, op2, vl); +} + +/* { dg-final { scan-assembler-times {vfnmadd\.v[vf]\s+v[0-9]+,\s*[fav]+[0-9]+,\s*v[0-9]+} 6 } } */ +/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 4 } } */ +/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 4 } } */ +/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 4 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-nmsac.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-nmsac.c new file mode 100644 index 000000000000..c30892342721 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-nmsac.c @@ -0,0 +1,47 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */ + +#include "riscv_vector.h" + +typedef float float32_t; + +vfloat32m1_t +test_riscv_vfnmsac_vv_f32m1_rm (vfloat32m1_t vd, vfloat32m1_t op1, + vfloat32m1_t op2, size_t vl) { + return __riscv_vfnmsac_vv_f32m1_rm (vd, op1, op2, 0, vl); +} + +vfloat32m1_t +test_vfnmsac_vv_f32m1_rm_m (vbool32_t mask, vfloat32m1_t vd, vfloat32m1_t op1, + vfloat32m1_t op2, size_t vl) { + return __riscv_vfnmsac_vv_f32m1_rm_m (mask, vd, op1, op2, 1, vl); +} + +vfloat32m1_t +test_vfnmsac_vf_f32m1_rm (vfloat32m1_t vd, float32_t op1, vfloat32m1_t op2, + size_t vl) { + return __riscv_vfnmsac_vf_f32m1_rm (vd, op1, op2, 2, vl); +} + +vfloat32m1_t +test_vfnmsac_vf_f32m1_rm_m (vfloat32m1_t vd, vbool32_t mask, float32_t op1, + vfloat32m1_t op2, size_t vl) { + return __riscv_vfnmsac_vf_f32m1_rm_m (mask, vd, op1, op2, 3, vl); +} + +vfloat32m1_t +test_riscv_vfnmsac_vv_f32m1 (vfloat32m1_t vd, vfloat32m1_t op1, + vfloat32m1_t op2, size_t vl) { + return __riscv_vfnmsac_vv_f32m1 (vd, op1, op2, vl); +} + +vfloat32m1_t +test_vfnmsac_vv_f32m1_m (vbool32_t mask, vfloat32m1_t vd, vfloat32m1_t op1, + vfloat32m1_t op2, size_t vl) { + return __riscv_vfnmsac_vv_f32m1_m (mask, vd, op1, op2, vl); +} + +/* { dg-final { scan-assembler-times {vfnmsac\.v[vf]\s+v[0-9]+,\s*[fav]+[0-9]+,\s*v[0-9]+} 6 } } */ +/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 4 } } */ +/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 4 } } */ +/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 4 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-nmsub.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-nmsub.c new file mode 100644 index 000000000000..1b3e939b1e10 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-nmsub.c @@ -0,0 +1,47 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */ + +#include "riscv_vector.h" + +typedef float float32_t; + +vfloat32m1_t +test_riscv_vfnmsub_vv_f32m1_rm (vfloat32m1_t vd, vfloat32m1_t op1, + vfloat32m1_t op2, size_t vl) { + return __riscv_vfnmsub_vv_f32m1_rm (vd, op1, op2, 0, vl); +} + +vfloat32m1_t +test_vfnmsub_vv_f32m1_rm_m (vbool32_t mask, vfloat32m1_t vd, vfloat32m1_t op1, + vfloat32m1_t op2, size_t vl) { + return __riscv_vfnmsub_vv_f32m1_rm_m (mask, vd, op1, op2, 1, vl); +} + +vfloat32m1_t +test_vfnmsub_vf_f32m1_rm (vfloat32m1_t vd, float32_t op1, vfloat32m1_t op2, + size_t vl) { + return __riscv_vfnmsub_vf_f32m1_rm (vd, op1, op2, 2, vl); +} + +vfloat32m1_t +test_vfnmsub_vf_f32m1_rm_m (vfloat32m1_t vd, vbool32_t mask, float32_t op1, + vfloat32m1_t op2, size_t vl) { + return __riscv_vfnmsub_vf_f32m1_rm_m (mask, vd, op1, op2, 3, vl); +} + +vfloat32m1_t +test_riscv_vfnmsub_vv_f32m1 (vfloat32m1_t vd, vfloat32m1_t op1, + vfloat32m1_t op2, size_t vl) { + return __riscv_vfnmsub_vv_f32m1 (vd, op1, op2, vl); +} + +vfloat32m1_t +test_vfnmsub_vv_f32m1_m (vbool32_t mask, vfloat32m1_t vd, vfloat32m1_t op1, + vfloat32m1_t op2, size_t vl) { + return __riscv_vfnmsub_vv_f32m1_m (mask, vd, op1, op2, vl); +} + +/* { dg-final { scan-assembler-times {vfnmsub\.v[vf]\s+v[0-9]+,\s*[fav]+[0-9]+,\s*v[0-9]+} 6 } } */ +/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 4 } } */ +/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 4 } } */ +/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 4 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-rec7.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-rec7.c new file mode 100644 index 000000000000..a8e10d0853aa --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-rec7.c @@ -0,0 +1,31 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */ + +#include "riscv_vector.h" + +typedef float float32_t; + +vfloat32m1_t +test_riscv_vfrec7_vv_f32m1_rm (vfloat32m1_t op1, size_t vl) { + return __riscv_vfrec7_v_f32m1_rm (op1, 0, vl); +} + +vfloat32m1_t +test_vfrec7_vv_f32m1_rm_m (vbool32_t mask, vfloat32m1_t op1, size_t vl) { + return __riscv_vfrec7_v_f32m1_rm_m (mask, op1, 1, vl); +} + +vfloat32m1_t +test_riscv_vfrec7_vv_f32m1 (vfloat32m1_t op1, size_t vl) { + return __riscv_vfrec7_v_f32m1 (op1, vl); +} + +vfloat32m1_t +test_vfrec7_vv_f32m1_m (vbool32_t mask, vfloat32m1_t op1, size_t vl) { + return __riscv_vfrec7_v_f32m1_m (mask, op1, vl); +} + +/* { dg-final { scan-assembler-times {vfrec7\.v\s+v[0-9]+,\s*v[0-9]+} 4 } } */ +/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */ +/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 2 } } */ +/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-redosum.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-redosum.c new file mode 100644 index 000000000000..2e6a3c28a89f --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-redosum.c @@ -0,0 +1,33 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */ + +#include "riscv_vector.h" + +vfloat32m1_t +test_riscv_vfredosum_vs_f32m1_f32m1_rm (vfloat32m1_t op1, vfloat32m1_t op2, + size_t vl) { + return __riscv_vfredosum_vs_f32m1_f32m1_rm (op1, op2, 0, vl); +} + +vfloat32m1_t +test_vfredosum_vs_f32m1_f32m1_rm_m (vbool32_t mask, vfloat32m1_t op1, + vfloat32m1_t op2, size_t vl) { + return __riscv_vfredosum_vs_f32m1_f32m1_rm_m (mask, op1, op2, 1, vl); +} + +vfloat32m1_t +test_riscv_vfredosum_vs_f32m1_f32m1 (vfloat32m1_t op1, vfloat32m1_t op2, + size_t vl) { + return __riscv_vfredosum_vs_f32m1_f32m1 (op1, op2, vl); +} + +vfloat32m1_t +test_vfredosum_vs_f32m1_f32m1_m (vbool32_t mask, vfloat32m1_t op1, + vfloat32m1_t op2, size_t vl) { + return __riscv_vfredosum_vs_f32m1_f32m1_m (mask, op1, op2, vl); +} + +/* { dg-final { scan-assembler-times {vfredosum\.vs\s+v[0-9]+,\s*v[0-9]+,\s*v[0-9]+} 4 } } */ +/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */ +/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 2 } } */ +/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-redusum.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-redusum.c new file mode 100644 index 000000000000..36da6dd46f72 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-redusum.c @@ -0,0 +1,33 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */ + +#include "riscv_vector.h" + +vfloat32m1_t +test_riscv_vfredusum_vs_f32m1_f32m1_rm (vfloat32m1_t op1, vfloat32m1_t op2, + size_t vl) { + return __riscv_vfredusum_vs_f32m1_f32m1_rm (op1, op2, 0, vl); +} + +vfloat32m1_t +test_vfredusum_vs_f32m1_f32m1_rm_m (vbool32_t mask, vfloat32m1_t op1, + vfloat32m1_t op2, size_t vl) { + return __riscv_vfredusum_vs_f32m1_f32m1_rm_m (mask, op1, op2, 1, vl); +} + +vfloat32m1_t +test_riscv_vfredusum_vs_f32m1_f32m1 (vfloat32m1_t op1, vfloat32m1_t op2, + size_t vl) { + return __riscv_vfredusum_vs_f32m1_f32m1 (op1, op2, vl); +} + +vfloat32m1_t +test_vfredusum_vs_f32m1_f32m1_m (vbool32_t mask, vfloat32m1_t op1, + vfloat32m1_t op2, size_t vl) { + return __riscv_vfredusum_vs_f32m1_f32m1_m (mask, op1, op2, vl); +} + +/* { dg-final { scan-assembler-times {vfredusum\.vs\s+v[0-9]+,\s*v[0-9]+} 4 } } */ +/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */ +/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 2 } } */ +/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-single-rsub.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-single-rsub.c index 1d770adc32c9..86c56b7c6cbb 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-single-rsub.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-single-rsub.c @@ -16,4 +16,18 @@ test_vfrsub_vf_f32m1_rm_m (vbool32_t mask, vfloat32m1_t op1, float32_t op2, return __riscv_vfrsub_vf_f32m1_rm_m (mask, op1, op2, 3, vl); } -/* { dg-final { scan-assembler-times {vfrsub\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */ +vfloat32m1_t +test_vfrsub_vf_f32m1 (vfloat32m1_t op1, float32_t op2, size_t vl) { + return __riscv_vfrsub_vf_f32m1 (op1, op2, vl); +} + +vfloat32m1_t +test_vfrsub_vf_f32m1_m (vbool32_t mask, vfloat32m1_t op1, float32_t op2, + size_t vl) { + return __riscv_vfrsub_vf_f32m1_m (mask, op1, op2, vl); +} + +/* { dg-final { scan-assembler-times {vfrsub\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 4 } } */ +/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */ +/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 2 } } */ +/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-single-sub.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-single-sub.c index 34ed03a31d9e..8075dced0b9d 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-single-sub.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-single-sub.c @@ -27,4 +27,18 @@ test_vfsub_vf_f32m1_rm_m (vbool32_t mask, vfloat32m1_t op1, float32_t op2, return __riscv_vfsub_vf_f32m1_rm_m (mask, op1, op2, 3, vl); } -/* { dg-final { scan-assembler-times {vfsub\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 4 } } */ +vfloat32m1_t +test_riscv_vfsub_vv_f32m1 (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl) { + return __riscv_vfsub_vv_f32m1 (op1, op2, vl); +} + +vfloat32m1_t +test_vfsub_vv_f32m1_m (vbool32_t mask, vfloat32m1_t op1, vfloat32m1_t op2, + size_t vl) { + return __riscv_vfsub_vv_f32m1_m (mask, op1, op2, vl); +} + +/* { dg-final { scan-assembler-times {vfsub\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 6 } } */ +/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 4 } } */ +/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 4 } } */ +/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 4 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-sqrt.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-sqrt.c new file mode 100644 index 000000000000..afd1fb2b8f68 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-sqrt.c @@ -0,0 +1,31 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */ + +#include "riscv_vector.h" + +typedef float float32_t; + +vfloat32m1_t +test_riscv_vfsqrt_vv_f32m1_rm (vfloat32m1_t op1, size_t vl) { + return __riscv_vfsqrt_v_f32m1_rm (op1, 0, vl); +} + +vfloat32m1_t +test_vfsqrt_vv_f32m1_rm_m (vbool32_t mask, vfloat32m1_t op1, size_t vl) { + return __riscv_vfsqrt_v_f32m1_rm_m (mask, op1, 1, vl); +} + +vfloat32m1_t +test_riscv_vfsqrt_vv_f32m1 (vfloat32m1_t op1, size_t vl) { + return __riscv_vfsqrt_v_f32m1 (op1, vl); +} + +vfloat32m1_t +test_vfsqrt_vv_f32m1_m (vbool32_t mask, vfloat32m1_t op1, size_t vl) { + return __riscv_vfsqrt_v_f32m1_m (mask, op1, vl); +} + +/* { dg-final { scan-assembler-times {vfsqrt\.v\s+v[0-9]+,\s*v[0-9]+} 4 } } */ +/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */ +/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 2 } } */ +/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-wcvt-x.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-wcvt-x.c new file mode 100644 index 000000000000..8f67ec00966d --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-wcvt-x.c @@ -0,0 +1,29 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */ + +#include "riscv_vector.h" + +vint64m2_t +test_riscv_vfwcvt_x_f_v_i64m2_rm (vfloat32m1_t op1, size_t vl) { + return __riscv_vfwcvt_x_f_v_i64m2_rm (op1, 0, vl); +} + +vint64m2_t +test_vfwcvt_x_f_v_i64m2_rm_m (vbool32_t mask, vfloat32m1_t op1, size_t vl) { + return __riscv_vfwcvt_x_f_v_i64m2_rm_m (mask, op1, 1, vl); +} + +vint64m2_t +test_riscv_vfwcvt_x_f_v_i64m2 (vfloat32m1_t op1, size_t vl) { + return __riscv_vfwcvt_x_f_v_i64m2 (op1, vl); +} + +vint64m2_t +test_vfwcvt_x_f_v_i64m2_m (vbool32_t mask, vfloat32m1_t op1, size_t vl) { + return __riscv_vfwcvt_x_f_v_i64m2_m (mask, op1, vl); +} + +/* { dg-final { scan-assembler-times {vfwcvt\.x\.f\.v\s+v[0-9]+,\s*v[0-9]+} 4 } } */ +/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */ +/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 2 } } */ +/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-wcvt-xu.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-wcvt-xu.c new file mode 100644 index 000000000000..29449e79b69f --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-wcvt-xu.c @@ -0,0 +1,29 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */ + +#include "riscv_vector.h" + +vuint64m2_t +test_riscv_vfwcvt_xu_f_v_u64m2_rm (vfloat32m1_t op1, size_t vl) { + return __riscv_vfwcvt_xu_f_v_u64m2_rm (op1, 0, vl); +} + +vuint64m2_t +test_vfwcvt_xu_f_v_u64m2_rm_m (vbool32_t mask, vfloat32m1_t op1, size_t vl) { + return __riscv_vfwcvt_xu_f_v_u64m2_rm_m (mask, op1, 1, vl); +} + +vuint64m2_t +test_riscv_vfwcvt_xu_f_v_u64m2 (vfloat32m1_t op1, size_t vl) { + return __riscv_vfwcvt_xu_f_v_u64m2 (op1, vl); +} + +vuint64m2_t +test_vfwcvt_xu_f_v_u64m2_m (vbool32_t mask, vfloat32m1_t op1, size_t vl) { + return __riscv_vfwcvt_xu_f_v_u64m2_m (mask, op1, vl); +} + +/* { dg-final { scan-assembler-times {vfwcvt\.xu\.f\.v\s+v[0-9]+,\s*v[0-9]+} 4 } } */ +/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */ +/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 2 } } */ +/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-wmsac.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-wmsac.c new file mode 100644 index 000000000000..886a0b136954 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-wmsac.c @@ -0,0 +1,47 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */ + +#include "riscv_vector.h" + +typedef float float32_t; + +vfloat64m2_t +test_vfwmsac_vv_f32m1_rm (vfloat64m2_t vd, vfloat32m1_t op1, vfloat32m1_t op2, + size_t vl) { + return __riscv_vfwmsac_vv_f64m2_rm (vd, op1, op2, 0, vl); +} + +vfloat64m2_t +test_vfwmsac_vv_f32m1_rm_m (vbool32_t mask, vfloat64m2_t vd, vfloat32m1_t op1, + vfloat32m1_t op2, size_t vl) { + return __riscv_vfwmsac_vv_f64m2_rm_m (mask, vd, op1, op2, 1, vl); +} + +vfloat64m2_t +test_vfwmsac_vf_f32m1_rm (vfloat64m2_t vd, float32_t op1, vfloat32m1_t op2, + size_t vl) { + return __riscv_vfwmsac_vf_f64m2_rm (vd, op1, op2, 2, vl); +} + +vfloat64m2_t +test_vfwmsac_vf_f32m1_rm_m (vbool32_t mask, vfloat64m2_t vd, float32_t op1, + vfloat32m1_t op2, size_t vl) { + return __riscv_vfwmsac_vf_f64m2_rm_m (mask, vd, op1, op2, 3, vl); +} + +vfloat64m2_t +test_vfwmsac_vv_f32m1 (vfloat64m2_t vd, vfloat32m1_t op1, vfloat32m1_t op2, + size_t vl) { + return __riscv_vfwmsac_vv_f64m2 (vd, op1, op2, vl); +} + +vfloat64m2_t +test_vfwmsac_vv_f32m1_m (vbool32_t mask, vfloat64m2_t vd, vfloat32m1_t op1, + vfloat32m1_t op2, size_t vl) { + return __riscv_vfwmsac_vv_f64m2_m (mask, vd, op1, op2, vl); +} + +/* { dg-final { scan-assembler-times {vfwmsac\.[vw][vf]\s+v[0-9]+,\s*[fav]+[0-9]+,\s*[fav]+[0-9]+} 6 } } */ +/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 4 } } */ +/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 4 } } */ +/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 4 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-wnmacc.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-wnmacc.c new file mode 100644 index 000000000000..2602289ec88f --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-wnmacc.c @@ -0,0 +1,47 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */ + +#include "riscv_vector.h" + +typedef float float32_t; + +vfloat64m2_t +test_vfwnmacc_vv_f32m1_rm (vfloat64m2_t vd, vfloat32m1_t op1, vfloat32m1_t op2, + size_t vl) { + return __riscv_vfwnmacc_vv_f64m2_rm (vd, op1, op2, 0, vl); +} + +vfloat64m2_t +test_vfwnmacc_vv_f32m1_rm_m (vbool32_t mask, vfloat64m2_t vd, vfloat32m1_t op1, + vfloat32m1_t op2, size_t vl) { + return __riscv_vfwnmacc_vv_f64m2_rm_m (mask, vd, op1, op2, 1, vl); +} + +vfloat64m2_t +test_vfwnmacc_vf_f32m1_rm (vfloat64m2_t vd, float32_t op1, vfloat32m1_t op2, + size_t vl) { + return __riscv_vfwnmacc_vf_f64m2_rm (vd, op1, op2, 2, vl); +} + +vfloat64m2_t +test_vfwnmacc_vf_f32m1_rm_m (vbool32_t mask, vfloat64m2_t vd, float32_t op1, + vfloat32m1_t op2, size_t vl) { + return __riscv_vfwnmacc_vf_f64m2_rm_m (mask, vd, op1, op2, 3, vl); +} + +vfloat64m2_t +test_vfwnmacc_vv_f32m1 (vfloat64m2_t vd, vfloat32m1_t op1, vfloat32m1_t op2, + size_t vl) { + return __riscv_vfwnmacc_vv_f64m2 (vd, op1, op2, vl); +} + +vfloat64m2_t +test_vfwnmacc_vv_f32m1_m (vbool32_t mask, vfloat64m2_t vd, vfloat32m1_t op1, + vfloat32m1_t op2, size_t vl) { + return __riscv_vfwnmacc_vv_f64m2_m (mask, vd, op1, op2, vl); +} + +/* { dg-final { scan-assembler-times {vfwnmacc\.[vw][vf]\s+v[0-9]+,\s*[fav]+[0-9]+,\s*[fav]+[0-9]+} 6 } } */ +/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 4 } } */ +/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 4 } } */ +/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 4 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-wnmsac.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-wnmsac.c new file mode 100644 index 000000000000..13eb306313c0 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-wnmsac.c @@ -0,0 +1,47 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */ + +#include "riscv_vector.h" + +typedef float float32_t; + +vfloat64m2_t +test_vfwnmsac_vv_f32m1_rm (vfloat64m2_t vd, vfloat32m1_t op1, vfloat32m1_t op2, + size_t vl) { + return __riscv_vfwnmsac_vv_f64m2_rm (vd, op1, op2, 0, vl); +} + +vfloat64m2_t +test_vfwnmsac_vv_f32m1_rm_m (vbool32_t mask, vfloat64m2_t vd, vfloat32m1_t op1, + vfloat32m1_t op2, size_t vl) { + return __riscv_vfwnmsac_vv_f64m2_rm_m (mask, vd, op1, op2, 1, vl); +} + +vfloat64m2_t +test_vfwnmsac_vf_f32m1_rm (vfloat64m2_t vd, float32_t op1, vfloat32m1_t op2, + size_t vl) { + return __riscv_vfwnmsac_vf_f64m2_rm (vd, op1, op2, 2, vl); +} + +vfloat64m2_t +test_vfwnmsac_vf_f32m1_rm_m (vbool32_t mask, vfloat64m2_t vd, float32_t op1, + vfloat32m1_t op2, size_t vl) { + return __riscv_vfwnmsac_vf_f64m2_rm_m (mask, vd, op1, op2, 3, vl); +} + +vfloat64m2_t +test_vfwnmsac_vv_f32m1 (vfloat64m2_t vd, vfloat32m1_t op1, vfloat32m1_t op2, + size_t vl) { + return __riscv_vfwnmsac_vv_f64m2 (vd, op1, op2, vl); +} + +vfloat64m2_t +test_vfwnmsac_vv_f32m1_m (vbool32_t mask, vfloat64m2_t vd, vfloat32m1_t op1, + vfloat32m1_t op2, size_t vl) { + return __riscv_vfwnmsac_vv_f64m2_m (mask, vd, op1, op2, vl); +} + +/* { dg-final { scan-assembler-times {vfwnmsac\.[vw][vf]\s+v[0-9]+,\s*[fav]+[0-9]+,\s*[fav]+[0-9]+} 6 } } */ +/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 4 } } */ +/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 4 } } */ +/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 4 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-wredosum.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-wredosum.c new file mode 100644 index 000000000000..acf79569a226 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-wredosum.c @@ -0,0 +1,33 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */ + +#include "riscv_vector.h" + +vfloat64m1_t +test_riscv_vfwredosum_vs_f32m1_f64m1_rm (vfloat32m1_t op1, vfloat64m1_t op2, + size_t vl) { + return __riscv_vfwredosum_vs_f32m1_f64m1_rm (op1, op2, 0, vl); +} + +vfloat64m1_t +test_vfwredosum_vs_f32m1_f64m1_rm_m (vbool32_t mask, vfloat32m1_t op1, + vfloat64m1_t op2, size_t vl) { + return __riscv_vfwredosum_vs_f32m1_f64m1_rm_m (mask, op1, op2, 1, vl); +} + +vfloat64m1_t +test_riscv_vfwredosum_vs_f32m1_f64m1 (vfloat32m1_t op1, vfloat64m1_t op2, + size_t vl) { + return __riscv_vfwredosum_vs_f32m1_f64m1 (op1, op2, vl); +} + +vfloat64m1_t +test_vfwredosum_vs_f32m1_f64m1_m (vbool32_t mask, vfloat32m1_t op1, + vfloat64m1_t op2, size_t vl) { + return __riscv_vfwredosum_vs_f32m1_f64m1_m (mask, op1, op2, vl); +} + +/* { dg-final { scan-assembler-times {vfwredosum\.vs\s+v[0-9]+,\s*v[0-9]+} 4 } } */ +/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */ +/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 2 } } */ +/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-wredusum.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-wredusum.c new file mode 100644 index 000000000000..6c888c10c0db --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-wredusum.c @@ -0,0 +1,33 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */ + +#include "riscv_vector.h" + +vfloat64m1_t +test_riscv_vfwredusum_vs_f32m1_f64m1_rm (vfloat32m1_t op1, vfloat64m1_t op2, + size_t vl) { + return __riscv_vfwredusum_vs_f32m1_f64m1_rm (op1, op2, 0, vl); +} + +vfloat64m1_t +test_vfwredusum_vs_f32m1_f64m1_rm_m (vbool32_t mask, vfloat32m1_t op1, + vfloat64m1_t op2, size_t vl) { + return __riscv_vfwredusum_vs_f32m1_f64m1_rm_m (mask, op1, op2, 1, vl); +} + +vfloat64m1_t +test_riscv_vfwredusum_vs_f32m1_f64m1 (vfloat32m1_t op1, vfloat64m1_t op2, + size_t vl) { + return __riscv_vfwredusum_vs_f32m1_f64m1 (op1, op2, vl); +} + +vfloat64m1_t +test_vfwredusum_vs_f32m1_f64m1_m (vbool32_t mask, vfloat32m1_t op1, + vfloat64m1_t op2, size_t vl) { + return __riscv_vfwredusum_vs_f32m1_f64m1_m (mask, op1, op2, vl); +} + +/* { dg-final { scan-assembler-times {vfwredusum\.vs\s+v[0-9]+,\s*v[0-9]+} 4 } } */ +/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */ +/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 2 } } */ +/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/narrow_constraint-1.c b/gcc/testsuite/gcc.target/riscv/rvv/base/narrow_constraint-1.c index 0cdf60cde067..02d155dc5bf2 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/base/narrow_constraint-1.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/narrow_constraint-1.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-march=rv32gcv -mabi=ilp32d -O3" } */ +/* { dg-options "-march=rv32gcv -mabi=ilp32d -O3 -fno-sched-pressure" } */ #include "riscv_vector.h" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/narrow_constraint-17.c b/gcc/testsuite/gcc.target/riscv/rvv/base/narrow_constraint-17.c index 97df21dd743c..35ef18817fae 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/base/narrow_constraint-17.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/narrow_constraint-17.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-march=rv32gcv -mabi=ilp32d -O3" } */ +/* { dg-options "-march=rv32gcv -mabi=ilp32d -O3 -fno-sched-pressure" } */ #include "riscv_vector.h" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/narrow_constraint-18.c b/gcc/testsuite/gcc.target/riscv/rvv/base/narrow_constraint-18.c index 56c95d9c884e..1c17b763fabc 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/base/narrow_constraint-18.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/narrow_constraint-18.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-march=rv32gcv -mabi=ilp32d -O3" } */ +/* { dg-options "-march=rv32gcv -mabi=ilp32d -O3 -fno-sched-pressure" } */ #include "riscv_vector.h" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/narrow_constraint-19.c b/gcc/testsuite/gcc.target/riscv/rvv/base/narrow_constraint-19.c index d50e497d6c97..923bc27b36b9 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/base/narrow_constraint-19.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/narrow_constraint-19.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-march=rv32gcv -mabi=ilp32d -O3" } */ +/* { dg-options "-march=rv32gcv -mabi=ilp32d -O3 -fno-sched-pressure" } */ #include "riscv_vector.h" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/narrow_constraint-20.c b/gcc/testsuite/gcc.target/riscv/rvv/base/narrow_constraint-20.c index 4e77c51d0580..6dd1b84678bb 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/base/narrow_constraint-20.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/narrow_constraint-20.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-march=rv32gcv -mabi=ilp32d -O3" } */ +/* { dg-options "-march=rv32gcv -mabi=ilp32d -O3 -fno-sched-pressure" } */ #include "riscv_vector.h" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/narrow_constraint-21.c b/gcc/testsuite/gcc.target/riscv/rvv/base/narrow_constraint-21.c index 4f7efd508b16..ecf6d267fdb9 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/base/narrow_constraint-21.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/narrow_constraint-21.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-march=rv32gcv -mabi=ilp32d -O3" } */ +/* { dg-options "-march=rv32gcv -mabi=ilp32d -O3 -fno-sched-pressure" } */ #include "riscv_vector.h" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/narrow_constraint-22.c b/gcc/testsuite/gcc.target/riscv/rvv/base/narrow_constraint-22.c index 92084be99b26..201860795934 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/base/narrow_constraint-22.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/narrow_constraint-22.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-march=rv32gcv -mabi=ilp32d -O3" } */ +/* { dg-options "-march=rv32gcv -mabi=ilp32d -O3 -fno-sched-pressure" } */ #include "riscv_vector.h" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/narrow_constraint-23.c b/gcc/testsuite/gcc.target/riscv/rvv/base/narrow_constraint-23.c index f9817caca1e4..847d27cc7601 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/base/narrow_constraint-23.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/narrow_constraint-23.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-march=rv64gcv -mabi=lp64d -O3" } */ +/* { dg-options "-march=rv64gcv -mabi=lp64d -O3 -fno-sched-pressure" } */ #include "riscv_vector.h" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/narrow_constraint-24.c b/gcc/testsuite/gcc.target/riscv/rvv/base/narrow_constraint-24.c index 62d1f6dddd52..603bfa20f82c 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/base/narrow_constraint-24.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/narrow_constraint-24.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-march=rv64gcv -mabi=lp64d -O3" } */ +/* { dg-options "-march=rv64gcv -mabi=lp64d -O3 -fno-sched-pressure" } */ #include "riscv_vector.h" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/narrow_constraint-25.c b/gcc/testsuite/gcc.target/riscv/rvv/base/narrow_constraint-25.c index 250c3fdb89af..4f295ecaaafb 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/base/narrow_constraint-25.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/narrow_constraint-25.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-march=rv64gcv -mabi=lp64d -O3" } */ +/* { dg-options "-march=rv64gcv -mabi=lp64d -O3 -fno-sched-pressure" } */ #include "riscv_vector.h" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/narrow_constraint-26.c b/gcc/testsuite/gcc.target/riscv/rvv/base/narrow_constraint-26.c index 72e2d210c055..1a652399f87f 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/base/narrow_constraint-26.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/narrow_constraint-26.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-march=rv64gcv -mabi=lp64d -O3" } */ +/* { dg-options "-march=rv64gcv -mabi=lp64d -O3 -fno-sched-pressure" } */ #include "riscv_vector.h" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/narrow_constraint-27.c b/gcc/testsuite/gcc.target/riscv/rvv/base/narrow_constraint-27.c index 0842700475ca..4d70a4c39fdf 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/base/narrow_constraint-27.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/narrow_constraint-27.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-march=rv32gcv -mabi=ilp32d -O3" } */ +/* { dg-options "-march=rv32gcv -mabi=ilp32d -O3 -fno-sched-pressure" } */ #include "riscv_vector.h" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/narrow_constraint-28.c b/gcc/testsuite/gcc.target/riscv/rvv/base/narrow_constraint-28.c index 9c1eddfac7e5..c625d96a94c7 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/base/narrow_constraint-28.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/narrow_constraint-28.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-march=rv32gcv -mabi=ilp32d -O3" } */ +/* { dg-options "-march=rv32gcv -mabi=ilp32d -O3 -fno-sched-pressure" } */ #include "riscv_vector.h" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/narrow_constraint-29.c b/gcc/testsuite/gcc.target/riscv/rvv/base/narrow_constraint-29.c index 6988c24bd922..109ebc84112d 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/base/narrow_constraint-29.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/narrow_constraint-29.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-march=rv32gcv -mabi=ilp32d -O3" } */ +/* { dg-options "-march=rv32gcv -mabi=ilp32d -O3 -fno-sched-pressure" } */ #include "riscv_vector.h" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/narrow_constraint-30.c b/gcc/testsuite/gcc.target/riscv/rvv/base/narrow_constraint-30.c index fe181de4d561..b993e480765f 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/base/narrow_constraint-30.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/narrow_constraint-30.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-march=rv32gcv -mabi=ilp32d -O3" } */ +/* { dg-options "-march=rv32gcv -mabi=ilp32d -O3 -fno-sched-pressure" } */ #include "riscv_vector.h" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/narrow_constraint-31.c b/gcc/testsuite/gcc.target/riscv/rvv/base/narrow_constraint-31.c index ae5b4ed69131..d0bf4a80c9e4 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/base/narrow_constraint-31.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/narrow_constraint-31.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-march=rv32gcv -mabi=ilp32d -O3" } */ +/* { dg-options "-march=rv32gcv -mabi=ilp32d -O3 -fno-sched-pressure" } */ #include "riscv_vector.h" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/narrow_constraint-4.c b/gcc/testsuite/gcc.target/riscv/rvv/base/narrow_constraint-4.c index 28971a0aad8c..273f15a21ab0 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/base/narrow_constraint-4.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/narrow_constraint-4.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-march=rv32gcv -mabi=ilp32d -O3" } */ +/* { dg-options "-march=rv32gcv -mabi=ilp32d -O3 -fno-sched-pressure" } */ #include "riscv_vector.h" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/narrow_constraint-5.c b/gcc/testsuite/gcc.target/riscv/rvv/base/narrow_constraint-5.c index 26675bcc87c7..d75dc7786384 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/base/narrow_constraint-5.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/narrow_constraint-5.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-march=rv32gcv -mabi=ilp32d -O3" } */ +/* { dg-options "-march=rv32gcv -mabi=ilp32d -O3 -fno-sched-pressure" } */ #include "riscv_vector.h" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/narrow_constraint-8.c b/gcc/testsuite/gcc.target/riscv/rvv/base/narrow_constraint-8.c index 0dac85a3203a..c96ab5988834 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/base/narrow_constraint-8.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/narrow_constraint-8.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-march=rv32gcv -mabi=ilp32d -O3" } */ +/* { dg-options "-march=rv32gcv -mabi=ilp32d -O3 -fno-sched-pressure" } */ #include "riscv_vector.h" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/narrow_constraint-9.c b/gcc/testsuite/gcc.target/riscv/rvv/base/narrow_constraint-9.c index 448ca859dbbf..53130d326068 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/base/narrow_constraint-9.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/narrow_constraint-9.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-march=rv32gcv -mabi=ilp32d -O3" } */ +/* { dg-options "-march=rv32gcv -mabi=ilp32d -O3 -fno-sched-pressure" } */ #include "riscv_vector.h" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/pr110943.c b/gcc/testsuite/gcc.target/riscv/rvv/base/pr110943.c new file mode 100644 index 000000000000..8a6c00fc94d2 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/pr110943.c @@ -0,0 +1,33 @@ +/* { dg-do compile } */ +/* { dg-options "-O3 -march=rv64gcv -mabi=lp64d" } */ +/* { dg-final { check-function-bodies "**" "" } } */ + +#include + +/* +** foo9: +** vsetivli\tzero,1,e64,m2,t[au],m[au] +** ... +** vs2r.v\tv[0-9]+,0\([a-x0-9]+\) +** ret +*/ +void foo9 (void *base, void *out, size_t vl) +{ + int64_t scalar = *(int64_t*)(base + 100); + vint64m2_t v = __riscv_vmv_v_x_i64m2 (0, 1); + *(vint64m2_t*)out = v; +} + +/* +** foo10: +** vsetivli\tzero,1,e64,m2,t[au],m[au] +** ... +** vs2r.v\tv[0-9]+,0\([a-x0-9]+\) +** ret +*/ +void foo10 (void *base, void *out, size_t vl) +{ + int64_t scalar = *(int64_t*)(base + 100); + vint64m2_t v = __riscv_vmv_s_x_i64m2 (0, 1); + *(vint64m2_t*)out = v; +} diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/pr111037-1.c b/gcc/testsuite/gcc.target/riscv/rvv/base/pr111037-1.c new file mode 100644 index 000000000000..0b7b32fc3e61 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/pr111037-1.c @@ -0,0 +1,15 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv32gc_zve64f_zvfh -mabi=ilp32d -O3" } */ + +#include "riscv_vector.h" + +void foo(_Float16 y, int64_t *i64p) +{ + vint64m1_t vx =__riscv_vle64_v_i64m1 (i64p, 1); + vx = __riscv_vadd_vv_i64m1 (vx, vx, 1); + vfloat16m1_t vy =__riscv_vfmv_s_f_f16m1 (y, 1); + asm volatile ("# use %0 %1" : : "vr"(vx), "vr" (vy)); +} + +/* { dg-final { scan-assembler-times {vsetivli\s+zero,\s*1,\s*e16,\s*mf4,\s*t[au],\s*m[au]} 1 } } */ +/* { dg-final { scan-assembler-times {vsetvli\s+zero,\s*zero,\s*e64,\s*m1,\s*t[au],\s*m[au]} 1 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/pr111037-2.c b/gcc/testsuite/gcc.target/riscv/rvv/base/pr111037-2.c new file mode 100644 index 000000000000..ac50da71726b --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/pr111037-2.c @@ -0,0 +1,8 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv32gc_zve64d_zvfh -mabi=ilp32d -O3" } */ + +#include "pr111037-1.c" + +/* { dg-final { scan-assembler-times {vsetivli\s+zero,\s*1,\s*e64,\s*m1,\s*t[au],\s*m[au]} 1 } } */ +/* { dg-final { scan-assembler-not {vsetvli} } } */ +/* { dg-final { scan-assembler-times {vsetivli} 1 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/scalar_move-5.c b/gcc/testsuite/gcc.target/riscv/rvv/base/scalar_move-5.c index db6800c89781..2e897a4896fe 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/base/scalar_move-5.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/scalar_move-5.c @@ -121,7 +121,7 @@ void foo8 (void *base, void *out, size_t vl, double x) /* ** foo9: ** ... -** vmv.v.i\tv[0-9]+,\s*-15 +** vmv.s.x\tv[0-9]+,\s*[a-x0-9]+ ** ... ** ret */ @@ -150,7 +150,7 @@ void foo10 (void *base, void *out, size_t vl) /* ** foo11: ** ... -** vmv.v.i\tv[0-9]+,\s*0 +** vmv.s.x\tv[0-9]+,\s*zero ** ... ** ret */ @@ -164,7 +164,7 @@ void foo11 (void *base, void *out, size_t vl) /* ** foo12: ** ... -** vfmv.s.f\tv[0-9]+,\s*[a-x0-9]+ +** vmv.s.x\tv[0-9]+,\s*zero ** ... ** ret */ @@ -174,3 +174,17 @@ void foo12 (void *base, void *out, size_t vl) vfloat64m2_t v = __riscv_vfmv_s_f_f64m2_tu (merge, 0, vl); *(vfloat64m2_t*)out = v; } + +/* +** foo13: +** ... +** vfmv.s.f\tv[0-9]+,\s*[a-x0-9]+ +** ... +** ret +*/ +void foo13 (void *base, void *out, size_t vl) +{ + vfloat64m2_t merge = *(vfloat64m2_t*) (base + 200); + vfloat64m2_t v = __riscv_vfmv_s_f_f64m2_tu (merge, 0.2, vl); + *(vfloat64m2_t*)out = v; +} diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/scalar_move-6.c b/gcc/testsuite/gcc.target/riscv/rvv/base/scalar_move-6.c index f27f85cdb586..326cfd8e2ff4 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/base/scalar_move-6.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/scalar_move-6.c @@ -119,7 +119,7 @@ void foo8 (void *base, void *out, size_t vl, double x) /* ** foo9: ** ... -** vmv.v.i\tv[0-9]+,\s*-15 +** vmv.s.x\tv[0-9]+,\s*[a-x0-9]+ ** ... ** ret */ @@ -133,7 +133,7 @@ void foo9 (void *base, void *out, size_t vl) /* ** foo10: ** ... -** vmv.v.i\tv[0-9]+,\s*-15 +** vmv.s.x\tv[0-9]+,\s*[a-x0-9]+ ** ... */ void foo10 (void *base, void *out, size_t vl) @@ -147,7 +147,7 @@ void foo10 (void *base, void *out, size_t vl) /* ** foo11: ** ... -** vmv.v.i\tv[0-9]+,\s*0 +** vmv.s.x\tv[0-9]+,\s*zero ** ... ** ret */ @@ -161,7 +161,7 @@ void foo11 (void *base, void *out, size_t vl) /* ** foo12: ** ... -** vmv.v.i\tv[0-9]+,\s*0 +** vmv.s.x\tv[0-9]+,\s*zero ** ... ** ret */ @@ -172,6 +172,20 @@ void foo12 (void *base, void *out, size_t vl) *(vfloat64m2_t*)out = v; } +/* +** foo12_1: +** ... +** vfmv.s.f\tv[0-9]+,\s*[a-x0-9]+ +** ... +** ret +*/ +void foo12_1 (void *base, void *out, size_t vl) +{ + vfloat64m2_t merge = *(vfloat64m2_t*) (base + 200); + vfloat64m2_t v = __riscv_vfmv_s_f_f64m2_tu (merge, 0.2, vl); + *(vfloat64m2_t*)out = v; +} + /* ** foo13: ** ... diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/simplify-vrsub.c b/gcc/testsuite/gcc.target/riscv/rvv/base/simplify-vrsub.c new file mode 100644 index 000000000000..df87ed94ea44 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/simplify-vrsub.c @@ -0,0 +1,18 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */ + +#include "riscv_vector.h" + +#define VRSUB_WITH_LMUL(LMUL, DTYPE) \ + vint##DTYPE##m##LMUL##_t \ + shortcut_for_riscv_vrsub_case_##LMUL##_##DTYPE \ + (vint##DTYPE##m##LMUL##_t v1, \ + size_t vl) \ + { \ + return __riscv_vrsub_vx_i##DTYPE##m##LMUL (v1, -1, vl); \ + } + +VRSUB_WITH_LMUL (1, 16) +VRSUB_WITH_LMUL (1, 32) + +/* { dg-final { scan-assembler-times {vnot\.v} 2 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/spill-11.c b/gcc/testsuite/gcc.target/riscv/rvv/base/spill-11.c index 179be1c8c5bc..484a25108852 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/base/spill-11.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/spill-11.c @@ -9,7 +9,7 @@ void fn3 (char*); /* ** stack_save_restore_2: -** call\tt0,__riscv_save_2 +** call\tt0,__riscv_save_1 ** csrr\tt0,vlenb ** slli\tt1,t0,1 ** sub\tsp,sp,t1 @@ -23,7 +23,7 @@ void fn3 (char*); ** li\tt0,8192 ** addi\tt0,t0,-192 ** add\tsp,sp,t0 -** tail\t__riscv_restore_2 +** tail\t__riscv_restore_1 */ int stack_save_restore_2 (float a1, float a2, float a3, float a4, float a5, float a6, float a7, float a8, diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/spill-12.c b/gcc/testsuite/gcc.target/riscv/rvv/base/spill-12.c index de6e0604a3cd..7e83cb7b7c1c 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/base/spill-12.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/spill-12.c @@ -15,12 +15,7 @@ void fn3 (char*); ** addi\tt0,t0,192 ** add\tsp,sp,t0 ** ... -** li\ta0,-8192 -** addi\ta0,a0,192 -** li\ta5,8192 -** addi\ta5,a5,-192 -** add\ta5,a5,a0 -** add\ta0,a5,sp +** mv\ta0,sp ** ... ** tail\t__riscv_restore_0 */ diff --git a/gcc/testsuite/gcc.target/riscv/vector-abi-1.c b/gcc/testsuite/gcc.target/riscv/rvv/base/vector-abi-1.c similarity index 100% rename from gcc/testsuite/gcc.target/riscv/vector-abi-1.c rename to gcc/testsuite/gcc.target/riscv/rvv/base/vector-abi-1.c diff --git a/gcc/testsuite/gcc.target/riscv/vector-abi-2.c b/gcc/testsuite/gcc.target/riscv/rvv/base/vector-abi-2.c similarity index 100% rename from gcc/testsuite/gcc.target/riscv/vector-abi-2.c rename to gcc/testsuite/gcc.target/riscv/rvv/base/vector-abi-2.c diff --git a/gcc/testsuite/gcc.target/riscv/vector-abi-3.c b/gcc/testsuite/gcc.target/riscv/rvv/base/vector-abi-3.c similarity index 100% rename from gcc/testsuite/gcc.target/riscv/vector-abi-3.c rename to gcc/testsuite/gcc.target/riscv/rvv/base/vector-abi-3.c diff --git a/gcc/testsuite/gcc.target/riscv/vector-abi-4.c b/gcc/testsuite/gcc.target/riscv/rvv/base/vector-abi-4.c similarity index 100% rename from gcc/testsuite/gcc.target/riscv/vector-abi-4.c rename to gcc/testsuite/gcc.target/riscv/rvv/base/vector-abi-4.c diff --git a/gcc/testsuite/gcc.target/riscv/vector-abi-5.c b/gcc/testsuite/gcc.target/riscv/rvv/base/vector-abi-5.c similarity index 100% rename from gcc/testsuite/gcc.target/riscv/vector-abi-5.c rename to gcc/testsuite/gcc.target/riscv/rvv/base/vector-abi-5.c diff --git a/gcc/testsuite/gcc.target/riscv/vector-abi-6.c b/gcc/testsuite/gcc.target/riscv/rvv/base/vector-abi-6.c similarity index 100% rename from gcc/testsuite/gcc.target/riscv/vector-abi-6.c rename to gcc/testsuite/gcc.target/riscv/rvv/base/vector-abi-6.c diff --git a/gcc/testsuite/gcc.target/riscv/vector-abi-7.c b/gcc/testsuite/gcc.target/riscv/rvv/base/vector-abi-7.c similarity index 100% rename from gcc/testsuite/gcc.target/riscv/vector-abi-7.c rename to gcc/testsuite/gcc.target/riscv/rvv/base/vector-abi-7.c diff --git a/gcc/testsuite/gcc.target/riscv/vector-abi-8.c b/gcc/testsuite/gcc.target/riscv/rvv/base/vector-abi-8.c similarity index 100% rename from gcc/testsuite/gcc.target/riscv/vector-abi-8.c rename to gcc/testsuite/gcc.target/riscv/rvv/base/vector-abi-8.c diff --git a/gcc/testsuite/gcc.target/riscv/vector-abi-9.c b/gcc/testsuite/gcc.target/riscv/rvv/base/vector-abi-9.c similarity index 100% rename from gcc/testsuite/gcc.target/riscv/vector-abi-9.c rename to gcc/testsuite/gcc.target/riscv/rvv/base/vector-abi-9.c diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/vslide1down-1.c b/gcc/testsuite/gcc.target/riscv/rvv/base/vslide1down-1.c new file mode 100644 index 000000000000..541745be2a1e --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/vslide1down-1.c @@ -0,0 +1,22 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv32gc_zve64x -mabi=ilp32d -Wno-psabi -O3 -fno-schedule-insns -fno-schedule-insns2" } */ + +#include "riscv_vector.h" + +vint64m1_t test_vslide1down_vx_i64m1_m(vbool64_t mask, vint64m1_t src, int64_t value, size_t vl) { + return __riscv_vslide1down_vx_i64m1_m(mask, src, value, vl); +} + +vint64m2_t test_vslide1down_vx_i64m2_m(vbool32_t mask, vint64m2_t src, int64_t value, size_t vl) { + return __riscv_vslide1down_vx_i64m2_m(mask, src, value, vl); +} + +vint64m4_t test_vslide1down_vx_i64m4_m(vbool16_t mask, vint64m4_t src, int64_t value, size_t vl) { + return __riscv_vslide1down_vx_i64m4_m(mask, src, value, vl); +} + +vint64m8_t test_vslide1down_vx_i64m8_m(vbool8_t mask, vint64m8_t src, int64_t value, size_t vl) { + return __riscv_vslide1down_vx_i64m8_m(mask, src, value, vl); +} + +/* { dg-final { scan-assembler-times {vseti?vli\s+[a-z0-9]+,\s*[a-z0-9]+,\s*e[0-9]+,\s*mf?[1248],\s*t[au],\s*m[au]\s+vslide1down\.[ivxfswum.]+\s+} 4 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/vslide1down-2.c b/gcc/testsuite/gcc.target/riscv/rvv/base/vslide1down-2.c new file mode 100644 index 000000000000..9b5a240a9e69 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/vslide1down-2.c @@ -0,0 +1,22 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv32gc_zve64d -mabi=ilp32d -Wno-psabi -O3 -fno-schedule-insns -fno-schedule-insns2" } */ + +#include "riscv_vector.h" + +vint64m1_t test_vslide1down_vx_i64m1_m(vbool64_t mask, vint64m1_t src, int64_t value, size_t vl) { + return __riscv_vslide1down_vx_i64m1_m(mask, src, value, vl); +} + +vint64m2_t test_vslide1down_vx_i64m2_m(vbool32_t mask, vint64m2_t src, int64_t value, size_t vl) { + return __riscv_vslide1down_vx_i64m2_m(mask, src, value, vl); +} + +vint64m4_t test_vslide1down_vx_i64m4_m(vbool16_t mask, vint64m4_t src, int64_t value, size_t vl) { + return __riscv_vslide1down_vx_i64m4_m(mask, src, value, vl); +} + +vint64m8_t test_vslide1down_vx_i64m8_m(vbool8_t mask, vint64m8_t src, int64_t value, size_t vl) { + return __riscv_vslide1down_vx_i64m8_m(mask, src, value, vl); +} + +/* { dg-final { scan-assembler-times {vseti?vli\s+[a-z0-9]+,\s*[a-z0-9]+,\s*e[0-9]+,\s*mf?[1248],\s*t[au],\s*m[au]\s+vslide1down\.[ivxfswum.]+\s+} 4 } } */ \ No newline at end of file diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/vslide1down-3.c b/gcc/testsuite/gcc.target/riscv/rvv/base/vslide1down-3.c new file mode 100644 index 000000000000..7b05c85a243a --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/vslide1down-3.c @@ -0,0 +1,22 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv32gc_zve64f -mabi=ilp32d -Wno-psabi -O3 -fno-schedule-insns -fno-schedule-insns2" } */ + +#include "riscv_vector.h" + +vint64m1_t test_vslide1down_vx_i64m1_m(vbool64_t mask, vint64m1_t src, int64_t value, size_t vl) { + return __riscv_vslide1down_vx_i64m1_m(mask, src, value, vl); +} + +vint64m2_t test_vslide1down_vx_i64m2_m(vbool32_t mask, vint64m2_t src, int64_t value, size_t vl) { + return __riscv_vslide1down_vx_i64m2_m(mask, src, value, vl); +} + +vint64m4_t test_vslide1down_vx_i64m4_m(vbool16_t mask, vint64m4_t src, int64_t value, size_t vl) { + return __riscv_vslide1down_vx_i64m4_m(mask, src, value, vl); +} + +vint64m8_t test_vslide1down_vx_i64m8_m(vbool8_t mask, vint64m8_t src, int64_t value, size_t vl) { + return __riscv_vslide1down_vx_i64m8_m(mask, src, value, vl); +} + +/* { dg-final { scan-assembler-times {vseti?vli\s+[a-z0-9]+,\s*[a-z0-9]+,\s*e[0-9]+,\s*mf?[1248],\s*t[au],\s*m[au]\s+vslide1down\.[ivxfswum.]+\s+} 4 } } */ \ No newline at end of file diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/vslide1up-1.c b/gcc/testsuite/gcc.target/riscv/rvv/base/vslide1up-1.c new file mode 100644 index 000000000000..74e8e5e63f70 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/vslide1up-1.c @@ -0,0 +1,22 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv32gc_zve64x -mabi=ilp32d -Wno-psabi -O3 -fno-schedule-insns -fno-schedule-insns2" } */ + +#include "riscv_vector.h" + +vint64m1_t test_vslide1up_vx_i64m1_m(vbool64_t mask, vint64m1_t src, int64_t value, size_t vl) { + return __riscv_vslide1up_vx_i64m1_m(mask, src, value, vl); +} + +vint64m2_t test_vslide1up_vx_i64m2_m(vbool32_t mask, vint64m2_t src, int64_t value, size_t vl) { + return __riscv_vslide1up_vx_i64m2_m(mask, src, value, vl); +} + +vint64m4_t test_vslide1up_vx_i64m4_m(vbool16_t mask, vint64m4_t src, int64_t value, size_t vl) { + return __riscv_vslide1up_vx_i64m4_m(mask, src, value, vl); +} + +vint64m8_t test_vslide1up_vx_i64m8_m(vbool8_t mask, vint64m8_t src, int64_t value, size_t vl) { + return __riscv_vslide1up_vx_i64m8_m(mask, src, value, vl); +} + +/* { dg-final { scan-assembler-times {vseti?vli\s+[a-z0-9]+,\s*[a-z0-9]+,\s*e[0-9]+,\s*mf?[1248],\s*t[au],\s*m[au]\s+vslide1up\.[ivxfswum.]+\s+} 4 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/vslide1up-2.c b/gcc/testsuite/gcc.target/riscv/rvv/base/vslide1up-2.c new file mode 100644 index 000000000000..e7e2ee950c73 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/vslide1up-2.c @@ -0,0 +1,22 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv32gc_zve64d -mabi=ilp32d -Wno-psabi -O3 -fno-schedule-insns -fno-schedule-insns2" } */ + +#include "riscv_vector.h" + +vint64m1_t test_vslide1up_vx_i64m1_m(vbool64_t mask, vint64m1_t src, int64_t value, size_t vl) { + return __riscv_vslide1up_vx_i64m1_m(mask, src, value, vl); +} + +vint64m2_t test_vslide1up_vx_i64m2_m(vbool32_t mask, vint64m2_t src, int64_t value, size_t vl) { + return __riscv_vslide1up_vx_i64m2_m(mask, src, value, vl); +} + +vint64m4_t test_vslide1up_vx_i64m4_m(vbool16_t mask, vint64m4_t src, int64_t value, size_t vl) { + return __riscv_vslide1up_vx_i64m4_m(mask, src, value, vl); +} + +vint64m8_t test_vslide1up_vx_i64m8_m(vbool8_t mask, vint64m8_t src, int64_t value, size_t vl) { + return __riscv_vslide1up_vx_i64m8_m(mask, src, value, vl); +} + +/* { dg-final { scan-assembler-times {vseti?vli\s+[a-z0-9]+,\s*[a-z0-9]+,\s*e[0-9]+,\s*mf?[1248],\s*t[au],\s*m[au]\s+vslide1up\.[ivxfswum.]+\s+} 4 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/vslide1up-3.c b/gcc/testsuite/gcc.target/riscv/rvv/base/vslide1up-3.c new file mode 100644 index 000000000000..b0b3af24e644 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/vslide1up-3.c @@ -0,0 +1,22 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv32gc_zve64f -mabi=ilp32d -Wno-psabi -O3 -fno-schedule-insns -fno-schedule-insns2" } */ + +#include "riscv_vector.h" + +vint64m1_t test_vslide1up_vx_i64m1_m(vbool64_t mask, vint64m1_t src, int64_t value, size_t vl) { + return __riscv_vslide1up_vx_i64m1_m(mask, src, value, vl); +} + +vint64m2_t test_vslide1up_vx_i64m2_m(vbool32_t mask, vint64m2_t src, int64_t value, size_t vl) { + return __riscv_vslide1up_vx_i64m2_m(mask, src, value, vl); +} + +vint64m4_t test_vslide1up_vx_i64m4_m(vbool16_t mask, vint64m4_t src, int64_t value, size_t vl) { + return __riscv_vslide1up_vx_i64m4_m(mask, src, value, vl); +} + +vint64m8_t test_vslide1up_vx_i64m8_m(vbool8_t mask, vint64m8_t src, int64_t value, size_t vl) { + return __riscv_vslide1up_vx_i64m8_m(mask, src, value, vl); +} + +/* { dg-final { scan-assembler-times {vseti?vli\s+[a-z0-9]+,\s*[a-z0-9]+,\s*e[0-9]+,\s*mf?[1248],\s*t[au],\s*m[au]\s+vslide1up\.[ivxfswum.]+\s+} 4 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/vxrm-8.c b/gcc/testsuite/gcc.target/riscv/rvv/base/vxrm-8.c index 3ed0d00d1e93..4c178dd17c7a 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/base/vxrm-8.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/vxrm-8.c @@ -14,5 +14,6 @@ void f (void * in, void *out, int32_t x, int n, int m) } } -/* { dg-final { scan-assembler-times {csrwi\s+vxrm,\s*2\s+vsetivli\s+zero,\s*4,\s*e32,\s*m1,\s*tu,\s*m[au]} 1 } } */ +/* { dg-final { scan-assembler-times {vsetivli\s+zero,\s*4,\s*e32,\s*m1,\s*tu,\s*m[au]} 1 } } */ /* { dg-final { scan-assembler-times {csrwi\s+vxrm,\s*2} 1 } } */ +/* { dg-final { scan-assembler-times {\.L[0-9]+:\s+vle32\.v} 1 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/vxrm-9.c b/gcc/testsuite/gcc.target/riscv/rvv/base/vxrm-9.c index 0939705b2e76..7344ed8a9872 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/base/vxrm-9.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/vxrm-9.c @@ -22,5 +22,6 @@ void f (void * in, void *out, int32_t x, int n, int m) } } -/* { dg-final { scan-assembler-times {csrwi\s+vxrm,\s*2\s+vsetivli\s+zero,\s*4,\s*e32,\s*m1,\s*tu,\s*m[au]} 1 } } */ +/* { dg-final { scan-assembler-times {vsetivli\s+zero,\s*4,\s*e32,\s*m1,\s*tu,\s*m[au]} 1 } } */ /* { dg-final { scan-assembler-times {csrwi\s+vxrm,\s*2} 1 } } */ +/* { dg-final { scan-assembler-times {\.L[0-9]+:\s+vle32\.v} 2 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/zvfhmin-intrinsic.c b/gcc/testsuite/gcc.target/riscv/rvv/base/zvfhmin-intrinsic.c index fc70c54c7fca..500748b8e792 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/base/zvfhmin-intrinsic.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/zvfhmin-intrinsic.c @@ -194,12 +194,12 @@ vfloat16m4_t test_vget_v_f16m8_f16m4(vfloat16m8_t src, size_t index) { /* { dg-final { scan-assembler-times {vsetvli\s+[a-x0-9]+,\s*zero,\s*e16,\s*m8,\s*t[au],\s*m[au]} 5 } } */ /* { dg-final { scan-assembler-times {vfwcvt\.f\.f\.v\s+v[0-9]+,\s*v[0-9]+} 5 } } */ /* { dg-final { scan-assembler-times {vfncvt\.f\.f\.w\s+v[0-9]+,\s*v[0-9]+} 5 } } */ -/* { dg-final { scan-assembler-times {vle16\.v\s+v[0-9]+,\s*0\([a-x][0-9]+\)} 20 } } */ +/* { dg-final { scan-assembler-times {vle16\.v\s+v[0-9]+,\s*0\([a-x][0-9]+\)} 15 } } */ /* { dg-final { scan-assembler-times {vse16\.v\s+v[0-9]+,\s*0\([a-x][0-9]+\)} 15 } } */ -/* { dg-final { scan-assembler-times {vl1re16\.v\s+v[0-9]+,\s*0\([a-x][0-9]+\)} 5 } } */ -/* { dg-final { scan-assembler-times {vl2re16\.v\s+v[0-9]+,\s*0\([a-x][0-9]+\)} 4 } } */ -/* { dg-final { scan-assembler-times {vl8re16\.v\s+v[0-9]+,\s*0\([a-x][0-9]+\)} 5 } } */ -/* { dg-final { scan-assembler-times {vl4re16\.v\s+v[0-9]+,\s*0\([a-x][0-9]+\)} 5 } } */ +/* { dg-final { scan-assembler-times {vl1re16\.v\s+v[0-9]+,\s*0\([a-x][0-9]+\)} 7 } } */ +/* { dg-final { scan-assembler-times {vl2re16\.v\s+v[0-9]+,\s*0\([a-x][0-9]+\)} 5 } } */ +/* { dg-final { scan-assembler-times {vl8re16\.v\s+v[0-9]+,\s*0\([a-x][0-9]+\)} 6 } } */ +/* { dg-final { scan-assembler-times {vl4re16\.v\s+v[0-9]+,\s*0\([a-x][0-9]+\)} 6 } } */ /* { dg-final { scan-assembler-times {vs1r\.v\s+v[0-9]+,\s*0\([a-x][0-9]+\)} 5 } } */ /* { dg-final { scan-assembler-times {vs2r\.v\s+v[0-9]+,\s*0\([a-x][0-9]+\)} 5 } } */ /* { dg-final { scan-assembler-times {vs4r\.v\s+v[0-9]+,\s*0\([a-x][0-9]+\)} 5 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/intrisinc-vrgatherei16.c b/gcc/testsuite/gcc.target/riscv/rvv/intrisinc-vrgatherei16.c new file mode 100644 index 000000000000..59c6d7c887d7 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/intrisinc-vrgatherei16.c @@ -0,0 +1,28 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gcv_zvfh -mabi=lp64 -O3 -Wno-psabi" } */ + +#include "riscv_vector.h" + +typedef _Float16 float16_t; + +vfloat16mf4_t test_vrgatherei16_vv_f16mf4(vfloat16mf4_t op1, vuint16mf4_t op2, + size_t vl) { + return __riscv_vrgatherei16_vv_f16mf4(op1, op2, vl); +} + +vfloat16m8_t test_vrgatherei16_vv_f16m8(vfloat16m8_t op1, vuint16m8_t op2, + size_t vl) { + return __riscv_vrgatherei16_vv_f16m8(op1, op2, vl); +} + +vfloat16mf4_t test_vrgatherei16_vv_f16mf4_m(vbool64_t mask, vfloat16mf4_t op1, + vuint16mf4_t op2, size_t vl) { + return __riscv_vrgatherei16_vv_f16mf4_m(mask, op1, op2, vl); +} + +vfloat16m8_t test_vrgatherei16_vv_f16m8_m(vbool2_t mask, vfloat16m8_t op1, + vuint16m8_t op2, size_t vl) { + return __riscv_vrgatherei16_vv_f16m8_m(mask, op1, op2, vl); +} + +/* { dg-final { scan-assembler-times {vrgatherei16.vv\s+v[0-9]+,\s*v[0-9]+,\s*v[0-9]+} 4 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/rvv.exp b/gcc/testsuite/gcc.target/riscv/rvv/rvv.exp index b41553bc2f59..ff76e17d0e6c 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/rvv.exp +++ b/gcc/testsuite/gcc.target/riscv/rvv/rvv.exp @@ -50,6 +50,8 @@ dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/autovec/*.\[cS\]]] \ "-O3 -ftree-vectorize" $CFLAGS dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/autovec/vls/*.\[cS\]]] \ "-O3 -ftree-vectorize --param riscv-autovec-preference=scalable" $CFLAGS +dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/autovec/struct/*.\[cS\]]] \ + "" "-O3 -ftree-vectorize" set AUTOVEC_TEST_OPTS [list \ {-ftree-vectorize -O3 --param riscv-autovec-lmul=m1} \ @@ -75,6 +77,8 @@ foreach op $AUTOVEC_TEST_OPTS { "" "$op" dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/autovec/reduc/*.\[cS\]]] \ "" "$op" + dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/autovec/cond/*.\[cS\]]] \ + "" "$op" } # widening operation only test on LMUL < 8 diff --git a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_multiple-7.c b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_multiple-7.c index c1d1986528c7..96dc76faa0d8 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_multiple-7.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_multiple-7.c @@ -37,4 +37,4 @@ void f (void * restrict in, void * restrict out, int l, int n, int m, int cond) } } -/* { dg-final { scan-assembler {add\s+\s*[a-x0-9]+,\s*[a-x0-9]+,\s*[a-x0-9]+\s+vsetvli\s+zero,\s*[a-x0-9]+,\s*e8,\s*mf8,\s*t[au],\s*m[au]} { target { no-opts "-O0" no-opts "-O1" no-opts "-Os" no-opts "-Oz" no-opts "-g" no-opts "-funroll-loops" } } } } */ +/* { dg-final { scan-assembler {add\s+\s*[a-x0-9]+,\s*[a-x0-9]+,\s*[a-x0-9]+\s+ble\s+[a-x0-9]+,\s*zero,\.L[0-9]+\s+vsetvli\s+zero,\s*[a-x0-9]+,\s*e8,\s*mf8,\s*t[au],\s*m[au]} { target { no-opts "-O0" no-opts "-O1" no-opts "-Os" no-opts "-Oz" no-opts "-g" no-opts "-funroll-loops" } } } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_multiple-8.c b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_multiple-8.c index 7ccb71241741..9ada32e3d06a 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_multiple-8.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_multiple-8.c @@ -36,4 +36,4 @@ void f (void * restrict in, void * restrict out, int l, int n, int m, int cond) } } -/* { dg-final { scan-assembler {add\s+\s*[a-x0-9]+,\s*[a-x0-9]+,\s*[a-x0-9]+\s+vsetvli\s+zero,\s*[a-x0-9]+,\s*e8,\s*mf8,\s*t[au],\s*m[au]} { target { no-opts "-O0" no-opts "-O1" no-opts "-Os" no-opts "-Oz" no-opts "-g" no-opts "-funroll-loops" } } } } */ +/* { dg-final { scan-assembler {add\s+\s*[a-x0-9]+,\s*[a-x0-9]+,\s*[a-x0-9]+\s+ble\s+[a-x0-9]+,\s*zero,\.L[0-9]+\s+vsetvli\s+zero,\s*[a-x0-9]+,\s*e8,\s*mf8,\s*t[au],\s*m[au]} { target { no-opts "-O0" no-opts "-O1" no-opts "-Os" no-opts "-Oz" no-opts "-g" no-opts "-funroll-loops" } } } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-102.c b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-102.c index 8236d4e7f189..ae1208cd7aa6 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-102.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-102.c @@ -6,6 +6,7 @@ void f (int8_t* base1,int8_t* base2,int8_t* out,int n) { vint8mf4_t v = __riscv_vle8_v_i8mf4 (base1, 32); + v = __riscv_vle8_v_i8mf4_tu (v, base2 + 100, 32); for (int i = 0; i < n; i++){ v = __riscv_vor_vx_i8mf4 (v, 101, 32); v = __riscv_vle8_v_i8mf4_tu (v, base2, 32); diff --git a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-103.c b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-103.c new file mode 100644 index 000000000000..51306fd7a63f --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-103.c @@ -0,0 +1,27 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv32gcv -mabi=ilp32 -fno-schedule-insns -fno-schedule-insns2 -fno-tree-vectorize" } */ + +#include "riscv_vector.h" + +void f(void *base, void *out, void *mask_in, size_t m) { + vbool64_t mask = *(vbool64_t*)mask_in; + size_t vl = 105; + vint32mf2_t v0 = __riscv_vle32_v_i32mf2(base + 1000, vl); + __riscv_vse32_v_i32mf2 (out + 1000, v0, vl); + for (size_t i = 0; i < m; i++) { + if (i % 2 == 0) { + vint8mf8_t v0 = __riscv_vle8_v_i8mf8(base + i, vl); + vint8mf8_t v1 = __riscv_vle8_v_i8mf8_tu(v0, base + i + 100, vl); + v1 = __riscv_vadd_vv_i8mf8 (v0,v1,vl); + __riscv_vse8_v_i8mf8 (out + i, v1, vl); + } else { + vint16mf4_t v0 = __riscv_vle16_v_i16mf4(base + i, vl); + vint16mf4_t v1 = __riscv_vle16_v_i16mf4_mu(mask, v0, base + i + 100, vl); + __riscv_vse16_v_i16mf4 (out + i, v1, vl); + } + } +} + +/* { dg-final { scan-assembler-times {vsetvli\s+[a-x0-9]+,\s*zero,\s*e8,\s*mf8,\s*t[au],\s*m[au]} 1 { target { no-opts "-O0" no-opts "-Os" no-opts "-O1" no-opts "-g" no-opts "-funroll-loops" } } } } */ +/* { dg-final { scan-assembler-times {vsetvli\s+zero,\s*[a-x0-9]+,\s*e8,\s*mf8,\s*tu,\s*mu} 1 { target { no-opts "-O0" no-opts "-Os" no-opts "-O1" no-opts "-g" no-opts "-funroll-loops" } } } } */ +/* { dg-final { scan-assembler-times {vsetvli} 2 { target { no-opts "-O0" no-opts "-O1" no-opts "-Os" no-opts "-g" no-opts "-funroll-loops" } } } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-14.c b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-14.c index b3a1d46b3c02..e464ceb0bd67 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-14.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-14.c @@ -5,7 +5,7 @@ void f (int8_t * restrict in, int8_t * restrict out, int n, int cond) { - size_t vl = 101; + size_t vl = cond + 101; for (size_t i = 0; i < n; i++) { diff --git a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-15.c b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-15.c index 501e0766c228..e32b60f05f9a 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-15.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-15.c @@ -5,7 +5,7 @@ void f (int8_t * restrict in, int8_t * restrict out, int n, int cond) { - size_t vl = 101; + size_t vl = cond + 101; for (size_t i = 0; i < n; i++) { diff --git a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-27.c b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-27.c index 22004dab18c4..0fa72c3d314a 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-27.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-27.c @@ -7,7 +7,7 @@ void f2 (int8_t * restrict in, int8_t * restrict out, int n, int m, unsigned con { vbool64_t mask = *(vbool64_t*) (in + 1000000); - vl = 101; + vl = vl + 10000; if (cond > 0) { for (size_t i = 0; i < n; i++) { diff --git a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-28.c b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-28.c index b5b3fda1bab1..d5f909168c65 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-28.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-28.c @@ -7,7 +7,7 @@ void f2 (int8_t * restrict in, int8_t * restrict out, int n, int m, unsigned con { vbool64_t mask = *(vbool64_t*) (in + 1000000); - vl = 101; + vl = vl + 10000; if (cond > 0) { vint8mf8_t v = __riscv_vle8_v_i8mf8 (in, vl); __riscv_vse8_v_i8mf8 (out, v, vl); diff --git a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-29.c b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-29.c index f6296e0af939..44297d11147d 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-29.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-29.c @@ -7,7 +7,7 @@ void f2 (int8_t * restrict in, int8_t * restrict out, int n, int m, unsigned con { vbool64_t mask = *(vbool64_t*) (in + 1000000); - vl = 101; + vl = vl + 10000; if (cond > 0) { vint8mf8_t v = __riscv_vle8_v_i8mf8 (in, vl); __riscv_vse8_v_i8mf8 (out, v, vl); diff --git a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-30.c b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-30.c index 687d84dcf8ca..92df1783b0b7 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-30.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-30.c @@ -7,7 +7,7 @@ void f (int8_t * restrict in, int8_t * restrict out, int n, int m, unsigned cond { vbool64_t mask = *(vbool64_t*) (in + 1000000); - vl = 101; + vl = vl + 10000; if (cond > 0) { vint8mf8_t v = __riscv_vle8_v_i8mf8 (in, vl); __riscv_vse8_v_i8mf8 (out, v, vl); diff --git a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-35.c b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-35.c index 28230914cf71..d1daafdee86f 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-35.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-35.c @@ -7,6 +7,7 @@ static int vl = 0x5545515; void f (int8_t * restrict in, int8_t * restrict out, int n, int cond) { + vl = vl + 101; for (size_t i = 0; i < n; i++) { vint8mf8_t v = __riscv_vle8_v_i8mf8 (in + i + 300, vl); diff --git a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-36.c b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-36.c index 3c93675a32df..7db2dc55d091 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-36.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-36.c @@ -7,19 +7,19 @@ void f (int8_t * restrict in, int8_t * restrict out, int n, int cond) { for (size_t i = 0; i < n; i++) { - vint8mf8_t v = __riscv_vle8_v_i8mf8 (in + i + 300,555); - __riscv_vse8_v_i8mf8 (out + i + 300, v,555); + vint8mf8_t v = __riscv_vle8_v_i8mf8 (in + i + 300,555 + cond); + __riscv_vse8_v_i8mf8 (out + i + 300, v,555 + cond); } for (size_t i = 0; i < n; i++) { - vint8mf8_t v = __riscv_vle8_v_i8mf8 (in + i,555); - __riscv_vse8_v_i8mf8 (out + i, v,555); + vint8mf8_t v = __riscv_vle8_v_i8mf8 (in + i,555 + cond); + __riscv_vse8_v_i8mf8 (out + i, v,555 + cond); - vint8mf8_t v2 = __riscv_vle8_v_i8mf8_tu (v, in + i + 100,555); - __riscv_vse8_v_i8mf8 (out + i + 100, v2,555); + vint8mf8_t v2 = __riscv_vle8_v_i8mf8_tu (v, in + i + 100,555 + cond); + __riscv_vse8_v_i8mf8 (out + i + 100, v2,555 + cond); } } /* { dg-final { scan-assembler-times {vsetvli\s+zero,\s*[a-x0-9]+,\s*e8,\s*mf8,\s*tu,\s*m[au]} 1 { target { no-opts "-O0" no-opts "-g" no-opts "-funroll-loops" } } } } */ -/* { dg-final { scan-assembler-times {vsetvli} 1 { target { no-opts "-O0" no-opts "-g" no-opts "-funroll-loops" } } } } */ +/* { dg-final { scan-assembler-times {vsetvli} 1 { target { no-opts "-O0" no-opts "-Os" no-opts "-g" no-opts "-funroll-loops" } } } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-46.c b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-46.c index 1c5ee6a60cc4..99fdd67db647 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-46.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-46.c @@ -3,9 +3,9 @@ #include "riscv_vector.h" -void f (int8_t * restrict in, int8_t * restrict out, int n, int cond) +void f (int8_t * restrict in, int8_t * restrict out, int n, int cond, size_t vl) { - int vl = 101; + vl = 101 + vl; if (n > cond) { vint8mf8_t v = __riscv_vle8_v_i8mf8 (in + 600, vl); vint8mf8_t v2 = __riscv_vle8_v_i8mf8_tu (v, in + 600, vl); diff --git a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-48.c b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-48.c index 79af2ef450a9..f1453487ee2d 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-48.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-48.c @@ -28,5 +28,5 @@ void f (int8_t * restrict in, int8_t * restrict out, int n, int n2) } } -/* { dg-final { scan-assembler-times {vsetvli\s+zero,\s*[a-x0-9]+,\s*e8,\s*mf8,\s*tu,\s*m[au]} 2 { target { no-opts "-O0" no-opts "-Os" no-opts "-Oz" no-opts "-g" no-opts "-funroll-loops" } } } } */ +/* { dg-final { scan-assembler-times {vsetvli\s+zero,\s*[a-x0-9]+,\s*e8,\s*mf8,\s*t[au],\s*m[au]} 2 { target { no-opts "-O0" no-opts "-Os" no-opts "-Oz" no-opts "-g" no-opts "-funroll-loops" } } } } */ /* { dg-final { scan-assembler-times {vsetvli} 2 { target { no-opts "-O0" no-opts "-Os" no-opts "-Oz" no-opts "-g" no-opts "-funroll-loops" } } } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-50.c b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-50.c index 1ee2ce3e71a4..e7bdb6dd035e 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-50.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-50.c @@ -3,13 +3,14 @@ #include "riscv_vector.h" -void f(void *base, void *out, void *mask_in, size_t m) { +void f(void *base, void *out, void *mask_in, size_t m, size_t vl) { vbool64_t mask = *(vbool64_t*)mask_in; - size_t vl = 105; + vl = 105 + vl; for (size_t i = 0; i < m; i++) { if (i % 2 == 0) { vint8mf8_t v0 = __riscv_vle8_v_i8mf8(base + i, vl); vint8mf8_t v1 = __riscv_vle8_v_i8mf8_tu(v0, base + i + 100, vl); + v1 = __riscv_vadd_vv_i8mf8 (v0,v1,vl); __riscv_vse8_v_i8mf8 (out + i, v1, vl); } else { vint16mf4_t v0 = __riscv_vle16_v_i16mf4(base + i, vl); diff --git a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-51.c b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-51.c index dc0da57e1eb0..2451e7c8dbe3 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-51.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-51.c @@ -3,14 +3,15 @@ #include "riscv_vector.h" -void f(void *base, void *out, void *mask_in, size_t m, size_t n) { +void f(void *base, void *out, void *mask_in, size_t m, size_t n, size_t vl) { vbool64_t mask = *(vbool64_t*)mask_in; - size_t vl = 106; + vl = 106 + vl; for (size_t i = 0; i < m; i++) { for (size_t j = 0; j < n; j++){ if ((i + j) % 2 == 0) { vint8mf8_t v0 = __riscv_vle8_v_i8mf8(base + i + j, vl); vint8mf8_t v1 = __riscv_vle8_v_i8mf8_tu(v0, base + i + j + 100, vl); + v1 = __riscv_vadd_vv_i8mf8 (v0,v1,vl); __riscv_vse8_v_i8mf8 (out + i + j, v1, vl); } else { vint16mf4_t v0 = __riscv_vle16_v_i16mf4(base + i + j, vl); diff --git a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-6.c b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-6.c index 7a8163925f85..3d3d71815fd2 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-6.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-6.c @@ -18,5 +18,5 @@ void f (void * restrict in, void * restrict out, int l, int n, int m, size_t vl) } /* { dg-final { scan-assembler-times {vsetvli} 1 { target { no-opts "-O0" no-opts "-g" no-opts "-funroll-loops" } } } } */ -/* { dg-final { scan-assembler-times {add\s+\s*[a-x0-9]+,\s*[a-x0-9]+,\s*[a-x0-9]+\s+vsetvli\s+zero,\s*[a-x0-9]+,\s*e8,\s*mf8,\s*t[au],\s*m[au]} 1 { target { no-opts "-O0" no-opts "-Os" no-opts "-Oz" no-opts "-g" no-opts "-funroll-loops" } } } } */ -/* { dg-final { scan-assembler-times {add\s+\s*[a-x0-9]+,\s*[a-x0-9]+,\s*[a-x0-9]+\s+li\s+[a-x0-9]+,0\s+vsetvli\s+zero,\s*[a-x0-9]+,\s*e8,\s*mf8,\s*t[au],\s*m[au]} 1 { target { no-opts "-O0" no-opts "-O1" no-opts "-O2" no-opts "-g" no-opts "-funroll-loops" } } } } */ +/* { dg-final { scan-assembler-times {add\s+\s*[a-x0-9]+,\s*[a-x0-9]+,\s*[a-x0-9]+\s+ble\s+[a-x0-9]+,\s*zero,\.L[0-9]+\s+vsetvli\s+zero,\s*[a-x0-9]+,\s*e8,\s*mf8,\s*t[au],\s*m[au]} 1 { target { no-opts "-O0" no-opts "-Os" no-opts "-Oz" no-opts "-g" no-opts "-funroll-loops" } } } } */ + diff --git a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-66.c b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-66.c index 77b1d2ac1e4d..aac6b52c752c 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-66.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-66.c @@ -17,5 +17,5 @@ void f2 (void * restrict in, void * restrict out, int l, int n, int m, size_t vl } } -/* { dg-final { scan-assembler-times {add\s+\s*[a-x0-9]+,\s*[a-x0-9]+,\s*[a-x0-9]+\s+vsetvli\s+zero,\s*[a-x0-9]+,\s*e8,\s*mf8,\s*t[au],\s*m[au]} 1 { target { no-opts "-O0" no-opts "-O1" no-opts "-Os" no-opts "-Oz" no-opts "-g" no-opts "-funroll-loops" } } } } */ +/* { dg-final { scan-assembler-times {add\s+\s*[a-x0-9]+,\s*[a-x0-9]+,\s*[a-x0-9]+\s+ble\s+[a-x0-9]+,\s*zero,\.L[0-9]+\s+} 1 { target { no-opts "-O0" no-opts "-O1" no-opts "-Os" no-opts "-Oz" no-opts "-g" no-opts "-funroll-loops" } } } } */ /* { dg-final { scan-assembler-times {vsetvli} 1 { target { no-opts "-O0" no-opts "-g" no-opts "-funroll-loops" } } } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-67.c b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-67.c index 8890c32020ef..7e77e0eff442 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-67.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-67.c @@ -21,7 +21,7 @@ void f2 (void * restrict in, void * restrict out, int l, int n, int m) } } -/* { dg-final { scan-assembler-times {vsetvli\s+zero,\s*[a-x0-9]+,\s*e8,\s*mf8,\s*t[au],\s*m[au]} 3 { target { no-opts "-O0" no-opts "-Os" no-opts "-Oz" no-opts "-g" no-opts "-funroll-loops" } } } } */ -/* { dg-final { scan-assembler-times {vsetvli} 3 { target { no-opts "-O0" no-opts "-Os" no-opts "-Oz" no-opts "-g" no-opts "-funroll-loops" } } } } */ +/* { dg-final { scan-assembler-times {vsetvli\s+zero,\s*[a-x0-9]+,\s*e8,\s*mf8,\s*t[au],\s*m[au]} 4 { target { no-opts "-O0" no-opts "-Os" no-opts "-Oz" no-opts "-g" no-opts "-funroll-loops" } } } } */ +/* { dg-final { scan-assembler-times {vsetvli} 4 { target { no-opts "-O0" no-opts "-Os" no-opts "-Oz" no-opts "-g" no-opts "-funroll-loops" } } } } */ /* { dg-final { scan-assembler-times {vsetvli\s+zero,\s*[a-x0-9]+,\s*e8,\s*mf8,\s*tu,\s*m[au]} 1 { target { no-opts "-O0" no-opts "-Os" no-opts "-Oz" no-opts "-g" no-opts "-funroll-loops" } } } } */ /* { dg-final { scan-assembler-times {addi\s+[a-x0-9]+,\s*[a-x0-9]+,\s*44} 1 { target { no-opts "-O0" no-opts "-Os" no-opts "-Oz" no-opts "-g" no-opts "-funroll-loops" } } } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-68.c b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-68.c index 0a4855a2eea2..a366a15f71bc 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-68.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-68.c @@ -21,6 +21,6 @@ void f2 (void * restrict in, void * restrict out, int l, int n, int m) } } -/* { dg-final { scan-assembler-times {vsetvli} 1 { target { no-opts "-O0" no-opts "-Os" no-opts "-Oz" no-opts "-g" no-opts "-funroll-loops" } } } } */ -/* { dg-final { scan-assembler-times {vsetvli\s+zero,\s*[a-x0-9]+,\s*e8,\s*mf8,\s*tu,\s*m[au]} 1 { target { no-opts "-O0" no-opts "-Os" no-opts "-Oz" no-opts "-g" no-opts "-funroll-loops" } } } } */ +/* { dg-final { scan-assembler-times {vsetvli} 2 { target { no-opts "-O0" no-opts "-Os" no-opts "-Oz" no-opts "-g" no-opts "-funroll-loops" } } } } */ +/* { dg-final { scan-assembler-times {vsetvli\s+zero,\s*[a-x0-9]+,\s*e8,\s*mf8,\s*tu,\s*m[au]} 2 { target { no-opts "-O0" no-opts "-Os" no-opts "-Oz" no-opts "-g" no-opts "-funroll-loops" } } } } */ /* { dg-final { scan-assembler-times {addi\s+[a-x0-9]+,\s*[a-x0-9]+,\s*44} 1 { target { no-opts "-O0" no-opts "-Os" no-opts "-Oz" no-opts "-g" no-opts "-funroll-loops" } } } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-69.c b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-69.c index 37707b00488d..633c4afd4f22 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-69.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-69.c @@ -5,7 +5,7 @@ void f (int8_t * restrict in, int8_t * restrict out, int l, int n, int m, size_t cond) { - size_t vl = 555; + size_t vl = 555 + cond; for (int i = 0; i < l; i++){ for (int j = 0; j < m; j++){ for (int k = 0; k < n; k++) diff --git a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-70.c b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-70.c index c066510336ad..8927fb128fb3 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-70.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-70.c @@ -5,7 +5,7 @@ void f (int8_t * restrict in, int8_t * restrict out, int l, int n, int m, size_t cond) { - size_t vl = 555; + size_t vl = cond + 555; if (cond) { for (int i = 0; i < l; i++){ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-71.c b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-71.c index 8409d06796a5..c59cc008e981 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-71.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-71.c @@ -5,7 +5,7 @@ void f (int8_t * restrict in, int8_t * restrict out, int l, int n, int m, size_t cond) { - size_t vl = 555; + size_t vl = in[0] + 555; if (cond) { for (int i = 0; i < l; i++){ @@ -50,5 +50,5 @@ void f (int8_t * restrict in, int8_t * restrict out, int l, int n, int m, size_t } } -/* { dg-final { scan-assembler-times {vsetvli\s+zero,\s*[a-x0-9]+,\s*e8,\s*mf8,\s*tu,\s*m[au]} 3 { target { no-opts "-O0" no-opts "-O1" no-opts "-Os" no-opts "-Oz" no-opts "-g" no-opts "-funroll-loops" } } } } */ -/* { dg-final { scan-assembler-times {vsetvli} 3 { target { no-opts "-O0" no-opts "-O1" no-opts "-Os" no-opts "-Oz" no-opts "-g" no-opts "-funroll-loops" } } } } */ +/* { dg-final { scan-assembler-times {vsetvli\s+zero,\s*[a-x0-9]+,\s*e8,\s*mf8,\s*tu,\s*m[au]} 2 { target { no-opts "-O0" no-opts "-O1" no-opts "-Os" no-opts "-Oz" no-opts "-g" no-opts "-funroll-loops" } } } } */ +/* { dg-final { scan-assembler-times {vsetvli} 2 { target { no-opts "-O0" no-opts "-O1" no-opts "-Os" no-opts "-Oz" no-opts "-g" no-opts "-funroll-loops" } } } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-72.c b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-72.c index b1e28abd4fe1..45b00f68ba33 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-72.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-72.c @@ -3,9 +3,9 @@ #include "riscv_vector.h" -void f (void * restrict in, void * restrict out, int n, int cond) +void f (void * restrict in, void * restrict out, int n, int cond, size_t vl) { - size_t vl = 101; + vl = vl + 101; for (size_t i = 0; i < n; i++) { vint8mf8_t v = __riscv_vle8_v_i8mf8 (in + i, vl); diff --git a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-76.c b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-76.c index 1b6e818d2093..142e43c2baab 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-76.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-76.c @@ -5,7 +5,7 @@ void f (void * restrict in, void * restrict out, int n, int cond) { - size_t vl = 101; + size_t vl = 101 + cond; for (size_t i = 0; i < n; i++) { vint8mf8_t v = __riscv_vle8_v_i8mf8 (in + i, vl); diff --git a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-77.c b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-77.c index 9fb160523852..ddd6766e1ef5 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-77.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-77.c @@ -5,7 +5,7 @@ void f (void * restrict in, void * restrict out, int n, int cond) { - size_t vl = 101; + size_t vl = 101 + cond; for (size_t i = 0; i < n; i++) { vint8mf8_t v = __riscv_vle8_v_i8mf8 (in + i, vl); diff --git a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-82.c b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-82.c index af1f08826cf6..17bac422508f 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-82.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-82.c @@ -25,6 +25,6 @@ float f0 (int8_t * restrict in, int8_t * restrict out, int n, int m, unsigned co } /* { dg-final { scan-assembler-times {vsetvli\s+[a-x0-9]+,\s*zero,\s*e32,\s*mf2,\s*t[au],\s*m[au]} 1 { target { no-opts "-O0" no-opts "-Os" no-opts "-Oz" no-opts "-O1" no-opts "-g" no-opts "-funroll-loops" } } } } */ -/* { dg-final { scan-assembler-times {vsetivli\s+zero,\s*4,\s*e32,\s*mf2,\s*tu,\s*mu} 2 { target { no-opts "-O0" no-opts "-Os" no-opts "-Oz" no-opts "-O1" no-opts "-g" no-opts "-funroll-loops" } } } } */ +/* { dg-final { scan-assembler-times {vsetivli\s+zero,\s*4,\s*e32,\s*mf2,\s*tu,\s*mu} 1 { target { no-opts "-O0" no-opts "-Os" no-opts "-Oz" no-opts "-O1" no-opts "-g" no-opts "-funroll-loops" } } } } */ /* { dg-final { scan-assembler-times {vsetvli} 1 { target { no-opts "-O0" no-opts "-O1" no-opts "-Os" no-opts "-Oz" no-opts "-g" no-opts "-funroll-loops" } } } } */ -/* { dg-final { scan-assembler-times {vsetivli} 2 { target { no-opts "-O0" no-opts "-O1" no-opts "-Os" no-opts "-Oz" no-opts "-g" no-opts "-funroll-loops" } } } } */ +/* { dg-final { scan-assembler-times {vsetivli} 1 { target { no-opts "-O0" no-opts "-O1" no-opts "-Os" no-opts "-Oz" no-opts "-g" no-opts "-funroll-loops" } } } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-83.c b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-83.c index 07263712cdbc..c7a3383d02ef 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-83.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-83.c @@ -26,6 +26,6 @@ float f0 (int8_t * restrict in, int8_t * restrict out, int n, int m, unsigned co } /* { dg-final { scan-assembler-times {vsetvli\s+[a-x0-9]+,\s*zero,\s*e32,\s*mf2,\s*t[au],\s*m[au]} 1 { target { no-opts "-O0" no-opts "-Os" no-opts "-Oz" no-opts "-O1" no-opts "-g" no-opts "-funroll-loops" } } } } */ -/* { dg-final { scan-assembler-times {vsetivli\s+zero,\s*4,\s*e32,\s*mf2,\s*tu,\s*mu} 2 { target { no-opts "-O0" no-opts "-Os" no-opts "-Oz" no-opts "-O1" no-opts "-g" no-opts "-funroll-loops" } } } } */ +/* { dg-final { scan-assembler-times {vsetivli\s+zero,\s*4,\s*e32,\s*mf2,\s*tu,\s*mu} 1 { target { no-opts "-O0" no-opts "-Os" no-opts "-Oz" no-opts "-O1" no-opts "-g" no-opts "-funroll-loops" } } } } */ /* { dg-final { scan-assembler-times {vsetvli} 1 { target { no-opts "-O0" no-opts "-O1" no-opts "-Os" no-opts "-Oz" no-opts "-g" no-opts "-funroll-loops" } } } } */ -/* { dg-final { scan-assembler-times {vsetivli} 2 { target { no-opts "-O0" no-opts "-O1" no-opts "-Os" no-opts "-Oz" no-opts "-g" no-opts "-funroll-loops" } } } } */ +/* { dg-final { scan-assembler-times {vsetivli} 1 { target { no-opts "-O0" no-opts "-O1" no-opts "-Os" no-opts "-Oz" no-opts "-g" no-opts "-funroll-loops" } } } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-84.c b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-84.c index f772af81ec4f..b3e90d260e7d 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-84.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-84.c @@ -17,7 +17,7 @@ double f0 (int8_t * restrict in, int8_t * restrict out, int n, int m, unsigned c } /* { dg-final { scan-assembler-times {vsetvli\s+[a-x0-9]+,\s*zero,\s*e8,\s*m2,\s*t[au],\s*m[au]} 1 { target { no-opts "-O0" no-opts "-Os" no-opts "-Oz" no-opts "-O1" no-opts "-g" no-opts "-funroll-loops" } } } } */ -/* { dg-final { scan-assembler-times {vsetivli\s+zero,\s*3,\s*e64,\s*m1,\s*t[au],\s*m[au]} 2 { target { no-opts "-O0" no-opts "-Os" no-opts "-Oz" no-opts "-O1" no-opts "-g" no-opts "-funroll-loops" } } } } */ +/* { dg-final { scan-assembler-times {vsetivli\s+zero,\s*3,\s*e64,\s*m1,\s*t[au],\s*m[au]} 1 { target { no-opts "-O0" no-opts "-Os" no-opts "-Oz" no-opts "-O1" no-opts "-g" no-opts "-funroll-loops" } } } } */ /* { dg-final { scan-assembler-times {vsetvli} 1 { target { no-opts "-O0" no-opts "-O1" no-opts "-Os" no-opts "-Oz" no-opts "-g" no-opts "-funroll-loops" } } } } */ /* { dg-final { scan-assembler-times {vsetivli} 2 { target { no-opts "-O0" no-opts "-O1" no-opts "-Os" no-opts "-Oz" no-opts "-g" no-opts "-funroll-loops" } } } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-89.c b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-89.c index a4ef350afc33..9f850880ae53 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-89.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-89.c @@ -25,7 +25,7 @@ float f (int8_t * restrict in, int8_t * restrict out, int n, int m, unsigned con return __riscv_vfmv_f_s_f32m1_f32 (v); } -/* { dg-final { scan-assembler-times {vsetivli\s+zero,\s*3,\s*e32,\s*m1,\s*t[au],\s*m[au]} 2 { target { no-opts "-O0" no-opts "-Os" no-opts "-Oz" no-opts "-O1" no-opts "-g" no-opts "-funroll-loops" } } } } */ +/* { dg-final { scan-assembler-times {vsetivli\s+zero,\s*3,\s*e32,\s*m1,\s*t[au],\s*m[au]} 1 { target { no-opts "-O0" no-opts "-Os" no-opts "-Oz" no-opts "-O1" no-opts "-g" no-opts "-funroll-loops" } } } } */ /* { dg-final { scan-assembler-times {vsetvli\s+[a-x0-9]+,\s*zero,\s*e32,\s*mf2,\s*tu,\s*mu} 1 { target { no-opts "-O0" no-opts "-Os" no-opts "-Oz" no-opts "-O1" no-opts "-g" no-opts "-funroll-loops" } } } } */ /* { dg-final { scan-assembler-times {vsetvli} 1 { target { no-opts "-O0" no-opts "-O1" no-opts "-Os" no-opts "-Oz" no-opts "-g" no-opts "-funroll-loops" } } } } */ -/* { dg-final { scan-assembler-times {vsetivli} 2 { target { no-opts "-O0" no-opts "-O1" no-opts "-Os" no-opts "-Oz" no-opts "-g" no-opts "-funroll-loops" } } } } */ +/* { dg-final { scan-assembler-times {vsetivli} 1 { target { no-opts "-O0" no-opts "-O1" no-opts "-Os" no-opts "-Oz" no-opts "-g" no-opts "-funroll-loops" } } } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-93.c b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-93.c index 592e067cfc6e..eaed7f1a1276 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-93.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-93.c @@ -16,6 +16,6 @@ float f (int8_t * restrict in, int8_t * restrict out, int n, int m, unsigned con *(vfloat32m1_t*)(out + 100000) = v; } -/* { dg-final { scan-assembler-times {vsetivli\s+zero,\s*3,\s*e64,\s*m1,\s*t[au],\s*m[au]} 1 { target { no-opts "-O0" no-opts "-Os" no-opts "-Oz" no-opts "-O1" no-opts "-g" no-opts "-funroll-loops" } } } } */ +/* { dg-final { scan-assembler-times {vsetivli\s+zero,\s*3,\s*e64,\s*m1,\s*t[au],\s*m[au]} 2 { target { no-opts "-O0" no-opts "-Os" no-opts "-Oz" no-opts "-O1" no-opts "-g" no-opts "-funroll-loops" } } } } */ /* { dg-final { scan-assembler-not {vsetvli} { target { no-opts "-O0" no-opts "-O1" no-opts "-Os" no-opts "-Oz" no-opts "-g" no-opts "-funroll-loops" } } } } */ -/* { dg-final { scan-assembler-times {vsetivli} 1 { target { no-opts "-O0" no-opts "-O1" no-opts "-Os" no-opts "-Oz" no-opts "-g" no-opts "-funroll-loops" } } } } */ +/* { dg-final { scan-assembler-times {vsetivli} 2 { target { no-opts "-O0" no-opts "-O1" no-opts "-Os" no-opts "-Oz" no-opts "-g" no-opts "-funroll-loops" } } } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-94.c b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-94.c index 694d591eeaed..a2f32dff7c18 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-94.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-94.c @@ -15,6 +15,6 @@ float f (int8_t * restrict in, int8_t * restrict out, int n, int m, unsigned con *(vfloat32m1_t*)(out + 100000) = v; } -/* { dg-final { scan-assembler-times {vsetivli\s+zero,\s*3,\s*e32,\s*m1,\s*t[au],\s*m[au]} 1 { target { no-opts "-O0" no-opts "-Os" no-opts "-Oz" no-opts "-O1" no-opts "-g" no-opts "-funroll-loops" } } } } */ +/* { dg-final { scan-assembler-times {vsetivli\s+zero,\s*3,\s*e32,\s*m1,\s*t[au],\s*m[au]} 2 { target { no-opts "-O0" no-opts "-Os" no-opts "-Oz" no-opts "-O1" no-opts "-g" no-opts "-funroll-loops" } } } } */ /* { dg-final { scan-assembler-not {vsetvli} { target { no-opts "-O0" no-opts "-O1" no-opts "-Os" no-opts "-Oz" no-opts "-g" no-opts "-funroll-loops" } } } } */ -/* { dg-final { scan-assembler-times {vsetivli} 1 { target { no-opts "-O0" no-opts "-O1" no-opts "-Os" no-opts "-Oz" no-opts "-g" no-opts "-funroll-loops" } } } } */ +/* { dg-final { scan-assembler-times {vsetivli} 2 { target { no-opts "-O0" no-opts "-O1" no-opts "-Os" no-opts "-Oz" no-opts "-g" no-opts "-funroll-loops" } } } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-95.c b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-95.c index 22644e764235..5dac25ee59cc 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-95.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-95.c @@ -15,6 +15,6 @@ float f (int8_t * restrict in, int8_t * restrict out, int n, int m, unsigned con *(vfloat32m1_t*)(out + 100000) = v; } -/* { dg-final { scan-assembler-times {vsetivli\s+zero,\s*3,\s*e32,\s*m2,\s*t[au],\s*m[au]} 1 { target { no-opts "-O0" no-opts "-Os" no-opts "-Oz" no-opts "-O1" no-opts "-g" no-opts "-funroll-loops" } } } } */ +/* { dg-final { scan-assembler-times {vsetivli\s+zero,\s*3,\s*e64,\s*m4,\s*t[au],\s*m[au]} 2 { target { no-opts "-O0" no-opts "-Os" no-opts "-Oz" no-opts "-O1" no-opts "-g" no-opts "-funroll-loops" } } } } */ /* { dg-final { scan-assembler-not {vsetvli} { target { no-opts "-O0" no-opts "-O1" no-opts "-Os" no-opts "-Oz" no-opts "-g" no-opts "-funroll-loops" } } } } */ -/* { dg-final { scan-assembler-times {vsetivli} 1 { target { no-opts "-O0" no-opts "-O1" no-opts "-Os" no-opts "-Oz" no-opts "-g" no-opts "-funroll-loops" } } } } */ +/* { dg-final { scan-assembler-times {vsetivli} 2 { target { no-opts "-O0" no-opts "-O1" no-opts "-Os" no-opts "-Oz" no-opts "-g" no-opts "-funroll-loops" } } } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-96.c b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-96.c index 0e261d888a47..19516eb271ec 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-96.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-96.c @@ -16,6 +16,6 @@ float f (int8_t * restrict in, int8_t * restrict out, int n, int m, unsigned con return __riscv_vfmv_f_s_f32m1_f32 (v); } -/* { dg-final { scan-assembler-times {vsetivli\s+zero,\s*3,\s*e32,\s*m2,\s*t[au],\s*m[au]} 1 { target { no-opts "-O0" no-opts "-Os" no-opts "-Oz" no-opts "-O1" no-opts "-g" no-opts "-funroll-loops" } } } } */ +/* { dg-final { scan-assembler-times {vsetivli\s+zero,\s*3,\s*e32,\s*m2,\s*t[au],\s*m[au]} 2 { target { no-opts "-O0" no-opts "-Os" no-opts "-Oz" no-opts "-O1" no-opts "-g" no-opts "-funroll-loops" } } } } */ /* { dg-final { scan-assembler-not {vsetvli} { target { no-opts "-O0" no-opts "-O1" no-opts "-Os" no-opts "-Oz" no-opts "-g" no-opts "-funroll-loops" } } } } */ -/* { dg-final { scan-assembler-times {vsetivli} 1 { target { no-opts "-O0" no-opts "-O1" no-opts "-Os" no-opts "-Oz" no-opts "-g" no-opts "-funroll-loops" } } } } */ +/* { dg-final { scan-assembler-times {vsetivli} 2 { target { no-opts "-O0" no-opts "-O1" no-opts "-Os" no-opts "-Oz" no-opts "-g" no-opts "-funroll-loops" } } } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/ffload-5.c b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/ffload-5.c index 895180cc54ec..04eb78b91c63 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/ffload-5.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/ffload-5.c @@ -26,4 +26,4 @@ void f (int8_t * restrict in, int8_t * restrict out, int n, int m, int cond) } } -/* { dg-final { scan-assembler-times {vsetvli\s+zero,\s*[a-x0-9]+,\s*e8,\s*mf8,\s*tu,\s*mu} 1 { target { no-opts "-O0" no-opts "-g" no-opts "-funroll-loops" } } } } */ +/* { dg-final { scan-assembler-times {vsetvli\s+zero,\s*[a-x0-9]+,\s*e8,\s*mf8,\s*tu,\s*mu} 1 { target { no-opts "-O0" no-opts "-Os" no-opts "-g" no-opts "-funroll-loops" } } } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/imm_bb_prop-3.c b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/imm_bb_prop-3.c index dbe6c67ee87b..a68947490172 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/imm_bb_prop-3.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/imm_bb_prop-3.c @@ -10,6 +10,7 @@ void f(void *base, void *out, void *mask_in, size_t vl, size_t m) { if (i % 2 == 0) { vint8mf8_t v0 = __riscv_vle8_v_i8mf8(base + i, 4); vint8mf8_t v1 = __riscv_vle8_v_i8mf8_tu(v0, base + i + 100, 4); + v1 = __riscv_vadd_vv_i8mf8 (v0,v1,4); __riscv_vse8_v_i8mf8 (out + i, v1, 4); } else { vint16mf4_t v0 = __riscv_vle16_v_i16mf4(base + i, 4); diff --git a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/imm_bb_prop-4.c b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/imm_bb_prop-4.c index 4fbeffb8b543..13d7c23ec6e7 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/imm_bb_prop-4.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/imm_bb_prop-4.c @@ -11,6 +11,7 @@ void f(void *base, void *out, void *mask_in, size_t vl, size_t m, size_t n) { if ((i + j) % 2 == 0) { vint8mf8_t v0 = __riscv_vle8_v_i8mf8(base + i + j, 4); vint8mf8_t v1 = __riscv_vle8_v_i8mf8_tu(v0, base + i + j + 100, 4); + v1 = __riscv_vadd_vv_i8mf8 (v0,v1,4); __riscv_vse8_v_i8mf8 (out + i + j, v1, 4); } else { vint16mf4_t v0 = __riscv_vle16_v_i16mf4(base + i + j, 4); diff --git a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/imm_bb_prop-9.c b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/imm_bb_prop-9.c index 3b486df4fe54..94d08bce54d6 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/imm_bb_prop-9.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/imm_bb_prop-9.c @@ -14,6 +14,7 @@ void f(void *base, void *out, void *mask_in, size_t vl, size_t m, size_t n) { } else { vint8mf8_t v0 = __riscv_vle8_v_i8mf8(base + i + 300 + j, 4); vint8mf8_t v1 = __riscv_vle8_v_i8mf8_tu(v0, base + i + 300 + j, 4); + v1 = __riscv_vadd_vv_i8mf8 (v0,v1,4); __riscv_vse8_v_i8mf8 (out + i + 300, v1, 4); } } diff --git a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/imm_switch-7.c b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/imm_switch-7.c index 8b67dcc216c4..af110ec3ba58 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/imm_switch-7.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/imm_switch-7.c @@ -25,5 +25,5 @@ void f (void * restrict in, void * restrict out, int n) } /* { dg-final { scan-assembler-times {vsetivli\s+zero,\s*5,\s*e8,\s*mf8,\s*t[au],\s*m[au]} 1 { target { no-opts "-O0" no-opts "-Os" no-opts "-Oz" no-opts "-g" no-opts "-funroll-loops" } } } } */ -/* { dg-final { scan-assembler-times {\.L[0-9]+\:\s+vsetivli\s+zero,\s*5,\s*e16,\s*mf4,\s*t[au],\s*m[au]\s+\.L[0-9]+} 1 { target { no-opts "-O0" no-opts "-Os" no-opts "-Oz" no-opts "-g" no-opts "-funroll-loops" } } } } */ +/* { dg-final { scan-assembler-times {\.L[0-9]+\:\s+vsetivli\s+zero,\s*5,\s*e16,\s*mf4,\s*t[au],\s*m[au]} 1 { target { no-opts "-O0" no-opts "-Os" no-opts "-Oz" no-opts "-g" no-opts "-funroll-loops" } } } } */ /* { dg-final { scan-assembler-times {vsetivli\s+zero,\s*8,\s*e16,\s*mf2,\s*t[au],\s*m[au]} 1 { target { no-opts "-O0" no-opts "-Os" no-opts "-Oz" no-opts "-g" no-opts "-funroll-loops" } } } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/imm_switch-9.c b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/imm_switch-9.c index 3825aea16f15..322e2719f3e9 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/imm_switch-9.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/imm_switch-9.c @@ -41,7 +41,5 @@ void f (void * restrict in, void * restrict out, void * restrict mask_in, int n, } } -/* { dg-final { scan-assembler-times {vsetvli\s+[a-x0-9]+,\s*zero,\s*e8,\s*mf8,\s*t[au],\s*m[au]} 1 { target { no-opts "-O0" no-opts "-O1" no-opts "-Os" no-opts "-Oz" no-opts "-funroll-loops" no-opts "-g" } } } } */ -/* { dg-final { scan-assembler-times {vsetivli\s+zero,\s*5,\s*e16,\s*mf4,\s*tu,\s*mu} 1 { target { no-opts "-O0" no-opts "-O1" no-opts "-Os" no-opts "-Oz" no-opts "-g" no-opts "-funroll-loops" } } } } */ -/* { dg-final { scan-assembler-times {vsetivli\s+zero,\s*5,\s*e32,\s*mf2,\s*tu,\s*m[au]} 1 { target { no-opts "-O0" no-opts "-O1" no-opts "-Os" no-opts "-Oz" no-opts "-g" no-opts "-funroll-loops" } } } } */ +/* { dg-final { scan-assembler-times {vsetivli} 11 { target { no-opts "-O0" no-opts "-O1" no-opts "-Os" no-opts "-Oz" no-opts "-g" no-opts "-funroll-loops" } } } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/pr111234.c b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/pr111234.c new file mode 100644 index 000000000000..ee5eec4a2575 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/pr111234.c @@ -0,0 +1,19 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gcv -mabi=lp64d -O3" } */ + +#include + +void +f (vint32m1_t *in, vint64m2_t *out, vbool32_t *m, int b) +{ + vint32m1_t va = *in; + vbool32_t mask = *m; + vint64m2_t vb + = __riscv_vwadd_vx_i64m2_m (mask, va, 1, __riscv_vsetvlmax_e64m2 ()); + vint64m2_t vc = __riscv_vadd_vx_i64m2 (vb, 1, __riscv_vsetvlmax_e64m2 ()); + + if (b != 0) + vc = __riscv_vadd_vx_i64m2_mu (mask, vc, vc, 1, __riscv_vsetvlmax_e64m2 ()); + + *out = vc; +} diff --git a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_back_prop-24.c b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_back_prop-24.c index bc98e5f8269f..fe41d15cb281 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_back_prop-24.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_back_prop-24.c @@ -30,7 +30,7 @@ void f (int32_t * restrict in, int32_t * restrict out, int n, int cond) *(vint32mf2_t*)(out + 7000) = v; for (int i = 0; i < n; i++) { - vbool64_t v; + vbool64_t v = *(vbool64_t*)(in + i + 9000); *(vbool64_t*)(out + i + 700) = v; } } diff --git a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_back_prop-25.c b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_back_prop-25.c index 0a10827daf51..c566f8a4751d 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_back_prop-25.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_back_prop-25.c @@ -10,7 +10,7 @@ void f (void * restrict in, void * restrict out, int n, int cond) *(vint8mf8_t*)(out + 100) = v; for (int i = 0; i < n; i++) { - vint16mf4_t v2; + vint16mf4_t v2 = __riscv_vmv_v_x_i16mf4 (0, __riscv_vsetvlmax_e16mf4 ()); *(vint16mf4_t*)(out + i + 100) = v2; } } else if (cond == 1) { @@ -18,7 +18,7 @@ void f (void * restrict in, void * restrict out, int n, int cond) *(vint8mf8_t*)(out + 200) = v; for (int i = 0; i < n; i++) { - vint32mf2_t v2; + vint32mf2_t v2 = __riscv_vmv_v_x_i32mf2 (0, __riscv_vsetvlmax_e32mf2 ()); *(vint32mf2_t*)(out + i + 200) = v2; } } else if (cond == 2) { @@ -26,7 +26,7 @@ void f (void * restrict in, void * restrict out, int n, int cond) *(vint8mf8_t*)(out + 300) = v; for (int i = 0; i < n; i++) { - vint8mf8_t v2; + vint8mf8_t v2 = __riscv_vmv_v_x_i8mf8 (0, __riscv_vsetvlmax_e8mf8 ()); *(vint8mf8_t*)(out + i + 300) = v2; } } else if (cond == 3) { @@ -34,7 +34,7 @@ void f (void * restrict in, void * restrict out, int n, int cond) *(vint8mf8_t*)(out + 400) = v; for (int i = 0; i < n; i++) { - vint64m1_t v2; + vint64m1_t v2 = __riscv_vmv_v_x_i64m1 (0, __riscv_vsetvlmax_e64m1 ()); *(vint64m1_t*)(out + i + 400) = v2; } } else if (cond == 4) { @@ -42,7 +42,7 @@ void f (void * restrict in, void * restrict out, int n, int cond) *(vint8mf8_t*)(out + 500) = v; for (int i = 0; i < n; i++) { - vfloat32mf2_t v2; + vfloat32mf2_t v2 = __riscv_vfmv_v_f_f32mf2 (0, __riscv_vsetvlmax_e32mf2 ()); *(vfloat32mf2_t*)(out + i + 500) = v2; } } else if (cond == 5) { @@ -50,7 +50,7 @@ void f (void * restrict in, void * restrict out, int n, int cond) *(vuint8mf8_t*)(out + 600) = v; for (int i = 0; i < n; i++) { - vuint16mf4_t v2; + vuint16mf4_t v2 = __riscv_vmv_v_x_u16mf4 (0, __riscv_vsetvlmax_e16mf4 ()); *(vuint16mf4_t*)(out + i + 600) = v2; } } else if (cond == 6) { @@ -58,7 +58,7 @@ void f (void * restrict in, void * restrict out, int n, int cond) *(vuint8mf8_t*)(out + 700) = v; for (int i = 0; i < n; i++) { - vuint32mf2_t v2; + vuint32mf2_t v2 = __riscv_vmv_v_x_u32mf2 (0, __riscv_vsetvlmax_e32mf2 ()); *(vuint32mf2_t*)(out + i + 700) = v2; } } else if (cond == 7) { @@ -66,7 +66,7 @@ void f (void * restrict in, void * restrict out, int n, int cond) *(vuint8mf8_t*)(out + 800) = v; for (int i = 0; i < n; i++) { - vuint8mf8_t v2; + vuint8mf8_t v2 = __riscv_vmv_v_x_u8mf8 (0, __riscv_vsetvlmax_e8mf8 ()); *(vuint8mf8_t*)(out + i + 800) = v2; } } else if (cond == 8) { @@ -74,7 +74,7 @@ void f (void * restrict in, void * restrict out, int n, int cond) *(vuint8mf8_t*)(out + 900) = v; for (int i = 0; i < n; i++) { - vuint64m1_t v2; + vuint64m1_t v2 = __riscv_vmv_v_x_u64m1 (0, __riscv_vsetvlmax_e64m1 ()); *(vuint64m1_t*)(out + i + 900) = v2; } } else { @@ -82,15 +82,14 @@ void f (void * restrict in, void * restrict out, int n, int cond) *(vuint8mf8_t*)(out + 1000) = v; for (int i = 0; i < n; i++) { - vfloat32mf2_t v2; + vfloat32mf2_t v2 = *(vfloat32mf2_t*)(in + i + 9000); *(vfloat32mf2_t*)(out + i + 1000) = v2; } } } -/* { dg-final { scan-assembler-times {vsetvli\s+zero,\s*zero,\s*e32,\s*mf2,\s*t[au],\s*m[au]} 4 { target { no-opts "-O0" no-opts "-O1" no-opts "-Os" no-opts "-Oz" no-opts "-funroll-loops" no-opts "-g" } } } } */ -/* { dg-final { scan-assembler-times {vsetvli\s+zero,\s*zero,\s*e16,\s*mf4,\s*t[au],\s*m[au]} 2 { target { no-opts "-O0" no-opts "-O1" no-opts "-Os" no-opts "-Oz" no-opts "-funroll-loops" no-opts "-g" } } } } */ -/* { dg-final { scan-assembler-times {vsetvli\s+zero,\s*zero,\s*e64,\s*m1,\s*t[au],\s*m[au]} 2 { target { no-opts "-O0" no-opts "-O1" no-opts "-Os" no-opts "-Oz" no-opts "-funroll-loops" no-opts "-g" } } } } */ -/* { dg-final { scan-assembler-times {vsetvli\s+[a-x0-9]+,\s*zero,\s*e8,\s*mf8,\s*t[au],\s*m[au]} 10 { target { no-opts "-O0" no-opts "-O1" no-opts "-Os" no-opts "-Oz" no-opts "-funroll-loops" no-opts "-g" } } } } */ -/* { dg-final { scan-assembler-times {vsetvli\s+zero,\s*zero,\s*e8,\s*mf8,\s*t[au],\s*m[au]} 2 { target { no-opts "-O0" no-opts "-O1" no-opts "-Os" no-opts "-Oz" no-opts "-funroll-loops" no-opts "-g" } } } } */ -/* { dg-final { scan-assembler-times {vsetvli} 20 { target { no-opts "-O0" no-opts "-O1" no-opts "-Os" no-opts "-Oz" no-opts "-funroll-loops" no-opts "-g" } } } } */ +/* { dg-final { scan-assembler-times {vsetvli\s+[a-x0-9]+,\s*zero,\s*e8,\s*mf8,\s*t[au],\s*m[au]} 3 { target { no-opts "-O0" no-opts "-O1" no-opts "-Os" no-opts "-Oz" no-opts "-funroll-loops" no-opts "-g" } } } } */ +/* { dg-final { scan-assembler-times {vsetvli\s+[a-x0-9]+,\s*zero,\s*e16,\s*mf4,\s*t[au],\s*m[au]} 2 { target { no-opts "-O0" no-opts "-O1" no-opts "-Os" no-opts "-Oz" no-opts "-funroll-loops" no-opts "-g" } } } } */ +/* { dg-final { scan-assembler-times {vsetvli\s+[a-x0-9]+,\s*zero,\s*e32,\s*mf2,\s*t[au],\s*m[au]} 3 { target { no-opts "-O0" no-opts "-O1" no-opts "-Os" no-opts "-Oz" no-opts "-funroll-loops" no-opts "-g" } } } } */ +/* { dg-final { scan-assembler-times {vsetvli\s+[a-x0-9]+,\s*zero,\s*e64,\s*m1,\s*t[au],\s*m[au]} 2 { target { no-opts "-O0" no-opts "-O1" no-opts "-Os" no-opts "-Oz" no-opts "-funroll-loops" no-opts "-g" } } } } */ +/* { dg-final { scan-assembler-times {vsetvli} 10 { target { no-opts "-O0" no-opts "-O1" no-opts "-Os" no-opts "-Oz" no-opts "-funroll-loops" no-opts "-g" } } } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_back_prop-26.c b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_back_prop-26.c index a65407513986..d0e752581889 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_back_prop-26.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_back_prop-26.c @@ -10,7 +10,7 @@ void f (void * restrict in, void * restrict out, int n, int cond) *(vint8mf8_t*)(out + 100) = v; for (int i = 0; i < n; i++) { - vint16mf4_t v2; + vint16mf4_t v2 = __riscv_vmv_v_x_i16mf4 (0, __riscv_vsetvlmax_e16mf4 ()); *(vint16mf4_t*)(out + i + 100) = v2; } } else if (cond == 1) { @@ -18,7 +18,7 @@ void f (void * restrict in, void * restrict out, int n, int cond) *(vint8mf8_t*)(out + 200) = v; for (int i = 0; i < n; i++) { - vint32mf2_t v2; + vint32mf2_t v2 = __riscv_vmv_v_x_i32mf2 (0, __riscv_vsetvlmax_e32mf2 ()); *(vint32mf2_t*)(out + i + 200) = v2; } } else if (cond == 2) { @@ -26,7 +26,7 @@ void f (void * restrict in, void * restrict out, int n, int cond) *(vint8mf8_t*)(out + 300) = v; for (int i = 0; i < n; i++) { - vint8mf8_t v2; + vint8mf8_t v2 = __riscv_vmv_v_x_i8mf8 (0, __riscv_vsetvlmax_e8mf8 ()); *(vint8mf8_t*)(out + i + 300) = v2; } } else if (cond == 3) { @@ -34,7 +34,7 @@ void f (void * restrict in, void * restrict out, int n, int cond) *(vint8mf8_t*)(out + 400) = v; for (int i = 0; i < n; i++) { - vint64m1_t v2; + vint64m1_t v2 = __riscv_vmv_v_x_i64m1 (0, __riscv_vsetvlmax_e64m1 ()); *(vint64m1_t*)(out + i + 400) = v2; } } else if (cond == 4) { @@ -42,7 +42,7 @@ void f (void * restrict in, void * restrict out, int n, int cond) *(vint8mf8_t*)(out + 500) = v; for (int i = 0; i < n; i++) { - vfloat32mf2_t v2; + vfloat32mf2_t v2 = __riscv_vfmv_v_f_f32mf2 (0, __riscv_vsetvlmax_e32mf2 ()); *(vfloat32mf2_t*)(out + i + 500) = v2; } } else if (cond == 5) { @@ -50,7 +50,7 @@ void f (void * restrict in, void * restrict out, int n, int cond) *(vuint8mf8_t*)(out + 600) = v; for (int i = 0; i < n; i++) { - vuint16mf4_t v2; + vuint16mf4_t v2 = __riscv_vmv_v_x_u16mf4 (0, __riscv_vsetvlmax_e16mf4 ()); *(vuint16mf4_t*)(out + i + 600) = v2; } } else if (cond == 6) { @@ -58,7 +58,7 @@ void f (void * restrict in, void * restrict out, int n, int cond) *(vuint8mf8_t*)(out + 700) = v; for (int i = 0; i < n; i++) { - vuint32mf2_t v2; + vuint32mf2_t v2 = __riscv_vmv_v_x_u32mf2 (0, __riscv_vsetvlmax_e32mf2 ()); *(vuint32mf2_t*)(out + i + 700) = v2; } } else if (cond == 7) { @@ -66,7 +66,7 @@ void f (void * restrict in, void * restrict out, int n, int cond) *(vuint8mf8_t*)(out + 800) = v; for (int i = 0; i < n; i++) { - vuint8mf8_t v2; + vuint8mf8_t v2 = __riscv_vmv_v_x_u8mf8 (0, __riscv_vsetvlmax_e8mf8 ()); *(vuint8mf8_t*)(out + i + 800) = v2; } } else if (cond == 8) { @@ -74,16 +74,14 @@ void f (void * restrict in, void * restrict out, int n, int cond) *(vuint8mf8_t*)(out + 900) = v; for (int i = 0; i < n; i++) { - vuint64m1_t v2; + vuint64m1_t v2 = *(vuint64m1_t*)(in + i + 9000); *(vuint64m1_t*)(out + i + 900) = v2; } } } -/* { dg-final { scan-assembler-times {vsetvli\s+zero,\s*zero,\s*e32,\s*mf2,\s*t[au],\s*m[au]} 3 { target { no-opts "-O0" no-opts "-O1" no-opts "-Os" no-opts "-Oz" no-opts "-funroll-loops" no-opts "-g" } } } } */ -/* { dg-final { scan-assembler-times {vsetvli\s+zero,\s*zero,\s*e16,\s*mf4,\s*t[au],\s*m[au]} 1 { target { no-opts "-O0" no-opts "-O1" no-opts "-Os" no-opts "-Oz" no-opts "-funroll-loops" no-opts "-g" } } } } */ -/* { dg-final { scan-assembler-times {vsetvli\s+zero,\s*zero,\s*e64,\s*m1,\s*t[au],\s*m[au]} 2 { target { no-opts "-O0" no-opts "-O1" no-opts "-Os" no-opts "-Oz" no-opts "-funroll-loops" no-opts "-g" } } } } */ -/* { dg-final { scan-assembler-times {vsetvli\s+zero,\s*zero,\s*e8,\s*mf8,\s*t[au],\s*m[au]} 2 { target { no-opts "-O0" no-opts "-O1" no-opts "-Os" no-opts "-Oz" no-opts "-funroll-loops" no-opts "-g" } } } } */ -/* { dg-final { scan-assembler-times {vsetvli\s+[a-x0-9]+,\s*zero,\s*e16,\s*mf4,\s*t[au],\s*m[au]} 1 { target { no-opts "-O0" no-opts "-O1" no-opts "-Os" no-opts "-Oz" no-opts "-funroll-loops" no-opts "-g" } } } } */ -/* { dg-final { scan-assembler-times {vsetvli\s+[a-x0-9]+,\s*zero,\s*e8,\s*mf8,\s*t[au],\s*m[au]} 8 { target { no-opts "-O0" no-opts "-O1" no-opts "-Os" no-opts "-Oz" no-opts "-funroll-loops" no-opts "-g" } } } } */ -/* { dg-final { scan-assembler-times {vsetvli} 17 { target { no-opts "-O0" no-opts "-O1" no-opts "-Os" no-opts "-Oz" no-opts "-funroll-loops" no-opts "-g" } } } } */ +/* { dg-final { scan-assembler-times {vsetvli\s+[a-x0-9]+,\s*zero,\s*e8,\s*mf8,\s*t[au],\s*m[au]} 3 { target { no-opts "-O0" no-opts "-O1" no-opts "-Os" no-opts "-Oz" no-opts "-funroll-loops" no-opts "-g" } } } } */ +/* { dg-final { scan-assembler-times {vsetvli\s+[a-x0-9]+,\s*zero,\s*e16,\s*mf4,\s*t[au],\s*m[au]} 2 { target { no-opts "-O0" no-opts "-O1" no-opts "-Os" no-opts "-Oz" no-opts "-funroll-loops" no-opts "-g" } } } } */ +/* { dg-final { scan-assembler-times {vsetvli\s+[a-x0-9]+,\s*zero,\s*e32,\s*mf2,\s*t[au],\s*m[au]} 3 { target { no-opts "-O0" no-opts "-O1" no-opts "-Os" no-opts "-Oz" no-opts "-funroll-loops" no-opts "-g" } } } } */ +/* { dg-final { scan-assembler-times {vsetvli\s+[a-x0-9]+,\s*zero,\s*e64,\s*m1,\s*t[au],\s*m[au]} 1 { target { no-opts "-O0" no-opts "-O1" no-opts "-Os" no-opts "-Oz" no-opts "-funroll-loops" no-opts "-g" } } } } */ +/* { dg-final { scan-assembler-times {vsetvli} 9 { target { no-opts "-O0" no-opts "-O1" no-opts "-Os" no-opts "-Oz" no-opts "-funroll-loops" no-opts "-g" } } } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_back_prop-36.c b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_back_prop-36.c index a6009b74101d..9be774c958b5 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_back_prop-36.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_back_prop-36.c @@ -37,7 +37,7 @@ void f (int32_t * restrict in, int32_t * restrict out, int32_t * restrict in2, i } for (int i = 0; i < n; i++) { - vint8mf8_t v1; + vint8mf8_t v1 = *(vint8mf8_t*)(in2 + i + 20); *(vint8mf8_t*)(out + i + 10) = v1; } } diff --git a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_back_prop-45.c b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_back_prop-45.c index f6ddacc8f8ea..2721ebb55899 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_back_prop-45.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_back_prop-45.c @@ -30,5 +30,4 @@ void foo5_5 (int32_t * restrict in, int32_t * restrict out, size_t n, size_t m, } } -/* { dg-final { scan-assembler-times {vsetvli\s+[a-x0-9]+,\s*zero,\s*e8,\s*mf8,\s*t[au],\s*m[au]\s+j\s+\.L[0-9]+} 1 { target { no-opts "-O0" no-opts "-O1" no-opts "-Os" no-opts "-Oz" no-opts "-funroll-loops" no-opts "-g" } } } } */ /* { dg-final { scan-assembler-times {vsetvli} 1 { target { no-opts "-O0" no-opts "-O1" no-opts "-Os" no-opts "-Oz" no-opts "-funroll-loops" no-opts "-g" } } } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_bb_prop-1.c b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_bb_prop-1.c index 24958def604f..20c2193c7038 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_bb_prop-1.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_bb_prop-1.c @@ -171,12 +171,12 @@ void f6 (int8_t * restrict in, int8_t * restrict out, int n) } } -/* { dg-final { scan-assembler-times {vsetvli\s+[a-x0-9]+,\s*zero,\s*e8,\s*mf8,\s*t[au],\s*m[au]} 3 { target { no-opts "-O0" no-opts "-Os" no-opts "-Oz" no-opts "-funroll-loops" no-opts "-g" no-opts "-O2" } } } } */ -/* { dg-final { scan-assembler-times {vsetvli\s+[a-x0-9]+,\s*zero,\s*e8,\s*mf4,\s*t[au],\s*m[au]} 3 { target { no-opts "-O0" no-opts "-Os" no-opts "-Oz" no-opts "-funroll-loops" no-opts "-g" no-opts "-O2" } } } } */ -/* { dg-final { scan-assembler-times {vsetvli\s+[a-x0-9]+,\s*zero,\s*e8,\s*mf2,\s*t[au],\s*m[au]} 3 { target { no-opts "-O0" no-opts "-Os" no-opts "-Oz" no-opts "-funroll-loops" no-opts "-g" no-opts "-O2" } } } } */ -/* { dg-final { scan-assembler-times {add\ta[0-7],a[0-7],a[0-7]\s+\.L[0-9][0-9]\:\s+vle8\.v\s+(?:v[0-9]|v[1-2][0-9]|v3[0-1]),0\s*\([a-x0-9]+\)} 3 { target { no-opts "-O0" no-opts "-Os" no-opts "-Oz" no-opts "-funroll-loops" no-opts "-g" no-opts "-O2" } } } } */ -/* { dg-final { scan-assembler-times {vsetvli\s+[a-x0-9]+,\s*zero,\s*e16,\s*mf4,\s*t[au],\s*m[au]} 3 { target { no-opts "-O0" no-opts "-Os" no-opts "-Oz" no-opts "-funroll-loops" no-opts "-g" no-opts "-O2" } } } } */ -/* { dg-final { scan-assembler-times {vsetvli\s+[a-x0-9]+,\s*zero,\s*e16,\s*mf2,\s*t[au],\s*m[au]} 3 { target { no-opts "-O0" no-opts "-Os" no-opts "-Oz" no-opts "-funroll-loops" no-opts "-g" no-opts "-O2" } } } } */ -/* { dg-final { scan-assembler-times {add\ta[0-7],a[0-7],a[0-7]\s+\.L[0-9][0-9]\:\s+vle16\.v\s+(?:v[0-9]|v[1-2][0-9]|v3[0-1]),0\s*\([a-x0-9]+\)} 2 { target { no-opts "-O0" no-opts "-Os" no-opts "-Oz" no-opts "-funroll-loops" no-opts "-g" no-opts "-O2" } } } } */ -/* { dg-final { scan-assembler-times {vsetvli\s+[a-x0-9]+,\s*zero,\s*e32,\s*mf2,\s*t[au],\s*m[au]} 3 { target { no-opts "-O0" no-opts "-Os" no-opts "-Oz" no-opts "-funroll-loops" no-opts "-g" no-opts "-O2" } } } } */ -/* { dg-final { scan-assembler-times {add\ta[0-7],a[0-7],a[0-7]\s+\.L[0-9][0-9]\:\s+vle32\.v\s+(?:v[0-9]|v[1-2][0-9]|v3[0-1]),0\s*\([a-x0-9]+\)} 1 { target { no-opts "-O0" no-opts "-Os" no-opts "-Oz" no-opts "-funroll-loops" no-opts "-g" no-opts "-O2" } } } } */ +/* { dg-final { scan-assembler-times {vsetvli\s+[a-x0-9]+,\s*zero,\s*e8,\s*mf8,\s*t[au],\s*m[au]} 3 { target { no-opts "-O0" no-opts "-O1" no-opts "-Os" no-opts "-Oz" no-opts "-funroll-loops" no-opts "-g" no-opts "-O2" } } } } */ +/* { dg-final { scan-assembler-times {vsetvli\s+[a-x0-9]+,\s*zero,\s*e8,\s*mf4,\s*t[au],\s*m[au]} 3 { target { no-opts "-O0" no-opts "-O1" no-opts "-Os" no-opts "-Oz" no-opts "-funroll-loops" no-opts "-g" no-opts "-O2" } } } } */ +/* { dg-final { scan-assembler-times {vsetvli\s+[a-x0-9]+,\s*zero,\s*e8,\s*mf2,\s*t[au],\s*m[au]} 3 { target { no-opts "-O0" no-opts "-O1" no-opts "-Os" no-opts "-Oz" no-opts "-funroll-loops" no-opts "-g" no-opts "-O2" } } } } */ +/* { dg-final { scan-assembler-times {add\ta[0-7],a[0-7],a[0-7]\s+\.L[0-9][0-9]\:\s+vle8\.v\s+(?:v[0-9]|v[1-2][0-9]|v3[0-1]),0\s*\([a-x0-9]+\)} 3 { target { no-opts "-O0" no-opts "-O1" no-opts "-Os" no-opts "-Oz" no-opts "-funroll-loops" no-opts "-g" no-opts "-O2" } } } } */ +/* { dg-final { scan-assembler-times {vsetvli\s+[a-x0-9]+,\s*zero,\s*e16,\s*mf4,\s*t[au],\s*m[au]} 3 { target { no-opts "-O0" no-opts "-O1" no-opts "-Os" no-opts "-Oz" no-opts "-funroll-loops" no-opts "-g" no-opts "-O2" } } } } */ +/* { dg-final { scan-assembler-times {vsetvli\s+[a-x0-9]+,\s*zero,\s*e16,\s*mf2,\s*t[au],\s*m[au]} 3 { target { no-opts "-O0" no-opts "-O1" no-opts "-Os" no-opts "-Oz" no-opts "-funroll-loops" no-opts "-g" no-opts "-O2" } } } } */ +/* { dg-final { scan-assembler-times {add\ta[0-7],a[0-7],a[0-7]\s+\.L[0-9][0-9]\:\s+vle16\.v\s+(?:v[0-9]|v[1-2][0-9]|v3[0-1]),0\s*\([a-x0-9]+\)} 2 { target { no-opts "-O0" no-opts "-O1" no-opts "-Os" no-opts "-Oz" no-opts "-funroll-loops" no-opts "-g" no-opts "-O2" } } } } */ +/* { dg-final { scan-assembler-times {vsetvli\s+[a-x0-9]+,\s*zero,\s*e32,\s*mf2,\s*t[au],\s*m[au]} 3 { target { no-opts "-O0" no-opts "-O1" no-opts "-Os" no-opts "-Oz" no-opts "-funroll-loops" no-opts "-g" no-opts "-O2" } } } } */ +/* { dg-final { scan-assembler-times {add\ta[0-7],a[0-7],a[0-7]\s+\.L[0-9][0-9]\:\s+vle32\.v\s+(?:v[0-9]|v[1-2][0-9]|v3[0-1]),0\s*\([a-x0-9]+\)} 1 { target { no-opts "-O0" no-opts "-O1" no-opts "-Os" no-opts "-Oz" no-opts "-funroll-loops" no-opts "-g" no-opts "-O2" } } } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_bb_prop-10.c b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_bb_prop-10.c index cf6470cea0d3..db8c23ff36d3 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_bb_prop-10.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_bb_prop-10.c @@ -222,9 +222,6 @@ void f6 (int8_t * restrict in, int8_t * restrict out, int n) /* { dg-final { scan-assembler-times {vsetvli\s+[a-x0-9]+,\s*zero,\s*e8,\s*mf8,\s*t[au],\s*m[au]} 3 { target { no-opts "-O0" no-opts "-Os" no-opts "-Oz" no-opts "-funroll-loops" no-opts "-g" no-opts "-O1" } } } } */ /* { dg-final { scan-assembler-times {vsetvli\s+[a-x0-9]+,\s*zero,\s*e8,\s*mf4,\s*t[au],\s*m[au]} 3 { target { no-opts "-O0" no-opts "-Os" no-opts "-Oz" no-opts "-funroll-loops" no-opts "-g" no-opts "-O1" } } } } */ /* { dg-final { scan-assembler-times {vsetvli\s+[a-x0-9]+,\s*zero,\s*e8,\s*mf2,\s*t[au],\s*m[au]} 3 { target { no-opts "-O0" no-opts "-Os" no-opts "-Oz" no-opts "-funroll-loops" no-opts "-g" no-opts "-O1" } } } } */ -/* { dg-final { scan-assembler-times {add\ta[0-7],a[0-7],a[0-7]\s+\.L[0-9][0-9]\:\s+vle8\.v\s+(?:v[0-9]|v[1-2][0-9]|v3[0-1]),0\s*\([a-x0-9]+\)} 3 { target { no-opts "-O0" no-opts "-Os" no-opts "-Oz" no-opts "-funroll-loops" no-opts "-g" no-opts "-O1" } } } } */ /* { dg-final { scan-assembler-times {vsetvli\s+[a-x0-9]+,\s*zero,\s*e16,\s*mf4,\s*t[au],\s*m[au]} 3 { target { no-opts "-O0" no-opts "-Os" no-opts "-Oz" no-opts "-funroll-loops" no-opts "-g" no-opts "-O1" } } } } */ /* { dg-final { scan-assembler-times {vsetvli\s+[a-x0-9]+,\s*zero,\s*e16,\s*mf2,\s*t[au],\s*m[au]} 3 { target { no-opts "-O0" no-opts "-Os" no-opts "-Oz" no-opts "-funroll-loops" no-opts "-g" no-opts "-O1" } } } } */ -/* { dg-final { scan-assembler-times {add\ta[0-7],a[0-7],a[0-7]\s+\.L[0-9][0-9]\:\s+vle16\.v\s+(?:v[0-9]|v[1-2][0-9]|v3[0-1]),0\s*\([a-x0-9]+\)} 2 { target { no-opts "-O0" no-opts "-Os" no-opts "-Oz" no-opts "-funroll-loops" no-opts "-g" no-opts "-O1" } } } } */ /* { dg-final { scan-assembler-times {vsetvli\s+[a-x0-9]+,\s*zero,\s*e32,\s*mf2,\s*t[au],\s*m[au]} 3 { target { no-opts "-O0" no-opts "-Os" no-opts "-Oz" no-opts "-funroll-loops" no-opts "-g" no-opts "-O1" } } } } */ -/* { dg-final { scan-assembler-times {add\ta[0-7],a[0-7],a[0-7]\s+\.L[0-9][0-9][0-9]\:\s+vle32\.v\s+(?:v[0-9]|v[1-2][0-9]|v3[0-1]),0\s*\([a-x0-9]+\)} 1 { target { no-opts "-O0" no-opts "-Os" no-opts "-Oz" no-opts "-funroll-loops" no-opts "-g" no-opts "-O1" } } } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_bb_prop-11.c b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_bb_prop-11.c index 4e2a717197b9..025a6deaea26 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_bb_prop-11.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_bb_prop-11.c @@ -39,5 +39,4 @@ void f (int8_t * restrict in, int8_t * restrict out, int n) } } -/* { dg-final { scan-assembler-times {vsetvli\s+[a-x0-9]+,\s*zero,\s*e32,\s*mf2,\s*t[au],\s*m[au]} 3 { target { no-opts "-O0" no-opts "-Os" no-opts "-Oz" no-opts "-funroll-loops" no-opts "-g" } } } } */ -/* { dg-final { scan-assembler-times {add\ta[0-7],a[0-7],a[0-7]\s+\.L[0-9][0-9]\:\s+vle32\.v\s+(?:v[0-9]|v[1-2][0-9]|v3[0-1]),0\s*\([a-x0-9]+\)} 1 { target { no-opts "-O0" no-opts "-Os" no-opts "-Oz" no-opts "-funroll-loops" no-opts "-g" } } } } */ +/* { dg-final { scan-assembler-times {vsetvli\s+[a-x0-9]+,\s*zero,\s*e32,\s*mf2,\s*t[au],\s*m[au]} 3 { target { no-opts "-O0" no-opts "-O1" no-opts "-Os" no-opts "-Oz" no-opts "-funroll-loops" no-opts "-g" } } } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_bb_prop-12.c b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_bb_prop-12.c index 026b40944c5c..c18aa3cc1a26 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_bb_prop-12.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_bb_prop-12.c @@ -262,5 +262,3 @@ void f7 (int8_t * restrict in, int8_t * restrict out, int n) /* { dg-final { scan-assembler-times {vsetvli\s+[a-x0-9]+,\s*zero,\s*e8,\s*m2,\s*t[au],\s*m[au]} 3 { target { no-opts "-O0" no-opts "-Os" no-opts "-Oz" no-opts "-funroll-loops" no-opts "-g" no-opts "-O1" no-opts "-O1" } } } } */ /* { dg-final { scan-assembler-times {vsetvli\s+[a-x0-9]+,\s*zero,\s*e8,\s*m4,\s*t[au],\s*m[au]} 3 { target { no-opts "-O0" no-opts "-Os" no-opts "-Oz" no-opts "-funroll-loops" no-opts "-g" no-opts "-O1" no-opts "-O1" } } } } */ /* { dg-final { scan-assembler-times {vsetvli\s+[a-x0-9]+,\s*zero,\s*e8,\s*m8,\s*t[au],\s*m[au]} 3 { target { no-opts "-O0" no-opts "-Os" no-opts "-Oz" no-opts "-funroll-loops" no-opts "-g" no-opts "-O1" no-opts "-O1" } } } } */ -/* { dg-final { scan-assembler-times {add\ta[0-7],a[0-7],a[0-7]\s+\.L[0-9][0-9]\:\s+vlm\.v\s+(?:v[0-9]|v[1-2][0-9]|v3[0-1]),0\s*\([a-x0-9]+\)} 5 { target { no-opts "-O0" no-opts "-Os" no-opts "-Oz" no-opts "-funroll-loops" no-opts "-g" no-opts "-O1" no-opts "-O1" } } } } */ -/* { dg-final { scan-assembler-times {add\ta[0-7],a[0-7],a[0-7]\s+\.L[0-9][0-9][0-9]\:\s+vlm\.v\s+(?:v[0-9]|v[1-2][0-9]|v3[0-1]),0\s*\([a-x0-9]+\)} 2 { target { no-opts "-O0" no-opts "-Os" no-opts "-Oz" no-opts "-funroll-loops" no-opts "-g" no-opts "-O1" no-opts "-O1" } } } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_bb_prop-3.c b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_bb_prop-3.c index ca57ecad7cfd..830e91080dd3 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_bb_prop-3.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_bb_prop-3.c @@ -32,4 +32,3 @@ void f (int8_t * restrict in, int8_t * restrict out, int n) } /* { dg-final { scan-assembler-times {vsetvli\s+[a-x0-9]+,\s*zero,\s*e32,\s*mf2,\s*t[au],\s*m[au]} 3 { target { no-opts "-O0" no-opts "-O1" no-opts "-Os" no-opts "-Oz" no-opts "-funroll-loops" no-opts "-g" } } } } */ -/* { dg-final { scan-assembler-times {add\ta[0-7],a[0-7],a[0-7]\s+\.L[0-9][0-9]\:\s+vle32\.v\s+(?:v[0-9]|v[1-2][0-9]|v3[0-1]),0\s*\([a-x0-9]+\)} 1 { target { no-opts "-O0" no-opts "-Os" no-opts "-Oz" no-opts "-funroll-loops" no-opts "-g" } } } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_bb_prop-4.c b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_bb_prop-4.c index fc6161edbbaf..81cdad2ea9d6 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_bb_prop-4.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_bb_prop-4.c @@ -199,12 +199,12 @@ void f7 (int8_t * restrict in, int8_t * restrict out, int n) } } -/* { dg-final { scan-assembler-times {vsetvli\s+[a-x0-9]+,\s*zero,\s*e8,\s*mf8,\s*t[au],\s*m[au]} 3 { target { no-opts "-O0" no-opts "-Os" no-opts "-Oz" no-opts "-funroll-loops" no-opts "-g" no-opts "-O2" } } } } */ -/* { dg-final { scan-assembler-times {vsetvli\s+[a-x0-9]+,\s*zero,\s*e8,\s*mf4,\s*t[au],\s*m[au]} 3 { target { no-opts "-O0" no-opts "-Os" no-opts "-Oz" no-opts "-funroll-loops" no-opts "-g" no-opts "-O2" } } } } */ -/* { dg-final { scan-assembler-times {vsetvli\s+[a-x0-9]+,\s*zero,\s*e8,\s*mf2,\s*t[au],\s*m[au]} 3 { target { no-opts "-O0" no-opts "-Os" no-opts "-Oz" no-opts "-funroll-loops" no-opts "-g" no-opts "-O2" } } } } */ -/* { dg-final { scan-assembler-times {vsetvli\s+[a-x0-9]+,\s*zero,\s*e8,\s*m1,\s*t[au],\s*m[au]} 3 { target { no-opts "-O0" no-opts "-Os" no-opts "-Oz" no-opts "-funroll-loops" no-opts "-g" no-opts "-O2" } } } } */ -/* { dg-final { scan-assembler-times {vsetvli\s+[a-x0-9]+,\s*zero,\s*e8,\s*m2,\s*t[au],\s*m[au]} 3 { target { no-opts "-O0" no-opts "-Os" no-opts "-Oz" no-opts "-funroll-loops" no-opts "-g" no-opts "-O2" } } } } */ -/* { dg-final { scan-assembler-times {vsetvli\s+[a-x0-9]+,\s*zero,\s*e8,\s*m4,\s*t[au],\s*m[au]} 3 { target { no-opts "-O0" no-opts "-Os" no-opts "-Oz" no-opts "-funroll-loops" no-opts "-g" no-opts "-O2" } } } } */ -/* { dg-final { scan-assembler-times {vsetvli\s+[a-x0-9]+,\s*zero,\s*e8,\s*m8,\s*t[au],\s*m[au]} 3 { target { no-opts "-O0" no-opts "-Os" no-opts "-Oz" no-opts "-funroll-loops" no-opts "-g" no-opts "-O2" } } } } */ -/* { dg-final { scan-assembler-times {add\ta[0-7],a[0-7],a[0-7]\s+\.L[0-9][0-9]\:\s+vlm\.v\s+(?:v[0-9]|v[1-2][0-9]|v3[0-1]),0\s*\([a-x0-9]+\)} 6 { target { no-opts "-O0" no-opts "-Os" no-opts "-Oz" no-opts "-funroll-loops" no-opts "-g" no-opts "-O2" } } } } */ -/* { dg-final { scan-assembler-times {add\ta[0-7],a[0-7],a[0-7]\s+\.L[0-9][0-9][0-9]\:\s+vlm\.v\s+(?:v[0-9]|v[1-2][0-9]|v3[0-1]),0\s*\([a-x0-9]+\)} 1 { target { no-opts "-O0" no-opts "-Os" no-opts "-Oz" no-opts "-funroll-loops" no-opts "-g" no-opts "-O2" } } } } */ +/* { dg-final { scan-assembler-times {vsetvli\s+[a-x0-9]+,\s*zero,\s*e8,\s*mf8,\s*t[au],\s*m[au]} 3 { target { no-opts "-O0" no-opts "-O1" no-opts "-Os" no-opts "-Oz" no-opts "-funroll-loops" no-opts "-g" no-opts "-O2" } } } } */ +/* { dg-final { scan-assembler-times {vsetvli\s+[a-x0-9]+,\s*zero,\s*e8,\s*mf4,\s*t[au],\s*m[au]} 3 { target { no-opts "-O0" no-opts "-O1" no-opts "-Os" no-opts "-Oz" no-opts "-funroll-loops" no-opts "-g" no-opts "-O2" } } } } */ +/* { dg-final { scan-assembler-times {vsetvli\s+[a-x0-9]+,\s*zero,\s*e8,\s*mf2,\s*t[au],\s*m[au]} 3 { target { no-opts "-O0" no-opts "-O1" no-opts "-Os" no-opts "-Oz" no-opts "-funroll-loops" no-opts "-g" no-opts "-O2" } } } } */ +/* { dg-final { scan-assembler-times {vsetvli\s+[a-x0-9]+,\s*zero,\s*e8,\s*m1,\s*t[au],\s*m[au]} 3 { target { no-opts "-O0" no-opts "-O1" no-opts "-Os" no-opts "-Oz" no-opts "-funroll-loops" no-opts "-g" no-opts "-O2" } } } } */ +/* { dg-final { scan-assembler-times {vsetvli\s+[a-x0-9]+,\s*zero,\s*e8,\s*m2,\s*t[au],\s*m[au]} 3 { target { no-opts "-O0" no-opts "-O1" no-opts "-Os" no-opts "-Oz" no-opts "-funroll-loops" no-opts "-g" no-opts "-O2" } } } } */ +/* { dg-final { scan-assembler-times {vsetvli\s+[a-x0-9]+,\s*zero,\s*e8,\s*m4,\s*t[au],\s*m[au]} 3 { target { no-opts "-O0" no-opts "-O1" no-opts "-Os" no-opts "-Oz" no-opts "-funroll-loops" no-opts "-g" no-opts "-O2" } } } } */ +/* { dg-final { scan-assembler-times {vsetvli\s+[a-x0-9]+,\s*zero,\s*e8,\s*m8,\s*t[au],\s*m[au]} 3 { target { no-opts "-O0" no-opts "-O1" no-opts "-Os" no-opts "-Oz" no-opts "-funroll-loops" no-opts "-g" no-opts "-O2" } } } } */ +/* { dg-final { scan-assembler-times {add\ta[0-7],a[0-7],a[0-7]\s+\.L[0-9][0-9]\:\s+vlm\.v\s+(?:v[0-9]|v[1-2][0-9]|v3[0-1]),0\s*\([a-x0-9]+\)} 6 { target { no-opts "-O0" no-opts "-O1" no-opts "-Os" no-opts "-Oz" no-opts "-funroll-loops" no-opts "-g" no-opts "-O2" } } } } */ +/* { dg-final { scan-assembler-times {add\ta[0-7],a[0-7],a[0-7]\s+\.L[0-9][0-9][0-9]\:\s+vlm\.v\s+(?:v[0-9]|v[1-2][0-9]|v3[0-1]),0\s*\([a-x0-9]+\)} 1 { target { no-opts "-O0" no-opts "-O1" no-opts "-Os" no-opts "-Oz" no-opts "-funroll-loops" no-opts "-g" no-opts "-O2" } } } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_bb_prop-9.c b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_bb_prop-9.c index a01b39184047..8dbc41b8a5b8 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_bb_prop-9.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_bb_prop-9.c @@ -222,9 +222,6 @@ void f6 (int8_t * restrict in, int8_t * restrict out, int n) /* { dg-final { scan-assembler-times {vsetvli\s+[a-x0-9]+,\s*zero,\s*e8,\s*mf8,\s*t[au],\s*m[au]} 3 { target { no-opts "-O0" no-opts "-Os" no-opts "-Oz" no-opts "-funroll-loops" no-opts "-g" no-opts "-O1" } } } } */ /* { dg-final { scan-assembler-times {vsetvli\s+[a-x0-9]+,\s*zero,\s*e8,\s*mf4,\s*t[au],\s*m[au]} 3 { target { no-opts "-O0" no-opts "-Os" no-opts "-Oz" no-opts "-funroll-loops" no-opts "-g" no-opts "-O1" } } } } */ /* { dg-final { scan-assembler-times {vsetvli\s+[a-x0-9]+,\s*zero,\s*e8,\s*mf2,\s*t[au],\s*m[au]} 3 { target { no-opts "-O0" no-opts "-Os" no-opts "-Oz" no-opts "-funroll-loops" no-opts "-g" no-opts "-O1" } } } } */ -/* { dg-final { scan-assembler-times {add\ta[0-7],a[0-7],a[0-7]\s+\.L[0-9][0-9]\:\s+vle8\.v\s+(?:v[0-9]|v[1-2][0-9]|v3[0-1]),0\s*\([a-x0-9]+\)} 3 { target { no-opts "-O0" no-opts "-Os" no-opts "-Oz" no-opts "-funroll-loops" no-opts "-g" no-opts "-O1" } } } } */ /* { dg-final { scan-assembler-times {vsetvli\s+[a-x0-9]+,\s*zero,\s*e16,\s*mf4,\s*t[au],\s*m[au]} 3 { target { no-opts "-O0" no-opts "-Os" no-opts "-Oz" no-opts "-funroll-loops" no-opts "-g" no-opts "-O1" } } } } */ /* { dg-final { scan-assembler-times {vsetvli\s+[a-x0-9]+,\s*zero,\s*e16,\s*mf2,\s*t[au],\s*m[au]} 3 { target { no-opts "-O0" no-opts "-Os" no-opts "-Oz" no-opts "-funroll-loops" no-opts "-g" no-opts "-O1" } } } } */ -/* { dg-final { scan-assembler-times {add\ta[0-7],a[0-7],a[0-7]\s+\.L[0-9][0-9]\:\s+vle16\.v\s+(?:v[0-9]|v[1-2][0-9]|v3[0-1]),0\s*\([a-x0-9]+\)} 2 { target { no-opts "-O0" no-opts "-Os" no-opts "-Oz" no-opts "-funroll-loops" no-opts "-g" no-opts "-O1" } } } } */ /* { dg-final { scan-assembler-times {vsetvli\s+[a-x0-9]+,\s*zero,\s*e32,\s*mf2,\s*t[au],\s*m[au]} 3 { target { no-opts "-O0" no-opts "-Os" no-opts "-Oz" no-opts "-funroll-loops" no-opts "-g" no-opts "-O1" } } } } */ -/* { dg-final { scan-assembler-times {add\ta[0-7],a[0-7],a[0-7]\s+\.L[0-9][0-9][0-9]\:\s+vle32\.v\s+(?:v[0-9]|v[1-2][0-9]|v3[0-1]),0\s*\([a-x0-9]+\)} 1 { target { no-opts "-O0" no-opts "-Os" no-opts "-Oz" no-opts "-funroll-loops" no-opts "-g" no-opts "-O1" } } } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_conflict-13.c b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_conflict-13.c new file mode 100644 index 000000000000..d3676900eae8 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_conflict-13.c @@ -0,0 +1,20 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv32gcv -mabi=ilp32 -fno-tree-vectorize -fno-schedule-insns -fno-schedule-insns2" } */ + +#include "riscv_vector.h" + +void f (int32_t * restrict in, int32_t * restrict out, size_t n, size_t cond, size_t cond2) +{ + for (size_t i = 0; i < n; i++) + { + if (i > cond) { + vint8mf8_t v = *(vint8mf8_t*)(in + i + 100); + *(vint8mf8_t*)(out + i + 100) = v; + } else { + vbool1_t v = *(vbool1_t*)(in + i + 400); + *(vbool1_t*)(out + i + 400) = v; + } + } +} + +/* { dg-final { scan-assembler-times {vsetvli} 2 { target { no-opts "-O0" no-opts "-Os" no-opts "-Oz" no-opts "-funroll-loops" no-opts "-g" } } } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_conflict-7.c b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_conflict-7.c index 60ad108666f8..dd0d51da834d 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_conflict-7.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_conflict-7.c @@ -20,6 +20,5 @@ void f (int32_t * restrict in, int32_t * restrict out, size_t n, size_t cond, si } } -/* { dg-final { scan-assembler-times {vsetvli} 4 { target { no-opts "-O0" no-opts "-O1" no-opts "-Os" no-opts "-Oz" no-opts "-funroll-loops" no-opts "-g" } } } } */ -/* { dg-final { scan-assembler-times {j\s+\.L[0-9]+\s+\.L[0-9]+:\s+vlm\.v} 1 { target { no-opts "-O0" no-opts "-O1" no-opts "-Os" no-opts "-Oz" no-opts "-funroll-loops" no-opts "-g" } } } } */ +/* { dg-final { scan-assembler-times {vsetvli} 5 { target { no-opts "-O0" no-opts "-O1" no-opts "-Os" no-opts "-Oz" no-opts "-funroll-loops" no-opts "-g" } } } } */ /* { dg-final { scan-assembler-times {vsetvli\s+[a-x0-9]+,\s*zero,\s*e8,\s*m8,\s*t[au],\s*m[au]} 3 { target { no-opts "-O0" no-opts "-O1" no-opts "-Os" no-opts "-Oz" no-opts "-funroll-loops" no-opts "-g" } } } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_conflict-8.c b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_conflict-8.c index 7b9574cc332d..fbca9b00e54e 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_conflict-8.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_conflict-8.c @@ -21,7 +21,6 @@ void f (int32_t * restrict in, int32_t * restrict out, size_t n, size_t cond, si } /* { dg-final { scan-assembler-times {vsetvli} 5 { target { no-opts "-O0" no-opts "-O1" no-opts "-Os" no-opts "-Oz" no-opts "-funroll-loops" no-opts "-g" } } } } */ -/* { dg-final { scan-assembler-times {j\s+\.L[0-9]+\s+\.L[0-9]+:\s+vlm\.v} 1 { target { no-opts "-O0" no-opts "-O1" no-opts "-Os" no-opts "-Oz" no-opts "-funroll-loops" no-opts "-g" } } } } */ /* { dg-final { scan-assembler-times {vsetvli\s+[a-x0-9]+,\s*zero,\s*e8,\s*m8,\s*t[au],\s*m[au]} 3 { target { no-opts "-O0" no-opts "-O1" no-opts "-Os" no-opts "-Oz" no-opts "-funroll-loops" no-opts "-g" } } } } */ /* { dg-final { scan-assembler-times {vsetvli\s+[a-x0-9]+,\s*zero,\s*e8,\s*mf8,\s*t[au],\s*m[au]} 1 { target { no-opts "-O0" no-opts "-O1" no-opts "-Os" no-opts "-Oz" no-opts "-funroll-loops" no-opts "-g" } } } } */ /* { dg-final { scan-assembler-times {vsetvli\s+[a-x0-9]+,\s*zero,\s*e16,\s*mf2,\s*t[au],\s*m[au]} 1 { target { no-opts "-O0" no-opts "-O1" no-opts "-Os" no-opts "-Oz" no-opts "-funroll-loops" no-opts "-g" } } } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-1.c b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-1.c index eebc6c0862e8..7648b8a2dc83 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-1.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-1.c @@ -23,4 +23,4 @@ void f (void * restrict in, void * restrict out, int n) } /* { dg-final { scan-assembler-times {vsetvli\s+[a-x0-9]+,\s*zero,\s*e8,\s*mf8,\s*t[au],\s*m[au]} 1 { target { no-opts "-O0" no-opts "-O1" no-opts "-Os" no-opts "-Oz" no-opts "-flto" no-opts "-g" } } } } */ -/* { dg-final { scan-assembler-times {vsetvli} 1 { target { no-opts "-O0" no-opts "-funroll-loops" no-opts "-Os" no-opts "-Oz" no-opts "-flto" no-opts "-g" } } } } */ +/* { dg-final { scan-assembler-times {vsetvli} 1 { target { no-opts "-O0" no-opts "-O1" no-opts "-funroll-loops" no-opts "-Os" no-opts "-Oz" no-opts "-flto" no-opts "-g" } } } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-14.c b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-14.c index f416a231f0e0..1fc97f8b6f2d 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-14.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-14.c @@ -6,7 +6,7 @@ void f (void * restrict in, void * restrict out, int32_t * a, int32_t * b, int n, int cond) { for (int i = 0; i < n; i++) { - vint16mf4_t v; + vint16mf4_t v = __riscv_vmv_v_x_i16mf4 (0, __riscv_vsetvlmax_e16mf4 ()); *(vint16mf4_t*)(out + i + 700) = v; } for (int i = 0; i < n; i++) { @@ -19,15 +19,15 @@ void f (void * restrict in, void * restrict out, int32_t * a, int32_t * b, int n a[i] = a[i] - b[i]; } for (int i = 0; i < n; i++) { - vint32mf2_t v; + vint32mf2_t v = __riscv_vmv_v_x_i32mf2 (0, __riscv_vsetvlmax_e32mf2 ()); *(vint32mf2_t*)(out + i + 7000) = v; } for (int i = 0; i < n; i++) { - vint64m1_t v; + vint64m1_t v = __riscv_vmv_v_x_i64m1 (0, __riscv_vsetvlmax_e64m1 ()); *(vint64m1_t*)(out + i + 8000) = v; } for (int i = 0; i < n; i++) { - vint8mf8_t v; + vint8mf8_t v = __riscv_vmv_v_x_i8mf8 (0, __riscv_vsetvlmax_e8mf8 ()); *(vint8mf8_t*)(out + i + 9000) = v; } } @@ -36,4 +36,4 @@ void f (void * restrict in, void * restrict out, int32_t * a, int32_t * b, int n /* { dg-final { scan-assembler-times {vsetvli\s+zero,\s*zero,\s*e32,\s*mf2,\s*t[au],\s*m[au]} 1 { target { no-opts "-O0" no-opts "-funroll-loops" no-opts "-O1" no-opts "-Os" no-opts "-Oz" no-opts "-flto" no-opts "-g" } } } } */ /* { dg-final { scan-assembler-times {vsetvli\s+zero,\s*zero,\s*e64,\s*m1,\s*t[au],\s*m[au]} 1 { target { no-opts "-O0" no-opts "-funroll-loops" no-opts "-O1" no-opts "-Os" no-opts "-Oz" no-opts "-flto" no-opts "-g" } } } } */ /* { dg-final { scan-assembler-times {vsetvli\s+zero,\s*zero,\s*e8,\s*mf8,\s*t[au],\s*m[au]} 1 { target { no-opts "-O0" no-opts "-funroll-loops" no-opts "-O1" no-opts "-Os" no-opts "-Oz" no-opts "-flto" no-opts "-g" } } } } */ -/* { dg-final { scan-assembler-times {vsetvli} 4 { target { no-opts "-O0" no-opts "-funroll-loops" no-opts "-Os" no-opts "-Oz" no-opts "-flto" no-opts "-g" } } } } */ +/* { dg-final { scan-assembler-times {vsetvli} 4 { target { no-opts "-O0" "-O1" no-opts "-funroll-loops" no-opts "-Os" no-opts "-Oz" no-opts "-flto" no-opts "-g" } } } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-15.c b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-15.c index a39b48ccb998..f3b37661fbeb 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-15.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-15.c @@ -6,7 +6,7 @@ void f (void * restrict in, void * restrict out, int32_t * a, int32_t * b, int n, int cond) { for (int i = 0; i < n; i++) { - vint16mf4_t v; + vint16mf4_t v = __riscv_vmv_v_x_i16mf4 (0, __riscv_vsetvlmax_e16mf4 ()); *(vint16mf4_t*)(out + i + 700) = v; } for (int i = 0; i < n; i++) { @@ -19,27 +19,27 @@ void f (void * restrict in, void * restrict out, int32_t * a, int32_t * b, int n a[i] = a[i] - b[i]; } for (int i = 0; i < n; i++) { - vint32mf2_t v; + vint32mf2_t v = __riscv_vmv_v_x_i32mf2 (0, __riscv_vsetvlmax_e32mf2 ()); *(vint32mf2_t*)(out + i + 7000) = v; } for (int i = 0; i < n; i++) { - vint16mf2_t v; + vint16mf2_t v = __riscv_vmv_v_x_i16mf2 (0, __riscv_vsetvlmax_e16mf2 ()); *(vint16mf2_t*)(out + i + 777) = v; } for (int i = 0; i < n; i++) { - vint64m1_t v; + vint64m1_t v = __riscv_vmv_v_x_i64m1 (0, __riscv_vsetvlmax_e64m1 ()); *(vint64m1_t*)(out + i + 8000) = v; } for (int i = 0; i < n; i++) { - vfloat32mf2_t v; + vfloat32mf2_t v = __riscv_vfmv_v_f_f32mf2 (0, __riscv_vsetvlmax_e32mf2 ()); *(vfloat32mf2_t*)(out + i + 7777) = v; } for (int i = 0; i < n; i++) { - vuint16mf2_t v; + vuint16mf2_t v = __riscv_vmv_v_x_u16mf2 (0, __riscv_vsetvlmax_e16mf2 ()); *(vuint16mf2_t*)(out + i + 888) = v; } for (int i = 0; i < n; i++) { - vint8mf8_t v; + vint8mf8_t v = __riscv_vmv_v_x_i8mf8 (0, __riscv_vsetvlmax_e8mf8 ()); *(vint8mf8_t*)(out + i + 9000) = v; } } diff --git a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-16.c b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-16.c index 1ab92df0fdca..a1587e7e20ff 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-16.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-16.c @@ -52,7 +52,7 @@ void f (void * restrict in, void * restrict out, int32_t * a, int32_t * b, int n } /* { dg-final { scan-assembler-times {vsetvli\s+[a-x0-9]+,\s*zero,\s*e16,\s*mf4,\s*t[au],\s*m[au]} 1 { target { no-opts "-O0" no-opts "-funroll-loops" no-opts "-O1" no-opts "-Os" no-opts "-Oz" no-opts "-flto" no-opts "-g" } } } } */ -/* { dg-final { scan-assembler-times {vsetvli\s+zero,\s*zero,\s*e32,\s*mf2,\s*t[au],\s*m[au]} 2 { target { no-opts "-O0" no-opts "-funroll-loops" no-opts "-O1" no-opts "-Os" no-opts "-Oz" no-opts "-flto" no-opts "-g" } } } } */ +/* { dg-final { scan-assembler-times {vsetvli\s+zero,\s*zero} 3 { target { no-opts "-O0" no-opts "-funroll-loops" no-opts "-O1" no-opts "-Os" no-opts "-Oz" no-opts "-flto" no-opts "-g" } } } } */ /* { dg-final { scan-assembler-times {vsetvli\s+[a-x0-9]+,\s*zero,\s*e16,\s*mf2,\s*t[au],\s*m[au]} 2 { target { no-opts "-O0" no-opts "-funroll-loops" no-opts "-O1" no-opts "-Os" no-opts "-Oz" no-opts "-flto" no-opts "-g" } } } } */ /* { dg-final { scan-assembler-times {vsetvli\s+[a-x0-9]+,\s*zero,\s*e64,\s*m1,\s*t[au],\s*m[au]} 1 { target { no-opts "-O0" no-opts "-funroll-loops" no-opts "-O1" no-opts "-Os" no-opts "-Oz" no-opts "-flto" no-opts "-g" } } } } */ /* { dg-final { scan-assembler-times {vsetvli\s+zero,\s*zero,\s*e8,\s*mf8,\s*t[au],\s*m[au]} 1 { target { no-opts "-O0" no-opts "-funroll-loops" no-opts "-O1" no-opts "-Os" no-opts "-Oz" no-opts "-flto" no-opts "-g" } } } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vsetvl-11.c b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vsetvl-11.c index 3ef0fdcb66d3..8936d3be6a7a 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vsetvl-11.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vsetvl-11.c @@ -18,4 +18,4 @@ void foo(int32_t *in1, int32_t *in2, int32_t *in3, int32_t *out, size_t n, int c } } -/* { dg-final { scan-assembler-times {vsetvli} 2 { target { no-opts "-O0" no-opts "-g" no-opts "-funroll-loops" } } } } */ +/* { dg-final { scan-assembler-times {vsetvli} 2 { target { no-opts "-O0" no-opts "-Os" no-opts "-g" no-opts "-funroll-loops" } } } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vsetvl-23.c b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vsetvl-23.c index f3420be8ab68..fc4015e66b8d 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vsetvl-23.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vsetvl-23.c @@ -33,5 +33,4 @@ void f(int8_t *base, int8_t *out, size_t vl, size_t m, size_t k) { /* { dg-final { scan-assembler-times {slli\s+[a-x0-9]+,\s*[a-x0-9]+,\s*4} 1 { target { no-opts "-O0" no-opts "-g" no-opts "-funroll-loops" } } } } */ /* { dg-final { scan-assembler-times {srli\s+[a-x0-9]+,\s*[a-x0-9]+,\s*8} 1 { target { no-opts "-O0" no-opts "-g" no-opts "-funroll-loops" } } } } */ -/* { dg-final { scan-assembler-times {vsetvli} 5 { target { no-opts "-O0" no-opts "-Os" no-opts "-Oz" no-opts "-g" no-opts "-funroll-loops" } } } } */ -/* { dg-final { scan-assembler-times {vsetvli\s+zero,\s*[a-x0-9]+,\s*e8,\s*mf8,\s*tu,\s*m[au]} 5 { target { no-opts "-O0" no-opts "-Os" no-opts "-Oz" no-opts "-g" no-opts "-funroll-loops" } } } } */ +/* { dg-final { scan-assembler-times {vsetvli} 6 { target { no-opts "-O0" no-opts "-Os" no-opts "-Oz" no-opts "-g" no-opts "-funroll-loops" } } } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vsetvl-24.c b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vsetvl-24.c new file mode 100644 index 000000000000..1703c739f5e4 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vsetvl-24.c @@ -0,0 +1,11 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gcv -mabi=lp64d" } */ + +#include + +size_t foo () +{ + return __riscv_vsetvlmax_e8m1 (); +} + +/* { dg-final { scan-assembler-times {\tvsetvli\t[a-x0-9]+,zero,e8,m1,ta,ma} 1 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vsetvlmax-2.c b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vsetvlmax-2.c index 482a48314e29..853ffee14145 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vsetvlmax-2.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vsetvlmax-2.c @@ -17,5 +17,5 @@ void foo(int32_t *in1, int32_t *in2, int32_t *in3, int32_t *out, size_t n) { } } -/* { dg-final { scan-assembler-times {vsetvli\s+[a-x0-9]+,\s*zero,\s*e32,\s*m1,\s*tu,\s*m[au]} 1 { target { no-opts "-O0" no-opts "-g" no-opts "-funroll-loops" } } } } */ -/* { dg-final { scan-assembler-times {vsetvli} 1 { target { no-opts "-O0" no-opts "-g" no-opts "-funroll-loops" } } } } */ +/* { dg-final { scan-assembler-times {vsetvli\s+[a-x0-9]+,\s*zero,\s*e32,\s*m1,\s*tu,\s*m[au]} 1 { target { no-opts "-O0" no-opts "-Os" no-opts "-g" no-opts "-funroll-loops" } } } } */ +/* { dg-final { scan-assembler-times {vsetvli} 1 { target { no-opts "-O0" no-opts "-Os" no-opts "-g" no-opts "-funroll-loops" } } } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vsetvlmax-4.c b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vsetvlmax-4.c index 3b9865e3bab9..2a535b5f2a83 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vsetvlmax-4.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vsetvlmax-4.c @@ -17,5 +17,5 @@ void foo(int32_t *in1, int32_t *in2, int32_t *in3, int32_t *out, size_t n) { } } -/* { dg-final { scan-assembler-times {vsetvli\s+[a-x0-9]+,\s*zero,\s*e32,\s*m1,\s*tu,\s*m[au]} 1 { target { no-opts "-O0" no-opts "-g" no-opts "-funroll-loops" } } } } */ -/* { dg-final { scan-assembler-times {vsetvli} 1 { target { no-opts "-O0" no-opts "-g" no-opts "-funroll-loops" } } } } */ +/* { dg-final { scan-assembler-times {vsetvli\s+[a-x0-9]+,\s*zero,\s*e32,\s*m1,\s*tu,\s*m[au]} 1 { target { no-opts "-O0" no-opts "-Os" no-opts "-g" no-opts "-funroll-loops" } } } } */ +/* { dg-final { scan-assembler-times {vsetvli} 1 { target { no-opts "-O0" no-opts "-Os" no-opts "-g" no-opts "-funroll-loops" } } } } */ diff --git a/gcc/testsuite/gcc.target/riscv/stack_save_restore_1.c b/gcc/testsuite/gcc.target/riscv/stack_save_restore_1.c index 255ce5f40c9e..d8b0668a820f 100644 --- a/gcc/testsuite/gcc.target/riscv/stack_save_restore_1.c +++ b/gcc/testsuite/gcc.target/riscv/stack_save_restore_1.c @@ -8,15 +8,15 @@ float getf(); /* ** bar: ** call t0,__riscv_save_(3|4) -** addi sp,sp,-2032 +** addi sp,sp,-[0-9]+ ** ... -** li t0,-12288 +** li t0,-[0-9]+ ** add sp,sp,t0 ** ... -** li t0,12288 +** li t0,[0-9]+ ** add sp,sp,t0 ** ... -** addi sp,sp,2032 +** addi sp,sp,[0-9]+ ** tail __riscv_restore_(3|4) */ int bar() diff --git a/gcc/testsuite/gcc.target/riscv/stack_save_restore_2.c b/gcc/testsuite/gcc.target/riscv/stack_save_restore_2.c index 4ce5e0118a49..4c549cb11aee 100644 --- a/gcc/testsuite/gcc.target/riscv/stack_save_restore_2.c +++ b/gcc/testsuite/gcc.target/riscv/stack_save_restore_2.c @@ -8,15 +8,15 @@ float getf(); /* ** bar: ** call t0,__riscv_save_(3|4) -** addi sp,sp,-2032 +** addi sp,sp,-[0-9]+ ** ... -** li t0,-12288 +** li t0,-[0-9]+ ** add sp,sp,t0 ** ... -** li t0,12288 +** li t0,[0-9]+ ** add sp,sp,t0 ** ... -** addi sp,sp,2032 +** addi sp,sp,[0-9]+ ** tail __riscv_restore_(3|4) */ int bar() diff --git a/gcc/testsuite/gcc.target/riscv/xtheadba.c b/gcc/testsuite/gcc.target/riscv/xtheadba.c index 14cdb1ffe2eb..64ad56011884 100644 --- a/gcc/testsuite/gcc.target/riscv/xtheadba.c +++ b/gcc/testsuite/gcc.target/riscv/xtheadba.c @@ -3,7 +3,7 @@ /* { dg-options "-march=rv64gc_xtheadba" { target { rv64 } } } */ #ifndef __riscv_xtheadba -#error Feature macro not defined +#error "Feature macro not defined" #endif int diff --git a/gcc/testsuite/gcc.target/riscv/xtheadbb.c b/gcc/testsuite/gcc.target/riscv/xtheadbb.c index 66988abf2213..803111b03fb2 100644 --- a/gcc/testsuite/gcc.target/riscv/xtheadbb.c +++ b/gcc/testsuite/gcc.target/riscv/xtheadbb.c @@ -3,7 +3,7 @@ /* { dg-options "-march=rv64gc_xtheadbb" { target { rv64 } } } */ #ifndef __riscv_xtheadbb -#error Feature macro not defined +#error "Feature macro not defined" #endif int diff --git a/gcc/testsuite/gcc.target/riscv/xtheadbs.c b/gcc/testsuite/gcc.target/riscv/xtheadbs.c index 808d7378a7be..ad9fba525971 100644 --- a/gcc/testsuite/gcc.target/riscv/xtheadbs.c +++ b/gcc/testsuite/gcc.target/riscv/xtheadbs.c @@ -3,7 +3,7 @@ /* { dg-options "-march=rv64gc_xtheadbs" { target { rv64 } } } */ #ifndef __riscv_xtheadbs -#error Feature macro not defined +#error "Feature macro not defined" #endif int diff --git a/gcc/testsuite/gcc.target/riscv/xtheadcmo.c b/gcc/testsuite/gcc.target/riscv/xtheadcmo.c index eab8fef421cd..fc13754fe521 100644 --- a/gcc/testsuite/gcc.target/riscv/xtheadcmo.c +++ b/gcc/testsuite/gcc.target/riscv/xtheadcmo.c @@ -3,7 +3,7 @@ /* { dg-options "-march=rv64gc_xtheadcmo" { target { rv64 } } } */ #ifndef __riscv_xtheadcmo -#error Feature macro not defined +#error "Feature macro not defined" #endif int diff --git a/gcc/testsuite/gcc.target/riscv/xtheadcondmov-indirect.c b/gcc/testsuite/gcc.target/riscv/xtheadcondmov-indirect.c index 8292999d0c7c..c3253ba5239f 100644 --- a/gcc/testsuite/gcc.target/riscv/xtheadcondmov-indirect.c +++ b/gcc/testsuite/gcc.target/riscv/xtheadcondmov-indirect.c @@ -1,6 +1,6 @@ /* { dg-do compile } */ -/* { dg-options "-march=rv32gc_xtheadcondmov" { target { rv32 } } } */ -/* { dg-options "-march=rv64gc_xtheadcondmov" { target { rv64 } } } */ +/* { dg-options "-march=rv32gc_xtheadcondmov -fno-sched-pressure" { target { rv32 } } } */ +/* { dg-options "-march=rv64gc_xtheadcondmov -fno-sched-pressure" { target { rv64 } } } */ /* { dg-skip-if "" { *-*-* } {"-O0" "-Os" "-Og" "-Oz" "-flto" } } */ /* { dg-final { check-function-bodies "**" "" } } */ diff --git a/gcc/testsuite/gcc.target/riscv/xtheadcondmov.c b/gcc/testsuite/gcc.target/riscv/xtheadcondmov.c index a239c3f9f46e..ad8a777ab2cc 100644 --- a/gcc/testsuite/gcc.target/riscv/xtheadcondmov.c +++ b/gcc/testsuite/gcc.target/riscv/xtheadcondmov.c @@ -3,7 +3,7 @@ /* { dg-options "-march=rv64gc_xtheadcondmov" { target { rv64 } } } */ #ifndef __riscv_xtheadcondmov -#error Feature macro not defined +#error "Feature macro not defined" #endif int diff --git a/gcc/testsuite/gcc.target/riscv/xtheadfmemidx.c b/gcc/testsuite/gcc.target/riscv/xtheadfmemidx.c index e450c5e5c5ac..1617d9475942 100644 --- a/gcc/testsuite/gcc.target/riscv/xtheadfmemidx.c +++ b/gcc/testsuite/gcc.target/riscv/xtheadfmemidx.c @@ -3,7 +3,7 @@ /* { dg-options "-march=rv64gc_xtheadfmemidx" { target { rv64 } } } */ #ifndef __riscv_xtheadfmemidx -#error Feature macro not defined +#error "Feature macro not defined" #endif int diff --git a/gcc/testsuite/gcc.target/riscv/xtheadfmv.c b/gcc/testsuite/gcc.target/riscv/xtheadfmv.c index e97e8f461f6e..f0558d95cb94 100644 --- a/gcc/testsuite/gcc.target/riscv/xtheadfmv.c +++ b/gcc/testsuite/gcc.target/riscv/xtheadfmv.c @@ -3,7 +3,7 @@ /* { dg-options "-march=rv64gc_xtheadfmv" { target { rv64 } } } */ #ifndef __riscv_xtheadfmv -#error Feature macro not defined +#error "Feature macro not defined" #endif int diff --git a/gcc/testsuite/gcc.target/riscv/xtheadint.c b/gcc/testsuite/gcc.target/riscv/xtheadint.c index ee6989a380ec..c9f45d577423 100644 --- a/gcc/testsuite/gcc.target/riscv/xtheadint.c +++ b/gcc/testsuite/gcc.target/riscv/xtheadint.c @@ -3,7 +3,7 @@ /* { dg-options "-march=rv64gc_xtheadint" { target { rv64 } } } */ #ifndef __riscv_xtheadint -#error Feature macro not defined +#error "Feature macro not defined" #endif int diff --git a/gcc/testsuite/gcc.target/riscv/xtheadmac.c b/gcc/testsuite/gcc.target/riscv/xtheadmac.c index 7c635407b310..aeb3cb034417 100644 --- a/gcc/testsuite/gcc.target/riscv/xtheadmac.c +++ b/gcc/testsuite/gcc.target/riscv/xtheadmac.c @@ -3,7 +3,7 @@ /* { dg-options "-march=rv64gc_xtheadmac" { target { rv64 } } } */ #ifndef __riscv_xtheadmac -#error Feature macro not defined +#error "Feature macro not defined" #endif int diff --git a/gcc/testsuite/gcc.target/riscv/xtheadmemidx.c b/gcc/testsuite/gcc.target/riscv/xtheadmemidx.c index 076eab00f54c..a4716acc0409 100644 --- a/gcc/testsuite/gcc.target/riscv/xtheadmemidx.c +++ b/gcc/testsuite/gcc.target/riscv/xtheadmemidx.c @@ -3,7 +3,7 @@ /* { dg-options "-march=rv64gc_xtheadmemidx" { target { rv64 } } } */ #ifndef __riscv_xtheadmemidx -#error Feature macro not defined +#error "Feature macro not defined" #endif int diff --git a/gcc/testsuite/gcc.target/riscv/xtheadmempair.c b/gcc/testsuite/gcc.target/riscv/xtheadmempair.c index 5135d2175dc6..de88d63ed5b3 100644 --- a/gcc/testsuite/gcc.target/riscv/xtheadmempair.c +++ b/gcc/testsuite/gcc.target/riscv/xtheadmempair.c @@ -3,7 +3,7 @@ /* { dg-options "-march=rv64gc_xtheadmempair" { target { rv64 } } } */ #ifndef __riscv_xtheadmempair -#error Feature macro not defined +#error "Feature macro not defined" #endif int diff --git a/gcc/testsuite/gcc.target/riscv/xtheadsync.c b/gcc/testsuite/gcc.target/riscv/xtheadsync.c index 835d60c96e9d..ddda51545f15 100644 --- a/gcc/testsuite/gcc.target/riscv/xtheadsync.c +++ b/gcc/testsuite/gcc.target/riscv/xtheadsync.c @@ -3,7 +3,7 @@ /* { dg-options "-march=rv64gc_xtheadsync" { target { rv64 } } } */ #ifndef __riscv_xtheadsync -#error Feature macro not defined +#error "Feature macro not defined" #endif int diff --git a/gcc/testsuite/gcc.target/riscv/zawrs.c b/gcc/testsuite/gcc.target/riscv/zawrs.c index 0b7e26623439..d61a17b7a487 100644 --- a/gcc/testsuite/gcc.target/riscv/zawrs.c +++ b/gcc/testsuite/gcc.target/riscv/zawrs.c @@ -3,7 +3,7 @@ /* { dg-options "-march=rv32gc_zawrs" { target { rv32 } } } */ #ifndef __riscv_zawrs -#error Feature macro not defined +#error "Feature macro not defined" #endif int diff --git a/gcc/testsuite/gcc.target/riscv/zbb-rol-ror-08.c b/gcc/testsuite/gcc.target/riscv/zbb-rol-ror-08.c new file mode 100644 index 000000000000..30696f3bb32f --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/zbb-rol-ror-08.c @@ -0,0 +1,25 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gc_zbb -mabi=lp64d -fno-lto -O2" } */ +/* { dg-skip-if "" { *-*-* } { "-g" } } */ +/* { dg-final { check-function-bodies "**" "" } } */ +/* { dg-final { scan-assembler-not "and" } } */ + +/* +**foo1: +** rori a0,a0,32 +** ret +*/ +unsigned long foo1(unsigned long rotate) +{ + return (rotate << 32) | (rotate >> 32); +} + +/* +**foo2: +** roriw a0,a0,16 +** ret +*/ +unsigned int foo2(unsigned int rotate) +{ + return (rotate << 16) | (rotate >> 16); +} diff --git a/gcc/testsuite/gcc.target/riscv/zbb-rol-ror-09.c b/gcc/testsuite/gcc.target/riscv/zbb-rol-ror-09.c new file mode 100644 index 000000000000..a3054553e184 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/zbb-rol-ror-09.c @@ -0,0 +1,15 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv32gc_zbb -mabi=ilp32 -fno-lto -O2" } */ +/* { dg-skip-if "" { *-*-* } { "-g" } } */ +/* { dg-final { check-function-bodies "**" "" } } */ +/* { dg-final { scan-assembler-not "and" } } */ + +/* +**foo1: +** rori a0,a0,16 +** ret +*/ +unsigned int foo1(unsigned int rs1) +{ + return (rs1 << 16) | (rs1 >> 16); +} diff --git a/gcc/testsuite/gcc.target/riscv/zcmp_push_fpr.c b/gcc/testsuite/gcc.target/riscv/zcmp_push_fpr.c new file mode 100644 index 000000000000..530b35b53dd0 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/zcmp_push_fpr.c @@ -0,0 +1,34 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64imafd_zicsr_zifencei_zca_zcmp -mabi=lp64d -Os -fno-shrink-wrap-separate" } */ +/* { dg-skip-if "" { *-*-* } {"-O0" "-O1" "-O2" "-Og" "-O3" "-Oz" "-flto"} } */ + +typedef struct +{ + struct + { + struct + { + struct + { + long a; + }; + } a[129]; + }; +} b; + +struct c +{ + void *a[129]; +}; + +extern void +f (struct c, b *); + +struct c +d () +{ + struct c a; + __builtin_unwind_init (); + b e; + f (a, &e); +} diff --git a/gcc/testsuite/gcc.target/riscv/zcmp_stack_alignment.c b/gcc/testsuite/gcc.target/riscv/zcmp_stack_alignment.c new file mode 100644 index 000000000000..2f2fa55baac5 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/zcmp_stack_alignment.c @@ -0,0 +1,24 @@ +/* { dg-do compile } */ +/* { dg-options " -O0 -march=rv32e_zca_zcb_zcmp -mabi=ilp32e -mcmodel=medlow -fomit-frame-pointer -fno-shrink-wrap-separate" } */ +/* { dg-skip-if "" { *-*-* } {"-O2" "-O1" "-Os" "-Og" "-O3" "-Oz" "-flto"} } */ +/* { dg-final { check-function-bodies "**" "" } } */ + +void +bar (); + +/* +**fool_rv32e: +** cm.push {ra}, -32 +** ... +** call bar +** ... +** lw a[0-5],32\(sp\) +** ... +** cm.popret {ra}, 32 +*/ +int +fool_rv32e (int a0, int a1, int a2, int a3, int a4, int a5, int incoming0) +{ + bar (); + return a0 + a1 + a2 + a3 + a4 + a5 + incoming0; +} diff --git a/gcc/testsuite/gcc.target/riscv/zfa-fleq-fltq.c b/gcc/testsuite/gcc.target/riscv/zfa-fleq-fltq.c new file mode 100644 index 000000000000..7c28b0bcccc7 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/zfa-fleq-fltq.c @@ -0,0 +1,20 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv32imafdc_zfa -mabi=ilp32d" { target { rv32 } } } */ +/* { dg-options "-march=rv64imafdc_zfa -mabi=lp64d" { target { rv64 } } } */ + +extern void abort(void); +extern float a, b; +extern double c, d; + +void +foo() +{ + if ((__builtin_isless(a, b) || __builtin_islessequal(c, d)) + && (__builtin_islessequal(a, b)|| __builtin_isless(c, d))) + abort(); +} + +/* { dg-final { scan-assembler-times "fleq.s" 1 } } */ +/* { dg-final { scan-assembler-times "fltq.s" 1 } } */ +/* { dg-final { scan-assembler-times "fleq.d" 1 } } */ +/* { dg-final { scan-assembler-times "fltq.d" 1 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/zfa-fli-1.c b/gcc/testsuite/gcc.target/riscv/zfa-fli-1.c new file mode 100644 index 000000000000..35ea5c477676 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/zfa-fli-1.c @@ -0,0 +1,24 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64imfd_zfa -mabi=lp64d" { target { rv64 } } } */ +/* { dg-options "-march=rv32imfd_zfa -mabi=ilp32d" { target { rv32 } } } */ +/* { dg-skip-if "" { *-*-* } {"-O0" "-O1" "-Os" "-Og" "-Oz"} } */ + +#ifndef __riscv_zfa +#error Feature macro not defined +#endif + +double +foo_positive_d (double a) +{ + /* Use 3 FLI FP constants. */ + return (2.5 * a - 1.0) / 0.875; +} + +float +foo_positive_s (float a) +{ + return ((float) 2.5 * a - (float) 1.0) / (float) 0.875; +} + +/* { dg-final { scan-assembler-times "fli\\.s\t" 3 } } */ +/* { dg-final { scan-assembler-times "fli\\.d\t" 3 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/zfa-fli-2.c b/gcc/testsuite/gcc.target/riscv/zfa-fli-2.c new file mode 100644 index 000000000000..10d49d116e46 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/zfa-fli-2.c @@ -0,0 +1,24 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64imfd_zfa -mabi=lp64d" { target { rv64 } } } */ +/* { dg-options "-march=rv32imfd_zfa -mabi=ilp32d" { target { rv32 } } } */ +/* { dg-skip-if "" { *-*-* } {"-O0" "-O1" "-O2" "-Os" "-Og" "-Oz"} } */ + +#ifndef __riscv_zfa +#error Feature macro not defined +#endif + +double +foo_negative_d (double a) +{ + /* Use 3 "non-FLI" FP constants. */ + return (3.5 * a - 5.0) / 0.1875; +} + +float +foo_negative_s (float a) +{ + return ((float) 3.5 * a - (float) 5.0) / (float) 0.1875; +} + +/* { dg-final { scan-assembler-not "fli\\.s\t" } } */ +/* { dg-final { scan-assembler-not "fli\\.d\t" } } */ diff --git a/gcc/testsuite/gcc.target/riscv/zfa-fli-3.c b/gcc/testsuite/gcc.target/riscv/zfa-fli-3.c new file mode 100644 index 000000000000..6d069b2a4a9c --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/zfa-fli-3.c @@ -0,0 +1,14 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64imfd_zfa -mabi=lp64d" { target { rv64 } } } */ +/* { dg-options "-march=rv32imfd_zfa -mabi=ilp32d" { target { rv32 } } } */ +/* { dg-skip-if "" { *-*-* } {"-O0" "-O1" "-Os" "-Og" "-Oz"} } */ + +double +foo_positive_s (float a) +{ + /* Use 3 FLI FP constants (but type conversion occur in the middle). */ + return (2.5f * a - 1.0) / 0.875; +} + +/* { dg-final { scan-assembler-times "fli\\.s\t" 1 } } */ +/* { dg-final { scan-assembler-times "fli\\.d\t" 2 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/zfa-fli-4.c b/gcc/testsuite/gcc.target/riscv/zfa-fli-4.c new file mode 100644 index 000000000000..e72cdd619a8e --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/zfa-fli-4.c @@ -0,0 +1,72 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64imfd_zfa_zfh -mabi=lp64d" { target { rv64 } } } */ +/* { dg-options "-march=rv32imfd_zfa_zfh -mabi=ilp32d" { target { rv32 } } } */ +/* { dg-skip-if "" { *-*-* } {"-O0" "-Og" "-Oz"} } */ + +#define TYPE_h _Float16 +#define TYPE_s float +#define TYPE_d double + +#define DECL_TYPE(TYPE_SHORT) TYPE_##TYPE_SHORT + +#define DECL_FUNC(TYPE_SHORT, N, VALUE) \ + DECL_TYPE (TYPE_SHORT) const_##TYPE_SHORT##_##N (void) \ + { \ + return VALUE; \ + } + +#define DECL_FINITE_FUNCS(TYPE_SHORT) \ + DECL_FUNC (TYPE_SHORT, 00, -1) \ + DECL_FUNC (TYPE_SHORT, 02, 0.0000152587890625) \ + DECL_FUNC (TYPE_SHORT, 03, 0.000030517578125) \ + DECL_FUNC (TYPE_SHORT, 04, 0.00390625) \ + DECL_FUNC (TYPE_SHORT, 05, 0.0078125) \ + DECL_FUNC (TYPE_SHORT, 06, 0.0625) \ + DECL_FUNC (TYPE_SHORT, 07, 0.125) \ + DECL_FUNC (TYPE_SHORT, 08, 0.25) \ + DECL_FUNC (TYPE_SHORT, 09, 0.3125) \ + DECL_FUNC (TYPE_SHORT, 10, 0.375) \ + DECL_FUNC (TYPE_SHORT, 11, 0.4375) \ + DECL_FUNC (TYPE_SHORT, 12, 0.5) \ + DECL_FUNC (TYPE_SHORT, 13, 0.625) \ + DECL_FUNC (TYPE_SHORT, 14, 0.75) \ + DECL_FUNC (TYPE_SHORT, 15, 0.875) \ + DECL_FUNC (TYPE_SHORT, 16, 1) \ + DECL_FUNC (TYPE_SHORT, 17, 1.25) \ + DECL_FUNC (TYPE_SHORT, 18, 1.5) \ + DECL_FUNC (TYPE_SHORT, 19, 1.75) \ + DECL_FUNC (TYPE_SHORT, 20, 2) \ + DECL_FUNC (TYPE_SHORT, 21, 2.5) \ + DECL_FUNC (TYPE_SHORT, 22, 3) \ + DECL_FUNC (TYPE_SHORT, 23, 4) \ + DECL_FUNC (TYPE_SHORT, 24, 8) \ + DECL_FUNC (TYPE_SHORT, 25, 16) \ + DECL_FUNC (TYPE_SHORT, 26, 128) \ + DECL_FUNC (TYPE_SHORT, 27, 256) \ + DECL_FUNC (TYPE_SHORT, 28, 32768) \ + DECL_FUNC (TYPE_SHORT, 29, 65536) + +/* Finite numbers (except 2^16 in _Float16, making an inf). */ +DECL_FINITE_FUNCS (h) +DECL_FINITE_FUNCS (s) +DECL_FINITE_FUNCS (d) + +/* min. */ +DECL_FUNC (h, 01, __FLT16_MIN__) +DECL_FUNC (s, 01, __FLT_MIN__) +DECL_FUNC (d, 01, __DBL_MIN__) + +/* inf. */ +DECL_FUNC (h, 30, __builtin_inff16 ()) +DECL_FUNC (s, 30, __builtin_inff ()) +DECL_FUNC (d, 30, __builtin_inf ()) + +/* nan. */ +DECL_FUNC (h, 31, __builtin_nanf16 ("")) +DECL_FUNC (s, 31, __builtin_nanf ("")) +DECL_FUNC (d, 31, __builtin_nan ("")) + + +/* { dg-final { scan-assembler-times "fli\\.h" 32 } } */ +/* { dg-final { scan-assembler-times "fli\\.s" 32 } } */ +/* { dg-final { scan-assembler-times "fli\\.d" 32 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/zfa-fli-5.c b/gcc/testsuite/gcc.target/riscv/zfa-fli-5.c new file mode 100644 index 000000000000..f6ec8f6d99d6 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/zfa-fli-5.c @@ -0,0 +1,99 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64imf_zfa_zvfh -mabi=lp64f" { target { rv64 } } } */ +/* { dg-options "-march=rv32imf_zfa_zvfh -mabi=ilp32f" { target { rv32 } } } */ +/* { dg-skip-if "" { *-*-* } {"-O0" "-Og" "-Oz"} } */ + +/* Even if 'Zfh' is disabled, "fli.h" is usable when + both 'Zfa' and 'Zvfh' are available. */ +#ifdef __riscv_zfh +#error Invalid feature macro defined +#endif + +#define TYPE_h _Float16 + +#define DECL_TYPE(TYPE_SHORT) TYPE_##TYPE_SHORT + +#define DECL_FUNC(TYPE_SHORT, N, VALUE) \ + DECL_TYPE (TYPE_SHORT) const_##TYPE_SHORT##_##N (void) \ + { \ + return VALUE; \ + } + +#define DECL_FINITE_FUNCS(TYPE_SHORT) \ + DECL_FUNC (TYPE_SHORT, 00, -1) \ + DECL_FUNC (TYPE_SHORT, 02, 0.0000152587890625) \ + DECL_FUNC (TYPE_SHORT, 03, 0.000030517578125) \ + DECL_FUNC (TYPE_SHORT, 04, 0.00390625) \ + DECL_FUNC (TYPE_SHORT, 05, 0.0078125) \ + DECL_FUNC (TYPE_SHORT, 06, 0.0625) \ + DECL_FUNC (TYPE_SHORT, 07, 0.125) \ + DECL_FUNC (TYPE_SHORT, 08, 0.25) \ + DECL_FUNC (TYPE_SHORT, 09, 0.3125) \ + DECL_FUNC (TYPE_SHORT, 10, 0.375) \ + DECL_FUNC (TYPE_SHORT, 11, 0.4375) \ + DECL_FUNC (TYPE_SHORT, 12, 0.5) \ + DECL_FUNC (TYPE_SHORT, 13, 0.625) \ + DECL_FUNC (TYPE_SHORT, 14, 0.75) \ + DECL_FUNC (TYPE_SHORT, 15, 0.875) \ + DECL_FUNC (TYPE_SHORT, 16, 1) \ + DECL_FUNC (TYPE_SHORT, 17, 1.25) \ + DECL_FUNC (TYPE_SHORT, 18, 1.5) \ + DECL_FUNC (TYPE_SHORT, 19, 1.75) \ + DECL_FUNC (TYPE_SHORT, 20, 2) \ + DECL_FUNC (TYPE_SHORT, 21, 2.5) \ + DECL_FUNC (TYPE_SHORT, 22, 3) \ + DECL_FUNC (TYPE_SHORT, 23, 4) \ + DECL_FUNC (TYPE_SHORT, 24, 8) \ + DECL_FUNC (TYPE_SHORT, 25, 16) \ + DECL_FUNC (TYPE_SHORT, 26, 128) \ + DECL_FUNC (TYPE_SHORT, 27, 256) \ + DECL_FUNC (TYPE_SHORT, 28, 32768) \ + DECL_FUNC (TYPE_SHORT, 29, 65536) + +/* Finite numbers (except 2^16 in _Float16, making an inf). */ +DECL_FINITE_FUNCS (h) + +/* min. */ +DECL_FUNC (h, 01, __FLT16_MIN__) + +/* inf. */ +DECL_FUNC (h, 30, __builtin_inff16 ()) + + +/* { dg-final { scan-assembler-times "fli\.h\tfa\[0-9\],-1.0\n" 1 } } */ +/* { dg-final { scan-assembler-times "fli\.h\tfa\[0-9\],1.52587890625e-05\n" 1 } } */ +/* { dg-final { scan-assembler-times "fli\.h\tfa\[0-9\],3.0517578125e-05\n" 1 } } */ +/* { dg-final { scan-assembler-times "fli\.h\tfa\[0-9\],0.00390625\n" 1 } } */ +/* { dg-final { scan-assembler-times "fli\.h\tfa\[0-9\],0.0078125\n" 1 } } */ +/* { dg-final { scan-assembler-times "fli\.h\tfa\[0-9\],0.0625\n" 1 } } */ +/* { dg-final { scan-assembler-times "fli\.h\tfa\[0-9\],0.125\n" 1 } } */ +/* { dg-final { scan-assembler-times "fli\.h\tfa\[0-9\],0.25\n" 1 } } */ +/* { dg-final { scan-assembler-times "fli\.h\tfa\[0-9\],0.3125\n" 1 } } */ +/* { dg-final { scan-assembler-times "fli\.h\tfa\[0-9\],0.375\n" 1 } } */ +/* { dg-final { scan-assembler-times "fli\.h\tfa\[0-9\],0.4375\n" 1 } } */ +/* { dg-final { scan-assembler-times "fli\.h\tfa\[0-9\],0.5\n" 1 } } */ +/* { dg-final { scan-assembler-times "fli\.h\tfa\[0-9\],0.625\n" 1 } } */ +/* { dg-final { scan-assembler-times "fli\.h\tfa\[0-9\],0.75\n" 1 } } */ +/* { dg-final { scan-assembler-times "fli\.h\tfa\[0-9\],0.875\n" 1 } } */ +/* { dg-final { scan-assembler-times "fli\.h\tfa\[0-9\],1.0\n" 1 } } */ +/* { dg-final { scan-assembler-times "fli\.h\tfa\[0-9\],1.25\n" 1 } } */ +/* { dg-final { scan-assembler-times "fli\.h\tfa\[0-9\],1.5\n" 1 } } */ +/* { dg-final { scan-assembler-times "fli\.h\tfa\[0-9\],1.75\n" 1 } } */ +/* { dg-final { scan-assembler-times "fli\.h\tfa\[0-9\],2.0\n" 1 } } */ +/* { dg-final { scan-assembler-times "fli\.h\tfa\[0-9\],2.5\n" 1 } } */ +/* { dg-final { scan-assembler-times "fli\.h\tfa\[0-9\],3.0\n" 1 } } */ +/* { dg-final { scan-assembler-times "fli\.h\tfa\[0-9\],4.0\n" 1 } } */ +/* { dg-final { scan-assembler-times "fli\.h\tfa\[0-9\],8.0\n" 1 } } */ +/* { dg-final { scan-assembler-times "fli\.h\tfa\[0-9\],16.0\n" 1 } } */ +/* { dg-final { scan-assembler-times "fli\.h\tfa\[0-9\],128.0\n" 1 } } */ +/* { dg-final { scan-assembler-times "fli\.h\tfa\[0-9\],256.0\n" 1 } } */ +/* { dg-final { scan-assembler-times "fli\.h\tfa\[0-9\],32768.0\n" 1 } } */ +/* { dg-final { scan-assembler-times "fli\.h\tfa\[0-9\],inf\n" 2 } } */ +/* { dg-final { scan-assembler-times "fli\.h\tfa\[0-9\],min\n" 1 } } */ +/* { dg-final { scan-assembler-times "fli\.h\tfa\[0-9\],nan\n" 1 } } */ + + +/* nan. */ +DECL_FUNC (h, 31, __builtin_nanf16 ("")) + +/* { dg-final { scan-assembler-times "fli\.h\tfa\[0-9\],nan\n" 1 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/zfa-fli-6.c b/gcc/testsuite/gcc.target/riscv/zfa-fli-6.c new file mode 100644 index 000000000000..7efcd811f01f --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/zfa-fli-6.c @@ -0,0 +1,61 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64imf_zfa_zfhmin -mabi=lp64f" { target { rv64 } } } */ +/* { dg-options "-march=rv32imf_zfa_zfhmin -mabi=ilp32f" { target { rv32 } } } */ +/* { dg-skip-if "" { *-*-* } {"-O0" "-Og" "-Oz"} } */ + +/* "fli.h" is unavailable even if both 'Zfa' and 'Zfhmin' is enabled. */ + +#define TYPE_h _Float16 + +#define DECL_TYPE(TYPE_SHORT) TYPE_##TYPE_SHORT + +#define DECL_FUNC(TYPE_SHORT, N, VALUE) \ + DECL_TYPE (TYPE_SHORT) const_##TYPE_SHORT##_##N (void) \ + { \ + return VALUE; \ + } + +#define DECL_FINITE_FUNCS(TYPE_SHORT) \ + DECL_FUNC (TYPE_SHORT, 00, -1) \ + DECL_FUNC (TYPE_SHORT, 02, 0.0000152587890625) \ + DECL_FUNC (TYPE_SHORT, 03, 0.000030517578125) \ + DECL_FUNC (TYPE_SHORT, 04, 0.00390625) \ + DECL_FUNC (TYPE_SHORT, 05, 0.0078125) \ + DECL_FUNC (TYPE_SHORT, 06, 0.0625) \ + DECL_FUNC (TYPE_SHORT, 07, 0.125) \ + DECL_FUNC (TYPE_SHORT, 08, 0.25) \ + DECL_FUNC (TYPE_SHORT, 09, 0.3125) \ + DECL_FUNC (TYPE_SHORT, 10, 0.375) \ + DECL_FUNC (TYPE_SHORT, 11, 0.4375) \ + DECL_FUNC (TYPE_SHORT, 12, 0.5) \ + DECL_FUNC (TYPE_SHORT, 13, 0.625) \ + DECL_FUNC (TYPE_SHORT, 14, 0.75) \ + DECL_FUNC (TYPE_SHORT, 15, 0.875) \ + DECL_FUNC (TYPE_SHORT, 16, 1) \ + DECL_FUNC (TYPE_SHORT, 17, 1.25) \ + DECL_FUNC (TYPE_SHORT, 18, 1.5) \ + DECL_FUNC (TYPE_SHORT, 19, 1.75) \ + DECL_FUNC (TYPE_SHORT, 20, 2) \ + DECL_FUNC (TYPE_SHORT, 21, 2.5) \ + DECL_FUNC (TYPE_SHORT, 22, 3) \ + DECL_FUNC (TYPE_SHORT, 23, 4) \ + DECL_FUNC (TYPE_SHORT, 24, 8) \ + DECL_FUNC (TYPE_SHORT, 25, 16) \ + DECL_FUNC (TYPE_SHORT, 26, 128) \ + DECL_FUNC (TYPE_SHORT, 27, 256) \ + DECL_FUNC (TYPE_SHORT, 28, 32768) \ + DECL_FUNC (TYPE_SHORT, 29, 65536) + +/* Finite numbers (except 2^16 in _Float16, making an inf). */ +DECL_FINITE_FUNCS (h) + +/* min. */ +DECL_FUNC (h, 01, __FLT16_MIN__) + +/* inf. */ +DECL_FUNC (h, 30, __builtin_inff16 ()) + +/* nan. */ +DECL_FUNC (h, 31, __builtin_nanf16 ("")) + +/* { dg-final { scan-assembler-not "fli\\.h\t" } } */ diff --git a/gcc/testsuite/gcc.target/riscv/zfa-fli-7.c b/gcc/testsuite/gcc.target/riscv/zfa-fli-7.c new file mode 100644 index 000000000000..88189f45dbe6 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/zfa-fli-7.c @@ -0,0 +1,30 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64imfd_zfa_zfh -mabi=lp64d" { target { rv64 } } } */ +/* { dg-options "-march=rv32imfd_zfa_zfh -mabi=ilp32d" { target { rv32 } } } */ +/* { dg-skip-if "" { *-*-* } {"-O0" "-Og" "-Oz"} } */ + +/* Canonical NaN is, positive, quiet NaN with zero payload. */ + +#define TYPE_h _Float16 +#define TYPE_s float +#define TYPE_d double + +#define DECL_TYPE(TYPE_SHORT) TYPE_##TYPE_SHORT + +#define DECL_FUNC(TYPE_SHORT, N, VALUE) \ + DECL_TYPE (TYPE_SHORT) const_##TYPE_SHORT##_##N (void) \ + { \ + return VALUE; \ + } + +/* Canonical NaN. */ +DECL_FUNC (h, 1, __builtin_nanf16 ("")) +DECL_FUNC (s, 1, __builtin_nanf ("")) +DECL_FUNC (d, 1, __builtin_nan ("")) +DECL_FUNC (h, 2, __builtin_nanf16 ("0")) +DECL_FUNC (s, 2, __builtin_nanf ("0")) +DECL_FUNC (d, 2, __builtin_nan ("0")) + +/* { dg-final { scan-assembler-times "fli\\.h\tfa\[0-9\],nan\n" 2 } } */ +/* { dg-final { scan-assembler-times "fli\\.s\tfa\[0-9\],nan\n" 2 } } */ +/* { dg-final { scan-assembler-times "fli\\.d\tfa\[0-9\],nan\n" 2 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/zfa-fli-8.c b/gcc/testsuite/gcc.target/riscv/zfa-fli-8.c new file mode 100644 index 000000000000..2ef2a1230ef7 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/zfa-fli-8.c @@ -0,0 +1,39 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64imfd_zfa_zfh -mabi=lp64d" { target { rv64 } } } */ +/* { dg-options "-march=rv32imfd_zfa_zfh -mabi=ilp32d" { target { rv32 } } } */ +/* { dg-skip-if "" { *-*-* } {"-O0" "-Og" "-Oz"} } */ + +/* Canonical NaN is, positive, quiet NaN with zero payload. */ + +#define TYPE_h _Float16 +#define TYPE_s float +#define TYPE_d double + +#define DECL_TYPE(TYPE_SHORT) TYPE_##TYPE_SHORT + +#define DECL_FUNC(TYPE_SHORT, N, VALUE) \ + DECL_TYPE (TYPE_SHORT) const_##TYPE_SHORT##_##N (void) \ + { \ + return VALUE; \ + } + +/* Non-canonical NaN. */ +DECL_FUNC (h, 1, __builtin_nansf16 ("")) +DECL_FUNC (s, 1, __builtin_nansf ("")) +DECL_FUNC (d, 1, __builtin_nans ("")) +DECL_FUNC (h, 2, __builtin_nansf16 ("0")) +DECL_FUNC (s, 2, __builtin_nansf ("0")) +DECL_FUNC (d, 2, __builtin_nans ("0")) +DECL_FUNC (h, 3, __builtin_nanf16 ("1")) +DECL_FUNC (s, 3, __builtin_nanf ("1")) +DECL_FUNC (d, 3, __builtin_nan ("1")) +DECL_FUNC (h, 4, __builtin_nansf16 ("1")) +DECL_FUNC (s, 4, __builtin_nansf ("1")) +DECL_FUNC (d, 4, __builtin_nans ("1")) + +/* Canonical NaN, negated (making it non-canonical). */ +DECL_FUNC (h, 5, -__builtin_nanf16 ("")) +DECL_FUNC (s, 5, -__builtin_nanf ("")) +DECL_FUNC (d, 5, -__builtin_nan ("")) + +/* { dg-final { scan-assembler-not "fli\\.\[hsd]\tfa\[0-9\],nan\n" } } */ diff --git a/gcc/testsuite/gcc.target/riscv/zfa-fli-zfh.c b/gcc/testsuite/gcc.target/riscv/zfa-fli-zfh.c new file mode 100644 index 000000000000..05e2dcbe45eb --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/zfa-fli-zfh.c @@ -0,0 +1,42 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv32imafdc_zfa_zfh -mabi=ilp32d -O0" { target { rv32 } } } */ +/* { dg-options "-march=rv64imafdc_zfa_zfh -mabi=lp64d -O0" { target { rv64 } } } */ + +void foo_float16 () +{ + volatile _Float16 a; + a = -1.0; + a = 6.104e-5; + a = 1.0/(1 << 16); + a = 1.0/(1 << 15); + a = 1.0/(1 << 8); + a = 1.0/(1 << 7); + a = 1.0/(1 << 4); + a = 1.0/(1 << 3); + a = 1.0/(1 << 2); + a = 0.3125; + a = 0.375; + a = 0.4375; + a = 0.5; + a = 0.625; + a = 0.75; + a = 0.875; + a = 1.0; + a = 1.25; + a = 1.5; + a = 1.75; + a = 2.0; + a = 2.5; + a = 3.0; + a = 1.0*(1 << 2); + a = 1.0*(1 << 3); + a = 1.0*(1 << 4); + a = 1.0*(1 << 7); + a = 1.0*(1 << 8); + a = 1.0*(1 << 15); + a = 1.0*(1 << 16); + a = __builtin_inff16 (); + a = __builtin_nanf16 (""); +} + +/* { dg-final { scan-assembler-times "fli.h" 32 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/zfa-fli.c b/gcc/testsuite/gcc.target/riscv/zfa-fli.c new file mode 100644 index 000000000000..e5c1e591c8c8 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/zfa-fli.c @@ -0,0 +1,80 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv32imafdc_zfa -mabi=ilp32d" { target { rv32 } } } */ +/* { dg-options "-march=rv64imafdc_zfa -mabi=lp64d" { target { rv64 } } } */ + +void foo_float32 () +{ + volatile float a; + a = -1.0; + a = 1.1754944e-38; + a = 1.0/(1 << 16); + a = 1.0/(1 << 15); + a = 1.0/(1 << 8); + a = 1.0/(1 << 7); + a = 1.0/(1 << 4); + a = 1.0/(1 << 3); + a = 1.0/(1 << 2); + a = 0.3125; + a = 0.375; + a = 0.4375; + a = 0.5; + a = 0.625; + a = 0.75; + a = 0.875; + a = 1.0; + a = 1.25; + a = 1.5; + a = 1.75; + a = 2.0; + a = 2.5; + a = 3.0; + a = 1.0*(1 << 2); + a = 1.0*(1 << 3); + a = 1.0*(1 << 4); + a = 1.0*(1 << 7); + a = 1.0*(1 << 8); + a = 1.0*(1 << 15); + a = 1.0*(1 << 16); + a = __builtin_inff (); + a = __builtin_nanf (""); +} + +void foo_double64 () +{ + volatile double a; + a = -1.0; + a = 2.2250738585072014e-308; + a = 1.0/(1 << 16); + a = 1.0/(1 << 15); + a = 1.0/(1 << 8); + a = 1.0/(1 << 7); + a = 1.0/(1 << 4); + a = 1.0/(1 << 3); + a = 1.0/(1 << 2); + a = 0.3125; + a = 0.375; + a = 0.4375; + a = 0.5; + a = 0.625; + a = 0.75; + a = 0.875; + a = 1.0; + a = 1.25; + a = 1.5; + a = 1.75; + a = 2.0; + a = 2.5; + a = 3.0; + a = 1.0*(1 << 2); + a = 1.0*(1 << 3); + a = 1.0*(1 << 4); + a = 1.0*(1 << 7); + a = 1.0*(1 << 8); + a = 1.0*(1 << 15); + a = 1.0*(1 << 16); + a = __builtin_inf (); + a = __builtin_nan (""); +} + +/* { dg-final { scan-assembler-times "fli.s" 32 } } */ +/* { dg-final { scan-assembler-times "fli.d" 32 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/zfa-fmovh-fmovp.c b/gcc/testsuite/gcc.target/riscv/zfa-fmovh-fmovp.c new file mode 100644 index 000000000000..5a52adce36ac --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/zfa-fmovh-fmovp.c @@ -0,0 +1,10 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv32g_zfa -mabi=ilp32 -O0" } */ + +double foo(long long a) +{ + return (double)(a + 3); +} + +/* { dg-final { scan-assembler-times "fmvp.d.x" 1 } } */ +/* { dg-final { scan-assembler-times "fmvh.x.d" 1 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/zfa-fround.c b/gcc/testsuite/gcc.target/riscv/zfa-fround.c new file mode 100644 index 000000000000..0765334b7ff2 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/zfa-fround.c @@ -0,0 +1,43 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv32imafdc_zfa -mabi=ilp32d" { target { rv32 } } } */ +/* { dg-options "-march=rv64imafdc_zfa -mabi=lp64d" { target { rv64 } } } */ + +extern float a; +extern double b; + +void foo (float *x, double *y) +{ + { + *x = __builtin_roundf (a); + *y = __builtin_round (b); + } + { + *x = __builtin_floorf (a); + *y = __builtin_floor (b); + } + { + *x = __builtin_ceilf (a); + *y = __builtin_ceil (b); + } + { + *x = __builtin_truncf (a); + *y = __builtin_trunc (b); + } + { + *x = __builtin_roundevenf (a); + *y = __builtin_roundeven (b); + } + { + *x = __builtin_nearbyintf (a); + *y = __builtin_nearbyint (b); + } + { + *x = __builtin_rintf (a); + *y = __builtin_rint (b); + } +} + +/* { dg-final { scan-assembler-times "fround.s" 6 } } */ +/* { dg-final { scan-assembler-times "fround.d" 6 } } */ +/* { dg-final { scan-assembler-times "froundnx.s" 1 } } */ +/* { dg-final { scan-assembler-times "froundnx.d" 1 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/zicond-ice-1.c b/gcc/testsuite/gcc.target/riscv/zicond-ice-1.c new file mode 100644 index 000000000000..d1f98a42582e --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/zicond-ice-1.c @@ -0,0 +1,13 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gc_zicond -mabi=lp64d" { target { rv64 } } } */ +/* { dg-options "-march=rv32gc_zicond -mabi=ilp32f" { target { rv32 } } } */ + +int a, c; +long b; + +void +d() { + for (;;) + if (a & (b < 8 ?: 1 << b)) + c = 1; +} diff --git a/gcc/testsuite/gcc.target/riscv/zicond-primitiveSemantics.c b/gcc/testsuite/gcc.target/riscv/zicond-primitiveSemantics.c index 76c5019a992f..47d4e4c5683a 100644 --- a/gcc/testsuite/gcc.target/riscv/zicond-primitiveSemantics.c +++ b/gcc/testsuite/gcc.target/riscv/zicond-primitiveSemantics.c @@ -1,7 +1,7 @@ /* { dg-do compile } */ /* { dg-options "-march=rv64gc_zicond -mabi=lp64d" { target { rv64 } } } */ /* { dg-options "-march=rv32gc_zicond -mabi=ilp32f" { target { rv32 } } } */ -/* { dg-skip-if "" { *-*-* } {"-O0"} } */ +/* { dg-skip-if "" { *-*-* } {"-O0" "-Og"} } */ long primitiveSemantics_00(long a, long b) { return a == 0 ? 0 : b; } diff --git a/gcc/testsuite/gcc.target/riscv/zicond-xor-01.c b/gcc/testsuite/gcc.target/riscv/zicond-xor-01.c new file mode 100644 index 000000000000..8362ffaf5ab1 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/zicond-xor-01.c @@ -0,0 +1,14 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gc_zicond -mabi=lp64" } */ +/* { dg-skip-if "" { *-*-* } { "-O0" "-Og" "-Os" "-Oz" } } */ + +long xor1(long crc, long poly) +{ + if (crc & 1) + crc ^= poly; + + return crc; +} + +/* { dg-final { scan-assembler-times "czero.eqz\t" 1 } } */ +/* { dg-final { scan-assembler-times "xor\t" 1 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/zihintpause-1.c b/gcc/testsuite/gcc.target/riscv/zihintpause-1.c new file mode 100644 index 000000000000..fc86efe55902 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/zihintpause-1.c @@ -0,0 +1,11 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64i_zihintpause -mabi=lp64" } */ +/* { dg-skip-if "" { *-*-* } { "-g" "-flto"} } */ + +void +test () +{ + __builtin_riscv_pause (); +} + +/* { dg-final { scan-assembler-times "\tpause" 1 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/zihintpause-2.c b/gcc/testsuite/gcc.target/riscv/zihintpause-2.c new file mode 100644 index 000000000000..4eaca95e9f02 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/zihintpause-2.c @@ -0,0 +1,11 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv32i_zihintpause -mabi=ilp32" } */ +/* { dg-skip-if "" { *-*-* } { "-g" "-flto"} } */ + +void +test () +{ + __builtin_riscv_pause (); +} + +/* { dg-final { scan-assembler-times "\tpause" 1 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/zihintpause-noarch.c b/gcc/testsuite/gcc.target/riscv/zihintpause-noarch.c new file mode 100644 index 000000000000..7ce5cba90d51 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/zihintpause-noarch.c @@ -0,0 +1,12 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64i -mabi=lp64" { target { rv64 } } } */ +/* { dg-options "-march=rv32i -mabi=ilp32" { target { rv32 } } } */ +/* { dg-skip-if "" { *-*-* } { "-g" "-flto"} } */ + +void +test () +{ + __builtin_riscv_pause (); +} + +/* { dg-final { scan-assembler-times "0x0100000f" 1 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/zvbb.c b/gcc/testsuite/gcc.target/riscv/zvbb.c index b592f56f6cfb..0b78fe4dc622 100644 --- a/gcc/testsuite/gcc.target/riscv/zvbb.c +++ b/gcc/testsuite/gcc.target/riscv/zvbb.c @@ -3,7 +3,7 @@ /* { dg-options "-march=rv32gc_zvbb" { target { rv32 } } } */ #ifndef __riscv_zvbb -#error Feature macro not defined +#error "Feature macro not defined" #endif int diff --git a/gcc/testsuite/gcc.target/riscv/zvbc.c b/gcc/testsuite/gcc.target/riscv/zvbc.c index 37239fa91b33..2a00c965f322 100644 --- a/gcc/testsuite/gcc.target/riscv/zvbc.c +++ b/gcc/testsuite/gcc.target/riscv/zvbc.c @@ -3,7 +3,7 @@ /* { dg-options "-march=rv32gc_zvbc" { target { rv32 } } } */ #ifndef __riscv_zvbc -#error Feature macro not defined +#error "Feature macro not defined" #endif int diff --git a/gcc/testsuite/gcc.target/riscv/zvkg.c b/gcc/testsuite/gcc.target/riscv/zvkg.c index 1e2a05aa1d87..fe0a841e745d 100644 --- a/gcc/testsuite/gcc.target/riscv/zvkg.c +++ b/gcc/testsuite/gcc.target/riscv/zvkg.c @@ -3,7 +3,7 @@ /* { dg-options "-march=rv32gc_zvkg" { target { rv32 } } } */ #ifndef __riscv_zvkg -#error Feature macro not defined +#error "Feature macro not defined" #endif int diff --git a/gcc/testsuite/gcc.target/riscv/zvkn-1.c b/gcc/testsuite/gcc.target/riscv/zvkn-1.c index 83935b068320..23b255b47790 100644 --- a/gcc/testsuite/gcc.target/riscv/zvkn-1.c +++ b/gcc/testsuite/gcc.target/riscv/zvkn-1.c @@ -3,23 +3,23 @@ /* { dg-options "-march=rv32gc_zvkned_zvknhb_zvbb_zvkt" { target { rv32 } } } */ #ifndef __riscv_zvkn -#error Feature macro not defined +#error "Feature macro for `Zvkn' not defined" #endif #ifndef __riscv_zvkned -#error Feature macro not defined +#error "Feature macro for `Zvkned' not defined" #endif #ifndef __riscv_zvknhb -#error Feature macro not defined +#error "Feature macro for `Zvknhb' not defined" #endif #ifndef __riscv_zvbb -#error Feature macro not defined +#error "Feature macro for `Zvbb' not defined" #endif #ifndef __riscv_zvkt -#error Feature macro not defined +#error "Feature macro for `Zvkt' not defined" #endif int diff --git a/gcc/testsuite/gcc.target/riscv/zvkn.c b/gcc/testsuite/gcc.target/riscv/zvkn.c index af3db40c8f68..0047ebdede6f 100644 --- a/gcc/testsuite/gcc.target/riscv/zvkn.c +++ b/gcc/testsuite/gcc.target/riscv/zvkn.c @@ -3,23 +3,23 @@ /* { dg-options "-march=rv32gc_zvkn" { target { rv32 } } } */ #ifndef __riscv_zvkn -#error Feature macro not defined +#error "Feature macro for `Zvkn' not defined" #endif #ifndef __riscv_zvkned -#error Feature macro not defined +#error "Feature macro for `Zvkned' not defined" #endif #ifndef __riscv_zvknhb -#error Feature macro not defined +#error "Feature macro for `Zvknhb' not defined" #endif #ifndef __riscv_zvbb -#error Feature macro not defined +#error "Feature macro for `Zvbb' not defined" #endif #ifndef __riscv_zvkt -#error Feature macro not defined +#error "Feature macro for `Zvkt' not defined" #endif int diff --git a/gcc/testsuite/gcc.target/riscv/zvknc-1.c b/gcc/testsuite/gcc.target/riscv/zvknc-1.c index eca276708954..d8a84c021180 100644 --- a/gcc/testsuite/gcc.target/riscv/zvknc-1.c +++ b/gcc/testsuite/gcc.target/riscv/zvknc-1.c @@ -3,31 +3,31 @@ /* { dg-options "-march=rv32gc_zvkned_zvknhb_zvbb_zvkt_zvbc" { target { rv32 } } } */ #ifndef __riscv_zvknc -#error Feature macro not defined +#error "Feature macro for `Zvknc' not defined" #endif #ifndef __riscv_zvkn -#error Feature macro not defined +#error "Feature macro for `Zvkn' not defined" #endif #ifndef __riscv_zvkned -#error Feature macro not defined +#error "Feature macro for `Zvkned' not defined" #endif #ifndef __riscv_zvknhb -#error Feature macro not defined +#error "Feature macro for `Zvknhb' not defined" #endif #ifndef __riscv_zvbb -#error Feature macro not defined +#error "Feature macro for `Zvbb' not defined" #endif #ifndef __riscv_zvkt -#error Feature macro not defined +#error "Feature macro for `Zvkt' not defined" #endif #ifndef __riscv_zvbc -#error Feature macro not defined +#error "Feature macro for `Zvbc' not defined" #endif int diff --git a/gcc/testsuite/gcc.target/riscv/zvknc-2.c b/gcc/testsuite/gcc.target/riscv/zvknc-2.c index e77343a27f35..36cc6335d135 100644 --- a/gcc/testsuite/gcc.target/riscv/zvknc-2.c +++ b/gcc/testsuite/gcc.target/riscv/zvknc-2.c @@ -3,31 +3,31 @@ /* { dg-options "-march=rv32gc_zvkn_zvbc" { target { rv32 } } } */ #ifndef __riscv_zvknc -#error Feature macro not defined +#error "Feature macro for `Zvknc' not defined" #endif #ifndef __riscv_zvkn -#error Feature macro not defined +#error "Feature macro for `Zvkn' not defined" #endif #ifndef __riscv_zvkned -#error Feature macro not defined +#error "Feature macro for `Zvkned' not defined" #endif #ifndef __riscv_zvknhb -#error Feature macro not defined +#error "Feature macro for `Zvknhb' not defined" #endif #ifndef __riscv_zvbb -#error Feature macro not defined +#error "Feature macro for `Zvbb' not defined" #endif #ifndef __riscv_zvkt -#error Feature macro not defined +#error "Feature macro for `Zvkt' not defined" #endif #ifndef __riscv_zvbc -#error Feature macro not defined +#error "Feature macro for `Zvbc' not defined" #endif int diff --git a/gcc/testsuite/gcc.target/riscv/zvknc.c b/gcc/testsuite/gcc.target/riscv/zvknc.c index 10bd471da45c..a177f17fbd7a 100644 --- a/gcc/testsuite/gcc.target/riscv/zvknc.c +++ b/gcc/testsuite/gcc.target/riscv/zvknc.c @@ -3,31 +3,31 @@ /* { dg-options "-march=rv32gc_zvknc" { target { rv32 } } } */ #ifndef __riscv_zvknc -#error Feature macro not defined +#error "Feature macro for `Zvknc' not defined" #endif #ifndef __riscv_zvkn -#error Feature macro not defined +#error "Feature macro for `Zvkn' not defined" #endif #ifndef __riscv_zvkned -#error Feature macro not defined +#error "Feature macro for `Zvkned' not defined" #endif #ifndef __riscv_zvknhb -#error Feature macro not defined +#error "Feature macro for `Zvknhb' not defined" #endif #ifndef __riscv_zvbb -#error Feature macro not defined +#error "Feature macro for `Zvbb' not defined" #endif #ifndef __riscv_zvkt -#error Feature macro not defined +#error "Feature macro for `Zvkt' not defined" #endif #ifndef __riscv_zvbc -#error Feature macro not defined +#error "Feature macro for `Zvbc' not defined" #endif int diff --git a/gcc/testsuite/gcc.target/riscv/zvkned.c b/gcc/testsuite/gcc.target/riscv/zvkned.c index fcdc4b45761e..8f9f2532f3d7 100644 --- a/gcc/testsuite/gcc.target/riscv/zvkned.c +++ b/gcc/testsuite/gcc.target/riscv/zvkned.c @@ -3,7 +3,7 @@ /* { dg-options "-march=rv32gc_zvkned" { target { rv32 } } } */ #ifndef __riscv_zvkned -#error Feature macro not defined +#error "Feature macro not defined" #endif int diff --git a/gcc/testsuite/gcc.target/riscv/zvkng-1.c b/gcc/testsuite/gcc.target/riscv/zvkng-1.c index f4f3cc8e4171..d996b42af00f 100644 --- a/gcc/testsuite/gcc.target/riscv/zvkng-1.c +++ b/gcc/testsuite/gcc.target/riscv/zvkng-1.c @@ -3,31 +3,31 @@ /* { dg-options "-march=rv32gc_zvkned_zvknhb_zvbb_zvkt_zvkg" { target { rv32 } } } */ #ifndef __riscv_zvkng -#error Feature macro not defined +#error "Feature macro for `Zvkng' not defined" #endif #ifndef __riscv_zvkn -#error Feature macro not defined +#error "Feature macro for `Zvkn' not defined" #endif #ifndef __riscv_zvkned -#error Feature macro not defined +#error "Feature macro for `Zvkned' not defined" #endif #ifndef __riscv_zvknhb -#error Feature macro not defined +#error "Feature macro for `Zvknhb' not defined" #endif #ifndef __riscv_zvbb -#error Feature macro not defined +#error "Feature macro for `Zvbb' not defined" #endif #ifndef __riscv_zvkt -#error Feature macro not defined +#error "Feature macro for `Zvkt' not defined" #endif #ifndef __riscv_zvkg -#error Feature macro not defined +#error "Feature macro for `Zvkg' not defined" #endif int diff --git a/gcc/testsuite/gcc.target/riscv/zvkng-2.c b/gcc/testsuite/gcc.target/riscv/zvkng-2.c index 2631c1a1c252..00199992d5c6 100644 --- a/gcc/testsuite/gcc.target/riscv/zvkng-2.c +++ b/gcc/testsuite/gcc.target/riscv/zvkng-2.c @@ -3,31 +3,31 @@ /* { dg-options "-march=rv32gc_zvkn_zvkg" { target { rv32 } } } */ #ifndef __riscv_zvkng -#error Feature macro not defined +#error "Feature macro for `Zvkng' not defined" #endif #ifndef __riscv_zvkn -#error Feature macro not defined +#error "Feature macro for `Zvkn' not defined" #endif #ifndef __riscv_zvkned -#error Feature macro not defined +#error "Feature macro for `Zvkned' not defined" #endif #ifndef __riscv_zvknhb -#error Feature macro not defined +#error "Feature macro for `Zvknhb' not defined" #endif #ifndef __riscv_zvbb -#error Feature macro not defined +#error "Feature macro for `Zvbb' not defined" #endif #ifndef __riscv_zvkt -#error Feature macro not defined +#error "Feature macro for `Zvkt' not defined" #endif #ifndef __riscv_zvkg -#error Feature macro not defined +#error "Feature macro for `Zvkg' not defined" #endif int diff --git a/gcc/testsuite/gcc.target/riscv/zvkng.c b/gcc/testsuite/gcc.target/riscv/zvkng.c index e6c950e93237..4605faf3c6cc 100644 --- a/gcc/testsuite/gcc.target/riscv/zvkng.c +++ b/gcc/testsuite/gcc.target/riscv/zvkng.c @@ -3,31 +3,31 @@ /* { dg-options "-march=rv32gc_zvkng" { target { rv32 } } } */ #ifndef __riscv_zvkng -#error Feature macro not defined +#error "Feature macro for `Zvkng' not defined" #endif #ifndef __riscv_zvkn -#error Feature macro not defined +#error "Feature macro for `Zvkn' not defined" #endif #ifndef __riscv_zvkned -#error Feature macro not defined +#error "Feature macro for `Zvkned' not defined" #endif #ifndef __riscv_zvknhb -#error Feature macro not defined +#error "Feature macro for `Zvknhb' not defined" #endif #ifndef __riscv_zvbb -#error Feature macro not defined +#error "Feature macro for `Zvbb' not defined" #endif #ifndef __riscv_zvkt -#error Feature macro not defined +#error "Feature macro for `Zvkt' not defined" #endif #ifndef __riscv_zvkg -#error Feature macro not defined +#error "Feature macro for `Zvkg' not defined" #endif int diff --git a/gcc/testsuite/gcc.target/riscv/zvknha.c b/gcc/testsuite/gcc.target/riscv/zvknha.c index 1275f9d11c18..70242a8cb049 100644 --- a/gcc/testsuite/gcc.target/riscv/zvknha.c +++ b/gcc/testsuite/gcc.target/riscv/zvknha.c @@ -3,7 +3,7 @@ /* { dg-options "-march=rv32gc_zvknha" { target { rv32 } } } */ #ifndef __riscv_zvknha -#error Feature macro not defined +#error "Feature macro not defined" #endif int diff --git a/gcc/testsuite/gcc.target/riscv/zvknhb.c b/gcc/testsuite/gcc.target/riscv/zvknhb.c index 669ff0191496..af89d7b1b7d1 100644 --- a/gcc/testsuite/gcc.target/riscv/zvknhb.c +++ b/gcc/testsuite/gcc.target/riscv/zvknhb.c @@ -3,7 +3,7 @@ /* { dg-options "-march=rv32gc_zvknhb" { target { rv32 } } } */ #ifndef __riscv_zvknhb -#error Feature macro not defined +#error "Feature macro not defined" #endif int diff --git a/gcc/testsuite/gcc.target/riscv/zvks-1.c b/gcc/testsuite/gcc.target/riscv/zvks-1.c index 28ad26af1c14..a576cdb0476f 100644 --- a/gcc/testsuite/gcc.target/riscv/zvks-1.c +++ b/gcc/testsuite/gcc.target/riscv/zvks-1.c @@ -3,23 +3,23 @@ /* { dg-options "-march=rv32gc_zvksed_zvksh_zvbb_zvkt" { target { rv32 } } } */ #ifndef __riscv_zvks -#error Feature macro not defined +#error "Feature macro for `Zvks' not defined" #endif #ifndef __riscv_zvksed -#error Feature macro not defined +#error "Feature macro for `Zvksed' not defined" #endif #ifndef __riscv_zvksh -#error Feature macro not defined +#error "Feature macro for `Zvksh' not defined" #endif #ifndef __riscv_zvbb -#error Feature macro not defined +#error "Feature macro for `Zvbb' not defined" #endif #ifndef __riscv_zvkt -#error Feature macro not defined +#error "Feature macro for `Zvkt' not defined" #endif int diff --git a/gcc/testsuite/gcc.target/riscv/zvks.c b/gcc/testsuite/gcc.target/riscv/zvks.c index a48c9186d5e4..d31b2610c202 100644 --- a/gcc/testsuite/gcc.target/riscv/zvks.c +++ b/gcc/testsuite/gcc.target/riscv/zvks.c @@ -3,23 +3,23 @@ /* { dg-options "-march=rv32gc_zvks" { target { rv32 } } } */ #ifndef __riscv_zvks -#error Feature macro not defined +#error "Feature macro for `Zvks' not defined" #endif #ifndef __riscv_zvksed -#error Feature macro not defined +#error "Feature macro for `Zvksed' not defined" #endif #ifndef __riscv_zvksh -#error Feature macro not defined +#error "Feature macro for `Zvksh' not defined" #endif #ifndef __riscv_zvbb -#error Feature macro not defined +#error "Feature macro for `Zvbb' not defined" #endif #ifndef __riscv_zvkt -#error Feature macro not defined +#error "Feature macro for `Zvkt' not defined" #endif int diff --git a/gcc/testsuite/gcc.target/riscv/zvksc-1.c b/gcc/testsuite/gcc.target/riscv/zvksc-1.c index 72d9676e68c5..3b76e6cea706 100644 --- a/gcc/testsuite/gcc.target/riscv/zvksc-1.c +++ b/gcc/testsuite/gcc.target/riscv/zvksc-1.c @@ -3,31 +3,31 @@ /* { dg-options "-march=rv32gc_zvksed_zvksh_zvbb_zvkt_zvbc" { target { rv32 } } } */ #ifndef __riscv_zvksc -#error Feature macro not defined +#error "Feature macro for `Zvksc' not defined" #endif #ifndef __riscv_zvks -#error Feature macro not defined +#error "Feature macro for `Zvks' not defined" #endif #ifndef __riscv_zvksed -#error Feature macro not defined +#error "Feature macro for `Zvksed' not defined" #endif #ifndef __riscv_zvksh -#error Feature macro not defined +#error "Feature macro for `Zvksh' not defined" #endif #ifndef __riscv_zvbb -#error Feature macro not defined +#error "Feature macro for `Zvbb' not defined" #endif #ifndef __riscv_zvkt -#error Feature macro not defined +#error "Feature macro for `Zvkt' not defined" #endif #ifndef __riscv_zvbc -#error Feature macro not defined +#error "Feature macro for `Zvbc' not defined" #endif int diff --git a/gcc/testsuite/gcc.target/riscv/zvksc-2.c b/gcc/testsuite/gcc.target/riscv/zvksc-2.c index c78b4fe90772..b95e34ec6e46 100644 --- a/gcc/testsuite/gcc.target/riscv/zvksc-2.c +++ b/gcc/testsuite/gcc.target/riscv/zvksc-2.c @@ -3,31 +3,31 @@ /* { dg-options "-march=rv32gc_zvks_zvbc" { target { rv32 } } } */ #ifndef __riscv_zvksc -#error Feature macro not defined +#error "Feature macro for `Zvksc' not defined" #endif #ifndef __riscv_zvks -#error Feature macro not defined +#error "Feature macro for `Zvks' not defined" #endif #ifndef __riscv_zvksed -#error Feature macro not defined +#error "Feature macro for `Zvksed' not defined" #endif #ifndef __riscv_zvksh -#error Feature macro not defined +#error "Feature macro for `Zvksh' not defined" #endif #ifndef __riscv_zvbb -#error Feature macro not defined +#error "Feature macro for `Zvbb' not defined" #endif #ifndef __riscv_zvkt -#error Feature macro not defined +#error "Feature macro for `Zvkt' not defined" #endif #ifndef __riscv_zvbc -#error Feature macro not defined +#error "Feature macro for `Zvbc' not defined" #endif int diff --git a/gcc/testsuite/gcc.target/riscv/zvksc.c b/gcc/testsuite/gcc.target/riscv/zvksc.c index fb61561a2af5..983f1aa89ec9 100644 --- a/gcc/testsuite/gcc.target/riscv/zvksc.c +++ b/gcc/testsuite/gcc.target/riscv/zvksc.c @@ -3,31 +3,31 @@ /* { dg-options "-march=rv32gc_zvksc" { target { rv32 } } } */ #ifndef __riscv_zvksc -#error Feature macro not defined +#error "Feature macro for `Zvksc' not defined" #endif #ifndef __riscv_zvks -#error Feature macro not defined +#error "Feature macro for `Zvks' not defined" #endif #ifndef __riscv_zvksed -#error Feature macro not defined +#error "Feature macro for `Zvksed' not defined" #endif #ifndef __riscv_zvksh -#error Feature macro not defined +#error "Feature macro for `Zvksh' not defined" #endif #ifndef __riscv_zvbb -#error Feature macro not defined +#error "Feature macro for `Zvbb' not defined" #endif #ifndef __riscv_zvkt -#error Feature macro not defined +#error "Feature macro for `Zvkt' not defined" #endif #ifndef __riscv_zvbc -#error Feature macro not defined +#error "Feature macro for `Zvbc' not defined" #endif int diff --git a/gcc/testsuite/gcc.target/riscv/zvksed.c b/gcc/testsuite/gcc.target/riscv/zvksed.c index 439b546bb8a4..2ac58f848199 100644 --- a/gcc/testsuite/gcc.target/riscv/zvksed.c +++ b/gcc/testsuite/gcc.target/riscv/zvksed.c @@ -3,7 +3,7 @@ /* { dg-options "-march=rv32gc_zvksed" { target { rv32 } } } */ #ifndef __riscv_zvksed -#error Feature macro not defined +#error "Feature macro not defined" #endif int diff --git a/gcc/testsuite/gcc.target/riscv/zvksg-1.c b/gcc/testsuite/gcc.target/riscv/zvksg-1.c index 8cbd0331168c..e6b30552e4ca 100644 --- a/gcc/testsuite/gcc.target/riscv/zvksg-1.c +++ b/gcc/testsuite/gcc.target/riscv/zvksg-1.c @@ -3,31 +3,31 @@ /* { dg-options "-march=rv32gc_zvksed_zvksh_zvbb_zvkt_zvkg" { target { rv32 } } } */ #ifndef __riscv_zvksg -#error Feature macro not defined +#error "Feature macro for `Zvksg' not defined" #endif #ifndef __riscv_zvks -#error Feature macro not defined +#error "Feature macro for `Zvks' not defined" #endif #ifndef __riscv_zvksed -#error Feature macro not defined +#error "Feature macro for `Zvksed' not defined" #endif #ifndef __riscv_zvksh -#error Feature macro not defined +#error "Feature macro for `Zvksh' not defined" #endif #ifndef __riscv_zvbb -#error Feature macro not defined +#error "Feature macro for `Zvbb' not defined" #endif #ifndef __riscv_zvkt -#error Feature macro not defined +#error "Feature macro for `Zvkt' not defined" #endif #ifndef __riscv_zvkg -#error Feature macro not defined +#error "Feature macro for `Zvkg' not defined" #endif int diff --git a/gcc/testsuite/gcc.target/riscv/zvksg-2.c b/gcc/testsuite/gcc.target/riscv/zvksg-2.c index d56c47e897cc..2475e8bba1a3 100644 --- a/gcc/testsuite/gcc.target/riscv/zvksg-2.c +++ b/gcc/testsuite/gcc.target/riscv/zvksg-2.c @@ -3,31 +3,31 @@ /* { dg-options "-march=rv32gc_zvks_zvkg" { target { rv32 } } } */ #ifndef __riscv_zvksg -#error Feature macro not defined +#error "Feature macro for `Zvksg' not defined" #endif #ifndef __riscv_zvks -#error Feature macro not defined +#error "Feature macro for `Zvks' not defined" #endif #ifndef __riscv_zvksed -#error Feature macro not defined +#error "Feature macro for `Zvksed' not defined" #endif #ifndef __riscv_zvksh -#error Feature macro not defined +#error "Feature macro for `Zvksh' not defined" #endif #ifndef __riscv_zvbb -#error Feature macro not defined +#error "Feature macro for `Zvbb' not defined" #endif #ifndef __riscv_zvkt -#error Feature macro not defined +#error "Feature macro for `Zvkt' not defined" #endif #ifndef __riscv_zvkg -#error Feature macro not defined +#error "Feature macro for `Zvkg' not defined" #endif int diff --git a/gcc/testsuite/gcc.target/riscv/zvksg.c b/gcc/testsuite/gcc.target/riscv/zvksg.c index 44dffb413954..4db9b5d6b9b1 100644 --- a/gcc/testsuite/gcc.target/riscv/zvksg.c +++ b/gcc/testsuite/gcc.target/riscv/zvksg.c @@ -3,31 +3,31 @@ /* { dg-options "-march=rv32gc_zvksg" { target { rv32 } } } */ #ifndef __riscv_zvksg -#error Feature macro not defined +#error "Feature macro for `Zvksg' not defined" #endif #ifndef __riscv_zvks -#error Feature macro not defined +#error "Feature macro for `Zvks' not defined" #endif #ifndef __riscv_zvksed -#error Feature macro not defined +#error "Feature macro for `Zvksed' not defined" #endif #ifndef __riscv_zvksh -#error Feature macro not defined +#error "Feature macro for `Zvksh' not defined" #endif #ifndef __riscv_zvbb -#error Feature macro not defined +#error "Feature macro for `Zvbb' not defined" #endif #ifndef __riscv_zvkt -#error Feature macro not defined +#error "Feature macro for `Zvkt' not defined" #endif #ifndef __riscv_zvkg -#error Feature macro not defined +#error "Feature macro for `Zvkg' not defined" #endif int diff --git a/gcc/testsuite/gcc.target/riscv/zvksh.c b/gcc/testsuite/gcc.target/riscv/zvksh.c index 5359ca50281b..f7190a42cc29 100644 --- a/gcc/testsuite/gcc.target/riscv/zvksh.c +++ b/gcc/testsuite/gcc.target/riscv/zvksh.c @@ -3,7 +3,7 @@ /* { dg-options "-march=rv32gc_zvksh" { target { rv32 } } } */ #ifndef __riscv_zvksh -#error Feature macro not defined +#error "Feature macro not defined" #endif int diff --git a/gcc/testsuite/gcc.target/riscv/zvkt.c b/gcc/testsuite/gcc.target/riscv/zvkt.c index 49822b75738d..8871a4aca4c0 100644 --- a/gcc/testsuite/gcc.target/riscv/zvkt.c +++ b/gcc/testsuite/gcc.target/riscv/zvkt.c @@ -3,7 +3,7 @@ /* { dg-options "-march=rv32gc_zvkt" { target { rv32 } } } */ #ifndef __riscv_zvkt -#error Feature macro not defined +#error "Feature macro not defined" #endif int diff --git a/gcc/testsuite/gdc.dg/pr110959.d b/gcc/testsuite/gdc.dg/pr110959.d new file mode 100644 index 000000000000..b1da90fad832 --- /dev/null +++ b/gcc/testsuite/gdc.dg/pr110959.d @@ -0,0 +1,32 @@ +// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=110959 +// { dg-do compile } +class ArsdExceptionBase : object.Exception { + this(string operation, string file = __FILE__, size_t line = __LINE__, Throwable next = null) { + super(operation, file, line, next); + } +} + +template ArsdException(alias Type, DataTuple...) { + static if(DataTuple.length) + alias Parent = ArsdException!(Type, DataTuple[0 .. $-1]); + else + alias Parent = ArsdExceptionBase; + + class ArsdException : Parent { + DataTuple data; + + this(DataTuple data, string file = __FILE__, size_t line = __LINE__) { + this.data = data; + static if(is(Parent == ArsdExceptionBase)) + super(null, file, line); + else + super(data[0 .. $-1], file, line); + } + + static opCall(R...)(R r, string file = __FILE__, size_t line = __LINE__) { + return new ArsdException!(Type, DataTuple, R)(r, file, line); + } + } +} + +__gshared pr110959 = ArsdException!"Test"(4, "four"); diff --git a/gcc/testsuite/gdc.test/compilable/cppmangle.d b/gcc/testsuite/gdc.test/compilable/cppmangle.d index fc74c944cad0..264b374dd553 100644 --- a/gcc/testsuite/gdc.test/compilable/cppmangle.d +++ b/gcc/testsuite/gdc.test/compilable/cppmangle.d @@ -528,7 +528,6 @@ version (CppMangle_Itanium) static assert(basic_ostream!(char, char_traits!char).food.mangleof == "_ZNSo4foodEv"); static assert(basic_iostream!(char, char_traits!char).fooe.mangleof == "_ZNSd4fooeEv"); - static assert(func_18957_2.mangleof == `_Z12func_18957_2PSaIiE`); static assert(func_18957_2!(allocator!int).mangleof == `_Z12func_18957_2ISaIiEET_PS1_`); static assert(func_20413.mangleof == `_Z10func_20413St4pairIifES_IfiE`); diff --git a/gcc/testsuite/gdc.test/compilable/deprecate14283.d b/gcc/testsuite/gdc.test/compilable/deprecate14283.d index e91db649ceeb..fc51cf3f0b67 100644 --- a/gcc/testsuite/gdc.test/compilable/deprecate14283.d +++ b/gcc/testsuite/gdc.test/compilable/deprecate14283.d @@ -1,12 +1,12 @@ -// REQUIRED_ARGS: -dw +// REQUIRED_ARGS: // PERMUTE_ARGS: class C { void bug() { - autoref(this); // 'auto ref' becomes non-ref parameter - autoref(super); // 'auto ref' becomes non-ref parameter + autoref!(true, C)(this); // 'auto ref' becomes ref parameter + autoref!(false, Object)(super); // 'auto ref' becomes non-ref parameter } } -void autoref(T)(auto ref T t) { static assert(__traits(isRef, t) == false); } +void autoref(bool result, T)(auto ref T t) { static assert(__traits(isRef, t) == result); } diff --git a/gcc/testsuite/gdc.test/compilable/emptystatement.d b/gcc/testsuite/gdc.test/compilable/emptystatement.d new file mode 100644 index 000000000000..e6bfc27caa42 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/emptystatement.d @@ -0,0 +1,19 @@ +/* +REQUIRED_ARGS: +TEST_OUTPUT: +--- +--- +*/ + +void foo() +{ + int x;; + enum A + { + a, + b, + c + }; + + void bar() {}; +} diff --git a/gcc/testsuite/gdc.test/compilable/imports/imp24022.c b/gcc/testsuite/gdc.test/compilable/imports/imp24022.c new file mode 100644 index 000000000000..b65e4e155bf4 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/imports/imp24022.c @@ -0,0 +1,5 @@ +// https://issues.dlang.org/show_bug.cgi?id=24022 +typedef enum { + A = 1, + B, +} E; diff --git a/gcc/testsuite/gdc.test/compilable/parens_inc.d b/gcc/testsuite/gdc.test/compilable/parens_inc.d new file mode 100644 index 000000000000..b9d11eb9b8e5 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/parens_inc.d @@ -0,0 +1,23 @@ +// Test UnaryExp (expr)++ parsing + +void main(){ + int[2] y; + int *x = y.ptr; + *(x)++=0; + (*(x)--)=0; + (*x++)=0; // ok + int*[] z; + *(z[0])++=0; //ok + (y[0])--; + *x++=0; +} + +void f() +{ + int b; + (b)++; + int[] a; + b = (a)[0]++; //ok + (a[0])--; + b = (int).init; //ok +} diff --git a/gcc/testsuite/gdc.test/compilable/test23951.d b/gcc/testsuite/gdc.test/compilable/test23951.d new file mode 100644 index 000000000000..e09a3d7b5d12 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test23951.d @@ -0,0 +1,10 @@ +// https://issues.dlang.org/show_bug.cgi?id=23951 + +struct S { int x; } +struct T { S a; alias a this; } +struct U { T t; } +static assert(__traits(hasMember, T, "x")); +static assert(__traits(hasMember, T.init, "x")); +static assert(__traits(hasMember, U.init.t, "x")); +static assert(__traits(hasMember, U.t, "a")); +static assert(__traits(hasMember, U.t, "x")); diff --git a/gcc/testsuite/gdc.test/compilable/test23966.d b/gcc/testsuite/gdc.test/compilable/test23966.d new file mode 100644 index 000000000000..71aa8ca229e1 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test23966.d @@ -0,0 +1,19 @@ +// https://issues.dlang.org/show_bug.cgi?id=23966 +module test23966; + +@("gigi") +void fun() {} +@("mimi") +void fun(int) {} +@("hihi") +void fun(int, int) {} +@("bibi") +void fun()(int, ulong) {} + +void main() +{ + static foreach (t; __traits(getOverloads, test23966, "fun", true)) + static foreach(attr; __traits(getAttributes, t)) + {} + +} diff --git a/gcc/testsuite/gdc.test/compilable/test24022.d b/gcc/testsuite/gdc.test/compilable/test24022.d new file mode 100644 index 000000000000..f499636f1267 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test24022.d @@ -0,0 +1,30 @@ +// https://issues.dlang.org/show_bug.cgi?id=24022 +// EXTRA_FILES: imports/imp24022.c +import imports.imp24022; + +auto some_d_func(E v) { + return v; +} + +auto some_d_other_func() { + const struct R { + E r; + this(in E vparam) { r = vparam; } + } + return R(A); +} + +void main(string[] args) { + E expected = E.A; + E res = some_d_func(A); + assert (res == A); + assert (res == expected); + + res = some_d_func(E.B); + assert (res == B); + assert (res == E.B); + + auto res2 = some_d_other_func(); + assert (res2.r == A); + assert (res2.r == expected); +} diff --git a/gcc/testsuite/gdc.test/compilable/test7172.d b/gcc/testsuite/gdc.test/compilable/test7172.d index 013630bd4836..49142d789885 100644 --- a/gcc/testsuite/gdc.test/compilable/test7172.d +++ b/gcc/testsuite/gdc.test/compilable/test7172.d @@ -1,8 +1,4 @@ -/* TEST_OUTPUT: ---- -compilable/test7172.d(14): Deprecation: `scope` as a type constraint is deprecated. Use `scope` at the usage site. ---- -*/ + void main() { abstract class AbstractC{} diff --git a/gcc/testsuite/gdc.test/fail_compilation/biterrors3.d b/gcc/testsuite/gdc.test/fail_compilation/biterrors3.d index f9e1df2b7b2f..c5031a4db105 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/biterrors3.d +++ b/gcc/testsuite/gdc.test/fail_compilation/biterrors3.d @@ -2,7 +2,7 @@ * TEST_OUTPUT: --- fail_compilation/biterrors3.d(103): Error: storage class not allowed for bit-field declaration -fail_compilation/biterrors3.d(106): Error: `d` is not a valid attribute for enum members +fail_compilation/biterrors3.d(106): Error: expected `,` or `=` after identifier, not `:` fail_compilation/biterrors3.d(106): Error: `:` is not a valid attribute for enum members fail_compilation/biterrors3.d(106): Error: `3` is not a valid attribute for enum members --- diff --git a/gcc/testsuite/gdc.test/fail_compilation/body.d b/gcc/testsuite/gdc.test/fail_compilation/body.d new file mode 100644 index 000000000000..7b718c250607 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/body.d @@ -0,0 +1,11 @@ +/* REQUIRED_ARGS: -wo -w +TEST_OUTPUT: +--- +fail_compilation/body.d(11): Warning: usage of identifer `body` as a keyword is obsolete. Use `do` instead. +Error: warnings are treated as errors + Use -wi if you wish to treat warnings only as informational. +--- +*/ + +void test() +in { } body { } diff --git a/gcc/testsuite/gdc.test/fail_compilation/ccast.d b/gcc/testsuite/gdc.test/fail_compilation/ccast.d index dab298441588..f1ca6c0fada9 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/ccast.d +++ b/gcc/testsuite/gdc.test/fail_compilation/ccast.d @@ -1,9 +1,28 @@ /* TEST_OUTPUT: --- -fail_compilation/ccast.d(9): Error: C style cast illegal, use `cast(byte)i` +fail_compilation/ccast.d(11): Error: C style cast illegal, use `cast(byte)i` +fail_compilation/ccast.d(24): Error: C style cast illegal, use `cast(foo)5` +fail_compilation/ccast.d(26): Error: C style cast illegal, use `cast(void*)5` --- */ int i; byte b = (byte)i; + +void bar(int x); + +void main() +{ + (&bar)(5); // ok + auto foo = &bar; + (foo = foo)(5); // ok + (*foo)(5); // ok + + (foo)(5); // ok + (bar)(5); // ok + (foo)5; + + (void*)5; + (void*)(5); // semantic implicit cast error +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag4596.d b/gcc/testsuite/gdc.test/fail_compilation/diag4596.d index f6b49d6bd134..517b328e8d60 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/diag4596.d +++ b/gcc/testsuite/gdc.test/fail_compilation/diag4596.d @@ -1,13 +1,13 @@ /* TEST_OUTPUT: --- -fail_compilation/diag4596.d(15): Error: `this` is not an lvalue and cannot be modified -fail_compilation/diag4596.d(16): Error: conditional expression `1 ? this : this` is not a modifiable lvalue fail_compilation/diag4596.d(18): Error: `super` is not an lvalue and cannot be modified fail_compilation/diag4596.d(19): Error: conditional expression `1 ? super : super` is not a modifiable lvalue --- */ + + class NoGo4596 { void fun() diff --git a/gcc/testsuite/gdc.test/fail_compilation/enum_function.d b/gcc/testsuite/gdc.test/fail_compilation/enum_function.d new file mode 100644 index 000000000000..b22f2ceccef7 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/enum_function.d @@ -0,0 +1,13 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/enum_function.d(10): Error: function cannot have enum storage class +fail_compilation/enum_function.d(11): Error: function cannot have enum storage class +fail_compilation/enum_function.d(12): Error: function cannot have enum storage class +fail_compilation/enum_function.d(13): Error: function cannot have enum storage class +--- +*/ +enum void f1() { return; } +enum f2() { return 5; } +enum f3() => 5; +enum int f4()() => 5; diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail10285.d b/gcc/testsuite/gdc.test/fail_compilation/fail10285.d index 3277b19e2aaf..c88e30688f72 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail10285.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail10285.d @@ -1,10 +1,18 @@ /* TEST_OUTPUT: --- -fail_compilation/fail10285.d(9): Error: no identifier for declarator `int` +fail_compilation/fail10285.d(13): Error: no identifier for declarator `int` +fail_compilation/fail10285.d(14): Error: expected `,` or `=` after identifier, not `y` +fail_compilation/fail10285.d(15): Error: expected identifier after type, not `bool` +fail_compilation/fail10285.d(16): Error: expected identifier after type, not `int` +fail_compilation/fail10285.d(18): Error: initializer required after `z` when type is specified --- */ enum { - int = 5 + int = 5, + int x y, + int bool i = 3, + j int k = 3, + int z } diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail13116.d b/gcc/testsuite/gdc.test/fail_compilation/fail13116.d index ac520d799976..077fa75ac77c 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail13116.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail13116.d @@ -1,7 +1,7 @@ /* TEST_OUTPUT: --- -fail_compilation/fail13116.d(14): Error: `this` is not an lvalue and cannot be modified +fail_compilation/fail13116.d(14): Error: returning `this` escapes a reference to parameter `this` fail_compilation/fail13116.d(23): Error: `super` is not an lvalue and cannot be modified --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail15896.d b/gcc/testsuite/gdc.test/fail_compilation/fail15896.d index e52503d0975c..3fdbf4e9f98d 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail15896.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail15896.d @@ -14,5 +14,6 @@ int func() { thebar +=1; packagebar += 1; + thebar +=1; return 0; } diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail22729.d b/gcc/testsuite/gdc.test/fail_compilation/fail22729.d index 38bbfeeed2b9..d0c8aa9c2f31 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail22729.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail22729.d @@ -22,7 +22,7 @@ class Form : WidgetI template Tuple(Specs) { - enum areCompatibleTuples(Tup2)(Tuple tup1, Tup2 tup2) + auto areCompatibleTuples(Tup2)(Tuple tup1, Tup2 tup2) { tup1.field == tup2; } diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail22780.d b/gcc/testsuite/gdc.test/fail_compilation/fail22780.d index e22be9fe047e..8d4c8a891f0c 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail22780.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail22780.d @@ -1,10 +1,10 @@ // https://issues.dlang.org/show_bug.cgi?id=22780 /* TEST_OUTPUT: --- -fail_compilation/fail22780.d(8): Deprecation: `scope` as a type constraint is deprecated. Use `scope` at the usage site. fail_compilation/fail22780.d(12): Error: variable `fail22780.test10717.c` reference to `scope class` must be `scope` --- */ + scope class C10717 { } void test10717() diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail4559.d b/gcc/testsuite/gdc.test/fail_compilation/fail4559.d deleted file mode 100644 index 657c184d7875..000000000000 --- a/gcc/testsuite/gdc.test/fail_compilation/fail4559.d +++ /dev/null @@ -1,22 +0,0 @@ -/* -REQUIRED_ARGS: -TEST_OUTPUT: ---- -fail_compilation/fail4559.d(13): Error: use `{ }` for an empty statement, not `;` -fail_compilation/fail4559.d(19): Error: use `{ }` for an empty statement, not `;` -fail_compilation/fail4559.d(21): Error: use `{ }` for an empty statement, not `;` ---- -*/ - -void foo() -{ - int x;; - enum A - { - a, - b, - c - }; - - void bar() {}; -} diff --git a/gcc/testsuite/gdc.test/fail_compilation/format.d b/gcc/testsuite/gdc.test/fail_compilation/format.d index bc40d9a527a4..cfd30bfc82e8 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/format.d +++ b/gcc/testsuite/gdc.test/fail_compilation/format.d @@ -1,10 +1,10 @@ /* TEST_OUTPUT: --- -fail_compilation/format.d(101): Error: function `format.printf1` `pragma(printf)` functions must be `extern(C) void printf1([parameters...], const(char)*, ...)` not `void(const(char)*, ...)` -fail_compilation/format.d(102): Error: function `format.printf2` `pragma(printf)` functions must be `extern(C) int printf2([parameters...], const(char)*, ...)` not `extern (C) int(const(int)*, ...)` -fail_compilation/format.d(103): Error: function `format.printf3` `pragma(printf)` functions must be `extern(C) int printf3([parameters...], const(char)*, va_list)` -fail_compilation/format.d(104): Error: function `format.printf4` `pragma(printf)` functions must be `extern(C) int printf4([parameters...], const(char)*, ...)` not `extern (C) int(const(char)*, int, ...)` +fail_compilation/format.d(101): Error: `pragma(printf)` function `printf1` must have `extern(C)` or `extern(C++)` linkage, not `extern(D)` +fail_compilation/format.d(102): Error: `pragma(printf)` function `printf2` must have signature `int printf2([parameters...], const(char)*, ...)` not `extern (C) int(const(int)*, ...)` +fail_compilation/format.d(103): Error: `pragma(printf)` function `printf3` must have signature `int printf3([parameters...], const(char)*, va_list)` +fail_compilation/format.d(104): Error: `pragma(printf)` function `printf4` must have signature `int printf4([parameters...], const(char)*, ...)` not `extern (C) int(const(char)*, int, ...)` --- */ @@ -22,10 +22,13 @@ pragma(printf) extern (C) int printf7(char*, ...); /* TEST_OUTPUT: --- -fail_compilation/format.d(203): Error: function `format.vprintf1` `pragma(printf)` functions must be `extern(C) void vprintf1([parameters...], const(char)*, va_list)` -fail_compilation/format.d(204): Error: function `format.vprintf2` `pragma(printf)` functions must be `extern(C) int vprintf2([parameters...], const(char)*, va_list)` -fail_compilation/format.d(205): Error: function `format.vprintf3` `pragma(printf)` functions must be `extern(C) int vprintf3([parameters...], const(char)*, va_list)` -fail_compilation/format.d(206): Error: function `format.vprintf4` `pragma(printf)` functions must be `extern(C) int vprintf4([parameters...], const(char)*, va_list)` +fail_compilation/format.d(203): Error: `pragma(printf)` function `vprintf1` must have `extern(C)` or `extern(C++)` linkage, not `extern(D)` +fail_compilation/format.d(204): Error: `pragma(printf)` function `vprintf2` must have signature `int vprintf2([parameters...], const(char)*, va_list)` +fail_compilation/format.d(205): Error: `pragma(printf)` function `vprintf3` must have signature `int vprintf3([parameters...], const(char)*, va_list)` +fail_compilation/format.d(206): Error: `pragma(printf)` function `vprintf4` must have signature `int vprintf4([parameters...], const(char)*, va_list)` +fail_compilation/format.d(207): Error: `pragma(printf)` function `vprintf5` must have C-style variadic `...` or `va_list` parameter +fail_compilation/format.d(208): Error: `pragma(scanf)` function `vscanf1` must have `extern(C)` or `extern(C++)` linkage, not `extern(Windows)` +fail_compilation/format.d(208): Error: `pragma(scanf)` function `vscanf1` must have signature `int vscanf1([parameters...], const(char)*, va_list)` --- */ @@ -37,6 +40,8 @@ pragma(printf) void vprintf1(const(char)*, va_list); pragma(printf) extern (C) int vprintf2(const(int )*, va_list); pragma(printf) extern (C) int vprintf3(const(char)*); pragma(printf) extern (C) int vprintf4(const(char)*, int, va_list); +pragma(printf) extern (C) int vprintf5(char*, int[] a...); +pragma(scanf) extern (Windows) int vscanf1(); pragma(printf) extern (C) int vprintf5(const(char)*, va_list); pragma(printf) extern (C) int vprintf6(immutable(char)*, va_list); diff --git a/gcc/testsuite/gdc.test/fail_compilation/reserved_version.d b/gcc/testsuite/gdc.test/fail_compilation/reserved_version.d index 29f96ece787e..f7a554ce729b 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/reserved_version.d +++ b/gcc/testsuite/gdc.test/fail_compilation/reserved_version.d @@ -118,6 +118,7 @@ fail_compilation/reserved_version.d(219): Error: version identifier `D_PostCondi fail_compilation/reserved_version.d(220): Error: version identifier `D_ProfileGC` is reserved and cannot be set fail_compilation/reserved_version.d(221): Error: version identifier `D_Invariants` is reserved and cannot be set fail_compilation/reserved_version.d(222): Error: version identifier `D_Optimized` is reserved and cannot be set +fail_compilation/reserved_version.d(223): Error: version identifier `VisionOS` is reserved and cannot be set --- */ @@ -242,6 +243,7 @@ version = D_PostConditions; version = D_ProfileGC; version = D_Invariants; version = D_Optimized; +version = VisionOS; // This should work though debug = DigitalMars; diff --git a/gcc/testsuite/gdc.test/fail_compilation/scope_class.d b/gcc/testsuite/gdc.test/fail_compilation/scope_class.d index bba149088330..b5e1a54d71bb 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/scope_class.d +++ b/gcc/testsuite/gdc.test/fail_compilation/scope_class.d @@ -1,12 +1,12 @@ /* TEST_OUTPUT: --- -fail_compilation/scope_class.d(10): Deprecation: `scope` as a type constraint is deprecated. Use `scope` at the usage site. fail_compilation/scope_class.d(12): Error: functions cannot return `scope scope_class.C` --- */ + scope class C { int i; } // Notice the use of `scope` here C increment(C c) diff --git a/gcc/testsuite/gdc.test/fail_compilation/scope_type.d b/gcc/testsuite/gdc.test/fail_compilation/scope_type.d deleted file mode 100644 index e0550138b7e4..000000000000 --- a/gcc/testsuite/gdc.test/fail_compilation/scope_type.d +++ /dev/null @@ -1,16 +0,0 @@ -/* -REQUIRED_ARGS: -de -TEST_OUTPUT: ---- -fail_compilation/scope_type.d(13): Deprecation: `scope` as a type constraint is deprecated. Use `scope` at the usage site. -fail_compilation/scope_type.d(14): Error: `scope` as a type constraint is obsolete. Use `scope` at the usage site. -fail_compilation/scope_type.d(15): Deprecation: `scope` as a type constraint is deprecated. Use `scope` at the usage site. -fail_compilation/scope_type.d(16): Deprecation: `scope` as a type constraint is deprecated. Use `scope` at the usage site. ---- -*/ - - -scope class C { } -scope interface I { } -scope struct S { } -scope enum E { e } diff --git a/gcc/testsuite/gdc.test/fail_compilation/test23279.d b/gcc/testsuite/gdc.test/fail_compilation/test23279.d new file mode 100644 index 000000000000..43f2d44a071f --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/test23279.d @@ -0,0 +1,14 @@ +// https://issues.dlang.org/show_bug.cgi?id=23279 + +/* +TEST_OUTPUT: +--- +fail_compilation/test23279.d(13): Error: undefined identifier `Sth` +--- +*/ + +class Tester +{ + enum a = __traits(hasMember, Tester, "setIt"); + void setIt(Sth sth){} +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/typeerrors.d b/gcc/testsuite/gdc.test/fail_compilation/typeerrors.d index 404a4c0e3fe0..4c8576c88d9d 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/typeerrors.d +++ b/gcc/testsuite/gdc.test/fail_compilation/typeerrors.d @@ -1,7 +1,6 @@ /* TEST_OUTPUT: --- -fail_compilation/typeerrors.d(32): Deprecation: `scope` as a type constraint is deprecated. Use `scope` at the usage site. fail_compilation/typeerrors.d(37): Error: sequence index `4` out of bounds `[0 .. 4]` fail_compilation/typeerrors.d(39): Error: variable `x` cannot be read at compile time fail_compilation/typeerrors.d(40): Error: cannot have array of `void()` @@ -25,6 +24,7 @@ fail_compilation/typeerrors.d(57): Error: slice `[2..1]` is out of range of [0.. + template tuple(T...) { alias T tuple; } void bar(); diff --git a/gcc/testsuite/gdc.test/runnable/betterc.d b/gcc/testsuite/gdc.test/runnable/betterc.d index 3d8f7da0fcc8..0fc32c75a1fa 100644 --- a/gcc/testsuite/gdc.test/runnable/betterc.d +++ b/gcc/testsuite/gdc.test/runnable/betterc.d @@ -210,3 +210,14 @@ int test20737() tlsVar = 123; return 0; } + +/*******************************************/ +// https://issues.dlang.org/show_bug.cgi?id=22427 +void test22427() +{ + if("a" == "a") + return; + + char[] p; + auto a = cast(int[])p; +} diff --git a/gcc/testsuite/gdc.test/runnable/sctor2.d b/gcc/testsuite/gdc.test/runnable/sctor2.d index bd820e498f41..a574c3e55f52 100644 --- a/gcc/testsuite/gdc.test/runnable/sctor2.d +++ b/gcc/testsuite/gdc.test/runnable/sctor2.d @@ -1,10 +1,5 @@ // REQUIRED_ARGS: -w -dw // PERMUTE_ARGS: -/* TEST_OUTPUT: ---- -runnable/sctor2.d(12): Deprecation: `scope` as a type constraint is deprecated. Use `scope` at the usage site. ---- -*/ /***************************************************/ // 15665 diff --git a/gcc/testsuite/gdc.test/runnable/test24029.c b/gcc/testsuite/gdc.test/runnable/test24029.c new file mode 100644 index 000000000000..145f2c28725a --- /dev/null +++ b/gcc/testsuite/gdc.test/runnable/test24029.c @@ -0,0 +1,23 @@ +// https://issues.dlang.org/show_bug.cgi?id=24029 + +int x = 0; +int y = 0; + +void a() +{ + (__extension__ ({ x += 2; })); // test.a.__dgliteral1 +} + +void b() +{ + (__extension__ ({ y += 1; })); // test.b.__dgliteral1 +} + +int main(void) +{ + a(); + b(); + __check(x == 2); + __check(y == 1); + return 0; +} diff --git a/gcc/testsuite/gdc.test/runnable/testcontracts.d b/gcc/testsuite/gdc.test/runnable/testcontracts.d index 439040b7b382..63d18fcc6270 100644 --- a/gcc/testsuite/gdc.test/runnable/testcontracts.d +++ b/gcc/testsuite/gdc.test/runnable/testcontracts.d @@ -1,20 +1,4 @@ /* PERMUTE_ARGS: -inline -g -O -TEST_OUTPUT: ---- -runnable/testcontracts.d(323): Deprecation: usage of the `body` keyword is deprecated. Use `do` instead. -runnable/testcontracts.d(324): Deprecation: usage of the `body` keyword is deprecated. Use `do` instead. -runnable/testcontracts.d(325): Deprecation: usage of the `body` keyword is deprecated. Use `do` instead. -runnable/testcontracts.d(326): Deprecation: usage of the `body` keyword is deprecated. Use `do` instead. -runnable/testcontracts.d(328): Deprecation: usage of the `body` keyword is deprecated. Use `do` instead. -runnable/testcontracts.d(329): Deprecation: usage of the `body` keyword is deprecated. Use `do` instead. -runnable/testcontracts.d(330): Deprecation: usage of the `body` keyword is deprecated. Use `do` instead. -runnable/testcontracts.d(331): Deprecation: usage of the `body` keyword is deprecated. Use `do` instead. -runnable/testcontracts.d(502): Deprecation: usage of the `body` keyword is deprecated. Use `do` instead. -runnable/testcontracts.d(503): Deprecation: usage of the `body` keyword is deprecated. Use `do` instead. -runnable/testcontracts.d(504): Deprecation: usage of the `body` keyword is deprecated. Use `do` instead. -runnable/testcontracts.d(505): Deprecation: usage of the `body` keyword is deprecated. Use `do` instead. -runnable/testcontracts.d(505): Deprecation: usage of the `body` keyword is deprecated. Use `do` instead. ---- */ extern(C) int printf(const char*, ...); diff --git a/gcc/testsuite/gfortran.dg/bind_c_usage_13.f03 b/gcc/testsuite/gfortran.dg/bind_c_usage_13.f03 index 470bd59ed383..3cc9f8e0fe9a 100644 --- a/gcc/testsuite/gfortran.dg/bind_c_usage_13.f03 +++ b/gcc/testsuite/gfortran.dg/bind_c_usage_13.f03 @@ -130,9 +130,9 @@ end program test ! { dg-final { scan-tree-dump "multiso .&.v..1..lb: 1 sz: 1., &.x..1..lb: 1 sz: 1..;" "original" } } ! { dg-final { scan-tree-dump "multiso2 .&.w..1..lb: 1 sz: 1., &.x..1..lb: 1 sz: 1..;" "original" } } ! -! { dg-final { scan-tree-dump "mult_val ..x., .x., 1, 1.;" "original" } } +! { dg-final { scan-tree-dump "mult_val .120, 120, 1, 1.;" "original" } } ! { dg-final { scan-tree-dump "multiso_val .121, 120.;" "original" } } -! { dg-final { scan-tree-dump "multiso2_val ..z., .x..;" "original" } } +! { dg-final { scan-tree-dump "multiso2_val .122, 120.;" "original" } } ! ! Single argument dump: ! @@ -144,7 +144,7 @@ end program test ! { dg-final { scan-tree-dump "subiso .&.v..1..lb: 1 sz: 1..;" "original" } } ! { dg-final { scan-tree-dump "subiso2 .&.w..1..lb: 1 sz: 1..;" "original" } } ! -! { dg-final { scan-tree-dump "sub_val ..x., 1.;" "original" } } +! { dg-final { scan-tree-dump "sub_val .120, 1.;" "original" } } ! { dg-final { scan-tree-dump "subiso_val .121.;" "original" } } -! { dg-final { scan-tree-dump "subiso2_val ..z..;" "original" } } +! { dg-final { scan-tree-dump "subiso2_val .122.;" "original" } } ! diff --git a/gcc/testsuite/gfortran.dg/bounds_check_fail_5.f90 b/gcc/testsuite/gfortran.dg/bounds_check_fail_5.f90 new file mode 100644 index 000000000000..436cc96621dc --- /dev/null +++ b/gcc/testsuite/gfortran.dg/bounds_check_fail_5.f90 @@ -0,0 +1,26 @@ +! { dg-do run } +! { dg-additional-options "-fcheck=bounds -g -fdump-tree-original" } +! { dg-output "At line 13 .*" } +! { dg-shouldfail "Array bound mismatch for dimension 1 of array 'ivec' (2/3)" } +! +! PR fortran/31059 - runtime bounds-checking in presence of array constructors + +program p + integer :: jvec(3) = [1,2,3] + integer, allocatable :: ivec(:), kvec(:), lvec(:), mvec(:), nvec(:) + ivec = [1,2] ! (re)allocation + kvec = [4,5,6] ! (re)allocation + ivec(:) = [4,5,6] ! runtime error (->dump) + ! not reached ... + print *, jvec + [1,2,3] ! OK & no check generated + print *, [4,5,6] + jvec ! OK & no check generated + print *, lvec + [1,2,3] ! check generated (->dump) + print *, [4,5,6] + mvec ! check generated (->dump) + nvec(:) = jvec ! check generated (->dump) +end + +! { dg-final { scan-tree-dump-times "Array bound mismatch " 4 "original" } } +! { dg-final { scan-tree-dump-times "Array bound mismatch .*ivec" 1 "original" } } +! { dg-final { scan-tree-dump-times "Array bound mismatch .*lvec" 1 "original" } } +! { dg-final { scan-tree-dump-times "Array bound mismatch .*mvec" 1 "original" } } +! { dg-final { scan-tree-dump-times "Array bound mismatch .*nvec" 1 "original" } } diff --git a/gcc/testsuite/gfortran.dg/common_28.f90 b/gcc/testsuite/gfortran.dg/common_28.f90 new file mode 100644 index 000000000000..9b583b9948df --- /dev/null +++ b/gcc/testsuite/gfortran.dg/common_28.f90 @@ -0,0 +1,7 @@ +! { dg-do compile } +! PR fortran/32986 - Improve diagnostic message for COMMON with automatic object + +function a(n) + real :: x(n) ! { dg-error "Automatic object" } + common /c/ x ! { dg-error "cannot appear in COMMON" } +end function diff --git a/gcc/testsuite/gfortran.dg/data_bounds_1.f90 b/gcc/testsuite/gfortran.dg/data_bounds_1.f90 index 24cdc7c98156..1e6321a28840 100644 --- a/gcc/testsuite/gfortran.dg/data_bounds_1.f90 +++ b/gcc/testsuite/gfortran.dg/data_bounds_1.f90 @@ -1,5 +1,5 @@ ! { dg-do compile } -! { dg-options "-std=gnu" } +! { dg-options "-std=gnu -w" } ! Checks the fix for PR32315, in which the bounds checks below were not being done. ! ! Contributed by Tobias Burnus diff --git a/gcc/testsuite/gfortran.dg/data_bounds_2.f90 b/gcc/testsuite/gfortran.dg/data_bounds_2.f90 new file mode 100644 index 000000000000..1aa9fd4c4232 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/data_bounds_2.f90 @@ -0,0 +1,9 @@ +! { dg-do compile } +! { dg-options "-std=f2018" } +! PR fortran/35095 - Improve bounds checking for DATA with implied-do + +program chkdata + character(len=2), dimension(2,2) :: str + data (str(i,1),i=1,3) / 'A','B','C' / ! { dg-error "above array upper bound" } + data (str(j,2),j=0,2) / 'A','B','C' / ! { dg-error "below array lower bound" } +end program chkdata diff --git a/gcc/testsuite/gfortran.dg/data_vector_section.f90 b/gcc/testsuite/gfortran.dg/data_vector_section.f90 new file mode 100644 index 000000000000..3e099de99d03 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/data_vector_section.f90 @@ -0,0 +1,26 @@ +! { dg-do run } +! PR fortran/49588 - vector sections in data statements + +block data + implicit none + integer :: a(8), b(3,2), i + data a(::2) /4*1/ + data a([2,6]) /2*2/ + data a([4]) /3/ + data a([(6+2*i,i=1,1)]) /1*5/ + data b( 1 ,[1,2]) /11,12/ + data b([2,3],[2,1]) /22,32,21,31/ + common /com/ a, b +end block data + +program test + implicit none + integer :: a(8), b(3,2), i, j + common /com/ a, b + print *, a + print *, b +! print *, a - [1,2,1,3,1,2,1,5] +! print *, ((b(i,j)-(10*i+j),i=1,3),j=1,2) + if (.not. all (a == [1,2,1,3,1,2,1,5])) stop 1 + if (.not. all (b == reshape ([((10*i+j,i=1,3),j=1,2)], shape (b)))) stop 2 +end program test diff --git a/gcc/testsuite/gfortran.dg/goacc/default-3.f95 b/gcc/testsuite/gfortran.dg/goacc/default-3.f95 index 98ed34200c6c..c1edf4c81371 100644 --- a/gcc/testsuite/gfortran.dg/goacc/default-3.f95 +++ b/gcc/testsuite/gfortran.dg/goacc/default-3.f95 @@ -5,14 +5,87 @@ subroutine f1 integer :: f1_a = 2 real, dimension (2) :: f1_b - !$acc kernels default (none) ! { dg-message "enclosing OpenACC .kernels. construct" } + !$acc kernels default (none) ! { dg-note "enclosing OpenACC .kernels. construct with 'default\\\(none\\\)' clause" } f1_b(1) & ! { dg-error ".f1_b. not specified in enclosing OpenACC .kernels. construct" "" { xfail *-*-* } } = f1_a; ! { dg-error ".f1_a. not specified in enclosing OpenACC .kernels. construct" } ! { dg-bogus ".f1_b. not specified in enclosing OpenACC .kernels. construct" "" { xfail *-*-* } .-1 } !$acc end kernels - !$acc parallel default (none) ! { dg-message "enclosing OpenACC .parallel. construct" } + !$acc parallel default (none) ! { dg-note "enclosing OpenACC .parallel. construct with 'default\\\(none\\\)' clause" } f1_b(1) & ! { dg-error ".f1_b. not specified in enclosing OpenACC .parallel. construct" "" { xfail *-*-* } } = f1_a; ! { dg-error ".f1_a. not specified in enclosing OpenACC .parallel. construct" } ! { dg-bogus ".f1_b. not specified in enclosing OpenACC .parallel. construct" "" { xfail *-*-* } .-1 } !$acc end parallel + + !$acc data default (none) ! { dg-note "enclosing OpenACC 'data' construct with 'default\\\(none\\\)' clause" } + !$acc kernels ! { dg-note "enclosing OpenACC 'kernels' construct and" } + f1_b(1) & ! { dg-error ".f1_b. not specified in enclosing OpenACC .kernels. construct" "" { xfail *-*-* } } + = f1_a; ! { dg-error ".f1_a. not specified in enclosing OpenACC .kernels. construct" } + ! { dg-bogus ".f1_b. not specified in enclosing OpenACC .kernels. construct" "" { xfail *-*-* } .-1 } + !$acc end kernels + !$acc end data + + !$acc data default (none) ! { dg-note "enclosing OpenACC 'data' construct with 'default\\\(none\\\)' clause" } + !$acc parallel ! { dg-note "enclosing OpenACC 'parallel' construct and" } + f1_b(1) & ! { dg-error ".f1_b. not specified in enclosing OpenACC .parallel. construct" "" { xfail *-*-* } } + = f1_a; ! { dg-error ".f1_a. not specified in enclosing OpenACC .parallel. construct" } + ! { dg-bogus ".f1_b. not specified in enclosing OpenACC .parallel. construct" "" { xfail *-*-* } .-1 } + !$acc end parallel + !$acc end data + + !$acc data default (none) + !$acc parallel default (none) ! { dg-note "enclosing OpenACC .parallel. construct with 'default\\\(none\\\)' clause" } + f1_b(1) & ! { dg-error ".f1_b. not specified in enclosing OpenACC .parallel. construct" "" { xfail *-*-* } } + = f1_a; ! { dg-error ".f1_a. not specified in enclosing OpenACC .parallel. construct" } + ! { dg-bogus ".f1_b. not specified in enclosing OpenACC .parallel. construct" "" { xfail *-*-* } .-1 } + !$acc end parallel + !$acc end data + + !$acc data default (none) ! { dg-note "enclosing OpenACC 'data' construct with 'default\\\(none\\\)' clause" } + !$acc data + !$acc data + !$acc parallel ! { dg-note "enclosing OpenACC 'parallel' construct and" } + f1_b(1) & ! { dg-error ".f1_b. not specified in enclosing OpenACC .parallel. construct" "" { xfail *-*-* } } + = f1_a; ! { dg-error ".f1_a. not specified in enclosing OpenACC .parallel. construct" } + ! { dg-bogus ".f1_b. not specified in enclosing OpenACC .parallel. construct" "" { xfail *-*-* } .-1 } + !$acc end parallel + !$acc end data + !$acc end data + !$acc end data + + !$acc data + !$acc data default (none) ! { dg-note "enclosing OpenACC 'data' construct with 'default\\\(none\\\)' clause" } + !$acc data + !$acc parallel ! { dg-note "enclosing OpenACC 'parallel' construct and" } + f1_b(1) & ! { dg-error ".f1_b. not specified in enclosing OpenACC .parallel. construct" "" { xfail *-*-* } } + = f1_a; ! { dg-error ".f1_a. not specified in enclosing OpenACC .parallel. construct" } + ! { dg-bogus ".f1_b. not specified in enclosing OpenACC .parallel. construct" "" { xfail *-*-* } .-1 } + !$acc end parallel + !$acc end data + !$acc end data + !$acc end data + + !$acc data + !$acc data + !$acc data default (none) ! { dg-note "enclosing OpenACC 'data' construct with 'default\\\(none\\\)' clause" } + !$acc parallel ! { dg-note "enclosing OpenACC 'parallel' construct and" } + f1_b(1) & ! { dg-error ".f1_b. not specified in enclosing OpenACC .parallel. construct" "" { xfail *-*-* } } + = f1_a; ! { dg-error ".f1_a. not specified in enclosing OpenACC .parallel. construct" } + ! { dg-bogus ".f1_b. not specified in enclosing OpenACC .parallel. construct" "" { xfail *-*-* } .-1 } + !$acc end parallel + !$acc end data + !$acc end data + !$acc end data + + !$acc data + !$acc data default (none) + !$acc data default (none) ! { dg-note "enclosing OpenACC 'data' construct with 'default\\\(none\\\)' clause" } + !$acc parallel ! { dg-note "enclosing OpenACC 'parallel' construct and" } + f1_b(1) & ! { dg-error ".f1_b. not specified in enclosing OpenACC .parallel. construct" "" { xfail *-*-* } } + = f1_a; ! { dg-error ".f1_a. not specified in enclosing OpenACC .parallel. construct" } + ! { dg-bogus ".f1_b. not specified in enclosing OpenACC .parallel. construct" "" { xfail *-*-* } .-1 } + !$acc end parallel + !$acc end data + !$acc end data + !$acc end data + end subroutine f1 diff --git a/gcc/testsuite/gfortran.dg/goacc/default-4.f b/gcc/testsuite/gfortran.dg/goacc/default-4.f index 30f411f70ab6..4e89b6859bad 100644 --- a/gcc/testsuite/gfortran.dg/goacc/default-4.f +++ b/gcc/testsuite/gfortran.dg/goacc/default-4.f @@ -38,6 +38,24 @@ !$ACC END DATA END SUBROUTINE F2 + SUBROUTINE F2_ + IMPLICIT NONE + INTEGER :: F2__A = 2 + REAL, DIMENSION (2) :: F2__B + +!$ACC DATA DEFAULT (NONE) COPYIN (F2__A) COPYOUT (F2__B) +! { dg-final { scan-tree-dump-times "omp target oacc_data map\\(to:f2__a \[^\\)\]+\\) map\\(from:f2__b \[^\\)\]+\\) default\\(none\\)" 1 "gimple" } } +!$ACC KERNELS +! { dg-final { scan-tree-dump-times "omp target oacc_kernels map\\(tofrom:f2__b \[^\\)\]+\\) map\\(tofrom:f2__a" 1 "gimple" } } + F2__B(1) = F2__A; +!$ACC END KERNELS +!$ACC PARALLEL +! { dg-final { scan-tree-dump-times "omp target oacc_parallel map\\(tofrom:f2__b \[^\\)\]+\\) map\\(tofrom:f2__a" 1 "gimple" } } + F2__B(1) = F2__A; +!$ACC END PARALLEL +!$ACC END DATA + END SUBROUTINE F2_ + SUBROUTINE F3 IMPLICIT NONE INTEGER :: F3_A = 2 @@ -55,3 +73,21 @@ !$ACC END PARALLEL !$ACC END DATA END SUBROUTINE F3 + + SUBROUTINE F3_ + IMPLICIT NONE + INTEGER :: F3__A = 2 + REAL, DIMENSION (2) :: F3__B + +!$ACC DATA DEFAULT (PRESENT) COPYIN (F3__A) COPYOUT (F3__B) +! { dg-final { scan-tree-dump-times "omp target oacc_data map\\(to:f3__a \[^\\)\]+\\) map\\(from:f3__b \[^\\)\]+\\) default\\(present\\)" 1 "gimple" } } +!$ACC KERNELS +! { dg-final { scan-tree-dump-times "omp target oacc_kernels map\\(tofrom:f3__b \[^\\)\]+\\) map\\(tofrom:f3__a" 1 "gimple" } } + F3__B(1) = F3__A; +!$ACC END KERNELS +!$ACC PARALLEL +! { dg-final { scan-tree-dump-times "omp target oacc_parallel map\\(tofrom:f3__b \[^\\)\]+\\) map\\(tofrom:f3__a" 1 "gimple" } } + F3__B(1) = F3__A; +!$ACC END PARALLEL +!$ACC END DATA + END SUBROUTINE F3_ diff --git a/gcc/testsuite/gfortran.dg/goacc/default-5.f b/gcc/testsuite/gfortran.dg/goacc/default-5.f index 9dc83cbe601d..2cb07a8cbca2 100644 --- a/gcc/testsuite/gfortran.dg/goacc/default-5.f +++ b/gcc/testsuite/gfortran.dg/goacc/default-5.f @@ -4,8 +4,8 @@ SUBROUTINE F1 IMPLICIT NONE - INTEGER :: F1_A = 2 - REAL, DIMENSION (2) :: F1_B + INTEGER :: F1_A = 2, F1_C = 3 + REAL, DIMENSION (2) :: F1_B, F1_D !$ACC KERNELS DEFAULT (PRESENT) ! { dg-final { scan-tree-dump-times "omp target oacc_kernels default\\(present\\) map\\(force_present:f1_b \[^\\)\]+\\) map\\(force_tofrom:f1_a" 1 "gimple" } } @@ -15,4 +15,19 @@ ! { dg-final { scan-tree-dump-times "omp target oacc_parallel default\\(present\\) map\\(force_present:f1_b \[^\\)\]+\\) firstprivate\\(f1_a\\)" 1 "gimple" } } F1_B(1) = F1_A; !$ACC END PARALLEL + +!$ACC DATA DEFAULT (PRESENT) +!$ACC KERNELS +! { dg-final { scan-tree-dump-times "omp target oacc_kernels map\\(force_present:f1_d \[^\\)\]+\\) map\\(force_tofrom:f1_c" 1 "gimple" } } + F1_D(1) = F1_C; +!$ACC END KERNELS +!$ACC END DATA +!$ACC DATA DEFAULT (NONE) +!$ACC DATA DEFAULT (PRESENT) +!$ACC PARALLEL DEFAULT (PRESENT) +! { dg-final { scan-tree-dump-times "omp target oacc_parallel default\\(present\\) map\\(force_present:f1_d \[^\\)\]+\\) firstprivate\\(f1_c\\)" 1 "gimple" } } + F1_D(1) = F1_C; +!$ACC END PARALLEL +!$ACC END DATA +!$ACC END DATA END SUBROUTINE F1 diff --git a/gcc/testsuite/gfortran.dg/gomp/collapse1.f90 b/gcc/testsuite/gfortran.dg/gomp/collapse1.f90 index 77b2bdd7fcbb..613f06f6ea92 100644 --- a/gcc/testsuite/gfortran.dg/gomp/collapse1.f90 +++ b/gcc/testsuite/gfortran.dg/gomp/collapse1.f90 @@ -31,11 +31,11 @@ subroutine collapse1 do i = 1, 3 do j = 4, 6 end do - k = 4 ! { dg-error "loops not perfectly nested" } + k = 4 end do - !$omp parallel do collapse(2) + !$omp parallel do collapse(2) ! { dg-error "not enough DO loops" } do i = 1, 3 - do ! { dg-error "cannot be a DO WHILE or DO without loop control" } + do end do end do !$omp parallel do collapse(2) diff --git a/gcc/testsuite/gfortran.dg/gomp/collapse2.f90 b/gcc/testsuite/gfortran.dg/gomp/collapse2.f90 index 1ab934e3d0dc..9af3b656829d 100644 --- a/gcc/testsuite/gfortran.dg/gomp/collapse2.f90 +++ b/gcc/testsuite/gfortran.dg/gomp/collapse2.f90 @@ -6,24 +6,24 @@ program p do j = 1, 8 do k = 1, 8 end do - x = 5 ! { dg-error "loops not perfectly nested" } + x = 5 end do end do - !$omp parallel do ordered(3) + !$omp parallel do ordered(3) ! { dg-error "inner loops must be perfectly nested" } do i = 1, 8 do j = 1, 8 do k = 1, 8 end do end do - x = 5 ! { dg-error "loops not perfectly nested" } + x = 5 end do - !$omp parallel do collapse(2) ! { dg-error "not enough DO loops for collapsed" } + !$omp parallel do collapse(2) do i = 1, 8 x = 5 do j = 1, 8 end do end do - !$omp parallel do ordered(2) ! { dg-error "not enough DO loops for collapsed" } + !$omp parallel do ordered(2) ! { dg-error "inner loops must be perfectly nested" } do i = 1, 8 x = 5 do j = 1, 8 diff --git a/gcc/testsuite/gfortran.dg/gomp/defaultmap-1.f90 b/gcc/testsuite/gfortran.dg/gomp/defaultmap-1.f90 index 1f1b8528aef0..5123e078e98d 100644 --- a/gcc/testsuite/gfortran.dg/gomp/defaultmap-1.f90 +++ b/gcc/testsuite/gfortran.dg/gomp/defaultmap-1.f90 @@ -4,7 +4,7 @@ implicit none !$omp target defaultmap(bar) ! { dg-error "25: Expected ALLOC, TO, FROM, TOFROM, FIRSTPRIVATE, PRESENT, NONE or DEFAULT" } -!$omp target defaultmap ( alloc: foo) ! { dg-error "34: Expected SCALAR, AGGREGATE, ALLOCATABLE or POINTER" } +!$omp target defaultmap ( alloc: foo) ! { dg-error "34: Expected SCALAR, AGGREGATE, ALLOCATABLE, POINTER or ALL" } !$omp target defaultmap(alloc:scalar) defaultmap(none:Scalar) ! { dg-error "DEFAULTMAP at .1. but prior DEFAULTMAP for category SCALAR" } diff --git a/gcc/testsuite/gfortran.dg/gomp/defaultmap-10.f90 b/gcc/testsuite/gfortran.dg/gomp/defaultmap-10.f90 new file mode 100644 index 000000000000..7e230d886f03 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/gomp/defaultmap-10.f90 @@ -0,0 +1,116 @@ +subroutine f + implicit none + type t + integer :: i + end type t + integer, target :: scalar + integer, target :: array(5) + integer, pointer :: ptr1, ptr2(:) + integer, allocatable :: alloc1, alloc2(:) + type(t) :: agg1, agg2(2) + + scalar = 1 + array = [1,2,3,4,5] + ptr1 => scalar + ptr2 => array + alloc1 = 5 + alloc2 = [1,2] + agg1%i = 1 + agg2(:)%i = [1,2] + + !$omp target defaultmap(firstprivate ) defaultmap(firstprivate : aggregate) ! { dg-error "DEFAULTMAP at .1. but prior DEFAULTMAP with unspecified category" } + block + scalar = 1; + array(1) = 2; + if (associated(ptr1)) & + agg1%i = 3; + if (associated(ptr2)) & + agg2(1)%i = 3; + if (allocated(alloc1)) & + alloc2(1) = 0 + end block + + !$omp target defaultmap(firstprivate : all ) defaultmap(alloc : pointer) ! { dg-error "DEFAULTMAP at .1. but prior DEFAULTMAP for category ALL" } + block + scalar = 1; + array(1) = 2; + if (associated(ptr1)) & + agg1%i = 3; + if (associated(ptr2)) & + agg2(1)%i = 3; + if (allocated(alloc1)) & + alloc2(1) = 0 + end block + + !$omp target defaultmap(firstprivate : aggregate) defaultmap(firstprivate ) ! { dg-error "DEFAULTMAP at .1. but prior DEFAULTMAP for category AGGREGATE" } + block + scalar = 1; + array(1) = 2; + if (associated(ptr1)) & + agg1%i = 3; + if (associated(ptr2)) & + agg2(1)%i = 3; + if (allocated(alloc1)) & + alloc2(1) = 0 + end block + + !$omp target defaultmap(alloc : pointer) defaultmap(firstprivate : all ) ! { dg-error "DEFAULTMAP at .1. but prior DEFAULTMAP for category POINTER" } + block + scalar = 1; + array(1) = 2; + if (associated(ptr1)) & + agg1%i = 3; + if (associated(ptr2)) & + agg2(1)%i = 3; + if (allocated(alloc1)) & + alloc2(1) = 0 + end block + + !$omp target defaultmap(firstprivate :all ) defaultmap(firstprivate : all) ! { dg-error "DEFAULTMAP at .1. but prior DEFAULTMAP for category ALL" } + block + scalar = 1; + array(1) = 2; + if (associated(ptr1)) & + agg1%i = 3; + if (associated(ptr2)) & + agg2(1)%i = 3; + if (allocated(alloc1)) & + alloc2(1) = 0 + end block + + !$omp target defaultmap(firstprivate ) defaultmap(firstprivate) ! { dg-error "DEFAULTMAP at .1. but prior DEFAULTMAP with unspecified category" } + block + scalar = 1; + array(1) = 2; + if (associated(ptr1)) & + agg1%i = 3; + if (associated(ptr2)) & + agg2(1)%i = 3; + if (allocated(alloc1)) & + alloc2(1) = 0 + end block + + !$omp target defaultmap(firstprivate ) defaultmap(firstprivate : all) ! { dg-error "DEFAULTMAP at .1. but prior DEFAULTMAP with unspecified category" } + block + scalar = 1; + array(1) = 2; + if (associated(ptr1)) & + agg1%i = 3; + if (associated(ptr2)) & + agg2(1)%i = 3; + if (allocated(alloc1)) & + alloc2(1) = 0 + end block + + !$omp target defaultmap(firstprivate : all) defaultmap(firstprivate) ! { dg-error "DEFAULTMAP at .1. but prior DEFAULTMAP for category ALL" } + block + scalar = 1; + array(1) = 2; + if (associated(ptr1)) & + agg1%i = 3; + if (associated(ptr2)) & + agg2(1)%i = 3; + if (allocated(alloc1)) & + alloc2(1) = 0 + end block +end diff --git a/gcc/testsuite/gfortran.dg/gomp/defaultmap-9.f90 b/gcc/testsuite/gfortran.dg/gomp/defaultmap-9.f90 new file mode 100644 index 000000000000..b24fc95fc747 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/gomp/defaultmap-9.f90 @@ -0,0 +1,71 @@ +! { dg-additional-options "-fdump-tree-original -fdump-tree-gimple" } + +subroutine f + implicit none + type t + integer :: i + end type t + integer, target :: scalar + integer, target :: array(5) + integer, pointer :: ptr1, ptr2(:) + integer, allocatable :: alloc1, alloc2(:) + type(t) :: agg1, agg2(2) + + scalar = 1 + array = [1,2,3,4,5] + ptr1 => scalar + ptr2 => array + alloc1 = 5 + alloc2 = [1,2] + agg1%i = 1 + agg2(:)%i = [1,2] + + ! firstprivate + unspecified modifer. + !$omp target defaultmap(firstprivate) + block + scalar = 1; + array(1) = 2; + if (associated(ptr1)) & + agg1%i = 3; + if (associated(ptr2)) & + agg2(1)%i = 3; + if (allocated(alloc1)) & + alloc2(1) = 0 + end block + + ! equivalent: firstprivate + ALL modifer. + !$omp target defaultmap(firstprivate : all) + block + scalar = 1; + array(1) = 2; + if (associated(ptr1)) & + agg1%i = 3; + if (associated(ptr2)) & + agg2(1)%i = 3; + if (allocated(alloc1)) & + alloc2(1) = 0 + end block + + ! tofrom + ALL modifer. + !$omp target defaultmap(tofrom : all) + block + scalar = 1; + array(1) = 2; + if (associated(ptr1)) & + agg1%i = 3; + if (associated(ptr2)) & + agg2(1)%i = 3; + if (allocated(alloc1)) & + alloc2(1) = 0 + end block +end subroutine + +! { dg-final { scan-tree-dump-times "#pragma omp target defaultmap\\(firstprivate\\)" 1 "original" } } +! { dg-final { scan-tree-dump-times "#pragma omp target defaultmap\\(firstprivate:all\\)" 1 "original" } } +! { dg-final { scan-tree-dump-times "#pragma omp target defaultmap\\(tofrom:all\\)" 1 "original" } } + +! { dg-final { scan-tree-dump-times "#pragma omp target.* defaultmap\\(firstprivate\\) firstprivate\\(scalar\\) firstprivate\\(ptr2\\) firstprivate\\(ptr1\\) firstprivate\\(array\\) firstprivate\\(alloc2\\) firstprivate\\(alloc1\\) firstprivate\\(agg2\\) firstprivate\\(agg1\\)" 1 "gimple" } } + +! { dg-final { scan-tree-dump-times "#pragma omp target.* defaultmap\\(firstprivate:all\\) firstprivate\\(scalar\\) firstprivate\\(ptr2\\) firstprivate\\(ptr1\\) firstprivate\\(array\\) firstprivate\\(alloc2\\) firstprivate\\(alloc1\\) firstprivate\\(agg2\\) firstprivate\\(agg1\\)" 1 "gimple" } } + +! { dg-final { scan-tree-dump-times "#pragma omp target.* defaultmap\\(tofrom:all\\) map\\(tofrom:scalar \\\[len: .\\\]\\\[implicit\\\]\\) map\\(tofrom:.*ptr2.data \\\[len: .*\\\]\\\[implicit\\\]\\) map\\(to:ptr2 \\\[pointer set, len: ..\\\]\\) map\\(always_pointer:.*ptr2.data \\\[pointer assign, bias: 0\\\]\\) map\\(tofrom:\\*ptr1 \\\[len: .\\\]\\\[implicit\\\]\\) map\\(alloc:ptr1 \\\[pointer assign, bias: 0\\\]\\) map\\(tofrom:array \\\[len: ..\\\]\\\[implicit\\\]\\) map\\(tofrom:.*alloc2.data \\\[len: .*\\\]\\\[implicit\\\]\\) map\\(to:alloc2 \\\[pointer set, len: ..\\\]\\) map\\(alloc:.*alloc2.data \\\[pointer assign, bias: 0\\\]\\) map\\(tofrom:\\*alloc1 \\\[len: .\\\]\\\[implicit\\\]\\) map\\(alloc:alloc1 \\\[pointer assign, bias: 0\\\]\\) map\\(tofrom:agg2 \\\[len: .\\\]\\\[implicit\\\]\\) map\\(tofrom:agg1 \\\[len: .\\\]\\\[implicit\\\]\\)" 1 "gimple" } } diff --git a/gcc/testsuite/gfortran.dg/gomp/imperfect-gotos.f90 b/gcc/testsuite/gfortran.dg/gomp/imperfect-gotos.f90 new file mode 100644 index 000000000000..e184ffe631e3 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/gomp/imperfect-gotos.f90 @@ -0,0 +1,69 @@ +! This test case is expected to fail due to errors. + +! These jumps are all OK since they are to/from the same structured block. +subroutine f1 () + integer :: i, j + !$omp do collapse(2) + do i = 1, 64 + go to 10 +10 continue + do j = 1, 64 + go to 11 +11 continue + end do + go to 12 +12 continue + end do +end subroutine + +! Jump around loop body to/from different structured blocks of intervening +! code. +subroutine f2 () + integer :: i, j + !$omp do collapse(2) + do i = 1, 64 + go to 20 +20 continue + if (i > 16) go to 22 ! { dg-error "invalid branch to/from OpenMP structured block" } + do j = 1, 64 + go to 21 +21 continue + end do + go to 22 +22 continue + end do +end subroutine + +! Jump into loop body from intervening code. +subroutine f3 () + integer :: i, j + !$omp do collapse(2) + do i = 1, 64 + go to 30 +30 continue + if (i > 16) go to 31 ! { dg-error "invalid branch to/from OpenMP structured block" } + ! { dg-warning "Legacy Extension:" "" { target *-*-* } .-1 } + do j = 1, 64 + go to 31 +31 continue ! { dg-warning "Legacy Extension:" } + end do + go to 32 +32 continue + end do +end subroutine + +! Jump out of loop body to intervening code. +subroutine f4 () + integer :: i, j + !$omp do collapse(2) + do i = 1, 64 + go to 40 +40 continue + do j = 1, 64 + if (i > 16) go to 41 ! { dg-error "invalid branch to/from OpenMP structured block" } + end do +41 continue + go to 42 +42 continue + end do +end subroutine diff --git a/gcc/testsuite/gfortran.dg/gomp/imperfect-invalid-scope.f90 b/gcc/testsuite/gfortran.dg/gomp/imperfect-invalid-scope.f90 new file mode 100644 index 000000000000..7cc609441314 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/gomp/imperfect-invalid-scope.f90 @@ -0,0 +1,81 @@ +! Test that various errors involving references to variables bound +! in intervening code in the DO loop control expressions are diagnosed. + +subroutine foo (x, y) + integer :: x, y +end subroutine + +subroutine f1 () + integer :: i, j + + !$omp do collapse (2) + do i = 1, 64 + block + integer :: v + v = (i + 4) * 2 + do j = v, 64 ! { dg-error "loop start expression at .1. uses variable bound in intervening code" } + call foo (i, j) + end do + end block + end do +end subroutine + +subroutine f2 () + integer :: i, j + + !$omp do collapse (2) + do i = 1, 64 + block + integer :: v + v = (i + 4) * 2 + do j = 1, v ! { dg-error "loop end expression at .1. uses variable bound in intervening code" } + call foo (i, j) + end do + end block + end do +end subroutine + +subroutine f3 () + integer :: i, j + + !$omp do collapse (2) + do i = 1, 64 + block + integer :: v + v = (i + 4) * 2 + do j = 1, 64, v ! { dg-error "loop increment expression at .1. uses variable bound in intervening code" } + call foo (i, j) + end do + end block + end do +end subroutine + +subroutine f4 () + integer :: i + + !$omp do collapse (2) + do i = 1, 64 + block + integer :: j + do j = 1, 64 ! { dg-error "iteration variable at .1. is bound in intervening code" } + call foo (i, j) + end do + end block + end do +end subroutine + +subroutine f5 () + integer :: i + + !$omp do collapse (2) + do i = 1, 64 + block + integer :: j + integer :: v + v = (i + 4) * 2 + do j = v, 64 ! { dg-error "iteration variable at .1. is bound in intervening code" } + call foo (i, j) + end do + end block + end do +end subroutine diff --git a/gcc/testsuite/gfortran.dg/gomp/imperfect1.f90 b/gcc/testsuite/gfortran.dg/gomp/imperfect1.f90 new file mode 100644 index 000000000000..4e750d9ad059 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/gomp/imperfect1.f90 @@ -0,0 +1,39 @@ +! This test case is expected to fail due to errors. + +subroutine f1 (depth, iter) + integer :: depth, iter +end subroutine + +subroutine f2 (depth, iter) + integer :: depth, iter +end subroutine + +subroutine s1 (a1, a2, a3) + integer :: a1, a2, a3 + integer :: i, j, k + + !$omp do collapse(3) + do i = 1, a1 + call f1 (1, i) + do j = 1, a2 + call f1 (2, j) + if (i == 3) then + cycle ! { dg-error "CYCLE statement" } + else + exit ! { dg-error "EXIT statement" } + endif +!$omp barrier ! { dg-error "OpenMP directive in intervening code" } + do k = 1, a3 + call f1 (3, k) + call f2 (3, k) + end do + call f2 (2, j) + end do + do k = 1, a3 ! { dg-error "loop in intervening code" } + call f1 (3, k) + call f2 (3, k) + end do + call f2 (1, i) + end do + +end subroutine diff --git a/gcc/testsuite/gfortran.dg/gomp/imperfect2.f90 b/gcc/testsuite/gfortran.dg/gomp/imperfect2.f90 new file mode 100644 index 000000000000..d02191050d9b --- /dev/null +++ b/gcc/testsuite/gfortran.dg/gomp/imperfect2.f90 @@ -0,0 +1,56 @@ +! This test case is expected to fail due to errors. + +! Note that the calls to these functions in the test case don't make +! any sense in terms of behavior, they're just there to test the error +! behavior. + +module omp_lib + use iso_c_binding + interface + integer function omp_get_thread_num () + end + subroutine omp_set_max_levels (i) + integer :: i + end + end interface +end module + +program junk + use omp_lib + implicit none + +contains + +subroutine f1 (depth, iter) + integer :: depth, iter +end subroutine + +subroutine f2 (depth, iter) + integer :: depth, iter +end subroutine + +subroutine s1 (a1, a2, a3) + integer :: a1, a2, a3 + integer :: i, j, k + + integer :: m + + !$omp do collapse(3) + do i = 1, a1 + call f1 (1, i) + m = omp_get_thread_num () ! { dg-error "OpenMP API call in intervening code" } + do j = 1, a2 + omp_get_thread_num () ! This is OK + call f1 (2, j) + do k = 1, a3 + call f1 (m, k) + call omp_set_max_active_levels (k) ! This is OK too + call f2 (m, k) + end do + call f2 (2, j) + call omp_set_max_active_levels (i) ! { dg-error "OpenMP API call in intervening code" } + end do + call f2 (1, i) + end do +end subroutine + +end program diff --git a/gcc/testsuite/gfortran.dg/gomp/imperfect3.f90 b/gcc/testsuite/gfortran.dg/gomp/imperfect3.f90 new file mode 100644 index 000000000000..aa26a4909291 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/gomp/imperfect3.f90 @@ -0,0 +1,45 @@ +! This test case is expected to fail due to errors. + +subroutine f1 (depth, iter) + integer :: depth, iter +end subroutine + +subroutine f2 (depth, iter) + integer :: depth, iter +end subroutine + +subroutine s1 (a1, a2, a3) + integer :: a1, a2, a3 + integer :: i, j, k + + ! This loop without intervening code ought to be OK. + !$omp do ordered(3) + do i = 1, a1 + do j = 1, a2 + do k = 1, a3 + call f1 (3, k) + call f2 (3, k) + !$omp ordered doacross(source:omp_cur_iteration) + !$omp ordered doacross(sink: i - 2, j + 2, k - 1) + end do + end do + end do + + ! Adding intervening code should make it error. + !$omp do ordered(3) ! { dg-error "inner loops must be perfectly nested" } + do i = 1, a1 + call f1 (1, i) + do j = 1, a2 + call f1 (2, j) + do k = 1, a3 + call f1 (3, k) + call f2 (3, k) + !$omp ordered doacross(source:omp_cur_iteration) + !$omp ordered doacross(sink: i - 2, j + 2, k - 1) + end do + call f2 (2, j) + end do + call f2 (1, i) + end do + +end subroutine diff --git a/gcc/testsuite/gfortran.dg/gomp/imperfect4.f90 b/gcc/testsuite/gfortran.dg/gomp/imperfect4.f90 new file mode 100644 index 000000000000..b7ccd8b6c53b --- /dev/null +++ b/gcc/testsuite/gfortran.dg/gomp/imperfect4.f90 @@ -0,0 +1,36 @@ +! This test case is expected to fail due to errors. + +subroutine f1 (depth, iter) + integer :: depth, iter +end subroutine + +subroutine f2 (depth, iter) + integer :: depth, iter +end subroutine + +! Unlike the C/C++ front ends, the Fortran front end already has the whole +! parse tree for the OMP DO construct before doing error checking on it. +! It gives up immediately if there are not enough nested loops for the +! specified COLLAPSE depth, without error-checking intervening code. + +subroutine s1 (a1, a2, a3) + integer :: a1, a2, a3 + integer :: i, j, k + + !$omp do collapse(4) ! { dg-error "not enough DO loops" } + do i = 1, a1 + call f1 (1, i) + do j = 1, a2 + call f1 (2, j) + do k = 1, a3 +! This is not valid intervening code, but the above error takes precedence. +!$omp barrier + call f1 (3, k) + call f2 (3, k) + end do + call f2 (2, j) + end do + call f2 (1, i) + end do + +end subroutine diff --git a/gcc/testsuite/gfortran.dg/gomp/imperfect5.f90 b/gcc/testsuite/gfortran.dg/gomp/imperfect5.f90 new file mode 100644 index 000000000000..d71073563299 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/gomp/imperfect5.f90 @@ -0,0 +1,85 @@ +! This test case is expected to fail due to errors. + +module mm + +implicit none +integer, parameter :: N = 30 +integer, parameter :: M = 3 + +integer :: a(M,N), b(M,N), c(M,N) + +contains + +subroutine dostuff (index, flag) + integer :: index, flag +end subroutine + +! These functions should compile without error. +subroutine good1 () + integer :: i, j, x, shift + + x = 0 + !$omp parallel do simd collapse(2) reduction(inscan,+: x) private(shift) + do i = 1, N + do j = 1, M + x = x + a(j,i) + x = x + b(j,i) + !$omp scan inclusive(x) + shift = i + 29*j + c(j,i) = x + shift; + end do + end do +end subroutine + +subroutine good2 () + integer :: i, j, x, shift + + x = 0 + !$omp parallel do simd collapse(2) reduction(inscan,+: x) private(shift) + do i = 1, N + do j = 1, M + shift = i + 29*j + c(j,i) = x + shift; + !$omp scan exclusive(x) + x = x + a(j,i) + x = x + b(j,i) + end do + end do +end subroutine + +! Adding intervening code should trigger an error. +subroutine bad1 () + integer :: i, j, x, shift + + x = 0 + !$omp parallel do simd collapse(2) reduction(inscan,+: x) private(shift) ! { dg-error "inner loops must be perfectly nested" } + do i = 1, N + call dostuff (i, 0) + do j = 1, M + x = x + a(j,i) + x = x + b(j,i) + !$omp scan inclusive(x) + shift = i + 29*j + c(j,i) = x + shift; + end do + end do +end subroutine + +subroutine bad2 () + integer :: i, j, x, shift + + x = 0 + !$omp parallel do simd collapse(2) reduction(inscan,+: x) private(shift) ! { dg-error "inner loops must be perfectly nested" } + do i = 1, N + do j = 1, M + shift = i + 29*j + c(j,i) = x + shift; + !$omp scan exclusive(x) + x = x + a(j,i) + x = x + b(j,i) + end do + call dostuff (i, 1) + end do +end subroutine + +end module \ No newline at end of file diff --git a/gcc/testsuite/gfortran.dg/interface_procedure_1.f90 b/gcc/testsuite/gfortran.dg/interface_procedure_1.f90 new file mode 100644 index 000000000000..6a58b6a7bccd --- /dev/null +++ b/gcc/testsuite/gfortran.dg/interface_procedure_1.f90 @@ -0,0 +1,23 @@ +! { dg-do compile } +! { dg-additional-options "-std=f95" } +! +! PR fortran/48776 +! The following used to generate a segmentation fault in the front-end, +! because a pointer to the get1 symbol was remaining in the get interface +! after the procedure statement was rejected and the symbol freed. + + interface get + procedure get1 ! { dg-error "Fortran 2003: PROCEDURE statement" } + end interface + + integer :: h + call set1 (get (h)) ! { dg-error "no specific function for the generic 'get'" } +contains + subroutine set1 (a) + integer, intent(in) :: a + end subroutine + + integer function get1 (s) + integer :: s + end function +end diff --git a/gcc/testsuite/gfortran.dg/pr92586.f90 b/gcc/testsuite/gfortran.dg/pr92586.f90 new file mode 100644 index 000000000000..40ad50cb777c --- /dev/null +++ b/gcc/testsuite/gfortran.dg/pr92586.f90 @@ -0,0 +1,61 @@ +! { dg-do compile } +! +! Contributed by Emanuele Pagone +! +module foo_m + implicit none + + type :: string + character(len=:), allocatable :: s + end type string + + type :: foo_t + type(string), allocatable :: foo_s(:) + contains + procedure, public :: get_s + end type foo_t + + type :: data_t + integer :: n_foo_s + type(foo_t), allocatable :: foo(:) + contains + procedure, public :: data_get_foo_s + end type data_t + +contains + + function get_s(self) + class(foo_t), intent(in) :: self + type(string) :: get_s( size(self%foo_s) ) + get_s = self%foo_s + end function get_s + + function data_get_foo_s(self, ith) + class(data_t), intent(in) :: self + integer, intent(in) :: ith + type(string) :: data_get_foo_s(self%n_foo_s) + + data_get_foo_s = self%foo(ith)%get_s() ! The lhs was not dereferenced in a byref call. + + end function data_get_foo_s + +end module foo_m + + +program bug_stringifor + use foo_m + implicit none + + type(data_t) :: data + type(string), allocatable :: bar(:) + + allocate( data%foo(1) ) + data%foo(1)%foo_s = [string("alpha"), string("bravo"), string("charlie"), & + string("delta"), string("foxtrot")] + data%n_foo_s = 5 + + bar = data%data_get_foo_s(1) + + print *, "bar = ", bar(1)%s + +end program bug_stringifor diff --git a/gcc/testsuite/gfortran.dg/value_9.f90 b/gcc/testsuite/gfortran.dg/value_9.f90 index 1a2fa80ed0dc..4813250ebaa9 100644 --- a/gcc/testsuite/gfortran.dg/value_9.f90 +++ b/gcc/testsuite/gfortran.dg/value_9.f90 @@ -20,78 +20,82 @@ program p ! Check len=1 actual argument cases first ca = "a"; cp = "b"; cd = "c" ca4 = 4_"d"; cp4 = 4_"e"; cd4 = 4_"f" - call val ("B","B") - call val ("A",char(65)) - call val ("A",char(a)) - call val ("A",mychar(65)) - call val ("A",mychar(a)) - call val ("1",c) - call val ("1",(c)) - call val4 (4_"C",4_"C") - call val4 (4_"A",char(65,kind=4)) - call val4 (4_"A",char(a, kind=4)) - call val4 (4_"4",c4) - call val4 (4_"4",(c4)) - call val (ca,ca) - call val (cp,cp) - call val (cd,cd) - call val (ca,(ca)) - call val4 (ca4,ca4) - call val4 (cp4,cp4) - call val4 (cd4,cd4) - call val4 (cd4,(cd4)) - call sub ("S") - call sub4 (4_"T") + call val ("B","B", 1, 2) + call val ("A",char(65), 3, 4) + call val ("A",char(a), 5, 6) + call val ("A",mychar(65), 7, 8) + call val ("A",mychar(a), 9, 10) + call val ("1",c, 11, 12) + call val ("1",(c), 13, 14) + call val4 (4_"C",4_"C", 15, 16) + call val4 (4_"A",char(65,kind=4), 17, 18) + call val4 (4_"A",char(a, kind=4), 19, 20) + call val4 (4_"4",c4, 21, 22) + call val4 (4_"4",(c4), 23, 24) + call val (ca,ca, 25, 26) + call val (cp,cp, 27, 28) + call val (cd,cd, 29, 30) + call val (ca,(ca), 31, 32) + call val4 (ca4,ca4, 33, 34) + call val4 (cp4,cp4, 35, 36) + call val4 (cd4,cd4, 37, 38) + call val4 (cd4,(cd4), 39, 40) + call sub ("S", 41, 42) + call sub4 (4_"T", 43, 44) ! Check that always the first character of the string is finally used - call val ( "U++", "U--") - call val4 (4_"V**",4_"V//") - call sub ( "WTY") - call sub4 (4_"ZXV") - call val ( "234", d ) - call val4 (4_"345", d4 ) - call val ( "234", (d) ) - call val4 (4_"345", (d4) ) - call val ( "234", d (1:2)) - call val4 (4_"345", d4(1:2)) - call val ( "234", d (1:l)) - call val4 (4_"345", d4(1:l)) - call val ("1",c // d) - call val ("1",trim (c // d)) - call val4 (4_"4",c4 // d4) - call val4 (4_"4",trim (c4 // d4)) + call val ( "U++", "U--", 45, 46) + call val4 (4_"V**",4_"V//", 47, 48) + call sub ( "WTY", 49, 50) + call sub4 (4_"ZXV", 51, 52) + call val ( "234", d , 53, 54) + call val4 (4_"345", d4 , 55, 56) + call val ( "234", (d) , 57, 58) + call val4 (4_"345", (d4) , 59, 60) + call val ( "234", d (1:2), 61, 62) + call val4 (4_"345", d4(1:2), 63, 64) + call val ( "234", d (1:l), 65, 66) + call val4 (4_"345", d4(1:l), 67, 68) + call val ("1",c // d, 69, 70) + call val ("1",trim (c // d), 71, 72) + call val4 (4_"4",c4 // d4, 73, 74) + call val4 (4_"4",trim (c4 // d4), 75, 76) cd = "gkl"; cd4 = 4_"hmn" - call val (cd,cd) - call val4 (cd4,cd4) - call sub (cd) - call sub4 (cd4) + call val (cd,cd, 77, 78) + call val4 (cd4,cd4, 79, 80) + call sub (cd, 81, 82) + call sub4 (cd4, 83, 84) deallocate (ca, cp, ca4, cp4, cd, cd4) contains - subroutine val (x, c) + subroutine val (x, c, err1, err2) character(kind=1), intent(in) :: x ! control: pass by reference character(kind=1), value :: c + integer, intent(in) :: err1, err2 print *, "by value(kind=1): ", c - if (c /= x) stop 1 + if (c /= x) stop err1 c = "*" - if (c /= "*") stop 2 + if (c /= "*") stop err2 end - subroutine val4 (x, c) + subroutine val4 (x, c, err1, err2) character(kind=4), intent(in) :: x ! control: pass by reference character(kind=4), value :: c + integer, intent(in) :: err1, err2 print *, "by value(kind=4): ", c - if (c /= x) stop 3 + if (c /= x) stop err1 c = 4_"#" - if (c /= 4_"#") stop 4 + if (c /= 4_"#") stop err2 end - subroutine sub (s) + subroutine sub (s, err1, err2) character(*), intent(in) :: s - call val (s, s) + integer, intent(in) :: err1, err2 + call val (s, s, err1, err2) end - subroutine sub4 (s) + subroutine sub4 (s, err1, err2) character(kind=4,len=*), intent(in) :: s - call val4 (s, s) + integer, intent(in) :: err1, err2 + call val4 (s, s, err1, err2) end character function mychar (i) diff --git a/gcc/testsuite/gfortran.dg/vect/pr49955.f b/gcc/testsuite/gfortran.dg/vect/pr49955.f new file mode 100644 index 000000000000..a73cd5ada03b --- /dev/null +++ b/gcc/testsuite/gfortran.dg/vect/pr49955.f @@ -0,0 +1,38 @@ +! { dg-do compile } +! { dg-additional-options "-ffast-math -fdump-tree-slp1" } + + subroutine shell(nx,ny,nz,q,dt,cfl,dx,dy,dz,cfll,gm,Pr,Re) + implicit none + integer nx,ny,nz,i,j,k + real*8 cfl,dx,dy,dz,dt + real*8 gm,Re,Pr,cfll,t1,t2,t3,t4,t5,t6,t7,t8,mu + real*8 q(5,nx,ny,nz) + + if (cfll.ge.cfl) cfll=cfl + t8=0.0d0 + + do k=1,nz + do j=1,ny + do i=1,nx + t1=q(1,i,j,k) + t2=q(2,i,j,k)/t1 + t3=q(3,i,j,k)/t1 + t4=q(4,i,j,k)/t1 + t5=(gm-1.0d0)*(q(5,i,j,k)-0.5d0*t1*(t2*t2+t3*t3+t4*t4)) + t6=dSQRT(gm*t5/t1) + mu=gm*Pr*(gm*t5/t1)**0.75d0*2.0d0/Re/t1 + t7=((dabs(t2)+t6)/dx+mu/dx**2)**2 + + 1 ((dabs(t3)+t6)/dy+mu/dy**2)**2 + + 2 ((dabs(t4)+t6)/dz+mu/dz**2)**2 + t7=DSQRT(t7) + t8=max(t8,t7) + enddo + enddo + enddo + dt=cfll / t8 + + return + end + +! We don't have an effective target for reduc_plus_scal optab support +! { dg-final { scan-tree-dump ".REDUC_PLUS" "slp1" { target x86_64-*-* } } } diff --git a/gcc/testsuite/gm2/iso/check/fail/iso-check-fail.exp b/gcc/testsuite/gm2/iso/check/fail/iso-check-fail.exp index 836760d6c666..8710e7b4fbf7 100644 --- a/gcc/testsuite/gm2/iso/check/fail/iso-check-fail.exp +++ b/gcc/testsuite/gm2/iso/check/fail/iso-check-fail.exp @@ -44,7 +44,7 @@ set TORTURE_OPTIONS [list \ { -O3 -fsoft-check-all } \ { -O3 -g -fsoft-check-all } ] -gm2_init_iso "${srcdir}/gm2/iso/check/fail" -fm2-pathname=- -I${srcdir}/gm2/iso/check/fail +gm2_init_iso "${srcdir}/gm2/iso/check/fail" -fm2-plugin -fm2-pathname=- -I${srcdir}/gm2/iso/check/fail foreach testcase [lsort [glob -nocomplain $srcdir/$subdir/*.mod]] { # If we're only testing specific files and this isn't one of them, skip it. diff --git a/gcc/testsuite/gm2/switches/auto-init/fail/switches-auto-init-fail.exp b/gcc/testsuite/gm2/switches/auto-init/fail/switches-auto-init-fail.exp index 44b44b42fe5f..aba9b4077efa 100644 --- a/gcc/testsuite/gm2/switches/auto-init/fail/switches-auto-init-fail.exp +++ b/gcc/testsuite/gm2/switches/auto-init/fail/switches-auto-init-fail.exp @@ -36,7 +36,7 @@ if $tracelevel then { # load support procs load_lib gm2-torture.exp -gm2_init_pim2 "${srcdir}/gm2/switches/auto-init/fail" -fsoft-check-all -O2 -fauto-init -fm2-pathname=- -I${srcdir}/gm2/switches/auto-init/fail +gm2_init_pim2 "${srcdir}/gm2/switches/auto-init/fail" -fm2-plugin -fsoft-check-all -O2 -fauto-init -fm2-pathname=- -I${srcdir}/gm2/switches/auto-init/fail foreach testcase [lsort [glob -nocomplain $srcdir/$subdir/*.mod]] { # If we're only testing specific files and this isn't one of them, skip it. diff --git a/gcc/testsuite/gm2/switches/check-all/pim2/fail/switches-check-all-pim2-fail.exp b/gcc/testsuite/gm2/switches/check-all/pim2/fail/switches-check-all-pim2-fail.exp index bd2d72373ea1..e9595cf37af2 100644 --- a/gcc/testsuite/gm2/switches/check-all/pim2/fail/switches-check-all-pim2-fail.exp +++ b/gcc/testsuite/gm2/switches/check-all/pim2/fail/switches-check-all-pim2-fail.exp @@ -36,7 +36,7 @@ if $tracelevel then { # load support procs load_lib gm2-torture.exp -gm2_init_pim2 "${srcdir}/gm2/switches/check-all/pim2/fail" -fsoft-check-all -O2 -g -fm2-pathname=- -I${srcdir}/gm2/switches/check-all/pim2/fail +gm2_init_pim2 "${srcdir}/gm2/switches/check-all/pim2/fail" -fsoft-check-all -fm2-plugin -O2 -g -fm2-pathname=- -I${srcdir}/gm2/switches/check-all/pim2/fail foreach testcase [lsort [glob -nocomplain $srcdir/$subdir/*.mod]] { # If we're only testing specific files and this isn't one of them, skip it. diff --git a/gcc/testsuite/gm2/switches/check-all/plugin/iso/fail/switches-check-all-plugin-iso-fail.exp b/gcc/testsuite/gm2/switches/check-all/plugin/iso/fail/switches-check-all-plugin-iso-fail.exp index b6a90ba3abb4..a3d40ae62087 100644 --- a/gcc/testsuite/gm2/switches/check-all/plugin/iso/fail/switches-check-all-plugin-iso-fail.exp +++ b/gcc/testsuite/gm2/switches/check-all/plugin/iso/fail/switches-check-all-plugin-iso-fail.exp @@ -45,7 +45,7 @@ set TORTURE_OPTIONS [list \ { -O3 -fsoft-check-all } \ { -O3 -g -fsoft-check-all } ] -gm2_init_iso "${srcdir}/gm2/switches/check-all/plugin/iso/fail/" +gm2_init_iso "${srcdir}/gm2/switches/check-all/plugin/iso/fail/" -fm2-plugin foreach testcase [lsort [glob -nocomplain $srcdir/$subdir/*.mod]] { # If we're only testing specific files and this isn't one of them, skip it. diff --git a/gcc/testsuite/gm2/switches/check-all/plugin/pim2/fail/switches-check-all-plugin-pim2-fail.exp b/gcc/testsuite/gm2/switches/check-all/plugin/pim2/fail/switches-check-all-plugin-pim2-fail.exp index a934961ddce2..d6b1a77b17b7 100644 --- a/gcc/testsuite/gm2/switches/check-all/plugin/pim2/fail/switches-check-all-plugin-pim2-fail.exp +++ b/gcc/testsuite/gm2/switches/check-all/plugin/pim2/fail/switches-check-all-plugin-pim2-fail.exp @@ -45,7 +45,7 @@ set TORTURE_OPTIONS [list \ { -O3 -fsoft-check-all } \ { -O3 -g -fsoft-check-all } ] -gm2_init_pim2 "${srcdir}/gm2/switches/check-all/plugin/pim2/fail/" +gm2_init_pim2 "${srcdir}/gm2/switches/check-all/plugin/pim2/fail/" -fm2-plugin foreach testcase [lsort [glob -nocomplain $srcdir/$subdir/*.mod]] { # If we're only testing specific files and this isn't one of them, skip it. diff --git a/gcc/testsuite/jit.dg/all-non-failing-tests.h b/gcc/testsuite/jit.dg/all-non-failing-tests.h index 80606076e787..e762563f9bdb 100644 --- a/gcc/testsuite/jit.dg/all-non-failing-tests.h +++ b/gcc/testsuite/jit.dg/all-non-failing-tests.h @@ -313,6 +313,9 @@ #undef create_code #undef verify_code +/* test-restrict.c: This can't be in the testcases array as it needs + the `-O3` flag. */ + /* test-register-variable.c: This can't be in the testcases array as it is target-specific. */ diff --git a/gcc/testsuite/jit.dg/test-restrict.c b/gcc/testsuite/jit.dg/test-restrict.c new file mode 100644 index 000000000000..a6ac96324d2c --- /dev/null +++ b/gcc/testsuite/jit.dg/test-restrict.c @@ -0,0 +1,77 @@ +/* { dg-do compile { target x86_64-*-* } } */ + +#include +#include + +#include "libgccjit.h" + +/* We don't want set_options() in harness.h to set -O3 to see that the restrict + attribute affects the optimizations. */ +#define TEST_ESCHEWS_SET_OPTIONS +static void set_options (gcc_jit_context *ctxt, const char *argv0) +{ + // Set "-O3". + gcc_jit_context_set_int_option(ctxt, GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL, 3); +} + +#define TEST_COMPILING_TO_FILE +#define OUTPUT_KIND GCC_JIT_OUTPUT_KIND_ASSEMBLER +#define OUTPUT_FILENAME "output-of-test-restrict.c.s" +#include "harness.h" + +void +create_code (gcc_jit_context *ctxt, void *user_data) +{ + /* Let's try to inject the equivalent of: +void t(int *__restrict__ a, int *__restrict__ b, char *__restrict__ c) { + *a += *c; + *b += *c; +} + */ + gcc_jit_type *int_type = + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT); + gcc_jit_type *pint_type = gcc_jit_type_get_pointer(int_type); + gcc_jit_type *pint_restrict_type = gcc_jit_type_get_restrict(pint_type); + + gcc_jit_type *void_type = + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID); + + gcc_jit_param *a = + gcc_jit_context_new_param (ctxt, NULL, pint_restrict_type, "a"); + gcc_jit_param *b = + gcc_jit_context_new_param (ctxt, NULL, pint_restrict_type, "b"); + gcc_jit_param *c = + gcc_jit_context_new_param (ctxt, NULL, pint_restrict_type, "c"); + gcc_jit_param *params[3] = {a, b, c}; + + gcc_jit_function *func_t = + gcc_jit_context_new_function (ctxt, NULL, + GCC_JIT_FUNCTION_EXPORTED, + void_type, + "t", + 3, params, + 0); + + gcc_jit_block *block = gcc_jit_function_new_block (func_t, NULL); + + /* *a += *c; */ + gcc_jit_block_add_assignment_op ( + block, NULL, + gcc_jit_rvalue_dereference (gcc_jit_param_as_rvalue (a), NULL), + GCC_JIT_BINARY_OP_PLUS, + gcc_jit_lvalue_as_rvalue ( + gcc_jit_rvalue_dereference (gcc_jit_param_as_rvalue (c), NULL))); + /* *b += *c; */ + gcc_jit_block_add_assignment_op ( + block, NULL, + gcc_jit_rvalue_dereference (gcc_jit_param_as_rvalue (b), NULL), + GCC_JIT_BINARY_OP_PLUS, + gcc_jit_lvalue_as_rvalue ( + gcc_jit_rvalue_dereference (gcc_jit_param_as_rvalue (c), NULL))); + + gcc_jit_block_end_with_void_return (block, NULL); +} + +/* { dg-final { jit-verify-output-file-was-created "" } } */ +/* { dg-final { jit-verify-assembler-output "addl %eax, (%rdi) + addl %eax, (%rsi)" } } */ diff --git a/gcc/testsuite/lib/target-supports.exp b/gcc/testsuite/lib/target-supports.exp index 7004711b3848..d353cc0aaf03 100644 --- a/gcc/testsuite/lib/target-supports.exp +++ b/gcc/testsuite/lib/target-supports.exp @@ -975,6 +975,9 @@ proc check_effective_target_untyped_assembly {} { # Return 1 if alloca is supported, 0 otherwise. proc check_effective_target_alloca {} { + if { [istarget bpf-*-*] } { + return 0 + } if { [istarget nvptx-*-*] } { return [check_no_compiler_messages alloca assembly { void f (void*); @@ -8397,7 +8400,8 @@ proc check_effective_target_vect_masked_load { } { # Return 1 if the target supports vector masked stores. proc check_effective_target_vect_masked_store { } { - return [expr { [check_effective_target_aarch64_sve] + return [expr { [check_avx_available] + || [check_effective_target_aarch64_sve] || [istarget amdgcn*-*-*] }] } @@ -8631,6 +8635,24 @@ proc check_effective_target_vect_variable_length { } { return [expr { [lindex [available_vector_sizes] 0] == 0 }] } +# Return 1 if the target supports vectors of 512 bits. + +proc check_effective_target_vect512 { } { + return [expr { [lsearch -exact [available_vector_sizes] 512] >= 0 }] +} + +# Return 1 if the target supports vectors of 256 bits. + +proc check_effective_target_vect256 { } { + return [expr { [lsearch -exact [available_vector_sizes] 256] >= 0 }] +} + +# Return 1 if the target supports vectors of 128 bits. + +proc check_effective_target_vect128 { } { + return [expr { [lsearch -exact [available_vector_sizes] 128] >= 0 }] +} + # Return 1 if the target supports vectors of 64 bits. proc check_effective_target_vect64 { } { @@ -12559,3 +12581,38 @@ proc check_effective_target_const_volatile_readonly_section { } { } return 1 } + +# Appends necessary Python flags to extra-tool-flags if Python.h is supported. +# Otherwise, modifies dg-do-what. +proc dg-require-python-h { args } { + upvar dg-extra-tool-flags extra-tool-flags + + verbose "ENTER dg-require-python-h" 2 + + set supported 0 + set result [remote_exec host "python3-config --includes"] + set status [lindex $result 0] + if { $status == 0 } { + # Remove trailing newline from python3-config output. + set python_flags [string trim [lindex $result 1]] + if [check_no_compiler_messages python_h assembly { + #include + int main (void) { return 0; } + } $python_flags] { + set supported 1 + } + } + + if { $supported == 0 } { + verbose "Python.h not supported" 2 + upvar dg-do-what dg-do-what + set dg-do-what [list [lindex ${dg-do-what} 0] "N" "P"] + return + } + + verbose "Python flags are: $python_flags" 2 + + verbose "Before appending, extra-tool-flags: ${extra-tool-flags}" 3 + eval lappend extra-tool-flags $python_flags + verbose "After appending, extra-tool-flags: ${extra-tool-flags}" 3 +} diff --git a/gcc/tree-cfg.cc b/gcc/tree-cfg.cc index ab1f8067c545..ffab7518b156 100644 --- a/gcc/tree-cfg.cc +++ b/gcc/tree-cfg.cc @@ -5684,6 +5684,26 @@ gimple_verify_flow_info (void) error ("fallthru to exit from bb %d", e->src->index); err = true; } + if (cfun->cfg->full_profile + && !ENTRY_BLOCK_PTR_FOR_FN (cfun)->count.initialized_p ()) + { + error ("entry block count not initialized"); + err = true; + } + if (cfun->cfg->full_profile + && !EXIT_BLOCK_PTR_FOR_FN (cfun)->count.initialized_p ()) + { + error ("exit block count not initialized"); + err = true; + } + if (cfun->cfg->full_profile + && !single_succ_edge + (ENTRY_BLOCK_PTR_FOR_FN (cfun))->probability.initialized_p ()) + { + error ("probability of edge from entry block not initialized"); + err = true; + } + FOR_EACH_BB_FN (bb, cfun) { @@ -5691,6 +5711,22 @@ gimple_verify_flow_info (void) stmt = NULL; + if (cfun->cfg->full_profile) + { + if (!bb->count.initialized_p ()) + { + error ("count of bb %d not initialized", bb->index); + err = true; + } + FOR_EACH_EDGE (e, ei, bb->succs) + if (!e->probability.initialized_p ()) + { + error ("probability of edge %d->%d not initialized", + bb->index, e->dest->index); + err = true; + } + } + /* Skip labels on the start of basic block. */ for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi)) { @@ -7734,11 +7770,14 @@ fold_loop_internal_call (gimple *g, tree value) test. This should not happen as the guarded code should start with pre-header. */ gcc_assert (single_pred_edge (taken_edge->dest)); - taken_edge->dest->count - = taken_edge->dest->count.apply_scale (new_count, - old_count); - scale_strictly_dominated_blocks (taken_edge->dest, - new_count, old_count); + if (old_count.nonzero_p ()) + { + taken_edge->dest->count + = taken_edge->dest->count.apply_scale (new_count, + old_count); + scale_strictly_dominated_blocks (taken_edge->dest, + new_count, old_count); + } } } } @@ -8565,7 +8604,7 @@ print_loop_info (FILE *file, const class loop *loop, const char *prefix) fprintf (file, "\n%siterations by profile: %f (%s%s) entry count:", prefix, iterations.to_double (), reliable ? "reliable" : "unreliable", maybe_flat_loop_profile (loop) ? ", maybe flat" : ""); - loop_count_in (loop).dump (dump_file, cfun); + loop_count_in (loop).dump (file, cfun); } } diff --git a/gcc/tree-core.h b/gcc/tree-core.h index 668808a29d07..91551fde9002 100644 --- a/gcc/tree-core.h +++ b/gcc/tree-core.h @@ -558,6 +558,7 @@ enum omp_clause_default_kind { enum omp_clause_defaultmap_kind { OMP_CLAUSE_DEFAULTMAP_CATEGORY_UNSPECIFIED, + OMP_CLAUSE_DEFAULTMAP_CATEGORY_ALL, OMP_CLAUSE_DEFAULTMAP_CATEGORY_SCALAR, OMP_CLAUSE_DEFAULTMAP_CATEGORY_AGGREGATE, OMP_CLAUSE_DEFAULTMAP_CATEGORY_ALLOCATABLE, diff --git a/gcc/tree-diagnostic.cc b/gcc/tree-diagnostic.cc index 731e3559cd81..d2f6637b6d95 100644 --- a/gcc/tree-diagnostic.cc +++ b/gcc/tree-diagnostic.cc @@ -377,5 +377,6 @@ tree_diagnostics_defaults (diagnostic_context *context) context->print_path = default_tree_diagnostic_path_printer; context->make_json_for_path = default_tree_make_json_for_path; context->set_locations_cb = set_inlining_locations; + delete context->m_client_data_hooks; context->m_client_data_hooks = make_compiler_data_hooks (); } diff --git a/gcc/tree-inline.cc b/gcc/tree-inline.cc index 954b39ae1c62..d63060c9429c 100644 --- a/gcc/tree-inline.cc +++ b/gcc/tree-inline.cc @@ -1708,6 +1708,11 @@ remap_gimple_stmt (gimple *stmt, copy_body_data *id) (s1, gimple_omp_sections_clauses (stmt)); break; + case GIMPLE_OMP_STRUCTURED_BLOCK: + s1 = remap_gimple_seq (gimple_omp_body (stmt), id); + copy = gimple_build_omp_structured_block (s1); + break; + case GIMPLE_OMP_SINGLE: s1 = remap_gimple_seq (gimple_omp_body (stmt), id); copy = gimple_build_omp_single @@ -2815,6 +2820,7 @@ initialize_cfun (tree new_fndecl, tree callee_fndecl, profile_count count) init_empty_tree_cfg (); profile_status_for_fn (cfun) = profile_status_for_fn (src_cfun); + cfun->cfg->full_profile = src_cfun->cfg->full_profile; profile_count num = count; profile_count den = ENTRY_BLOCK_PTR_FOR_FN (src_cfun)->count; @@ -4561,6 +4567,7 @@ estimate_num_insns (gimple *stmt, eni_weights *weights) case GIMPLE_OMP_SCAN: case GIMPLE_OMP_SECTION: case GIMPLE_OMP_SECTIONS: + case GIMPLE_OMP_STRUCTURED_BLOCK: case GIMPLE_OMP_SINGLE: case GIMPLE_OMP_TARGET: case GIMPLE_OMP_TEAMS: @@ -4953,6 +4960,7 @@ expand_call_inline (basic_block bb, gimple *stmt, copy_body_data *id, id->src_cfun = DECL_STRUCT_FUNCTION (fn); id->reset_location = DECL_IGNORED_P (fn); id->call_stmt = call_stmt; + cfun->cfg->full_profile &= id->src_cfun->cfg->full_profile; /* When inlining into an OpenMP SIMD-on-SIMT loop, arrange for new automatic variables to be added to IFN_GOMP_SIMT_ENTER argument list. */ diff --git a/gcc/tree-nested.cc b/gcc/tree-nested.cc index ae7d1f1f6a84..31c7b6001bd4 100644 --- a/gcc/tree-nested.cc +++ b/gcc/tree-nested.cc @@ -1795,6 +1795,7 @@ convert_nonlocal_reference_stmt (gimple_stmt_iterator *gsi, bool *handled_ops_p, break; case GIMPLE_OMP_SECTION: + case GIMPLE_OMP_STRUCTURED_BLOCK: case GIMPLE_OMP_MASTER: case GIMPLE_OMP_MASKED: case GIMPLE_OMP_ORDERED: @@ -2540,6 +2541,7 @@ convert_local_reference_stmt (gimple_stmt_iterator *gsi, bool *handled_ops_p, break; case GIMPLE_OMP_SECTION: + case GIMPLE_OMP_STRUCTURED_BLOCK: case GIMPLE_OMP_MASTER: case GIMPLE_OMP_MASKED: case GIMPLE_OMP_ORDERED: @@ -3050,6 +3052,7 @@ convert_gimple_call (gimple_stmt_iterator *gsi, bool *handled_ops_p, /* FALLTHRU */ case GIMPLE_OMP_SECTIONS: case GIMPLE_OMP_SECTION: + case GIMPLE_OMP_STRUCTURED_BLOCK: case GIMPLE_OMP_SINGLE: case GIMPLE_OMP_SCOPE: case GIMPLE_OMP_MASTER: diff --git a/gcc/tree-outof-ssa.cc b/gcc/tree-outof-ssa.cc index 0bf57a4bbc59..767623ab8eac 100644 --- a/gcc/tree-outof-ssa.cc +++ b/gcc/tree-outof-ssa.cc @@ -1283,6 +1283,33 @@ insert_backedge_copies (void) } } +/* Remove indirect clobbers. */ + +static void +remove_indirect_clobbers (void) +{ + basic_block bb; + + FOR_EACH_BB_FN (bb, cfun) + for (auto gsi = gsi_start_bb (bb); !gsi_end_p (gsi);) + { + gimple *stmt = gsi_stmt (gsi); + if (gimple_clobber_p (stmt)) + { + tree lhs = gimple_assign_lhs (stmt); + if (TREE_CODE (lhs) == MEM_REF + && TREE_CODE (TREE_OPERAND (lhs, 0)) == SSA_NAME) + { + unlink_stmt_vdef (stmt); + gsi_remove (&gsi, true); + release_defs (stmt); + continue; + } + } + gsi_next (&gsi); + } +} + /* Free all memory associated with going out of SSA form. SA is the outof-SSA info object. */ @@ -1305,6 +1332,10 @@ finish_out_of_ssa (struct ssaexpand *sa) unsigned int rewrite_out_of_ssa (struct ssaexpand *sa) { + /* Remove remaining indirect clobbers as we do not need those anymore. + Those might extend SSA lifetime and restrict coalescing. */ + remove_indirect_clobbers (); + /* If elimination of a PHI requires inserting a copy on a backedge, then we will have to split the backedge which has numerous undesirable performance effects. @@ -1313,7 +1344,6 @@ rewrite_out_of_ssa (struct ssaexpand *sa) copies into the loop itself. */ insert_backedge_copies (); - /* Eliminate PHIs which are of no use, such as virtual or dead phis. */ eliminate_useless_phis (); diff --git a/gcc/tree-pretty-print.cc b/gcc/tree-pretty-print.cc index 25d191b10fd7..4491176a126d 100644 --- a/gcc/tree-pretty-print.cc +++ b/gcc/tree-pretty-print.cc @@ -1248,6 +1248,9 @@ dump_omp_clause (pretty_printer *pp, tree clause, int spc, dump_flags_t flags) { case OMP_CLAUSE_DEFAULTMAP_CATEGORY_UNSPECIFIED: break; + case OMP_CLAUSE_DEFAULTMAP_CATEGORY_ALL: + pp_string (pp, ":all"); + break; case OMP_CLAUSE_DEFAULTMAP_CATEGORY_SCALAR: pp_string (pp, ":scalar"); break; @@ -1900,6 +1903,7 @@ dump_generic_node (pretty_printer *pp, tree node, int spc, dump_flags_t flags, case TREE_VEC: { size_t i; + pp_left_brace (pp); if (TREE_VEC_LENGTH (node) > 0) { size_t len = TREE_VEC_LENGTH (node); @@ -1913,6 +1917,7 @@ dump_generic_node (pretty_printer *pp, tree node, int spc, dump_flags_t flags, dump_generic_node (pp, TREE_VEC_ELT (node, len - 1), spc, flags, false); } + pp_right_brace (pp); } break; @@ -2482,14 +2487,16 @@ dump_generic_node (pretty_printer *pp, tree node, int spc, dump_flags_t flags, if (op_prio (op0) < op_prio (node)) pp_right_paren (pp); pp_string (pp, str); - dump_generic_node (pp, TREE_OPERAND (node, 1), spc, flags, false); - op0 = component_ref_field_offset (node); - if (op0 && TREE_CODE (op0) != INTEGER_CST) - { - pp_string (pp, "{off: "); - dump_generic_node (pp, op0, spc, flags, false); + op1 = TREE_OPERAND (node, 1); + dump_generic_node (pp, op1, spc, flags, false); + if (DECL_P (op1)) /* Not always a decl in the C++ FE. */ + if (tree off = component_ref_field_offset (node)) + if (TREE_CODE (off) != INTEGER_CST) + { + pp_string (pp, "{off: "); + dump_generic_node (pp, off, spc, flags, false); pp_right_brace (pp); - } + } break; case BIT_FIELD_REF: @@ -3741,6 +3748,10 @@ dump_generic_node (pretty_printer *pp, tree node, int spc, dump_flags_t flags, pp_string (pp, "#pragma omp section"); goto dump_omp_body; + case OMP_STRUCTURED_BLOCK: + pp_string (pp, "#pragma omp __structured_block"); + goto dump_omp_body; + case OMP_SCAN: if (OMP_SCAN_CLAUSES (node)) { diff --git a/gcc/tree-ssa-address.cc b/gcc/tree-ssa-address.cc index 0aaddde8d024..b942799f6f54 100644 --- a/gcc/tree-ssa-address.cc +++ b/gcc/tree-ssa-address.cc @@ -344,7 +344,7 @@ tree_mem_ref_addr (tree type, tree mem_ref) bool valid_mem_ref_p (machine_mode mode, addr_space_t as, - struct mem_address *addr) + struct mem_address *addr, code_helper ch) { rtx address; @@ -352,7 +352,7 @@ valid_mem_ref_p (machine_mode mode, addr_space_t as, if (!address) return false; - return memory_address_addr_space_p (mode, address, as); + return memory_address_addr_space_p (mode, address, as, ch); } /* Checks whether a TARGET_MEM_REF with type TYPE and parameters given by ADDR diff --git a/gcc/tree-ssa-address.h b/gcc/tree-ssa-address.h index 2eadbdef8102..faa1cb137452 100644 --- a/gcc/tree-ssa-address.h +++ b/gcc/tree-ssa-address.h @@ -31,7 +31,8 @@ extern rtx addr_for_mem_ref (struct mem_address *, addr_space_t, bool); extern rtx addr_for_mem_ref (tree exp, addr_space_t as, bool really_expand); extern void get_address_description (tree, struct mem_address *); extern tree tree_mem_ref_addr (tree, tree); -extern bool valid_mem_ref_p (machine_mode, addr_space_t, struct mem_address *); +extern bool valid_mem_ref_p (machine_mode, addr_space_t, struct mem_address *, + code_helper = ERROR_MARK); extern void move_fixed_address_to_symbol (struct mem_address *, class aff_tree *); tree create_mem_ref (gimple_stmt_iterator *, tree, diff --git a/gcc/tree-ssa-alias.cc b/gcc/tree-ssa-alias.cc index cf38fe506a8c..373940b5f6c2 100644 --- a/gcc/tree-ssa-alias.cc +++ b/gcc/tree-ssa-alias.cc @@ -2818,11 +2818,13 @@ ref_maybe_used_by_call_p_1 (gcall *call, ao_ref *ref, bool tbaa_p) case IFN_MASK_LEN_STORE: return false; case IFN_MASK_STORE_LANES: + case IFN_MASK_LEN_STORE_LANES: goto process_args; case IFN_MASK_LOAD: case IFN_LEN_LOAD: case IFN_MASK_LEN_LOAD: case IFN_MASK_LOAD_LANES: + case IFN_MASK_LEN_LOAD_LANES: { ao_ref rhs_ref; tree lhs = gimple_call_lhs (call); @@ -3072,6 +3074,7 @@ call_may_clobber_ref_p_1 (gcall *call, ao_ref *ref, bool tbaa_p) case IFN_LEN_STORE: case IFN_MASK_LEN_STORE: case IFN_MASK_STORE_LANES: + case IFN_MASK_LEN_STORE_LANES: { tree rhs = gimple_call_arg (call, internal_fn_stored_value_index (fn)); diff --git a/gcc/tree-ssa-ccp.cc b/gcc/tree-ssa-ccp.cc index 15e65f160084..e048675577fb 100644 --- a/gcc/tree-ssa-ccp.cc +++ b/gcc/tree-ssa-ccp.cc @@ -4302,22 +4302,7 @@ pass_fold_builtins::execute (function *fun) if (gimple_code (stmt) != GIMPLE_CALL) { - /* Remove all *ssaname_N ={v} {CLOBBER}; stmts, - after the last GIMPLE DSE they aren't needed and might - unnecessarily keep the SSA_NAMEs live. */ - if (gimple_clobber_p (stmt)) - { - tree lhs = gimple_assign_lhs (stmt); - if (TREE_CODE (lhs) == MEM_REF - && TREE_CODE (TREE_OPERAND (lhs, 0)) == SSA_NAME) - { - unlink_stmt_vdef (stmt); - gsi_remove (&i, true); - release_defs (stmt); - continue; - } - } - else if (gimple_assign_load_p (stmt) && gimple_store_p (stmt)) + if (gimple_assign_load_p (stmt) && gimple_store_p (stmt)) optimize_memcpy (&i, gimple_assign_lhs (stmt), gimple_assign_rhs1 (stmt), NULL_TREE); gsi_next (&i); diff --git a/gcc/tree-ssa-ifcombine.cc b/gcc/tree-ssa-ifcombine.cc index 58e19c1508e4..46b076804f4a 100644 --- a/gcc/tree-ssa-ifcombine.cc +++ b/gcc/tree-ssa-ifcombine.cc @@ -430,6 +430,10 @@ ifcombine_ifandif (basic_block inner_cond_bb, bool inner_inv, { tree t, t2; + if (TREE_CODE (name1) == SSA_NAME + && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (name1)) + return false; + /* Do it. */ gsi = gsi_for_stmt (inner_cond); t = fold_build2 (LSHIFT_EXPR, TREE_TYPE (name1), @@ -486,6 +490,12 @@ ifcombine_ifandif (basic_block inner_cond_bb, bool inner_inv, gimple_stmt_iterator gsi; tree t; + if ((TREE_CODE (name1) == SSA_NAME + && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (name1)) + || (TREE_CODE (name2) == SSA_NAME + && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (name2))) + return false; + /* Find the common name which is bit-tested. */ if (name1 == name2) ; diff --git a/gcc/tree-ssa-live.cc b/gcc/tree-ssa-live.cc index c9c2fdef0e3c..61789fae67d5 100644 --- a/gcc/tree-ssa-live.cc +++ b/gcc/tree-ssa-live.cc @@ -1676,23 +1676,27 @@ virtual_operand_live::get_live_in (basic_block bb) if (!liveout) init (); - /* Since we don't have a virtual PHI we can now pick any of the - incoming edges liveout value. All returns from the function have - a virtual use forcing generation of virtual PHIs. */ + /* Since we don't have a virtual PHI and we don't know whether there's + a downstream virtual use (and thus PHIs are inserted where necessary) + we now have to check each incoming edge live-out. */ edge_iterator ei; edge e; + tree livein = NULL_TREE; FOR_EACH_EDGE (e, ei, bb->preds) - if (liveout[e->src->index]) - { - if (EDGE_PRED (bb, 0) != e) - liveout[EDGE_PRED (bb, 0)->src->index] = liveout[e->src->index]; - return liveout[e->src->index]; - } + if (e->flags & EDGE_DFS_BACK) + /* We can ignore backedges since if there's a def there it would + have forced a PHI in the source because it also acts as use + downstream. */ + continue; + else if (!livein) + livein = get_live_out (e->src); + else if (get_live_out (e->src) != livein) + /* When there's no virtual use downstream this indicates a point + where we'd insert a PHI merging the different live virtual + operands. */ + return NULL_TREE; - /* Since virtuals are in SSA form at most the immediate dominator can - contain the definition of the live version. Skipping to that deals - with CFG cycles as well. */ - return get_live_out (get_immediate_dominator (CDI_DOMINATORS, bb)); + return livein; } /* Compute live-out of BB. */ diff --git a/gcc/tree-ssa-live.h b/gcc/tree-ssa-live.h index a7604448332c..d175ad7247e2 100644 --- a/gcc/tree-ssa-live.h +++ b/gcc/tree-ssa-live.h @@ -332,7 +332,8 @@ make_live_on_entry (tree_live_info_p live, basic_block bb , int p) /* On-demand virtual operand global live analysis. There is at most a single virtual operand live at a time, the following computes and caches the virtual operand live at the exit of a basic block - supporting related live-in and live-on-edge queries. */ + supporting related live-in and live-on-edge queries. It requires + up-to-date marked backedges. */ class virtual_operand_live { diff --git a/gcc/tree-ssa-loop-ch.cc b/gcc/tree-ssa-loop-ch.cc index 6cdb87a762fa..461416e40862 100644 --- a/gcc/tree-ssa-loop-ch.cc +++ b/gcc/tree-ssa-loop-ch.cc @@ -176,7 +176,7 @@ enum ch_decision ch_impossible, /* We can copy it if it enables wins. */ ch_possible, - /* We can "cop" it if it enables wins and doing + /* We can "copy" it if it enables wins and doing so will introduce no new code. */ ch_possible_zero_cost, /* We want to copy. */ @@ -464,7 +464,7 @@ should_duplicate_loop_header_p (basic_block header, class loop *loop, TODO: Even if duplication costs some size we may opt to do so in case exit probability is significant enough (do partial peeling). */ if (static_exit) - return code_size_cost ? ch_possible_zero_cost : ch_win; + return !code_size_cost ? ch_possible_zero_cost : ch_possible; /* We was not able to prove that conditional will be eliminated. */ int insns = estimate_num_insns (last, &eni_size_weights); @@ -824,6 +824,7 @@ ch_base::copy_headers (function *fun) int last_win_nheaders = 0; bool last_win_invariant_exit = false; ch_decision ret; + auto_vec decision; hash_set *invariant_exits = new hash_set ; hash_set *static_exits = new hash_set ; while ((ret = should_duplicate_loop_header_p (header, loop, ranger, @@ -833,6 +834,7 @@ ch_base::copy_headers (function *fun) != ch_impossible) { nheaders++; + decision.safe_push (ret); if (ret >= ch_win) { last_win_nheaders = nheaders; @@ -841,20 +843,6 @@ ch_base::copy_headers (function *fun) fprintf (dump_file, " Duplicating bb %i is a win\n", header->index); } - /* Duplicate BB if has zero cost but be sure it will not - imply duplication of other BBs. */ - else if (ret == ch_possible_zero_cost - && (last_win_nheaders == nheaders - 1 - || (last_win_nheaders == nheaders - 2 - && last_win_invariant_exit))) - { - last_win_nheaders = nheaders; - last_win_invariant_exit = false; - if (dump_file && (dump_flags & TDF_DETAILS)) - fprintf (dump_file, - " Duplicating bb %i is a win; it has zero cost\n", - header->index); - } else if (dump_file && (dump_flags & TDF_DETAILS)) fprintf (dump_file, " May duplicate bb %i\n", header->index); @@ -884,6 +872,16 @@ ch_base::copy_headers (function *fun) fprintf (dump_file, " Duplicating header BB to obtain do-while loop\n"); } + /* "Duplicate" all BBs with zero cost following last basic blocks we + decided to copy. */ + while (last_win_nheaders < (int)decision.length () + && decision[last_win_nheaders] == ch_possible_zero_cost) + { + if (dump_file && (dump_flags & TDF_DETAILS)) + fprintf (dump_file, + " Duplicating extra bb is a win; it has zero cost\n"); + last_win_nheaders++; + } if (last_win_nheaders) candidates.safe_push ({loop, last_win_nheaders, diff --git a/gcc/tree-ssa-loop-im.cc b/gcc/tree-ssa-loop-im.cc index 268f466bdc9f..b8e33a4d49a1 100644 --- a/gcc/tree-ssa-loop-im.cc +++ b/gcc/tree-ssa-loop-im.cc @@ -1665,11 +1665,21 @@ gather_mem_refs_stmt (class loop *loop, gimple *stmt) unshare_expr (mem_base)); if (TYPE_ALIGN (ref_type) != ref_align) ref_type = build_aligned_type (ref_type, ref_align); - (*slot)->mem.ref + tree new_ref = fold_build2 (MEM_REF, ref_type, tmp, build_int_cst (ref_alias_type, mem_off)); if ((*slot)->mem.volatile_p) - TREE_THIS_VOLATILE ((*slot)->mem.ref) = 1; + TREE_THIS_VOLATILE (new_ref) = 1; + (*slot)->mem.ref = new_ref; + /* Make sure the recorded base and offset are consistent + with the newly built ref. */ + if (TREE_CODE (TREE_OPERAND (new_ref, 0)) == ADDR_EXPR) + ; + else + { + (*slot)->mem.base = new_ref; + (*slot)->mem.offset = 0; + } gcc_checking_assert (TREE_CODE ((*slot)->mem.ref) == MEM_REF && is_gimple_mem_ref_addr (TREE_OPERAND ((*slot)->mem.ref, diff --git a/gcc/tree-ssa-loop-ivcanon.cc b/gcc/tree-ssa-loop-ivcanon.cc index a895e8e65be0..1330cf82a42e 100644 --- a/gcc/tree-ssa-loop-ivcanon.cc +++ b/gcc/tree-ssa-loop-ivcanon.cc @@ -63,6 +63,7 @@ along with GCC; see the file COPYING3. If not see #include "tree-cfgcleanup.h" #include "builtins.h" #include "tree-ssa-sccvn.h" +#include "tree-vectorizer.h" /* For find_loop_location */ #include "dbgcnt.h" /* Specifies types of loops that may be unrolled. */ @@ -166,6 +167,11 @@ constant_after_peeling (tree op, gimple *stmt, class loop *loop) if (CONSTANT_CLASS_P (op)) return true; + /* Get at the actual SSA operand. */ + if (handled_component_p (op) + && TREE_CODE (TREE_OPERAND (op, 0)) == SSA_NAME) + op = TREE_OPERAND (op, 0); + /* We can still fold accesses to constant arrays when index is known. */ if (TREE_CODE (op) != SSA_NAME) { @@ -198,7 +204,46 @@ constant_after_peeling (tree op, gimple *stmt, class loop *loop) tree ev = analyze_scalar_evolution (loop, op); if (chrec_contains_undetermined (ev) || chrec_contains_symbols (ev)) - return false; + { + if (ANY_INTEGRAL_TYPE_P (TREE_TYPE (op))) + { + gassign *ass = nullptr; + gphi *phi = nullptr; + if (is_a (SSA_NAME_DEF_STMT (op))) + { + ass = as_a (SSA_NAME_DEF_STMT (op)); + if (TREE_CODE (gimple_assign_rhs1 (ass)) == SSA_NAME) + phi = dyn_cast + (SSA_NAME_DEF_STMT (gimple_assign_rhs1 (ass))); + } + else if (is_a (SSA_NAME_DEF_STMT (op))) + { + phi = as_a (SSA_NAME_DEF_STMT (op)); + if (gimple_bb (phi) == loop->header) + { + tree def = gimple_phi_arg_def_from_edge + (phi, loop_latch_edge (loop)); + if (TREE_CODE (def) == SSA_NAME + && is_a (SSA_NAME_DEF_STMT (def))) + ass = as_a (SSA_NAME_DEF_STMT (def)); + } + } + if (ass && phi) + { + tree rhs1 = gimple_assign_rhs1 (ass); + if (gimple_assign_rhs_class (ass) == GIMPLE_BINARY_RHS + && CONSTANT_CLASS_P (gimple_assign_rhs2 (ass)) + && rhs1 == gimple_phi_result (phi) + && gimple_bb (phi) == loop->header + && (gimple_phi_arg_def_from_edge (phi, loop_latch_edge (loop)) + == gimple_assign_lhs (ass)) + && (CONSTANT_CLASS_P (gimple_phi_arg_def_from_edge + (phi, loop_preheader_edge (loop))))) + return true; + } + } + return false; + } return true; } @@ -1186,7 +1231,6 @@ canonicalize_loop_induction_variables (class loop *loop, tree niter; HOST_WIDE_INT maxiter; bool modified = false; - dump_user_location_t locus; class tree_niter_desc niter_desc; bool may_be_zero = false; @@ -1200,9 +1244,7 @@ canonicalize_loop_induction_variables (class loop *loop, may_be_zero = niter_desc.may_be_zero && !integer_zerop (niter_desc.may_be_zero); } - if (TREE_CODE (niter) == INTEGER_CST) - locus = last_nondebug_stmt (exit->src); - else + if (TREE_CODE (niter) != INTEGER_CST) { /* For non-constant niter fold may_be_zero into niter again. */ if (may_be_zero) @@ -1227,9 +1269,6 @@ canonicalize_loop_induction_variables (class loop *loop, || TREE_CODE (niter) != INTEGER_CST)) niter = find_loop_niter_by_eval (loop, &exit); - if (exit) - locus = last_nondebug_stmt (exit->src); - if (TREE_CODE (niter) != INTEGER_CST) exit = NULL; } @@ -1271,6 +1310,7 @@ canonicalize_loop_induction_variables (class loop *loop, populates the loop bounds. */ modified |= remove_redundant_iv_tests (loop); + dump_user_location_t locus = find_loop_location (loop); if (try_unroll_loop_completely (loop, exit, niter, may_be_zero, ul, maxiter, locus, allow_peel)) return true; diff --git a/gcc/tree-ssa-loop-ivopts.cc b/gcc/tree-ssa-loop-ivopts.cc index 934897af6917..3d3f28f7f3ba 100644 --- a/gcc/tree-ssa-loop-ivopts.cc +++ b/gcc/tree-ssa-loop-ivopts.cc @@ -2441,6 +2441,7 @@ get_mem_type_for_internal_fn (gcall *call, tree *op_p) { case IFN_MASK_LOAD: case IFN_MASK_LOAD_LANES: + case IFN_MASK_LEN_LOAD_LANES: case IFN_LEN_LOAD: case IFN_MASK_LEN_LOAD: if (op_p == gimple_call_arg_ptr (call, 0)) @@ -2449,6 +2450,7 @@ get_mem_type_for_internal_fn (gcall *call, tree *op_p) case IFN_MASK_STORE: case IFN_MASK_STORE_LANES: + case IFN_MASK_LEN_STORE_LANES: case IFN_LEN_STORE: case IFN_MASK_LEN_STORE: { @@ -4704,17 +4706,25 @@ get_address_cost (struct ivopts_data *data, struct iv_use *use, /* Only true if ratio != 1. */ bool ok_with_ratio_p = false; bool ok_without_ratio_p = false; + code_helper code = ERROR_MARK; + + if (use->type == USE_PTR_ADDRESS) + { + gcall *call = as_a (use->stmt); + gcc_assert (gimple_call_internal_p (call)); + code = gimple_call_internal_fn (call); + } if (!aff_combination_const_p (aff_inv)) { parts.index = integer_one_node; /* Addressing mode "base + index". */ - ok_without_ratio_p = valid_mem_ref_p (mem_mode, as, &parts); + ok_without_ratio_p = valid_mem_ref_p (mem_mode, as, &parts, code); if (ratio != 1) { parts.step = wide_int_to_tree (type, ratio); /* Addressing mode "base + index << scale". */ - ok_with_ratio_p = valid_mem_ref_p (mem_mode, as, &parts); + ok_with_ratio_p = valid_mem_ref_p (mem_mode, as, &parts, code); if (!ok_with_ratio_p) parts.step = NULL_TREE; } @@ -4724,7 +4734,7 @@ get_address_cost (struct ivopts_data *data, struct iv_use *use, { parts.offset = wide_int_to_tree (sizetype, aff_inv->offset); /* Addressing mode "base + index [<< scale] + offset". */ - if (!valid_mem_ref_p (mem_mode, as, &parts)) + if (!valid_mem_ref_p (mem_mode, as, &parts, code)) parts.offset = NULL_TREE; else aff_inv->offset = 0; @@ -4737,7 +4747,7 @@ get_address_cost (struct ivopts_data *data, struct iv_use *use, /* Addressing mode "symbol + base + index [<< scale] [+ offset]". */ if (parts.symbol != NULL_TREE - && !valid_mem_ref_p (mem_mode, as, &parts)) + && !valid_mem_ref_p (mem_mode, as, &parts, code)) { aff_combination_add_elt (aff_inv, parts.symbol, 1); parts.symbol = NULL_TREE; @@ -4775,7 +4785,7 @@ get_address_cost (struct ivopts_data *data, struct iv_use *use, { parts.offset = wide_int_to_tree (sizetype, aff_inv->offset); /* Addressing mode "base + offset". */ - if (!valid_mem_ref_p (mem_mode, as, &parts)) + if (!valid_mem_ref_p (mem_mode, as, &parts, code)) parts.offset = NULL_TREE; else aff_inv->offset = 0; @@ -7565,6 +7575,8 @@ get_alias_ptr_type_for_ptr_address (iv_use *use) case IFN_MASK_STORE: case IFN_MASK_LOAD_LANES: case IFN_MASK_STORE_LANES: + case IFN_MASK_LEN_LOAD_LANES: + case IFN_MASK_LEN_STORE_LANES: case IFN_LEN_LOAD: case IFN_LEN_STORE: case IFN_MASK_LEN_LOAD: diff --git a/gcc/tree-ssa-loop-split.cc b/gcc/tree-ssa-loop-split.cc index 2f7918c6e65a..64464802c1e5 100644 --- a/gcc/tree-ssa-loop-split.cc +++ b/gcc/tree-ssa-loop-split.cc @@ -703,7 +703,7 @@ split_loop (class loop *loop1) split between of the two new loops. Keep orignal estimate since it is likely better then completely dropping it. - TODO: If we know that onle of the new loops has constant + TODO: If we know that one of the new loops has constant number of iterations, we can do better. We could also update upper bounds. */ if (loop1->any_estimate @@ -713,11 +713,15 @@ split_loop (class loop *loop1) ? true_edge->probability.to_sreal () : (sreal)1; sreal scale2 = false_edge->probability.reliable_p () ? false_edge->probability.to_sreal () : (sreal)1; + sreal div1 = loop1_prob.to_sreal (); /* +1 to get header interations rather than latch iterations and then -1 to convert back. */ - loop1->nb_iterations_estimate - = MAX ((((sreal)loop1->nb_iterations_estimate.to_shwi () + 1) * scale - / loop1_prob.to_sreal ()).to_nearest_int () - 1, 0); + if (div1 != 0) + loop1->nb_iterations_estimate + = MAX ((((sreal)loop1->nb_iterations_estimate.to_shwi () + 1) + * scale / div1).to_nearest_int () - 1, 0); + else + loop1->any_estimate = false; loop2->nb_iterations_estimate = MAX ((((sreal)loop2->nb_iterations_estimate.to_shwi () + 1) * scale2 / profile_probability::very_likely ().to_sreal ()) diff --git a/gcc/tree-ssa-math-opts.cc b/gcc/tree-ssa-math-opts.cc index 712097ac5be0..95c22694368c 100644 --- a/gcc/tree-ssa-math-opts.cc +++ b/gcc/tree-ssa-math-opts.cc @@ -4641,8 +4641,135 @@ match_uaddc_usubc (gimple_stmt_iterator *gsi, gimple *stmt, tree_code code) __imag__ of something, verify it is .UADDC/.USUBC. */ tree rhs1 = gimple_assign_rhs1 (im); gimple *ovf = SSA_NAME_DEF_STMT (TREE_OPERAND (rhs1, 0)); + tree ovf_lhs = NULL_TREE; + tree ovf_arg1 = NULL_TREE, ovf_arg2 = NULL_TREE; if (gimple_call_internal_p (ovf, code == PLUS_EXPR - ? IFN_UADDC : IFN_USUBC) + ? IFN_ADD_OVERFLOW + : IFN_SUB_OVERFLOW)) + { + /* Or verify it is .ADD_OVERFLOW/.SUB_OVERFLOW. + This is for the case of 2 chained .UADDC/.USUBC, + where the first one uses 0 carry-in and the second + one ignores the carry-out. + So, something like: + _16 = .ADD_OVERFLOW (_1, _2); + _17 = REALPART_EXPR <_16>; + _18 = IMAGPART_EXPR <_16>; + _15 = _3 + _4; + _12 = _15 + _18; + where the first 3 statements come from the lower + limb addition and the last 2 from the higher limb + which ignores carry-out. */ + ovf_lhs = gimple_call_lhs (ovf); + tree ovf_lhs_type = TREE_TYPE (TREE_TYPE (ovf_lhs)); + ovf_arg1 = gimple_call_arg (ovf, 0); + ovf_arg2 = gimple_call_arg (ovf, 1); + /* In that case we need to punt if the types don't + mismatch. */ + if (!types_compatible_p (type, ovf_lhs_type) + || !types_compatible_p (type, TREE_TYPE (ovf_arg1)) + || !types_compatible_p (type, + TREE_TYPE (ovf_arg2))) + ovf_lhs = NULL_TREE; + else + { + for (int i = (code == PLUS_EXPR ? 1 : 0); + i >= 0; --i) + { + tree r = gimple_call_arg (ovf, i); + if (TREE_CODE (r) != SSA_NAME) + continue; + if (uaddc_is_cplxpart (SSA_NAME_DEF_STMT (r), + REALPART_EXPR)) + { + /* Punt if one of the args which isn't + subtracted isn't __real__; that could + then prevent better match later. + Consider: + _3 = .ADD_OVERFLOW (_1, _2); + _4 = REALPART_EXPR <_3>; + _5 = IMAGPART_EXPR <_3>; + _7 = .ADD_OVERFLOW (_4, _6); + _8 = REALPART_EXPR <_7>; + _9 = IMAGPART_EXPR <_7>; + _12 = _10 + _11; + _13 = _12 + _9; + _14 = _13 + _5; + We want to match this when called on + the last stmt as a pair of .UADDC calls, + but without this check we could turn + that prematurely on _13 = _12 + _9; + stmt into .UADDC with 0 carry-in just + on the second .ADD_OVERFLOW call and + another replacing the _12 and _13 + additions. */ + ovf_lhs = NULL_TREE; + break; + } + } + } + if (ovf_lhs) + { + use_operand_p use_p; + imm_use_iterator iter; + tree re_lhs = NULL_TREE; + FOR_EACH_IMM_USE_FAST (use_p, iter, ovf_lhs) + { + gimple *use_stmt = USE_STMT (use_p); + if (is_gimple_debug (use_stmt)) + continue; + if (use_stmt == im) + continue; + if (!uaddc_is_cplxpart (use_stmt, + REALPART_EXPR)) + { + ovf_lhs = NULL_TREE; + break; + } + re_lhs = gimple_assign_lhs (use_stmt); + } + if (ovf_lhs && re_lhs) + { + FOR_EACH_IMM_USE_FAST (use_p, iter, re_lhs) + { + gimple *use_stmt = USE_STMT (use_p); + if (is_gimple_debug (use_stmt)) + continue; + internal_fn ifn + = gimple_call_internal_fn (ovf); + /* Punt if the __real__ of lhs is used + in the same .*_OVERFLOW call. + Consider: + _3 = .ADD_OVERFLOW (_1, _2); + _4 = REALPART_EXPR <_3>; + _5 = IMAGPART_EXPR <_3>; + _7 = .ADD_OVERFLOW (_4, _6); + _8 = REALPART_EXPR <_7>; + _9 = IMAGPART_EXPR <_7>; + _12 = _10 + _11; + _13 = _12 + _5; + _14 = _13 + _9; + We want to match this when called on + the last stmt as a pair of .UADDC calls, + but without this check we could turn + that prematurely on _13 = _12 + _5; + stmt into .UADDC with 0 carry-in just + on the first .ADD_OVERFLOW call and + another replacing the _12 and _13 + additions. */ + if (gimple_call_internal_p (use_stmt, ifn)) + { + ovf_lhs = NULL_TREE; + break; + } + } + } + } + } + if ((ovf_lhs + || gimple_call_internal_p (ovf, + code == PLUS_EXPR + ? IFN_UADDC : IFN_USUBC)) && (optab_handler (code == PLUS_EXPR ? uaddc5_optab : usubc5_optab, TYPE_MODE (type)) @@ -4668,6 +4795,26 @@ match_uaddc_usubc (gimple_stmt_iterator *gsi, gimple *stmt, tree_code code) TREE_TYPE (ilhs), nlhs)); gsi_replace (gsi, g, true); + /* And if it is initialized from result of __imag__ + of .{ADD,SUB}_OVERFLOW call, replace that + call with .U{ADD,SUB}C call with the same arguments, + just 0 added as third argument. This isn't strictly + necessary, .ADD_OVERFLOW (x, y) and .UADDC (x, y, 0) + produce the same result, but may result in better + generated code on some targets where the backend can + better prepare in how the result will be used. */ + if (ovf_lhs) + { + tree zero = build_zero_cst (type); + g = gimple_build_call_internal (code == PLUS_EXPR + ? IFN_UADDC + : IFN_USUBC, + 3, ovf_arg1, + ovf_arg2, zero); + gimple_call_set_lhs (g, ovf_lhs); + gimple_stmt_iterator gsi2 = gsi_for_stmt (ovf); + gsi_replace (&gsi2, g, true); + } return true; } } diff --git a/gcc/tree-ssa-phiopt.cc b/gcc/tree-ssa-phiopt.cc index ff36bb0119b5..3148ad38e234 100644 --- a/gcc/tree-ssa-phiopt.cc +++ b/gcc/tree-ssa-phiopt.cc @@ -63,7 +63,13 @@ single_non_singleton_phi_for_edges (gimple_seq seq, edge e0, edge e1) gimple_stmt_iterator i; gphi *phi = NULL; if (gimple_seq_singleton_p (seq)) - return as_a (gsi_stmt (gsi_start (seq))); + { + phi = as_a (gsi_stmt (gsi_start (seq))); + /* Never return virtual phis. */ + if (virtual_operand_p (gimple_phi_result (phi))) + return NULL; + return phi; + } for (i = gsi_start (seq); !gsi_end_p (i); gsi_next (&i)) { gphi *p = as_a (gsi_stmt (i)); @@ -72,6 +78,10 @@ single_non_singleton_phi_for_edges (gimple_seq seq, edge e0, edge e1) gimple_phi_arg_def (p, e1->dest_idx))) continue; + /* Punt on virtual phis with different arguments from the edges. */ + if (virtual_operand_p (gimple_phi_result (p))) + return NULL; + /* If we already have a PHI that has the two edge arguments are different, then return it is not a singleton for these PHIs. */ if (phi) @@ -486,7 +496,6 @@ gimple_simplify_phiopt (bool early_p, tree type, gimple *comp_stmt, tree arg0, tree arg1, gimple_seq *seq) { - tree result; gimple_seq seq1 = NULL; enum tree_code comp_code = gimple_cond_code (comp_stmt); location_t loc = gimple_location (comp_stmt); @@ -516,18 +525,29 @@ gimple_simplify_phiopt (bool early_p, tree type, gimple *comp_stmt, if (op.resimplify (&seq1, follow_all_ssa_edges)) { - /* Early we want only to allow some generated tree codes. */ - if (!early_p - || phiopt_early_allow (seq1, op)) + bool allowed = !early_p || phiopt_early_allow (seq1, op); + tree result = maybe_push_res_to_seq (&op, &seq1); + if (dump_file && (dump_flags & TDF_FOLDING)) { - result = maybe_push_res_to_seq (&op, &seq1); + fprintf (dump_file, "\nphiopt match-simplify back:\n"); + if (seq1) + print_gimple_seq (dump_file, seq1, 0, TDF_VOPS|TDF_MEMSYMS); + fprintf (dump_file, "result: "); if (result) - { - if (loc != UNKNOWN_LOCATION) - annotate_all_with_location (seq1, loc); - gimple_seq_add_seq_without_update (seq, seq1); - return result; - } + print_generic_expr (dump_file, result); + else + fprintf (dump_file, " (none)"); + fprintf (dump_file, "\n"); + if (!allowed) + fprintf (dump_file, "rejected because early\n"); + } + /* Early we want only to allow some generated tree codes. */ + if (allowed && result) + { + if (loc != UNKNOWN_LOCATION) + annotate_all_with_location (seq1, loc); + gimple_seq_add_seq_without_update (seq, seq1); + return result; } } gimple_seq_discard (seq1); @@ -559,18 +579,29 @@ gimple_simplify_phiopt (bool early_p, tree type, gimple *comp_stmt, if (op1.resimplify (&seq1, follow_all_ssa_edges)) { - /* Early we want only to allow some generated tree codes. */ - if (!early_p - || phiopt_early_allow (seq1, op1)) + bool allowed = !early_p || phiopt_early_allow (seq1, op1); + tree result = maybe_push_res_to_seq (&op1, &seq1); + if (dump_file && (dump_flags & TDF_FOLDING)) { - result = maybe_push_res_to_seq (&op1, &seq1); + fprintf (dump_file, "\nphiopt match-simplify back:\n"); + if (seq1) + print_gimple_seq (dump_file, seq1, 0, TDF_VOPS|TDF_MEMSYMS); + fprintf (dump_file, "result: "); if (result) - { - if (loc != UNKNOWN_LOCATION) - annotate_all_with_location (seq1, loc); - gimple_seq_add_seq_without_update (seq, seq1); - return result; - } + print_generic_expr (dump_file, result); + else + fprintf (dump_file, " (none)"); + fprintf (dump_file, "\n"); + if (!allowed) + fprintf (dump_file, "rejected because early\n"); + } + /* Early we want only to allow some generated tree codes. */ + if (allowed && result) + { + if (loc != UNKNOWN_LOCATION) + annotate_all_with_location (seq1, loc); + gimple_seq_add_seq_without_update (seq, seq1); + return result; } } gimple_seq_discard (seq1); @@ -842,6 +873,8 @@ match_simplify_replacement (basic_block cond_bb, basic_block middle_bb, if (!result) return false; + if (dump_file && (dump_flags & TDF_FOLDING)) + fprintf (dump_file, "accepted the phiopt match-simplify.\n"); auto_bitmap exprs_maybe_dce; @@ -868,11 +901,6 @@ match_simplify_replacement (basic_block cond_bb, basic_block middle_bb, if (name && TREE_CODE (name) == SSA_NAME) bitmap_set_bit (exprs_maybe_dce, SSA_NAME_VERSION (name)); } - if (dump_file && (dump_flags & TDF_FOLDING)) - { - fprintf (dump_file, "Folded into the sequence:\n"); - print_gimple_seq (dump_file, seq, 0, TDF_VOPS|TDF_MEMSYMS); - } gsi_insert_seq_before (&gsi, seq, GSI_CONTINUE_LINKING); } diff --git a/gcc/tree-ssa-pre.cc b/gcc/tree-ssa-pre.cc index 0f2e458395c8..07fb165b2a89 100644 --- a/gcc/tree-ssa-pre.cc +++ b/gcc/tree-ssa-pre.cc @@ -3314,6 +3314,8 @@ do_pre_regular_insertion (basic_block block, basic_block dom, bool by_some = false; bool cant_insert = false; bool all_same = true; + unsigned num_inserts = 0; + unsigned num_const = 0; pre_expr first_s = NULL; edge pred; basic_block bprime; @@ -3370,11 +3372,14 @@ do_pre_regular_insertion (basic_block block, basic_block dom, { avail[pred->dest_idx] = eprime; all_same = false; + num_inserts++; } else { avail[pred->dest_idx] = edoubleprime; by_some = true; + if (edoubleprime->kind == CONSTANT) + num_const++; /* We want to perform insertions to remove a redundancy on a path in the CFG we want to optimize for speed. */ if (optimize_edge_for_speed_p (pred)) @@ -3391,6 +3396,12 @@ do_pre_regular_insertion (basic_block block, basic_block dom, partially redundant. */ if (!cant_insert && !all_same && by_some) { + /* If the expression is redundant on all edges and we need + to at most insert one copy from a constant do the PHI + insertion even when not optimizing a path that's to be + optimized for speed. */ + if (num_inserts == 0 && num_const <= 1) + do_insertion = true; if (!do_insertion) { if (dump_file && (dump_flags & TDF_DETAILS)) diff --git a/gcc/tree-ssa-sccvn.cc b/gcc/tree-ssa-sccvn.cc index 32e06fae3b9f..b1678911671e 100644 --- a/gcc/tree-ssa-sccvn.cc +++ b/gcc/tree-ssa-sccvn.cc @@ -74,6 +74,9 @@ along with GCC; see the file COPYING3. If not see #include "ipa-modref-tree.h" #include "ipa-modref.h" #include "tree-ssa-sccvn.h" +#include "alloc-pool.h" +#include "symbol-summary.h" +#include "ipa-prop.h" /* This algorithm is based on the SCC algorithm presented by Keith Cooper and L. Taylor Simpson in "SCC-Based Value numbering" @@ -2327,7 +2330,7 @@ vn_walk_cb_data::push_partial_def (pd_data pd, with the current VUSE and performs the expression lookup. */ static void * -vn_reference_lookup_2 (ao_ref *op ATTRIBUTE_UNUSED, tree vuse, void *data_) +vn_reference_lookup_2 (ao_ref *op, tree vuse, void *data_) { vn_walk_cb_data *data = (vn_walk_cb_data *)data_; vn_reference_t vr = data->vr; @@ -2361,6 +2364,35 @@ vn_reference_lookup_2 (ao_ref *op ATTRIBUTE_UNUSED, tree vuse, void *data_) return *slot; } + if (SSA_NAME_IS_DEFAULT_DEF (vuse)) + { + HOST_WIDE_INT op_offset, op_size; + tree v = NULL_TREE; + tree base = ao_ref_base (op); + + if (base + && op->offset.is_constant (&op_offset) + && op->size.is_constant (&op_size) + && op->max_size_known_p () + && known_eq (op->size, op->max_size)) + { + if (TREE_CODE (base) == PARM_DECL) + v = ipcp_get_aggregate_const (cfun, base, false, op_offset, + op_size); + else if (TREE_CODE (base) == MEM_REF + && integer_zerop (TREE_OPERAND (base, 1)) + && TREE_CODE (TREE_OPERAND (base, 0)) == SSA_NAME + && SSA_NAME_IS_DEFAULT_DEF (TREE_OPERAND (base, 0)) + && (TREE_CODE (SSA_NAME_VAR (TREE_OPERAND (base, 0))) + == PARM_DECL)) + v = ipcp_get_aggregate_const (cfun, + SSA_NAME_VAR (TREE_OPERAND (base, 0)), + true, op_offset, op_size); + } + if (v) + return data->finish (vr->set, vr->base_set, v); + } + return NULL; } diff --git a/gcc/tree-ssa-sink.cc b/gcc/tree-ssa-sink.cc index 6ad9d21589ef..a360c5cdd6e8 100644 --- a/gcc/tree-ssa-sink.cc +++ b/gcc/tree-ssa-sink.cc @@ -822,6 +822,7 @@ pass_sink_code::execute (function *fun) /* Arrange for the critical edge splitting to be undone if requested. */ unsigned todo = unsplit_edges ? TODO_cleanup_cfg : 0; connect_infinite_loops_to_exit (); + mark_dfs_back_edges (fun); memset (&sink_stats, 0, sizeof (sink_stats)); calculate_dominance_info (CDI_DOMINATORS); diff --git a/gcc/tree-ssa-strlen.cc b/gcc/tree-ssa-strlen.cc index 4bf183072d91..8b7ef919826b 100644 --- a/gcc/tree-ssa-strlen.cc +++ b/gcc/tree-ssa-strlen.cc @@ -3340,7 +3340,8 @@ strlen_pass::handle_builtin_memcpy (built_in_function bcode) && !integer_zerop (len)) { maybe_warn_overflow (stmt, false, len, olddsi, false, true); - adjust_last_stmt (olddsi, stmt, false); + if (tree_fits_uhwi_p (len)) + adjust_last_stmt (olddsi, stmt, false); } int idx = get_stridx (src, stmt); diff --git a/gcc/tree-ssa-threadupdate.cc b/gcc/tree-ssa-threadupdate.cc index d5416b21a783..a5b9a002a8ab 100644 --- a/gcc/tree-ssa-threadupdate.cc +++ b/gcc/tree-ssa-threadupdate.cc @@ -1059,14 +1059,19 @@ ssa_fix_duplicate_block_edges (struct redirection_data *rd, threading path. */ if (!any_remaining_duplicated_blocks (path, i)) { - e2 = redirect_edge_and_branch (victim, elast->dest); - /* If we redirected the edge, then we need to copy PHI arguments - at the target. If the edge already existed (e2 != victim - case), then the PHIs in the target already have the correct - arguments. */ - if (e2 == victim) - copy_phi_args (e2->dest, elast, e2, - path, multi_incomings ? 0 : i); + if (victim->dest != elast->dest) + { + e2 = redirect_edge_and_branch (victim, elast->dest); + /* If we redirected the edge, then we need to copy PHI arguments + at the target. If the edge already existed (e2 != victim + case), then the PHIs in the target already have the correct + arguments. */ + if (e2 == victim) + copy_phi_args (e2->dest, elast, e2, + path, multi_incomings ? 0 : i); + } + else + e2 = victim; } else { diff --git a/gcc/tree-vect-data-refs.cc b/gcc/tree-vect-data-refs.cc index a3570c45b520..40ab568fe355 100644 --- a/gcc/tree-vect-data-refs.cc +++ b/gcc/tree-vect-data-refs.cc @@ -670,158 +670,166 @@ vect_slp_analyze_data_ref_dependence (vec_info *vinfo, } -/* Analyze dependences involved in the transform of SLP NODE. STORES +/* Analyze dependences involved in the transform of a store SLP NODE. */ + +static bool +vect_slp_analyze_store_dependences (vec_info *vinfo, slp_tree node) +{ + /* This walks over all stmts involved in the SLP store done + in NODE verifying we can sink them up to the last stmt in the + group. */ + stmt_vec_info last_access_info = vect_find_last_scalar_stmt_in_slp (node); + gcc_assert (DR_IS_WRITE (STMT_VINFO_DATA_REF (last_access_info))); + + for (unsigned k = 0; k < SLP_TREE_SCALAR_STMTS (node).length (); ++k) + { + stmt_vec_info access_info + = vect_orig_stmt (SLP_TREE_SCALAR_STMTS (node)[k]); + if (access_info == last_access_info) + continue; + data_reference *dr_a = STMT_VINFO_DATA_REF (access_info); + ao_ref ref; + bool ref_initialized_p = false; + for (gimple_stmt_iterator gsi = gsi_for_stmt (access_info->stmt); + gsi_stmt (gsi) != last_access_info->stmt; gsi_next (&gsi)) + { + gimple *stmt = gsi_stmt (gsi); + if (! gimple_vuse (stmt)) + continue; + + /* If we couldn't record a (single) data reference for this + stmt we have to resort to the alias oracle. */ + stmt_vec_info stmt_info = vinfo->lookup_stmt (stmt); + data_reference *dr_b = STMT_VINFO_DATA_REF (stmt_info); + if (!dr_b) + { + /* We are moving a store - this means + we cannot use TBAA for disambiguation. */ + if (!ref_initialized_p) + ao_ref_init (&ref, DR_REF (dr_a)); + if (stmt_may_clobber_ref_p_1 (stmt, &ref, false) + || ref_maybe_used_by_stmt_p (stmt, &ref, false)) + return false; + continue; + } + + gcc_assert (!gimple_visited_p (stmt)); + + ddr_p ddr = initialize_data_dependence_relation (dr_a, + dr_b, vNULL); + bool dependent = vect_slp_analyze_data_ref_dependence (vinfo, ddr); + free_dependence_relation (ddr); + if (dependent) + return false; + } + } + return true; +} + +/* Analyze dependences involved in the transform of a load SLP NODE. STORES contain the vector of scalar stores of this instance if we are disambiguating the loads. */ static bool -vect_slp_analyze_node_dependences (vec_info *vinfo, slp_tree node, +vect_slp_analyze_load_dependences (vec_info *vinfo, slp_tree node, vec stores, stmt_vec_info last_store_info) { - /* This walks over all stmts involved in the SLP load/store done - in NODE verifying we can sink them up to the last stmt in the + /* This walks over all stmts involved in the SLP load done + in NODE verifying we can hoist them up to the first stmt in the group. */ - if (DR_IS_WRITE (STMT_VINFO_DATA_REF (SLP_TREE_REPRESENTATIVE (node)))) + stmt_vec_info first_access_info = vect_find_first_scalar_stmt_in_slp (node); + gcc_assert (DR_IS_READ (STMT_VINFO_DATA_REF (first_access_info))); + + for (unsigned k = 0; k < SLP_TREE_SCALAR_STMTS (node).length (); ++k) { - stmt_vec_info last_access_info = vect_find_last_scalar_stmt_in_slp (node); - for (unsigned k = 0; k < SLP_TREE_SCALAR_STMTS (node).length (); ++k) + stmt_vec_info access_info + = vect_orig_stmt (SLP_TREE_SCALAR_STMTS (node)[k]); + if (access_info == first_access_info) + continue; + data_reference *dr_a = STMT_VINFO_DATA_REF (access_info); + ao_ref ref; + bool ref_initialized_p = false; + hash_set grp_visited; + for (gimple_stmt_iterator gsi = gsi_for_stmt (access_info->stmt); + gsi_stmt (gsi) != first_access_info->stmt; gsi_prev (&gsi)) { - stmt_vec_info access_info - = vect_orig_stmt (SLP_TREE_SCALAR_STMTS (node)[k]); - if (access_info == last_access_info) + gimple *stmt = gsi_stmt (gsi); + if (! gimple_vdef (stmt)) continue; - data_reference *dr_a = STMT_VINFO_DATA_REF (access_info); - ao_ref ref; - bool ref_initialized_p = false; - for (gimple_stmt_iterator gsi = gsi_for_stmt (access_info->stmt); - gsi_stmt (gsi) != last_access_info->stmt; gsi_next (&gsi)) + + stmt_vec_info stmt_info = vinfo->lookup_stmt (stmt); + + /* If we run into a store of this same instance (we've just + marked those) then delay dependence checking until we run + into the last store because this is where it will have + been sunk to (and we verified that we can do that already). */ + if (gimple_visited_p (stmt)) { - gimple *stmt = gsi_stmt (gsi); - if (! gimple_vuse (stmt)) + if (stmt_info != last_store_info) continue; - /* If we couldn't record a (single) data reference for this - stmt we have to resort to the alias oracle. */ - stmt_vec_info stmt_info = vinfo->lookup_stmt (stmt); - data_reference *dr_b = STMT_VINFO_DATA_REF (stmt_info); - if (!dr_b) + for (stmt_vec_info &store_info : stores) { - /* We are moving a store - this means - we cannot use TBAA for disambiguation. */ - if (!ref_initialized_p) - ao_ref_init (&ref, DR_REF (dr_a)); - if (stmt_may_clobber_ref_p_1 (stmt, &ref, false) - || ref_maybe_used_by_stmt_p (stmt, &ref, false)) - return false; - continue; - } - - bool dependent = false; - /* If we run into a store of this same instance (we've just - marked those) then delay dependence checking until we run - into the last store because this is where it will have - been sunk to (and we verify if we can do that as well). */ - if (gimple_visited_p (stmt)) - { - if (stmt_info != last_store_info) - continue; - - for (stmt_vec_info &store_info : stores) - { - data_reference *store_dr - = STMT_VINFO_DATA_REF (store_info); - ddr_p ddr = initialize_data_dependence_relation - (dr_a, store_dr, vNULL); - dependent - = vect_slp_analyze_data_ref_dependence (vinfo, ddr); - free_dependence_relation (ddr); - if (dependent) - break; - } - } - else - { - ddr_p ddr = initialize_data_dependence_relation (dr_a, - dr_b, vNULL); - dependent = vect_slp_analyze_data_ref_dependence (vinfo, ddr); + data_reference *store_dr = STMT_VINFO_DATA_REF (store_info); + ddr_p ddr = initialize_data_dependence_relation + (dr_a, store_dr, vNULL); + bool dependent + = vect_slp_analyze_data_ref_dependence (vinfo, ddr); free_dependence_relation (ddr); + if (dependent) + return false; } - if (dependent) - return false; + continue; } - } - } - else /* DR_IS_READ */ - { - stmt_vec_info first_access_info - = vect_find_first_scalar_stmt_in_slp (node); - for (unsigned k = 0; k < SLP_TREE_SCALAR_STMTS (node).length (); ++k) - { - stmt_vec_info access_info - = vect_orig_stmt (SLP_TREE_SCALAR_STMTS (node)[k]); - if (access_info == first_access_info) - continue; - data_reference *dr_a = STMT_VINFO_DATA_REF (access_info); - ao_ref ref; - bool ref_initialized_p = false; - for (gimple_stmt_iterator gsi = gsi_for_stmt (access_info->stmt); - gsi_stmt (gsi) != first_access_info->stmt; gsi_prev (&gsi)) + + auto check_hoist = [&] (stmt_vec_info stmt_info) -> bool { - gimple *stmt = gsi_stmt (gsi); - if (! gimple_vdef (stmt)) - continue; - - /* If we couldn't record a (single) data reference for this - stmt we have to resort to the alias oracle. */ - stmt_vec_info stmt_info = vinfo->lookup_stmt (stmt); - data_reference *dr_b = STMT_VINFO_DATA_REF (stmt_info); - - /* We are hoisting a load - this means we can use - TBAA for disambiguation. */ + /* We are hoisting a load - this means we can use TBAA for + disambiguation. */ if (!ref_initialized_p) ao_ref_init (&ref, DR_REF (dr_a)); - if (stmt_may_clobber_ref_p_1 (stmt, &ref, true)) + if (stmt_may_clobber_ref_p_1 (stmt_info->stmt, &ref, true)) { + /* If we couldn't record a (single) data reference for this + stmt we have to give up now. */ + data_reference *dr_b = STMT_VINFO_DATA_REF (stmt_info); if (!dr_b) return false; - /* Resort to dependence checking below. */ - } - else - /* No dependence. */ - continue; - - bool dependent = false; - /* If we run into a store of this same instance (we've just - marked those) then delay dependence checking until we run - into the last store because this is where it will have - been sunk to (and we verify if we can do that as well). */ - if (gimple_visited_p (stmt)) - { - if (stmt_info != last_store_info) - continue; - - for (stmt_vec_info &store_info : stores) - { - data_reference *store_dr - = STMT_VINFO_DATA_REF (store_info); - ddr_p ddr = initialize_data_dependence_relation - (dr_a, store_dr, vNULL); - dependent - = vect_slp_analyze_data_ref_dependence (vinfo, ddr); - free_dependence_relation (ddr); - if (dependent) - break; - } - } - else - { ddr_p ddr = initialize_data_dependence_relation (dr_a, dr_b, vNULL); - dependent = vect_slp_analyze_data_ref_dependence (vinfo, ddr); + bool dependent + = vect_slp_analyze_data_ref_dependence (vinfo, ddr); free_dependence_relation (ddr); + if (dependent) + return false; } - if (dependent) + /* No dependence. */ + return true; + }; + if (STMT_VINFO_GROUPED_ACCESS (stmt_info)) + { + /* When we run into a store group we have to honor + that earlier stores might be moved here. We don't + know exactly which and where to since we lack a + back-mapping from DR to SLP node, so assume all + earlier stores are sunk here. It's enough to + consider the last stmt of a group for this. + ??? Both this and the fact that we disregard that + the conflicting instance might be removed later + is overly conservative. */ + if (!grp_visited.add (DR_GROUP_FIRST_ELEMENT (stmt_info))) + for (auto store_info = DR_GROUP_FIRST_ELEMENT (stmt_info); + store_info != NULL; + store_info = DR_GROUP_NEXT_ELEMENT (store_info)) + if ((store_info == stmt_info + || get_later_stmt (store_info, stmt_info) == stmt_info) + && !check_hoist (store_info)) + return false; + } + else + { + if (!check_hoist (stmt_info)) return false; } } @@ -850,7 +858,7 @@ vect_slp_analyze_instance_dependence (vec_info *vinfo, slp_instance instance) stmt_vec_info last_store_info = NULL; if (store) { - if (! vect_slp_analyze_node_dependences (vinfo, store, vNULL, NULL)) + if (! vect_slp_analyze_store_dependences (vinfo, store)) return false; /* Mark stores in this instance and remember the last one. */ @@ -864,7 +872,7 @@ vect_slp_analyze_instance_dependence (vec_info *vinfo, slp_instance instance) /* Verify we can sink loads to the vectorized stmt insert location, special-casing stores of this instance. */ for (slp_tree &load : SLP_INSTANCE_LOADS (instance)) - if (! vect_slp_analyze_node_dependences (vinfo, load, + if (! vect_slp_analyze_load_dependences (vinfo, load, store ? SLP_TREE_SCALAR_STMTS (store) : vNULL, last_store_info)) @@ -3048,8 +3056,7 @@ can_group_stmts_p (stmt_vec_info stmt1_info, stmt_vec_info stmt2_info, like those created by build_mask_conversion. */ tree mask1 = gimple_call_arg (call1, 2); tree mask2 = gimple_call_arg (call2, 2); - if (!operand_equal_p (mask1, mask2, 0) - && (ifn == IFN_MASK_STORE || !allow_slp_p)) + if (!operand_equal_p (mask1, mask2, 0) && !allow_slp_p) { mask1 = strip_conversion (mask1); if (!mask1) @@ -5438,22 +5445,31 @@ vect_grouped_store_supported (tree vectype, unsigned HOST_WIDE_INT count) return false; } +/* Return FN if vec_{mask_,mask_len_}store_lanes is available for COUNT vectors + of type VECTYPE. MASKED_P says whether the masked form is needed. */ -/* Return TRUE if vec_{mask_}store_lanes is available for COUNT vectors of - type VECTYPE. MASKED_P says whether the masked form is needed. */ - -bool +internal_fn vect_store_lanes_supported (tree vectype, unsigned HOST_WIDE_INT count, bool masked_p) { - if (masked_p) - return vect_lanes_optab_supported_p ("vec_mask_store_lanes", - vec_mask_store_lanes_optab, - vectype, count); + if (vect_lanes_optab_supported_p ("vec_mask_len_store_lanes", + vec_mask_len_store_lanes_optab, vectype, + count)) + return IFN_MASK_LEN_STORE_LANES; + else if (masked_p) + { + if (vect_lanes_optab_supported_p ("vec_mask_store_lanes", + vec_mask_store_lanes_optab, vectype, + count)) + return IFN_MASK_STORE_LANES; + } else - return vect_lanes_optab_supported_p ("vec_store_lanes", - vec_store_lanes_optab, - vectype, count); + { + if (vect_lanes_optab_supported_p ("vec_store_lanes", + vec_store_lanes_optab, vectype, count)) + return IFN_STORE_LANES; + } + return IFN_LAST; } @@ -6056,21 +6072,31 @@ vect_grouped_load_supported (tree vectype, bool single_element_p, return false; } -/* Return TRUE if vec_{masked_}load_lanes is available for COUNT vectors of - type VECTYPE. MASKED_P says whether the masked form is needed. */ +/* Return FN if vec_{masked_,mask_len_}load_lanes is available for COUNT vectors + of type VECTYPE. MASKED_P says whether the masked form is needed. */ -bool +internal_fn vect_load_lanes_supported (tree vectype, unsigned HOST_WIDE_INT count, bool masked_p) { - if (masked_p) - return vect_lanes_optab_supported_p ("vec_mask_load_lanes", - vec_mask_load_lanes_optab, - vectype, count); + if (vect_lanes_optab_supported_p ("vec_mask_len_load_lanes", + vec_mask_len_load_lanes_optab, vectype, + count)) + return IFN_MASK_LEN_LOAD_LANES; + else if (masked_p) + { + if (vect_lanes_optab_supported_p ("vec_mask_load_lanes", + vec_mask_load_lanes_optab, vectype, + count)) + return IFN_MASK_LOAD_LANES; + } else - return vect_lanes_optab_supported_p ("vec_load_lanes", - vec_load_lanes_optab, - vectype, count); + { + if (vect_lanes_optab_supported_p ("vec_load_lanes", vec_load_lanes_optab, + vectype, count)) + return IFN_LOAD_LANES; + } + return IFN_LAST; } /* Function vect_permute_load_chain. diff --git a/gcc/tree-vect-loop.cc b/gcc/tree-vect-loop.cc index 00058c3c13e3..23c6e8259e7b 100644 --- a/gcc/tree-vect-loop.cc +++ b/gcc/tree-vect-loop.cc @@ -32,6 +32,8 @@ along with GCC; see the file COPYING3. If not see #include "tree-pass.h" #include "ssa.h" #include "optabs-tree.h" +#include "memmodel.h" +#include "optabs.h" #include "diagnostic-core.h" #include "fold-const.h" #include "stor-layout.h" @@ -1465,10 +1467,13 @@ vect_verify_loop_lens (loop_vec_info loop_vinfo) if (LOOP_VINFO_LENS (loop_vinfo).is_empty ()) return false; - machine_mode len_load_mode = get_len_load_store_mode - (loop_vinfo->vector_mode, true).require (); - machine_mode len_store_mode = get_len_load_store_mode - (loop_vinfo->vector_mode, false).require (); + machine_mode len_load_mode, len_store_mode; + if (!get_len_load_store_mode (loop_vinfo->vector_mode, true) + .exists (&len_load_mode)) + return false; + if (!get_len_load_store_mode (loop_vinfo->vector_mode, false) + .exists (&len_store_mode)) + return false; signed char partial_load_bias = internal_len_load_store_bias (IFN_LEN_LOAD, len_load_mode); @@ -2061,8 +2066,7 @@ vect_analyze_loop_operations (loop_vec_info loop_vinfo) if (ok && STMT_VINFO_LIVE_P (stmt_info) && !PURE_SLP_STMT (stmt_info)) - ok = vectorizable_live_operation (loop_vinfo, - stmt_info, NULL, NULL, NULL, + ok = vectorizable_live_operation (loop_vinfo, stmt_info, NULL, NULL, -1, false, &cost_vec); if (!ok) @@ -2449,8 +2453,13 @@ vect_dissolve_slp_only_groups (loop_vec_info loop_vinfo) DR_GROUP_FIRST_ELEMENT (vinfo) = vinfo; DR_GROUP_NEXT_ELEMENT (vinfo) = NULL; DR_GROUP_SIZE (vinfo) = 1; - if (STMT_VINFO_STRIDED_P (first_element)) - DR_GROUP_GAP (vinfo) = 0; + if (STMT_VINFO_STRIDED_P (first_element) + /* We cannot handle stores with gaps. */ + || DR_IS_WRITE (dr_info->dr)) + { + STMT_VINFO_STRIDED_P (vinfo) = true; + DR_GROUP_GAP (vinfo) = 0; + } else DR_GROUP_GAP (vinfo) = group_size - 1; /* Duplicate and adjust alignment info, it needs to @@ -2840,7 +2849,8 @@ start_over: instructions record it and move on to the next instance. */ if (loads_permuted && SLP_INSTANCE_KIND (instance) == slp_inst_kind_store - && vect_store_lanes_supported (vectype, group_size, false)) + && vect_store_lanes_supported (vectype, group_size, false) + != IFN_LAST) { FOR_EACH_VEC_ELT (SLP_INSTANCE_LOADS (instance), i, load_node) { @@ -2849,9 +2859,9 @@ start_over: /* Use SLP for strided accesses (or if we can't load-lanes). */ if (STMT_VINFO_STRIDED_P (stmt_vinfo) - || ! vect_load_lanes_supported + || vect_load_lanes_supported (STMT_VINFO_VECTYPE (stmt_vinfo), - DR_GROUP_SIZE (stmt_vinfo), false)) + DR_GROUP_SIZE (stmt_vinfo), false) == IFN_LAST) break; } @@ -3154,7 +3164,7 @@ again: vinfo = DR_GROUP_FIRST_ELEMENT (vinfo); unsigned int size = DR_GROUP_SIZE (vinfo); tree vectype = STMT_VINFO_VECTYPE (vinfo); - if (! vect_store_lanes_supported (vectype, size, false) + if (vect_store_lanes_supported (vectype, size, false) == IFN_LAST && ! known_eq (TYPE_VECTOR_SUBPARTS (vectype), 1U) && ! vect_grouped_store_supported (vectype, size)) return opt_result::failure_at (vinfo->stmt, @@ -3166,7 +3176,7 @@ again: bool single_element_p = !DR_GROUP_NEXT_ELEMENT (vinfo); size = DR_GROUP_SIZE (vinfo); vectype = STMT_VINFO_VECTYPE (vinfo); - if (! vect_load_lanes_supported (vectype, size, false) + if (vect_load_lanes_supported (vectype, size, false) == IFN_LAST && ! vect_grouped_load_supported (vectype, single_element_p, size)) return opt_result::failure_at (vinfo->stmt, @@ -6906,7 +6916,17 @@ vectorize_fold_left_reduction (loop_vec_info loop_vinfo, tree vector_identity = NULL_TREE; if (LOOP_VINFO_FULLY_MASKED_P (loop_vinfo)) - vector_identity = build_zero_cst (vectype_out); + { + vector_identity = build_zero_cst (vectype_out); + if (!HONOR_SIGNED_ZEROS (vectype_out)) + ; + else + { + gcc_assert (!HONOR_SIGN_DEPENDENT_ROUNDING (vectype_out)); + vector_identity = const_unop (NEGATE_EXPR, vectype_out, + vector_identity); + } + } tree scalar_dest_var = vect_create_destination_var (scalar_dest, NULL); int i; @@ -7479,8 +7499,11 @@ vectorizable_reduction (loop_vec_info loop_vinfo, } if (reduc_chain_length == 1 - && direct_internal_fn_supported_p (IFN_FOLD_EXTRACT_LAST, - vectype_in, OPTIMIZE_FOR_SPEED)) + && (direct_internal_fn_supported_p (IFN_FOLD_EXTRACT_LAST, vectype_in, + OPTIMIZE_FOR_SPEED) + || direct_internal_fn_supported_p (IFN_LEN_FOLD_EXTRACT_LAST, + vectype_in, + OPTIMIZE_FOR_SPEED))) { if (dump_enabled_p ()) dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, @@ -8038,6 +8061,18 @@ vectorizable_reduction (loop_vec_info loop_vinfo, " no conditional operation is available.\n"); LOOP_VINFO_CAN_USE_PARTIAL_VECTORS_P (loop_vinfo) = false; } + else if (reduction_type == FOLD_LEFT_REDUCTION + && reduc_fn == IFN_LAST + && FLOAT_TYPE_P (vectype_in) + && HONOR_SIGNED_ZEROS (vectype_in) + && HONOR_SIGN_DEPENDENT_ROUNDING (vectype_in)) + { + if (dump_enabled_p ()) + dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, + "can't operate on partial vectors because" + " signed zeros cannot be preserved.\n"); + LOOP_VINFO_CAN_USE_PARTIAL_VECTORS_P (loop_vinfo) = false; + } else { internal_fn mask_reduc_fn @@ -10185,9 +10220,7 @@ vectorizable_induction (loop_vec_info loop_vinfo, it can be supported. */ bool -vectorizable_live_operation (vec_info *vinfo, - stmt_vec_info stmt_info, - gimple_stmt_iterator *gsi, +vectorizable_live_operation (vec_info *vinfo, stmt_vec_info stmt_info, slp_tree slp_node, slp_instance slp_node_instance, int slp_index, bool vec_stmt_p, stmt_vector_for_cost *cost_vec) @@ -10281,17 +10314,7 @@ vectorizable_live_operation (vec_info *vinfo, /* No transformation required. */ if (loop_vinfo && LOOP_VINFO_CAN_USE_PARTIAL_VECTORS_P (loop_vinfo)) { - if (!direct_internal_fn_supported_p (IFN_EXTRACT_LAST, vectype, - OPTIMIZE_FOR_SPEED)) - { - if (dump_enabled_p ()) - dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, - "can't operate on partial vectors " - "because the target doesn't support extract " - "last reduction.\n"); - LOOP_VINFO_CAN_USE_PARTIAL_VECTORS_P (loop_vinfo) = false; - } - else if (slp_node) + if (slp_node) { if (dump_enabled_p ()) dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, @@ -10311,9 +10334,26 @@ vectorizable_live_operation (vec_info *vinfo, else { gcc_assert (ncopies == 1 && !slp_node); - vect_record_loop_mask (loop_vinfo, - &LOOP_VINFO_MASKS (loop_vinfo), - 1, vectype, NULL); + if (direct_internal_fn_supported_p (IFN_EXTRACT_LAST, vectype, + OPTIMIZE_FOR_SPEED)) + vect_record_loop_mask (loop_vinfo, + &LOOP_VINFO_MASKS (loop_vinfo), + 1, vectype, NULL); + else if (can_vec_extract_var_idx_p ( + TYPE_MODE (vectype), TYPE_MODE (TREE_TYPE (vectype)))) + vect_record_loop_len (loop_vinfo, + &LOOP_VINFO_LENS (loop_vinfo), + 1, vectype, 1); + else + { + if (dump_enabled_p ()) + dump_printf_loc ( + MSG_MISSED_OPTIMIZATION, vect_location, + "can't operate on partial vectors " + "because the target doesn't support extract " + "last reduction.\n"); + LOOP_VINFO_CAN_USE_PARTIAL_VECTORS_P (loop_vinfo) = false; + } } } /* ??? Enable for loop costing as well. */ @@ -10339,7 +10379,9 @@ vectorizable_live_operation (vec_info *vinfo, gimple *vec_stmt; if (slp_node) { - gcc_assert (!loop_vinfo || !LOOP_VINFO_FULLY_MASKED_P (loop_vinfo)); + gcc_assert (!loop_vinfo + || (!LOOP_VINFO_FULLY_MASKED_P (loop_vinfo) + && !LOOP_VINFO_FULLY_WITH_LENGTH_P (loop_vinfo))); /* Get the correct slp vectorized stmt. */ vec_lhs = SLP_TREE_VEC_DEFS (slp_node)[vec_entry]; @@ -10383,7 +10425,42 @@ vectorizable_live_operation (vec_info *vinfo, gimple_seq stmts = NULL; tree new_tree; - if (LOOP_VINFO_FULLY_MASKED_P (loop_vinfo)) + if (LOOP_VINFO_FULLY_WITH_LENGTH_P (loop_vinfo)) + { + /* Emit: + + SCALAR_RES = VEC_EXTRACT + + where VEC_LHS is the vectorized live-out result and MASK is + the loop mask for the final iteration. */ + gcc_assert (ncopies == 1 && !slp_node); + gimple_seq tem = NULL; + gimple_stmt_iterator gsi = gsi_last (tem); + tree len + = vect_get_loop_len (loop_vinfo, &gsi, + &LOOP_VINFO_LENS (loop_vinfo), + 1, vectype, 0, 0); + + /* BIAS - 1. */ + signed char biasval = LOOP_VINFO_PARTIAL_LOAD_STORE_BIAS (loop_vinfo); + tree bias_minus_one + = int_const_binop (MINUS_EXPR, + build_int_cst (TREE_TYPE (len), biasval), + build_one_cst (TREE_TYPE (len))); + + /* LAST_INDEX = LEN + (BIAS - 1). */ + tree last_index = gimple_build (&stmts, PLUS_EXPR, TREE_TYPE (len), + len, bias_minus_one); + + /* SCALAR_RES = VEC_EXTRACT . */ + tree scalar_res + = gimple_build (&stmts, CFN_VEC_EXTRACT, TREE_TYPE (vectype), + vec_lhs_phi, last_index); + + /* Convert the extracted vector element to the scalar type. */ + new_tree = gimple_convert (&stmts, lhs_type, scalar_res); + } + else if (LOOP_VINFO_FULLY_MASKED_P (loop_vinfo)) { /* Emit: @@ -10393,9 +10470,12 @@ vectorizable_live_operation (vec_info *vinfo, the loop mask for the final iteration. */ gcc_assert (ncopies == 1 && !slp_node); tree scalar_type = TREE_TYPE (STMT_VINFO_VECTYPE (stmt_info)); - tree mask = vect_get_loop_mask (loop_vinfo, gsi, + gimple_seq tem = NULL; + gimple_stmt_iterator gsi = gsi_last (tem); + tree mask = vect_get_loop_mask (loop_vinfo, &gsi, &LOOP_VINFO_MASKS (loop_vinfo), 1, vectype, 0); + gimple_seq_add_seq (&stmts, tem); tree scalar_res = gimple_build (&stmts, CFN_EXTRACT_LAST, scalar_type, mask, vec_lhs_phi); diff --git a/gcc/tree-vect-patterns.cc b/gcc/tree-vect-patterns.cc index cda27fed95bb..a2ed0365b18c 100644 --- a/gcc/tree-vect-patterns.cc +++ b/gcc/tree-vect-patterns.cc @@ -3121,7 +3121,7 @@ vect_recog_over_widening_pattern (vec_info *vinfo, = gimple_build_assign (new_var, MIN_EXPR, ops[1], build_int_cst (op_type, new_precision - 1)); gimple_set_location (pattern_stmt, gimple_location (last_stmt)); - if (unprom[1].dt == vect_external_def) + if (ops[1] == unprom[1].op && unprom[1].dt == vect_external_def) { if (edge e = vect_get_external_def_edge (vinfo, ops[1])) { diff --git a/gcc/tree-vect-slp.cc b/gcc/tree-vect-slp.cc index eab3dcd40ec1..0cf6e02285e9 100644 --- a/gcc/tree-vect-slp.cc +++ b/gcc/tree-vect-slp.cc @@ -209,6 +209,7 @@ vect_free_slp_instance (slp_instance instance) vect_free_slp_tree (SLP_INSTANCE_TREE (instance)); SLP_INSTANCE_LOADS (instance).release (); SLP_INSTANCE_ROOT_STMTS (instance).release (); + SLP_INSTANCE_REMAIN_DEFS (instance).release (); instance->subgraph_entries.release (); instance->cost_vec.release (); free (instance); @@ -502,6 +503,7 @@ static const int cond_expr_maps[3][5] = { static const int arg1_map[] = { 1, 1 }; static const int arg2_map[] = { 1, 2 }; static const int arg1_arg4_map[] = { 2, 1, 4 }; +static const int arg3_arg2_map[] = { 2, 3, 2 }; static const int op1_op0_map[] = { 2, 1, 0 }; /* For most SLP statements, there is a one-to-one mapping between @@ -542,6 +544,9 @@ vect_get_operand_map (const gimple *stmt, unsigned char swap = 0) case IFN_MASK_GATHER_LOAD: return arg1_arg4_map; + case IFN_MASK_STORE: + return arg3_arg2_map; + default: break; } @@ -549,6 +554,20 @@ vect_get_operand_map (const gimple *stmt, unsigned char swap = 0) return nullptr; } +/* Return the SLP node child index for operand OP of STMT. */ + +int +vect_slp_child_index_for_operand (const gimple *stmt, int op) +{ + const int *opmap = vect_get_operand_map (stmt); + if (!opmap) + return op; + for (int i = 1; i < 1 + opmap[0]; ++i) + if (opmap[i] == op) + return i - 1; + gcc_unreachable (); +} + /* Get the defs for the rhs of STMT (collect them in OPRNDS_INFO), check that they are of a valid type and that they match the defs of the first stmt of the SLP group (stored in OPRNDS_INFO). This function tries to match stmts @@ -965,7 +984,7 @@ vect_build_slp_tree_1 (vec_info *vinfo, unsigned char *swap, bool need_same_oprnds = false; tree vectype = NULL_TREE, first_op1 = NULL_TREE; stmt_vec_info first_load = NULL, prev_first_load = NULL; - bool first_stmt_load_p = false, load_p = false; + bool first_stmt_ldst_p = false, ldst_p = false; bool first_stmt_phi_p = false, phi_p = false; bool maybe_soft_fail = false; tree soft_fail_nunits_vectype = NULL_TREE; @@ -1002,8 +1021,12 @@ vect_build_slp_tree_1 (vec_info *vinfo, unsigned char *swap, return false; } + gcall *call_stmt = dyn_cast (stmt); lhs = gimple_get_lhs (stmt); - if (lhs == NULL_TREE) + if (lhs == NULL_TREE + && (!call_stmt + || !gimple_call_internal_p (stmt) + || !internal_store_fn_p (gimple_call_internal_fn (stmt)))) { if (dump_enabled_p ()) dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, @@ -1040,7 +1063,6 @@ vect_build_slp_tree_1 (vec_info *vinfo, unsigned char *swap, gcc_assert (vectype); - gcall *call_stmt = dyn_cast (stmt); if (call_stmt) { combined_fn cfn = gimple_call_combined_fn (call_stmt); @@ -1052,7 +1074,12 @@ vect_build_slp_tree_1 (vec_info *vinfo, unsigned char *swap, if (cfn == CFN_MASK_LOAD || cfn == CFN_GATHER_LOAD || cfn == CFN_MASK_GATHER_LOAD) - load_p = true; + ldst_p = true; + else if (cfn == CFN_MASK_STORE) + { + ldst_p = true; + rhs_code = CFN_MASK_STORE; + } else if ((internal_fn_p (cfn) && !vectorizable_internal_fn_p (as_internal_fn (cfn))) || gimple_call_tail_p (call_stmt) @@ -1078,7 +1105,7 @@ vect_build_slp_tree_1 (vec_info *vinfo, unsigned char *swap, else { rhs_code = gimple_assign_rhs_code (stmt); - load_p = gimple_vuse (stmt); + ldst_p = STMT_VINFO_DATA_REF (stmt_info) != nullptr; } /* Check the operation. */ @@ -1086,7 +1113,7 @@ vect_build_slp_tree_1 (vec_info *vinfo, unsigned char *swap, { *node_vectype = vectype; first_stmt_code = rhs_code; - first_stmt_load_p = load_p; + first_stmt_ldst_p = ldst_p; first_stmt_phi_p = phi_p; /* Shift arguments should be equal in all the packed stmts for a @@ -1120,7 +1147,7 @@ vect_build_slp_tree_1 (vec_info *vinfo, unsigned char *swap, need_same_oprnds = true; first_op1 = gimple_assign_rhs2 (stmt); } - else if (!load_p + else if (!ldst_p && rhs_code == BIT_FIELD_REF) { tree vec = TREE_OPERAND (gimple_assign_rhs1 (stmt), 0); @@ -1183,7 +1210,7 @@ vect_build_slp_tree_1 (vec_info *vinfo, unsigned char *swap, || rhs_code == INDIRECT_REF || rhs_code == COMPONENT_REF || rhs_code == MEM_REF))) - || first_stmt_load_p != load_p + || first_stmt_ldst_p != ldst_p || first_stmt_phi_p != phi_p) { if (dump_enabled_p ()) @@ -1198,7 +1225,7 @@ vect_build_slp_tree_1 (vec_info *vinfo, unsigned char *swap, continue; } - if (!load_p + if (!ldst_p && first_stmt_code == BIT_FIELD_REF && (TREE_OPERAND (gimple_assign_rhs1 (first_stmt_info->stmt), 0) != TREE_OPERAND (gimple_assign_rhs1 (stmt_info->stmt), 0))) @@ -1211,7 +1238,9 @@ vect_build_slp_tree_1 (vec_info *vinfo, unsigned char *swap, continue; } - if (call_stmt && first_stmt_code != CFN_MASK_LOAD) + if (call_stmt + && first_stmt_code != CFN_MASK_LOAD + && first_stmt_code != CFN_MASK_STORE) { if (!compatible_calls_p (as_a (stmts[0]->stmt), call_stmt)) @@ -1265,10 +1294,13 @@ vect_build_slp_tree_1 (vec_info *vinfo, unsigned char *swap, /* Grouped store or load. */ if (STMT_VINFO_GROUPED_ACCESS (stmt_info)) { - if (REFERENCE_CLASS_P (lhs)) + gcc_assert (ldst_p); + if (DR_IS_WRITE (STMT_VINFO_DATA_REF (stmt_info))) { /* Store. */ - ; + gcc_assert (rhs_code == CFN_MASK_STORE + || REFERENCE_CLASS_P (lhs) + || DECL_P (lhs)); } else { @@ -1293,10 +1325,11 @@ vect_build_slp_tree_1 (vec_info *vinfo, unsigned char *swap, else prev_first_load = first_load; } - } /* Grouped access. */ - else + } + /* Non-grouped store or load. */ + else if (ldst_p) { - if (load_p + if (DR_IS_READ (STMT_VINFO_DATA_REF (stmt_info)) && rhs_code != CFN_GATHER_LOAD && rhs_code != CFN_MASK_GATHER_LOAD /* Not grouped loads are handled as externals for BB @@ -1317,10 +1350,11 @@ vect_build_slp_tree_1 (vec_info *vinfo, unsigned char *swap, matches[0] = false; return false; } - - /* Not memory operation. */ - if (!load_p - && !phi_p + } + /* Not memory operation. */ + else + { + if (!phi_p && rhs_code.is_tree_code () && TREE_CODE_CLASS (tree_code (rhs_code)) != tcc_binary && TREE_CODE_CLASS (tree_code (rhs_code)) != tcc_unary @@ -3093,7 +3127,7 @@ vect_slp_prefer_store_lanes_p (vec_info *vinfo, stmt_vec_info stmt_info, if (multiple_p (group_size - new_group_size, TYPE_VECTOR_SUBPARTS (vectype)) || multiple_p (new_group_size, TYPE_VECTOR_SUBPARTS (vectype))) return false; - return vect_store_lanes_supported (vectype, group_size, false); + return vect_store_lanes_supported (vectype, group_size, false) != IFN_LAST; } /* Analyze an SLP instance starting from a group of grouped stores. Call @@ -3114,11 +3148,20 @@ vect_build_slp_instance (vec_info *vinfo, slp_instance_kind kind, vec &scalar_stmts, vec &root_stmt_infos, + vec &remain, unsigned max_tree_size, unsigned *limit, scalar_stmts_to_slp_tree_map_t *bst_map, /* ??? We need stmt_info for group splitting. */ stmt_vec_info stmt_info_) { + if (kind == slp_inst_kind_ctor) + { + if (dump_enabled_p ()) + dump_printf_loc (MSG_NOTE, vect_location, + "Analyzing vectorizable constructor: %G\n", + root_stmt_infos[0]->stmt); + } + if (dump_enabled_p ()) { dump_printf_loc (MSG_NOTE, vect_location, @@ -3128,6 +3171,15 @@ vect_build_slp_instance (vec_info *vinfo, " %G", scalar_stmts[i]->stmt); } + /* When a BB reduction doesn't have an even number of lanes + strip it down, treating the remaining lane as scalar. + ??? Selecting the optimal set of lanes to vectorize would be nice + but SLP build for all lanes will fail quickly because we think + we're going to need unrolling. */ + if (kind == slp_inst_kind_bb_reduc + && (scalar_stmts.length () & 1)) + remain.safe_insert (0, gimple_get_lhs (scalar_stmts.pop ()->stmt)); + /* Build the tree for the SLP instance. */ unsigned int group_size = scalar_stmts.length (); bool *matches = XALLOCAVEC (bool, group_size); @@ -3175,6 +3227,7 @@ vect_build_slp_instance (vec_info *vinfo, SLP_INSTANCE_UNROLLING_FACTOR (new_instance) = unrolling_factor; SLP_INSTANCE_LOADS (new_instance) = vNULL; SLP_INSTANCE_ROOT_STMTS (new_instance) = root_stmt_infos; + SLP_INSTANCE_REMAIN_DEFS (new_instance) = remain; SLP_INSTANCE_KIND (new_instance) = kind; new_instance->reduc_phis = NULL; new_instance->cost_vec = vNULL; @@ -3415,22 +3468,6 @@ vect_analyze_slp_instance (vec_info *vinfo, STMT_VINFO_REDUC_DEF (vect_orig_stmt (stmt_info)) = STMT_VINFO_REDUC_DEF (vect_orig_stmt (scalar_stmts.last ())); } - else if (kind == slp_inst_kind_ctor) - { - tree rhs = gimple_assign_rhs1 (stmt_info->stmt); - tree val; - scalar_stmts.create (CONSTRUCTOR_NELTS (rhs)); - FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (rhs), i, val) - { - stmt_vec_info def_info = vinfo->lookup_def (val); - def_info = vect_stmt_to_vectorize (def_info); - scalar_stmts.quick_push (def_info); - } - if (dump_enabled_p ()) - dump_printf_loc (MSG_NOTE, vect_location, - "Analyzing vectorizable constructor: %G\n", - stmt_info->stmt); - } else if (kind == slp_inst_kind_reduc_group) { /* Collect reduction statements. */ @@ -3454,19 +3491,13 @@ vect_analyze_slp_instance (vec_info *vinfo, gcc_unreachable (); vec roots = vNULL; - if (kind == slp_inst_kind_ctor) - { - roots.create (1); - roots.quick_push (stmt_info); - } + vec remain = vNULL; /* Build the tree for the SLP instance. */ bool res = vect_build_slp_instance (vinfo, kind, scalar_stmts, - roots, + roots, remain, max_tree_size, limit, bst_map, kind == slp_inst_kind_store ? stmt_info : NULL); - if (!res) - roots.release (); /* ??? If this is slp_inst_kind_store and the above succeeded here's where we should do store group splitting. */ @@ -3494,9 +3525,7 @@ vect_analyze_slp (vec_info *vinfo, unsigned max_tree_size) /* Find SLP sequences starting from groups of grouped stores. */ FOR_EACH_VEC_ELT (vinfo->grouped_stores, i, first_element) vect_analyze_slp_instance (vinfo, bst_map, first_element, - STMT_VINFO_GROUPED_ACCESS (first_element) - ? slp_inst_kind_store : slp_inst_kind_ctor, - max_tree_size, &limit); + slp_inst_kind_store, max_tree_size, &limit); if (bb_vec_info bb_vinfo = dyn_cast (vinfo)) { @@ -3506,10 +3535,12 @@ vect_analyze_slp (vec_info *vinfo, unsigned max_tree_size) if (vect_build_slp_instance (bb_vinfo, bb_vinfo->roots[i].kind, bb_vinfo->roots[i].stmts, bb_vinfo->roots[i].roots, + bb_vinfo->roots[i].remain, max_tree_size, &limit, bst_map, NULL)) { bb_vinfo->roots[i].stmts = vNULL; bb_vinfo->roots[i].roots = vNULL; + bb_vinfo->roots[i].remain = vNULL; } } } @@ -5940,6 +5971,7 @@ _bb_vec_info::~_bb_vec_info () { roots[i].stmts.release (); roots[i].roots.release (); + roots[i].remain.release (); } roots.release (); } @@ -5997,8 +6029,7 @@ vect_slp_analyze_node_operations_1 (vec_info *vinfo, slp_tree node, FOR_EACH_VEC_ELT (SLP_TREE_SCALAR_STMTS (node), i, slp_stmt_info) { if (STMT_VINFO_LIVE_P (slp_stmt_info) - && !vectorizable_live_operation (vinfo, - slp_stmt_info, NULL, node, + && !vectorizable_live_operation (vinfo, slp_stmt_info, node, node_instance, i, false, cost_vec)) return false; @@ -6315,7 +6346,7 @@ vect_bb_slp_mark_live_stmts (bb_vec_info bb_vinfo, slp_tree node, { STMT_VINFO_LIVE_P (stmt_info) = true; if (vectorizable_live_operation (bb_vinfo, stmt_info, - NULL, node, instance, i, + node, instance, i, false, cost_vec)) /* ??? So we know we can vectorize the live stmt from one SLP node. If we cannot do so from all @@ -6391,7 +6422,13 @@ vectorizable_bb_reduc_epilogue (slp_instance instance, || !direct_internal_fn_supported_p (reduc_fn, vectype, OPTIMIZE_FOR_BOTH) || !useless_type_conversion_p (TREE_TYPE (gimple_assign_lhs (stmt)), TREE_TYPE (vectype))) - return false; + { + if (dump_enabled_p ()) + dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, + "not vectorized: basic block reduction epilogue " + "operation unsupported.\n"); + return false; + } /* There's no way to cost a horizontal vector reduction via REDUC_FN so cost log2 vector operations plus shuffles and one extraction. */ @@ -6402,6 +6439,11 @@ vectorizable_bb_reduc_epilogue (slp_instance instance, vectype, 0, vect_body); record_stmt_cost (cost_vec, 1, vec_to_scalar, instance->root_stmts[0], vectype, 0, vect_body); + + /* Since we replace all stmts of a possibly longer scalar reduction + chain account for the extra scalar stmts for that. */ + record_stmt_cost (cost_vec, instance->remain_defs.length (), scalar_stmt, + instance->root_stmts[0], 0, vect_body); return true; } @@ -7075,7 +7117,7 @@ vect_slp_is_lane_insert (gimple *use_stmt, tree vec, unsigned *this_lane) array. */ static void -vect_slp_check_for_constructors (bb_vec_info bb_vinfo) +vect_slp_check_for_roots (bb_vec_info bb_vinfo) { for (unsigned i = 0; i < bb_vinfo->bbs.length (); ++i) for (gimple_stmt_iterator gsi = gsi_start_bb (bb_vinfo->bbs[i]); @@ -7101,14 +7143,21 @@ vect_slp_check_for_constructors (bb_vec_info bb_vinfo) unsigned j; tree val; FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (rhs), j, val) - if (TREE_CODE (val) != SSA_NAME - || !bb_vinfo->lookup_def (val)) - break; + if (TREE_CODE (val) != SSA_NAME + || !bb_vinfo->lookup_def (val)) + break; if (j != CONSTRUCTOR_NELTS (rhs)) continue; - stmt_vec_info stmt_info = bb_vinfo->lookup_stmt (assign); - BB_VINFO_GROUPED_STORES (bb_vinfo).safe_push (stmt_info); + vec roots = vNULL; + roots.safe_push (bb_vinfo->lookup_stmt (assign)); + vec stmts; + stmts.create (CONSTRUCTOR_NELTS (rhs)); + FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (rhs), j, val) + stmts.quick_push + (vect_stmt_to_vectorize (bb_vinfo->lookup_def (val))); + bb_vinfo->roots.safe_push (slp_root (slp_inst_kind_ctor, + stmts, roots)); } else if (code == BIT_INSERT_EXPR && VECTOR_TYPE_P (TREE_TYPE (rhs)) @@ -7206,13 +7255,10 @@ vect_slp_check_for_constructors (bb_vec_info bb_vinfo) } else if (!VECTOR_TYPE_P (TREE_TYPE (rhs)) && (associative_tree_code (code) || code == MINUS_EXPR) - /* ??? The flag_associative_math and TYPE_OVERFLOW_WRAPS - checks pessimize a two-element reduction. PR54400. + /* ??? This pessimizes a two-element reduction. PR54400. ??? In-order reduction could be handled if we only traverse one operand chain in vect_slp_linearize_chain. */ - && ((FLOAT_TYPE_P (TREE_TYPE (rhs)) && flag_associative_math) - || (INTEGRAL_TYPE_P (TREE_TYPE (rhs)) - && TYPE_OVERFLOW_WRAPS (TREE_TYPE (rhs)))) + && !needs_fold_left_reduction_p (TREE_TYPE (rhs), code) /* Ops with constants at the tail can be stripped here. */ && TREE_CODE (rhs) == SSA_NAME && TREE_CODE (gimple_assign_rhs2 (assign)) == SSA_NAME @@ -7248,22 +7294,37 @@ vect_slp_check_for_constructors (bb_vec_info bb_vinfo) but record those to be handled in the epilogue. */ /* ??? For now do not allow mixing ops or externs/constants. */ bool invalid = false; + unsigned remain_cnt = 0; for (unsigned i = 0; i < chain.length (); ++i) - if (chain[i].dt != vect_internal_def - || chain[i].code != code) - invalid = true; - if (!invalid) + { + if (chain[i].code != code) + { + invalid = true; + break; + } + if (chain[i].dt != vect_internal_def) + remain_cnt++; + } + if (!invalid && chain.length () - remain_cnt > 1) { vec stmts; + vec remain = vNULL; stmts.create (chain.length ()); + if (remain_cnt > 0) + remain.create (remain_cnt); for (unsigned i = 0; i < chain.length (); ++i) - stmts.quick_push (bb_vinfo->lookup_def (chain[i].op)); + { + if (chain[i].dt == vect_internal_def) + stmts.quick_push (bb_vinfo->lookup_def (chain[i].op)); + else + remain.quick_push (chain[i].op); + } vec roots; roots.create (chain_stmts.length ()); for (unsigned i = 0; i < chain_stmts.length (); ++i) roots.quick_push (bb_vinfo->lookup_stmt (chain_stmts[i])); bb_vinfo->roots.safe_push (slp_root (slp_inst_kind_bb_reduc, - stmts, roots)); + stmts, roots, remain)); } } } @@ -7351,7 +7412,7 @@ vect_slp_analyze_bb_1 (bb_vec_info bb_vinfo, int n_stmts, bool &fatal, return false; } - vect_slp_check_for_constructors (bb_vinfo); + vect_slp_check_for_roots (bb_vinfo); /* If there are no grouped stores and no constructors in the region there is no need to continue with pattern recog as vect_analyze_slp @@ -7560,25 +7621,34 @@ vect_slp_region (vec bbs, vec datarefs, "using SLP\n"); vectorized = true; + /* Dump before scheduling as store vectorization will remove + the original stores and mess with the instance tree + so querying its location will eventually ICE. */ + if (flag_checking) + for (slp_instance sub : instance->subgraph_entries) + gcc_assert (SLP_TREE_VECTYPE (SLP_INSTANCE_TREE (sub))); + unsigned HOST_WIDE_INT bytes; + if (dump_enabled_p ()) + for (slp_instance sub : instance->subgraph_entries) + { + tree vtype = SLP_TREE_VECTYPE (SLP_INSTANCE_TREE (sub)); + if (GET_MODE_SIZE (TYPE_MODE (vtype)).is_constant (&bytes)) + dump_printf_loc (MSG_OPTIMIZED_LOCATIONS, + sub->location (), + "basic block part vectorized using %wu " + "byte vectors\n", bytes); + else + dump_printf_loc (MSG_OPTIMIZED_LOCATIONS, + sub->location (), + "basic block part vectorized using " + "variable length vectors\n"); + } + dump_user_location_t saved_vect_location = vect_location; vect_location = instance->location (); vect_schedule_slp (bb_vinfo, instance->subgraph_entries); - unsigned HOST_WIDE_INT bytes; - if (dump_enabled_p ()) - { - if (GET_MODE_SIZE - (bb_vinfo->vector_mode).is_constant (&bytes)) - dump_printf_loc (MSG_OPTIMIZED_LOCATIONS, vect_location, - "basic block part vectorized using %wu " - "byte vectors\n", bytes); - else - dump_printf_loc (MSG_OPTIMIZED_LOCATIONS, vect_location, - "basic block part vectorized using " - "variable length vectors\n"); - } - vect_location = saved_vect_location; } } @@ -7738,6 +7808,17 @@ vect_slp_function (function *fun) bbs[0]->loop_father->num, bb->index); split = true; } + else if (!bbs.is_empty () + && bb->loop_father->header == bb + && bb->loop_father->dont_vectorize) + { + if (dump_enabled_p ()) + dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, + "splitting region at dont-vectorize loop %d " + "entry at bb%d\n", + bb->loop_father->num, bb->index); + split = true; + } if (split && !bbs.is_empty ()) { @@ -7745,19 +7826,25 @@ vect_slp_function (function *fun) bbs.truncate (0); } - /* We need to be able to insert at the head of the region which - we cannot for region starting with a returns-twice call. */ if (bbs.is_empty ()) - if (gcall *first = safe_dyn_cast (first_stmt (bb))) - if (gimple_call_flags (first) & ECF_RETURNS_TWICE) - { - if (dump_enabled_p ()) - dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, - "skipping bb%d as start of region as it " - "starts with returns-twice call\n", - bb->index); - continue; - } + { + /* We need to be able to insert at the head of the region which + we cannot for region starting with a returns-twice call. */ + if (gcall *first = safe_dyn_cast (first_stmt (bb))) + if (gimple_call_flags (first) & ECF_RETURNS_TWICE) + { + if (dump_enabled_p ()) + dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, + "skipping bb%d as start of region as it " + "starts with returns-twice call\n", + bb->index); + continue; + } + /* If the loop this BB belongs to is marked as not to be vectorized + honor that also for BB vectorization. */ + if (bb->loop_father->dont_vectorize) + continue; + } bbs.safe_push (bb); @@ -9015,8 +9102,7 @@ vect_schedule_slp_node (vec_info *vinfo, FOR_EACH_VEC_ELT (SLP_TREE_SCALAR_STMTS (node), i, slp_stmt_info) if (STMT_VINFO_LIVE_P (slp_stmt_info)) { - done = vectorizable_live_operation (vinfo, - slp_stmt_info, &si, node, + done = vectorizable_live_operation (vinfo, slp_stmt_info, node, instance, i, true, NULL); gcc_assert (done); } @@ -9059,10 +9145,17 @@ vect_remove_slp_scalar_calls (vec_info *vinfo, || !PURE_SLP_STMT (stmt_info)) continue; lhs = gimple_call_lhs (stmt); - new_stmt = gimple_build_assign (lhs, build_zero_cst (TREE_TYPE (lhs))); + if (lhs) + new_stmt = gimple_build_assign (lhs, build_zero_cst (TREE_TYPE (lhs))); + else + { + new_stmt = gimple_build_nop (); + unlink_stmt_vdef (stmt_info->stmt); + } gsi = gsi_for_stmt (stmt); vinfo->replace_stmt (&gsi, stmt_info, new_stmt); - SSA_NAME_DEF_STMT (gimple_assign_lhs (new_stmt)) = new_stmt; + if (lhs) + SSA_NAME_DEF_STMT (lhs) = new_stmt; } } @@ -9127,9 +9220,26 @@ vectorize_slp_instance_root_stmt (slp_tree node, slp_instance instance) /* We may end up with more than one vector result, reduce them to one vector. */ tree vec_def = vec_defs[0]; + tree vectype = TREE_TYPE (vec_def); + tree compute_vectype = vectype; + bool pun_for_overflow_p = (ANY_INTEGRAL_TYPE_P (vectype) + && TYPE_OVERFLOW_UNDEFINED (vectype) + && operation_can_overflow (reduc_code)); + if (pun_for_overflow_p) + { + compute_vectype = unsigned_type_for (vectype); + vec_def = gimple_build (&epilogue, VIEW_CONVERT_EXPR, + compute_vectype, vec_def); + } for (unsigned i = 1; i < vec_defs.length (); ++i) - vec_def = gimple_build (&epilogue, reduc_code, TREE_TYPE (vec_def), - vec_def, vec_defs[i]); + { + tree def = vec_defs[i]; + if (pun_for_overflow_p) + def = gimple_build (&epilogue, VIEW_CONVERT_EXPR, + compute_vectype, def); + vec_def = gimple_build (&epilogue, reduc_code, compute_vectype, + vec_def, def); + } vec_defs.release (); /* ??? Support other schemes than direct internal fn. */ internal_fn reduc_fn; @@ -9137,8 +9247,26 @@ vectorize_slp_instance_root_stmt (slp_tree node, slp_instance instance) || reduc_fn == IFN_LAST) gcc_unreachable (); tree scalar_def = gimple_build (&epilogue, as_combined_fn (reduc_fn), - TREE_TYPE (TREE_TYPE (vec_def)), vec_def); - + TREE_TYPE (compute_vectype), vec_def); + if (!SLP_INSTANCE_REMAIN_DEFS (instance).is_empty ()) + { + tree rem_def = NULL_TREE; + for (auto def : SLP_INSTANCE_REMAIN_DEFS (instance)) + { + def = gimple_convert (&epilogue, TREE_TYPE (scalar_def), def); + if (!rem_def) + rem_def = def; + else + rem_def = gimple_build (&epilogue, reduc_code, + TREE_TYPE (scalar_def), + rem_def, def); + } + scalar_def = gimple_build (&epilogue, reduc_code, + TREE_TYPE (scalar_def), + scalar_def, rem_def); + } + scalar_def = gimple_convert (&epilogue, + TREE_TYPE (vectype), scalar_def); gimple_stmt_iterator rgsi = gsi_for_stmt (instance->root_stmts[0]->stmt); gsi_insert_seq_before (&rgsi, epilogue, GSI_SAME_STMT); gimple_assign_set_rhs_from_tree (&rgsi, scalar_def); diff --git a/gcc/tree-vect-stmts.cc b/gcc/tree-vect-stmts.cc index 6a4e8fce126a..cd7c1090d888 100644 --- a/gcc/tree-vect-stmts.cc +++ b/gcc/tree-vect-stmts.cc @@ -1610,9 +1610,15 @@ check_load_store_for_partial_vectors (loop_vec_info loop_vinfo, tree vectype, bool is_load = (vls_type == VLS_LOAD); if (memory_access_type == VMAT_LOAD_STORE_LANES) { - if (is_load - ? !vect_load_lanes_supported (vectype, group_size, true) - : !vect_store_lanes_supported (vectype, group_size, true)) + internal_fn ifn + = (is_load ? vect_load_lanes_supported (vectype, group_size, true) + : vect_store_lanes_supported (vectype, group_size, true)); + if (ifn == IFN_MASK_LEN_LOAD_LANES || ifn == IFN_MASK_LEN_STORE_LANES) + vect_record_loop_len (loop_vinfo, lens, nvectors, vectype, 1); + else if (ifn == IFN_MASK_LOAD_LANES || ifn == IFN_MASK_STORE_LANES) + vect_record_loop_mask (loop_vinfo, masks, nvectors, vectype, + scalar_mask); + else { if (dump_enabled_p ()) dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, @@ -1620,10 +1626,7 @@ check_load_store_for_partial_vectors (loop_vec_info loop_vinfo, tree vectype, " the target doesn't have an appropriate" " load/store-lanes instruction.\n"); LOOP_VINFO_CAN_USE_PARTIAL_VECTORS_P (loop_vinfo) = false; - return; } - vect_record_loop_mask (loop_vinfo, masks, nvectors, vectype, - scalar_mask); return; } @@ -2074,7 +2077,8 @@ get_group_load_store_type (vec_info *vinfo, stmt_vec_info stmt_info, poly_int64 *poffset, dr_alignment_support *alignment_support_scheme, int *misalignment, - gather_scatter_info *gs_info) + gather_scatter_info *gs_info, + internal_fn *lanes_ifn) { loop_vec_info loop_vinfo = dyn_cast (vinfo); class loop *loop = loop_vinfo ? LOOP_VINFO_LOOP (loop_vinfo) : NULL; @@ -2272,24 +2276,30 @@ get_group_load_store_type (vec_info *vinfo, stmt_vec_info stmt_info, if (known_eq (TYPE_VECTOR_SUBPARTS (vectype), 1U)) ; - /* Otherwise try using LOAD/STORE_LANES. */ - else if (vls_type == VLS_LOAD - ? vect_load_lanes_supported (vectype, group_size, masked_p) - : vect_store_lanes_supported (vectype, group_size, - masked_p)) + else { - *memory_access_type = VMAT_LOAD_STORE_LANES; - overrun_p = would_overrun_p; - } + /* Otherwise try using LOAD/STORE_LANES. */ + *lanes_ifn + = vls_type == VLS_LOAD + ? vect_load_lanes_supported (vectype, group_size, masked_p) + : vect_store_lanes_supported (vectype, group_size, + masked_p); + if (*lanes_ifn != IFN_LAST) + { + *memory_access_type = VMAT_LOAD_STORE_LANES; + overrun_p = would_overrun_p; + } - /* If that fails, try using permuting loads. */ - else if (vls_type == VLS_LOAD - ? vect_grouped_load_supported (vectype, single_element_p, - group_size) - : vect_grouped_store_supported (vectype, group_size)) - { - *memory_access_type = VMAT_CONTIGUOUS_PERMUTE; - overrun_p = would_overrun_p; + /* If that fails, try using permuting loads. */ + else if (vls_type == VLS_LOAD + ? vect_grouped_load_supported (vectype, + single_element_p, + group_size) + : vect_grouped_store_supported (vectype, group_size)) + { + *memory_access_type = VMAT_CONTIGUOUS_PERMUTE; + overrun_p = would_overrun_p; + } } } @@ -2378,7 +2388,8 @@ get_load_store_type (vec_info *vinfo, stmt_vec_info stmt_info, poly_int64 *poffset, dr_alignment_support *alignment_support_scheme, int *misalignment, - gather_scatter_info *gs_info) + gather_scatter_info *gs_info, + internal_fn *lanes_ifn) { loop_vec_info loop_vinfo = dyn_cast (vinfo); poly_uint64 nunits = TYPE_VECTOR_SUBPARTS (vectype); @@ -2441,7 +2452,7 @@ get_load_store_type (vec_info *vinfo, stmt_vec_info stmt_info, masked_p, vls_type, memory_access_type, poffset, alignment_support_scheme, - misalignment, gs_info)) + misalignment, gs_info, lanes_ifn)) return false; } else if (STMT_VINFO_STRIDED_P (stmt_info)) @@ -2618,12 +2629,14 @@ vect_check_store_rhs (vec_info *vinfo, stmt_vec_info stmt_info, return false; } - unsigned op_no = 0; + int op_no = 0; if (gcall *call = dyn_cast (stmt_info->stmt)) { if (gimple_call_internal_p (call) && internal_store_fn_p (gimple_call_internal_fn (call))) op_no = internal_fn_stored_value_index (gimple_call_internal_fn (call)); + if (slp_node) + op_no = vect_slp_child_index_for_operand (call, op_no); } enum vect_def_type rhs_dt; @@ -2978,6 +2991,216 @@ vect_build_gather_load_calls (vec_info *vinfo, stmt_vec_info stmt_info, *vec_stmt = STMT_VINFO_VEC_STMTS (stmt_info)[0]; } +/* Build a scatter store call while vectorizing STMT_INFO. Insert new + instructions before GSI and add them to VEC_STMT. GS_INFO describes + the scatter store operation. If the store is conditional, MASK is the + unvectorized condition, otherwise MASK is null. */ + +static void +vect_build_scatter_store_calls (vec_info *vinfo, stmt_vec_info stmt_info, + gimple_stmt_iterator *gsi, gimple **vec_stmt, + gather_scatter_info *gs_info, tree mask) +{ + loop_vec_info loop_vinfo = dyn_cast (vinfo); + tree vectype = STMT_VINFO_VECTYPE (stmt_info); + poly_uint64 nunits = TYPE_VECTOR_SUBPARTS (vectype); + int ncopies = vect_get_num_copies (loop_vinfo, vectype); + enum { NARROW, NONE, WIDEN } modifier; + poly_uint64 scatter_off_nunits + = TYPE_VECTOR_SUBPARTS (gs_info->offset_vectype); + + tree perm_mask = NULL_TREE, mask_halfvectype = NULL_TREE; + if (known_eq (nunits, scatter_off_nunits)) + modifier = NONE; + else if (known_eq (nunits * 2, scatter_off_nunits)) + { + modifier = WIDEN; + + /* Currently gathers and scatters are only supported for + fixed-length vectors. */ + unsigned int count = scatter_off_nunits.to_constant (); + vec_perm_builder sel (count, count, 1); + for (unsigned i = 0; i < (unsigned int) count; ++i) + sel.quick_push (i | (count / 2)); + + vec_perm_indices indices (sel, 1, count); + perm_mask = vect_gen_perm_mask_checked (gs_info->offset_vectype, indices); + gcc_assert (perm_mask != NULL_TREE); + } + else if (known_eq (nunits, scatter_off_nunits * 2)) + { + modifier = NARROW; + + /* Currently gathers and scatters are only supported for + fixed-length vectors. */ + unsigned int count = nunits.to_constant (); + vec_perm_builder sel (count, count, 1); + for (unsigned i = 0; i < (unsigned int) count; ++i) + sel.quick_push (i | (count / 2)); + + vec_perm_indices indices (sel, 2, count); + perm_mask = vect_gen_perm_mask_checked (vectype, indices); + gcc_assert (perm_mask != NULL_TREE); + ncopies *= 2; + + if (mask) + mask_halfvectype = truth_type_for (gs_info->offset_vectype); + } + else + gcc_unreachable (); + + tree rettype = TREE_TYPE (TREE_TYPE (gs_info->decl)); + tree arglist = TYPE_ARG_TYPES (TREE_TYPE (gs_info->decl)); + tree ptrtype = TREE_VALUE (arglist); arglist = TREE_CHAIN (arglist); + tree masktype = TREE_VALUE (arglist); arglist = TREE_CHAIN (arglist); + tree idxtype = TREE_VALUE (arglist); arglist = TREE_CHAIN (arglist); + tree srctype = TREE_VALUE (arglist); arglist = TREE_CHAIN (arglist); + tree scaletype = TREE_VALUE (arglist); + + gcc_checking_assert (TREE_CODE (masktype) == INTEGER_TYPE + && TREE_CODE (rettype) == VOID_TYPE); + + tree ptr = fold_convert (ptrtype, gs_info->base); + if (!is_gimple_min_invariant (ptr)) + { + gimple_seq seq; + ptr = force_gimple_operand (ptr, &seq, true, NULL_TREE); + class loop *loop = LOOP_VINFO_LOOP (loop_vinfo); + edge pe = loop_preheader_edge (loop); + basic_block new_bb = gsi_insert_seq_on_edge_immediate (pe, seq); + gcc_assert (!new_bb); + } + + tree mask_arg = NULL_TREE; + if (mask == NULL_TREE) + { + mask_arg = build_int_cst (masktype, -1); + mask_arg = vect_init_vector (vinfo, stmt_info, mask_arg, masktype, NULL); + } + + tree scale = build_int_cst (scaletype, gs_info->scale); + + auto_vec vec_oprnds0; + auto_vec vec_oprnds1; + auto_vec vec_masks; + if (mask) + { + tree mask_vectype = truth_type_for (vectype); + vect_get_vec_defs_for_operand (vinfo, stmt_info, + modifier == NARROW ? ncopies / 2 : ncopies, + mask, &vec_masks, mask_vectype); + } + vect_get_vec_defs_for_operand (vinfo, stmt_info, + modifier == WIDEN ? ncopies / 2 : ncopies, + gs_info->offset, &vec_oprnds0); + tree op = vect_get_store_rhs (stmt_info); + vect_get_vec_defs_for_operand (vinfo, stmt_info, + modifier == NARROW ? ncopies / 2 : ncopies, op, + &vec_oprnds1); + + tree vec_oprnd0 = NULL_TREE, vec_oprnd1 = NULL_TREE; + tree mask_op = NULL_TREE; + tree src, vec_mask; + for (int j = 0; j < ncopies; ++j) + { + if (modifier == WIDEN) + { + if (j & 1) + op = permute_vec_elements (vinfo, vec_oprnd0, vec_oprnd0, perm_mask, + stmt_info, gsi); + else + op = vec_oprnd0 = vec_oprnds0[j / 2]; + src = vec_oprnd1 = vec_oprnds1[j]; + if (mask) + mask_op = vec_mask = vec_masks[j]; + } + else if (modifier == NARROW) + { + if (j & 1) + src = permute_vec_elements (vinfo, vec_oprnd1, vec_oprnd1, + perm_mask, stmt_info, gsi); + else + src = vec_oprnd1 = vec_oprnds1[j / 2]; + op = vec_oprnd0 = vec_oprnds0[j]; + if (mask) + mask_op = vec_mask = vec_masks[j / 2]; + } + else + { + op = vec_oprnd0 = vec_oprnds0[j]; + src = vec_oprnd1 = vec_oprnds1[j]; + if (mask) + mask_op = vec_mask = vec_masks[j]; + } + + if (!useless_type_conversion_p (srctype, TREE_TYPE (src))) + { + gcc_assert (known_eq (TYPE_VECTOR_SUBPARTS (TREE_TYPE (src)), + TYPE_VECTOR_SUBPARTS (srctype))); + tree var = vect_get_new_ssa_name (srctype, vect_simple_var); + src = build1 (VIEW_CONVERT_EXPR, srctype, src); + gassign *new_stmt = gimple_build_assign (var, VIEW_CONVERT_EXPR, src); + vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi); + src = var; + } + + if (!useless_type_conversion_p (idxtype, TREE_TYPE (op))) + { + gcc_assert (known_eq (TYPE_VECTOR_SUBPARTS (TREE_TYPE (op)), + TYPE_VECTOR_SUBPARTS (idxtype))); + tree var = vect_get_new_ssa_name (idxtype, vect_simple_var); + op = build1 (VIEW_CONVERT_EXPR, idxtype, op); + gassign *new_stmt = gimple_build_assign (var, VIEW_CONVERT_EXPR, op); + vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi); + op = var; + } + + if (mask) + { + tree utype; + mask_arg = mask_op; + if (modifier == NARROW) + { + tree var + = vect_get_new_ssa_name (mask_halfvectype, vect_simple_var); + gassign *new_stmt + = gimple_build_assign (var, + (j & 1) ? VEC_UNPACK_HI_EXPR + : VEC_UNPACK_LO_EXPR, + mask_op); + vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi); + mask_arg = var; + } + tree optype = TREE_TYPE (mask_arg); + if (TYPE_MODE (masktype) == TYPE_MODE (optype)) + utype = masktype; + else + utype = lang_hooks.types.type_for_mode (TYPE_MODE (optype), 1); + tree var = vect_get_new_ssa_name (utype, vect_scalar_var); + mask_arg = build1 (VIEW_CONVERT_EXPR, utype, mask_arg); + gassign *new_stmt + = gimple_build_assign (var, VIEW_CONVERT_EXPR, mask_arg); + vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi); + mask_arg = var; + if (!useless_type_conversion_p (masktype, utype)) + { + gcc_assert (TYPE_PRECISION (utype) <= TYPE_PRECISION (masktype)); + tree var = vect_get_new_ssa_name (masktype, vect_scalar_var); + new_stmt = gimple_build_assign (var, NOP_EXPR, mask_arg); + vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi); + mask_arg = var; + } + } + + gcall *new_stmt + = gimple_build_call (gs_info->decl, 5, ptr, mask_arg, op, src, scale); + vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi); + + STMT_VINFO_VEC_STMTS (stmt_info).safe_push (new_stmt); + } + *vec_stmt = STMT_VINFO_VEC_STMTS (stmt_info)[0]; +} + /* Prepare the base and offset in GS_INFO for vectorization. Set *DATAREF_PTR to the loop-invariant base address and *VEC_OFFSET to the vectorized offset argument for the first copy of STMT_INFO. @@ -3087,11 +3310,8 @@ vect_get_loop_variant_data_ptr_increment ( loop_vec_info loop_vinfo = dyn_cast (vinfo); tree step = vect_dr_behavior (vinfo, dr_info)->step; - /* TODO: We don't support gather/scatter or load_lanes/store_lanes for pointer - IVs are updated by variable amount but we will support them in the future. - */ - gcc_assert (memory_access_type != VMAT_GATHER_SCATTER - && memory_access_type != VMAT_LOAD_STORE_LANES); + /* gather/scatter never reach here. */ + gcc_assert (memory_access_type != VMAT_GATHER_SCATTER); /* When we support SELECT_VL pattern, we dynamic adjust the memory address by .SELECT_VL result. @@ -3540,7 +3760,10 @@ vectorizable_call (vec_info *vinfo, int reduc_idx = STMT_VINFO_REDUC_IDX (stmt_info); internal_fn cond_fn = get_conditional_internal_fn (ifn); + internal_fn cond_len_fn = get_len_internal_fn (ifn); + int len_opno = internal_fn_len_index (cond_len_fn); vec_loop_masks *masks = (loop_vinfo ? &LOOP_VINFO_MASKS (loop_vinfo) : NULL); + vec_loop_lens *lens = (loop_vinfo ? &LOOP_VINFO_LENS (loop_vinfo) : NULL); if (!vec_stmt) /* transformation not required. */ { if (slp_node) @@ -3569,6 +3792,9 @@ vectorizable_call (vec_info *vinfo, if (reduc_idx >= 0 && (cond_fn == IFN_LAST || !direct_internal_fn_supported_p (cond_fn, vectype_out, + OPTIMIZE_FOR_SPEED)) + && (cond_len_fn == IFN_LAST + || !direct_internal_fn_supported_p (cond_len_fn, vectype_out, OPTIMIZE_FOR_SPEED))) { if (dump_enabled_p ()) @@ -3586,8 +3812,14 @@ vectorizable_call (vec_info *vinfo, tree scalar_mask = NULL_TREE; if (mask_opno >= 0) scalar_mask = gimple_call_arg (stmt_info->stmt, mask_opno); - vect_record_loop_mask (loop_vinfo, masks, nvectors, - vectype_out, scalar_mask); + if (cond_len_fn != IFN_LAST + && direct_internal_fn_supported_p (cond_len_fn, vectype_out, + OPTIMIZE_FOR_SPEED)) + vect_record_loop_len (loop_vinfo, lens, nvectors, vectype_out, + 1); + else + vect_record_loop_mask (loop_vinfo, masks, nvectors, vectype_out, + scalar_mask); } } return true; @@ -3603,8 +3835,20 @@ vectorizable_call (vec_info *vinfo, vec_dest = vect_create_destination_var (scalar_dest, vectype_out); bool masked_loop_p = loop_vinfo && LOOP_VINFO_FULLY_MASKED_P (loop_vinfo); + bool len_loop_p = loop_vinfo && LOOP_VINFO_FULLY_WITH_LENGTH_P (loop_vinfo); unsigned int vect_nargs = nargs; - if (masked_loop_p && reduc_idx >= 0) + if (len_loop_p) + { + if (len_opno >= 0) + { + ifn = cond_len_fn; + /* COND_* -> COND_LEN_* takes 2 extra arguments:LEN,BIAS. */ + vect_nargs += 2; + } + else if (reduc_idx >= 0) + gcc_unreachable (); + } + else if (masked_loop_p && reduc_idx >= 0) { ifn = cond_fn; vect_nargs += 2; @@ -3671,7 +3915,21 @@ vectorizable_call (vec_info *vinfo, } else { - if (mask_opno >= 0 && masked_loop_p) + if (len_opno >= 0 && len_loop_p) + { + unsigned int vec_num = vec_oprnds0.length (); + /* Always true for SLP. */ + gcc_assert (ncopies == 1); + tree len + = vect_get_loop_len (loop_vinfo, gsi, lens, vec_num, + vectype_out, i, 1); + signed char biasval + = LOOP_VINFO_PARTIAL_LOAD_STORE_BIAS (loop_vinfo); + tree bias = build_int_cst (intQI_type_node, biasval); + vargs[len_opno] = len; + vargs[len_opno + 1] = bias; + } + else if (mask_opno >= 0 && masked_loop_p) { unsigned int vec_num = vec_oprnds0.length (); /* Always true for SLP. */ @@ -3719,7 +3977,17 @@ vectorizable_call (vec_info *vinfo, if (masked_loop_p && reduc_idx >= 0) vargs[varg++] = vargs[reduc_idx + 1]; - if (mask_opno >= 0 && masked_loop_p) + if (len_opno >= 0 && len_loop_p) + { + tree len = vect_get_loop_len (loop_vinfo, gsi, lens, ncopies, + vectype_out, j, 1); + signed char biasval + = LOOP_VINFO_PARTIAL_LOAD_STORE_BIAS (loop_vinfo); + tree bias = build_int_cst (intQI_type_node, biasval); + vargs[len_opno] = len; + vargs[len_opno + 1] = bias; + } + else if (mask_opno >= 0 && masked_loop_p) { tree mask = vect_get_loop_mask (loop_vinfo, gsi, masks, ncopies, vectype_out, j); @@ -7934,9 +8202,6 @@ vectorizable_store (vec_info *vinfo, stmt_vec_info first_stmt_info; bool grouped_store; unsigned int group_size, i; - vec oprnds = vNULL; - vec result_chain = vNULL; - vec vec_oprnds = vNULL; bool slp = (slp_node != NULL); unsigned int vec_num; bb_vec_info bb_vinfo = dyn_cast (vinfo); @@ -7981,15 +8246,9 @@ vectorizable_store (vec_info *vinfo, if (!internal_store_fn_p (ifn)) return false; - if (slp_node != NULL) - { - if (dump_enabled_p ()) - dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, - "SLP of masked stores not supported.\n"); - return false; - } - int mask_index = internal_fn_mask_index (ifn); + if (mask_index >= 0 && slp_node) + mask_index = vect_slp_child_index_for_operand (call, mask_index); if (mask_index >= 0 && !vect_check_scalar_mask (vinfo, stmt_info, slp_node, mask_index, &mask, NULL, &mask_dt, &mask_vectype)) @@ -8046,9 +8305,11 @@ vectorizable_store (vec_info *vinfo, enum dr_alignment_support alignment_support_scheme; int misalignment; poly_int64 poffset; + internal_fn lanes_ifn; if (!get_load_store_type (vinfo, stmt_info, vectype, slp_node, mask, vls_type, ncopies, &memory_access_type, &poffset, - &alignment_support_scheme, &misalignment, &gs_info)) + &alignment_support_scheme, &misalignment, &gs_info, + &lanes_ifn)) return false; if (mask) @@ -8154,228 +8415,18 @@ vectorizable_store (vec_info *vinfo, if (memory_access_type == VMAT_GATHER_SCATTER && gs_info.decl) { - tree vec_oprnd0 = NULL_TREE, vec_oprnd1 = NULL_TREE, src; - tree arglist = TYPE_ARG_TYPES (TREE_TYPE (gs_info.decl)); - tree rettype, srctype, ptrtype, idxtype, masktype, scaletype; - tree ptr, var, scale, vec_mask; - tree mask_arg = NULL_TREE, mask_op = NULL_TREE, perm_mask = NULL_TREE; - tree mask_halfvectype = mask_vectype; - edge pe = loop_preheader_edge (loop); - gimple_seq seq; - basic_block new_bb; - enum { NARROW, NONE, WIDEN } modifier; - poly_uint64 scatter_off_nunits - = TYPE_VECTOR_SUBPARTS (gs_info.offset_vectype); - - if (known_eq (nunits, scatter_off_nunits)) - modifier = NONE; - else if (known_eq (nunits * 2, scatter_off_nunits)) - { - modifier = WIDEN; - - /* Currently gathers and scatters are only supported for - fixed-length vectors. */ - unsigned int count = scatter_off_nunits.to_constant (); - vec_perm_builder sel (count, count, 1); - for (i = 0; i < (unsigned int) count; ++i) - sel.quick_push (i | (count / 2)); - - vec_perm_indices indices (sel, 1, count); - perm_mask = vect_gen_perm_mask_checked (gs_info.offset_vectype, - indices); - gcc_assert (perm_mask != NULL_TREE); - } - else if (known_eq (nunits, scatter_off_nunits * 2)) - { - modifier = NARROW; - - /* Currently gathers and scatters are only supported for - fixed-length vectors. */ - unsigned int count = nunits.to_constant (); - vec_perm_builder sel (count, count, 1); - for (i = 0; i < (unsigned int) count; ++i) - sel.quick_push (i | (count / 2)); - - vec_perm_indices indices (sel, 2, count); - perm_mask = vect_gen_perm_mask_checked (vectype, indices); - gcc_assert (perm_mask != NULL_TREE); - ncopies *= 2; - - if (mask) - mask_halfvectype = truth_type_for (gs_info.offset_vectype); - } - else - gcc_unreachable (); - - rettype = TREE_TYPE (TREE_TYPE (gs_info.decl)); - ptrtype = TREE_VALUE (arglist); arglist = TREE_CHAIN (arglist); - masktype = TREE_VALUE (arglist); arglist = TREE_CHAIN (arglist); - idxtype = TREE_VALUE (arglist); arglist = TREE_CHAIN (arglist); - srctype = TREE_VALUE (arglist); arglist = TREE_CHAIN (arglist); - scaletype = TREE_VALUE (arglist); - - gcc_checking_assert (TREE_CODE (masktype) == INTEGER_TYPE - && TREE_CODE (rettype) == VOID_TYPE); - - ptr = fold_convert (ptrtype, gs_info.base); - if (!is_gimple_min_invariant (ptr)) - { - ptr = force_gimple_operand (ptr, &seq, true, NULL_TREE); - new_bb = gsi_insert_seq_on_edge_immediate (pe, seq); - gcc_assert (!new_bb); - } - - if (mask == NULL_TREE) - { - mask_arg = build_int_cst (masktype, -1); - mask_arg = vect_init_vector (vinfo, stmt_info, - mask_arg, masktype, NULL); - } - - scale = build_int_cst (scaletype, gs_info.scale); - - auto_vec vec_oprnds0; - auto_vec vec_oprnds1; - auto_vec vec_masks; - if (mask) - { - tree mask_vectype = truth_type_for (vectype); - vect_get_vec_defs_for_operand (vinfo, stmt_info, - modifier == NARROW - ? ncopies / 2 : ncopies, - mask, &vec_masks, mask_vectype); - } - vect_get_vec_defs_for_operand (vinfo, stmt_info, - modifier == WIDEN - ? ncopies / 2 : ncopies, - gs_info.offset, &vec_oprnds0); - vect_get_vec_defs_for_operand (vinfo, stmt_info, - modifier == NARROW - ? ncopies / 2 : ncopies, - op, &vec_oprnds1); - for (j = 0; j < ncopies; ++j) - { - if (modifier == WIDEN) - { - if (j & 1) - op = permute_vec_elements (vinfo, vec_oprnd0, vec_oprnd0, - perm_mask, stmt_info, gsi); - else - op = vec_oprnd0 = vec_oprnds0[j / 2]; - src = vec_oprnd1 = vec_oprnds1[j]; - if (mask) - mask_op = vec_mask = vec_masks[j]; - } - else if (modifier == NARROW) - { - if (j & 1) - src = permute_vec_elements (vinfo, vec_oprnd1, vec_oprnd1, - perm_mask, stmt_info, gsi); - else - src = vec_oprnd1 = vec_oprnds1[j / 2]; - op = vec_oprnd0 = vec_oprnds0[j]; - if (mask) - mask_op = vec_mask = vec_masks[j / 2]; - } - else - { - op = vec_oprnd0 = vec_oprnds0[j]; - src = vec_oprnd1 = vec_oprnds1[j]; - if (mask) - mask_op = vec_mask = vec_masks[j]; - } - - if (!useless_type_conversion_p (srctype, TREE_TYPE (src))) - { - gcc_assert (known_eq (TYPE_VECTOR_SUBPARTS (TREE_TYPE (src)), - TYPE_VECTOR_SUBPARTS (srctype))); - var = vect_get_new_ssa_name (srctype, vect_simple_var); - src = build1 (VIEW_CONVERT_EXPR, srctype, src); - gassign *new_stmt - = gimple_build_assign (var, VIEW_CONVERT_EXPR, src); - vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi); - src = var; - } - - if (!useless_type_conversion_p (idxtype, TREE_TYPE (op))) - { - gcc_assert (known_eq (TYPE_VECTOR_SUBPARTS (TREE_TYPE (op)), - TYPE_VECTOR_SUBPARTS (idxtype))); - var = vect_get_new_ssa_name (idxtype, vect_simple_var); - op = build1 (VIEW_CONVERT_EXPR, idxtype, op); - gassign *new_stmt - = gimple_build_assign (var, VIEW_CONVERT_EXPR, op); - vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi); - op = var; - } - - if (mask) - { - tree utype; - mask_arg = mask_op; - if (modifier == NARROW) - { - var = vect_get_new_ssa_name (mask_halfvectype, - vect_simple_var); - gassign *new_stmt - = gimple_build_assign (var, (j & 1) ? VEC_UNPACK_HI_EXPR - : VEC_UNPACK_LO_EXPR, - mask_op); - vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi); - mask_arg = var; - } - tree optype = TREE_TYPE (mask_arg); - if (TYPE_MODE (masktype) == TYPE_MODE (optype)) - utype = masktype; - else - utype = lang_hooks.types.type_for_mode (TYPE_MODE (optype), 1); - var = vect_get_new_ssa_name (utype, vect_scalar_var); - mask_arg = build1 (VIEW_CONVERT_EXPR, utype, mask_arg); - gassign *new_stmt - = gimple_build_assign (var, VIEW_CONVERT_EXPR, mask_arg); - vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi); - mask_arg = var; - if (!useless_type_conversion_p (masktype, utype)) - { - gcc_assert (TYPE_PRECISION (utype) - <= TYPE_PRECISION (masktype)); - var = vect_get_new_ssa_name (masktype, vect_scalar_var); - new_stmt = gimple_build_assign (var, NOP_EXPR, mask_arg); - vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi); - mask_arg = var; - } - } - - gcall *new_stmt - = gimple_build_call (gs_info.decl, 5, ptr, mask_arg, op, src, scale); - vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi); - - STMT_VINFO_VEC_STMTS (stmt_info).safe_push (new_stmt); - } - *vec_stmt = STMT_VINFO_VEC_STMTS (stmt_info)[0]; + vect_build_scatter_store_calls (vinfo, stmt_info, gsi, vec_stmt, + &gs_info, mask); return true; } else if (STMT_VINFO_SIMD_LANE_ACCESS_P (stmt_info) >= 3) return vectorizable_scan_store (vinfo, stmt_info, gsi, vec_stmt, ncopies); - if (STMT_VINFO_GROUPED_ACCESS (stmt_info)) - DR_GROUP_STORE_COUNT (DR_GROUP_FIRST_ELEMENT (stmt_info))++; - if (grouped_store) { /* FORNOW */ gcc_assert (!loop || !nested_in_vect_loop_p (loop, stmt_info)); - /* We vectorize all the stmts of the interleaving group when we - reach the last stmt in the group. */ - if (DR_GROUP_STORE_COUNT (first_stmt_info) - < DR_GROUP_SIZE (first_stmt_info) - && !slp) - { - *vec_stmt = NULL; - return true; - } - if (slp) { grouped_store = false; @@ -8533,6 +8584,7 @@ vectorizable_store (vec_info *vinfo, alias_off = build_int_cst (ref_type, 0); stmt_vec_info next_stmt_info = first_stmt_info; + auto_vec vec_oprnds (ncopies); for (g = 0; g < group_size; g++) { running_off = offvar; @@ -8614,7 +8666,7 @@ vectorizable_store (vec_info *vinfo, } } next_stmt_info = DR_GROUP_NEXT_ELEMENT (next_stmt_info); - vec_oprnds.release (); + vec_oprnds.truncate(0); if (slp) break; } @@ -8622,9 +8674,6 @@ vectorizable_store (vec_info *vinfo, return true; } - auto_vec dr_chain (group_size); - oprnds.create (group_size); - gcc_assert (alignment_support_scheme); vec_loop_masks *loop_masks = (loop_vinfo && LOOP_VINFO_FULLY_MASKED_P (loop_vinfo) @@ -8715,31 +8764,344 @@ vectorizable_store (vec_info *vinfo, STMT_VINFO_RELATED_STMT for the next copies. */ + auto_vec dr_chain (group_size); auto_vec vec_masks; tree vec_mask = NULL; - auto_vec vec_offsets; - auto_vec > gvec_oprnds; - gvec_oprnds.safe_grow_cleared (group_size, true); + auto_delete_vec> gvec_oprnds (group_size); + for (i = 0; i < group_size; i++) + gvec_oprnds.quick_push (new auto_vec (ncopies)); + + if (memory_access_type == VMAT_LOAD_STORE_LANES) + { + gcc_assert (!slp && grouped_store); + for (j = 0; j < ncopies; j++) + { + gimple *new_stmt; + if (j == 0) + { + /* For interleaved stores we collect vectorized defs for all + the stores in the group in DR_CHAIN. DR_CHAIN is then used + as an input to vect_permute_store_chain(). */ + stmt_vec_info next_stmt_info = first_stmt_info; + for (i = 0; i < group_size; i++) + { + /* Since gaps are not supported for interleaved stores, + DR_GROUP_SIZE is the exact number of stmts in the + chain. Therefore, NEXT_STMT_INFO can't be NULL_TREE. */ + op = vect_get_store_rhs (next_stmt_info); + vect_get_vec_defs_for_operand (vinfo, next_stmt_info, ncopies, + op, gvec_oprnds[i]); + vec_oprnd = (*gvec_oprnds[i])[0]; + dr_chain.quick_push (vec_oprnd); + next_stmt_info = DR_GROUP_NEXT_ELEMENT (next_stmt_info); + } + if (mask) + { + vect_get_vec_defs_for_operand (vinfo, stmt_info, ncopies, + mask, &vec_masks, + mask_vectype); + vec_mask = vec_masks[0]; + } + + /* We should have catched mismatched types earlier. */ + gcc_assert ( + useless_type_conversion_p (vectype, TREE_TYPE (vec_oprnd))); + dataref_ptr + = vect_create_data_ref_ptr (vinfo, first_stmt_info, aggr_type, + NULL, offset, &dummy, gsi, + &ptr_incr, false, bump); + } + else + { + gcc_assert (!LOOP_VINFO_USING_SELECT_VL_P (loop_vinfo)); + /* DR_CHAIN is then used as an input to + vect_permute_store_chain(). */ + for (i = 0; i < group_size; i++) + { + vec_oprnd = (*gvec_oprnds[i])[j]; + dr_chain[i] = vec_oprnd; + } + if (mask) + vec_mask = vec_masks[j]; + dataref_ptr = bump_vector_ptr (vinfo, dataref_ptr, ptr_incr, gsi, + stmt_info, bump); + } + + /* Get an array into which we can store the individual vectors. */ + tree vec_array = create_vector_array (vectype, vec_num); + + /* Invalidate the current contents of VEC_ARRAY. This should + become an RTL clobber too, which prevents the vector registers + from being upward-exposed. */ + vect_clobber_variable (vinfo, stmt_info, gsi, vec_array); + + /* Store the individual vectors into the array. */ + for (i = 0; i < vec_num; i++) + { + vec_oprnd = dr_chain[i]; + write_vector_array (vinfo, stmt_info, gsi, vec_oprnd, vec_array, + i); + } + + tree final_mask = NULL; + tree final_len = NULL; + tree bias = NULL; + if (loop_masks) + final_mask = vect_get_loop_mask (loop_vinfo, gsi, loop_masks, + ncopies, vectype, j); + if (vec_mask) + final_mask = prepare_vec_mask (loop_vinfo, mask_vectype, final_mask, + vec_mask, gsi); + + if (lanes_ifn == IFN_MASK_LEN_STORE_LANES) + { + if (loop_lens) + final_len = vect_get_loop_len (loop_vinfo, gsi, loop_lens, + ncopies, vectype, j, 1); + else + final_len = size_int (TYPE_VECTOR_SUBPARTS (vectype)); + signed char biasval + = LOOP_VINFO_PARTIAL_LOAD_STORE_BIAS (loop_vinfo); + bias = build_int_cst (intQI_type_node, biasval); + if (!final_mask) + { + mask_vectype = truth_type_for (vectype); + final_mask = build_minus_one_cst (mask_vectype); + } + } + + gcall *call; + if (final_len && final_mask) + { + /* Emit: + MASK_LEN_STORE_LANES (DATAREF_PTR, ALIAS_PTR, VEC_MASK, + LEN, BIAS, VEC_ARRAY). */ + unsigned int align = TYPE_ALIGN (TREE_TYPE (vectype)); + tree alias_ptr = build_int_cst (ref_type, align); + call = gimple_build_call_internal (IFN_MASK_LEN_STORE_LANES, 6, + dataref_ptr, alias_ptr, + final_mask, final_len, bias, + vec_array); + } + else if (final_mask) + { + /* Emit: + MASK_STORE_LANES (DATAREF_PTR, ALIAS_PTR, VEC_MASK, + VEC_ARRAY). */ + unsigned int align = TYPE_ALIGN (TREE_TYPE (vectype)); + tree alias_ptr = build_int_cst (ref_type, align); + call = gimple_build_call_internal (IFN_MASK_STORE_LANES, 4, + dataref_ptr, alias_ptr, + final_mask, vec_array); + } + else + { + /* Emit: + MEM_REF[...all elements...] = STORE_LANES (VEC_ARRAY). */ + data_ref = create_array_ref (aggr_type, dataref_ptr, ref_type); + call = gimple_build_call_internal (IFN_STORE_LANES, 1, vec_array); + gimple_call_set_lhs (call, data_ref); + } + gimple_call_set_nothrow (call, true); + vect_finish_stmt_generation (vinfo, stmt_info, call, gsi); + new_stmt = call; + + /* Record that VEC_ARRAY is now dead. */ + vect_clobber_variable (vinfo, stmt_info, gsi, vec_array); + if (j == 0) + *vec_stmt = new_stmt; + STMT_VINFO_VEC_STMTS (stmt_info).safe_push (new_stmt); + } + + return true; + } + + if (memory_access_type == VMAT_GATHER_SCATTER) + { + gcc_assert (!slp && !grouped_store); + auto_vec vec_offsets; + for (j = 0; j < ncopies; j++) + { + gimple *new_stmt; + if (j == 0) + { + /* Since the store is not grouped, DR_GROUP_SIZE is 1, and + DR_CHAIN is of size 1. */ + gcc_assert (group_size == 1); + op = vect_get_store_rhs (first_stmt_info); + vect_get_vec_defs_for_operand (vinfo, first_stmt_info, ncopies, + op, gvec_oprnds[0]); + vec_oprnd = (*gvec_oprnds[0])[0]; + dr_chain.quick_push (vec_oprnd); + if (mask) + { + vect_get_vec_defs_for_operand (vinfo, stmt_info, ncopies, + mask, &vec_masks, + mask_vectype); + vec_mask = vec_masks[0]; + } + + /* We should have catched mismatched types earlier. */ + gcc_assert (useless_type_conversion_p (vectype, + TREE_TYPE (vec_oprnd))); + if (STMT_VINFO_GATHER_SCATTER_P (stmt_info)) + vect_get_gather_scatter_ops (loop_vinfo, loop, stmt_info, + slp_node, &gs_info, &dataref_ptr, + &vec_offsets); + else + dataref_ptr + = vect_create_data_ref_ptr (vinfo, first_stmt_info, aggr_type, + NULL, offset, &dummy, gsi, + &ptr_incr, false, bump); + } + else + { + gcc_assert (!LOOP_VINFO_USING_SELECT_VL_P (loop_vinfo)); + vec_oprnd = (*gvec_oprnds[0])[j]; + dr_chain[0] = vec_oprnd; + if (mask) + vec_mask = vec_masks[j]; + if (!STMT_VINFO_GATHER_SCATTER_P (stmt_info)) + dataref_ptr = bump_vector_ptr (vinfo, dataref_ptr, ptr_incr, + gsi, stmt_info, bump); + } + + new_stmt = NULL; + unsigned HOST_WIDE_INT align; + tree final_mask = NULL_TREE; + tree final_len = NULL_TREE; + tree bias = NULL_TREE; + if (loop_masks) + final_mask = vect_get_loop_mask (loop_vinfo, gsi, loop_masks, + ncopies, vectype, j); + if (vec_mask) + final_mask = prepare_vec_mask (loop_vinfo, mask_vectype, final_mask, + vec_mask, gsi); + + if (gs_info.ifn != IFN_LAST) + { + if (STMT_VINFO_GATHER_SCATTER_P (stmt_info)) + vec_offset = vec_offsets[j]; + tree scale = size_int (gs_info.scale); + + if (gs_info.ifn == IFN_MASK_LEN_SCATTER_STORE) + { + if (loop_lens) + final_len = vect_get_loop_len (loop_vinfo, gsi, loop_lens, + ncopies, vectype, j, 1); + else + final_len = build_int_cst (sizetype, + TYPE_VECTOR_SUBPARTS (vectype)); + signed char biasval + = LOOP_VINFO_PARTIAL_LOAD_STORE_BIAS (loop_vinfo); + bias = build_int_cst (intQI_type_node, biasval); + if (!final_mask) + { + mask_vectype = truth_type_for (vectype); + final_mask = build_minus_one_cst (mask_vectype); + } + } + + gcall *call; + if (final_len && final_mask) + call = gimple_build_call_internal (IFN_MASK_LEN_SCATTER_STORE, + 7, dataref_ptr, vec_offset, + scale, vec_oprnd, final_mask, + final_len, bias); + else if (final_mask) + call + = gimple_build_call_internal (IFN_MASK_SCATTER_STORE, 5, + dataref_ptr, vec_offset, scale, + vec_oprnd, final_mask); + else + call = gimple_build_call_internal (IFN_SCATTER_STORE, 4, + dataref_ptr, vec_offset, + scale, vec_oprnd); + gimple_call_set_nothrow (call, true); + vect_finish_stmt_generation (vinfo, stmt_info, call, gsi); + new_stmt = call; + } + else + { + /* Emulated scatter. */ + gcc_assert (!final_mask); + unsigned HOST_WIDE_INT const_nunits = nunits.to_constant (); + unsigned HOST_WIDE_INT const_offset_nunits + = TYPE_VECTOR_SUBPARTS (gs_info.offset_vectype).to_constant (); + vec *ctor_elts; + vec_alloc (ctor_elts, const_nunits); + gimple_seq stmts = NULL; + tree elt_type = TREE_TYPE (vectype); + unsigned HOST_WIDE_INT elt_size + = tree_to_uhwi (TYPE_SIZE (elt_type)); + /* We support offset vectors with more elements + than the data vector for now. */ + unsigned HOST_WIDE_INT factor + = const_offset_nunits / const_nunits; + vec_offset = vec_offsets[j / factor]; + unsigned elt_offset = (j % factor) * const_nunits; + tree idx_type = TREE_TYPE (TREE_TYPE (vec_offset)); + tree scale = size_int (gs_info.scale); + align = get_object_alignment (DR_REF (first_dr_info->dr)); + tree ltype = build_aligned_type (TREE_TYPE (vectype), align); + for (unsigned k = 0; k < const_nunits; ++k) + { + /* Compute the offsetted pointer. */ + tree boff = size_binop (MULT_EXPR, TYPE_SIZE (idx_type), + bitsize_int (k + elt_offset)); + tree idx + = gimple_build (&stmts, BIT_FIELD_REF, idx_type, vec_offset, + TYPE_SIZE (idx_type), boff); + idx = gimple_convert (&stmts, sizetype, idx); + idx = gimple_build (&stmts, MULT_EXPR, sizetype, idx, scale); + tree ptr + = gimple_build (&stmts, PLUS_EXPR, TREE_TYPE (dataref_ptr), + dataref_ptr, idx); + ptr = gimple_convert (&stmts, ptr_type_node, ptr); + /* Extract the element to be stored. */ + tree elt + = gimple_build (&stmts, BIT_FIELD_REF, TREE_TYPE (vectype), + vec_oprnd, TYPE_SIZE (elt_type), + bitsize_int (k * elt_size)); + gsi_insert_seq_before (gsi, stmts, GSI_SAME_STMT); + stmts = NULL; + tree ref + = build2 (MEM_REF, ltype, ptr, build_int_cst (ref_type, 0)); + new_stmt = gimple_build_assign (ref, elt); + vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi); + } + } + if (j == 0) + *vec_stmt = new_stmt; + STMT_VINFO_VEC_STMTS (stmt_info).safe_push (new_stmt); + } + return true; + } + + auto_vec result_chain (group_size); + auto_vec vec_oprnds; for (j = 0; j < ncopies; j++) { gimple *new_stmt; if (j == 0) { - if (slp) - { + if (slp) + { /* Get vectorized arguments for SLP_NODE. */ - vect_get_vec_defs (vinfo, stmt_info, slp_node, 1, - op, &vec_oprnds); - vec_oprnd = vec_oprnds[0]; - } - else - { + vect_get_vec_defs (vinfo, stmt_info, slp_node, 1, op, + &vec_oprnds, mask, &vec_masks); + vec_oprnd = vec_oprnds[0]; + if (mask) + vec_mask = vec_masks[0]; + } + else + { /* For interleaved stores we collect vectorized defs for all the - stores in the group in DR_CHAIN and OPRNDS. DR_CHAIN is then - used as an input to vect_permute_store_chain(). + stores in the group in DR_CHAIN. DR_CHAIN is then used as an + input to vect_permute_store_chain(). If the store is not grouped, DR_GROUP_SIZE is 1, and DR_CHAIN - and OPRNDS are of size 1. */ + is of size 1. */ stmt_vec_info next_stmt_info = first_stmt_info; for (i = 0; i < group_size; i++) { @@ -8749,17 +9111,17 @@ vectorizable_store (vec_info *vinfo, that there is no interleaving, DR_GROUP_SIZE is 1, and only one iteration of the loop will be executed. */ op = vect_get_store_rhs (next_stmt_info); - vect_get_vec_defs_for_operand (vinfo, next_stmt_info, - ncopies, op, &gvec_oprnds[i]); - vec_oprnd = gvec_oprnds[i][0]; - dr_chain.quick_push (gvec_oprnds[i][0]); - oprnds.quick_push (gvec_oprnds[i][0]); + vect_get_vec_defs_for_operand (vinfo, next_stmt_info, ncopies, + op, gvec_oprnds[i]); + vec_oprnd = (*gvec_oprnds[i])[0]; + dr_chain.quick_push (vec_oprnd); next_stmt_info = DR_GROUP_NEXT_ELEMENT (next_stmt_info); } if (mask) { vect_get_vec_defs_for_operand (vinfo, stmt_info, ncopies, - mask, &vec_masks, mask_vectype); + mask, &vec_masks, + mask_vectype); vec_mask = vec_masks[0]; } } @@ -8781,10 +9143,6 @@ vectorizable_store (vec_info *vinfo, dataref_ptr = unshare_expr (DR_BASE_ADDRESS (first_dr_info->dr)); dataref_offset = build_int_cst (ref_type, 0); } - else if (STMT_VINFO_GATHER_SCATTER_P (stmt_info)) - vect_get_gather_scatter_ops (loop_vinfo, loop, stmt_info, - slp_node, &gs_info, &dataref_ptr, - &vec_offsets); else dataref_ptr = vect_create_data_ref_ptr (vinfo, first_stmt_info, aggr_type, @@ -8794,385 +9152,206 @@ vectorizable_store (vec_info *vinfo, } else { - gcc_assert (!LOOP_VINFO_USING_SELECT_VL_P (loop_vinfo)); - /* For interleaved stores we created vectorized defs for all the - defs stored in OPRNDS in the previous iteration (previous copy). - DR_CHAIN is then used as an input to vect_permute_store_chain(). - If the store is not grouped, DR_GROUP_SIZE is 1, and DR_CHAIN and - OPRNDS are of size 1. */ + gcc_assert (!LOOP_VINFO_USING_SELECT_VL_P (loop_vinfo)); + /* DR_CHAIN is then used as an input to vect_permute_store_chain(). + If the store is not grouped, DR_GROUP_SIZE is 1, and DR_CHAIN is + of size 1. */ for (i = 0; i < group_size; i++) { - vec_oprnd = gvec_oprnds[i][j]; - dr_chain[i] = gvec_oprnds[i][j]; - oprnds[i] = gvec_oprnds[i][j]; + vec_oprnd = (*gvec_oprnds[i])[j]; + dr_chain[i] = vec_oprnd; } if (mask) vec_mask = vec_masks[j]; if (dataref_offset) - dataref_offset - = int_const_binop (PLUS_EXPR, dataref_offset, bump); - else if (!STMT_VINFO_GATHER_SCATTER_P (stmt_info)) + dataref_offset = int_const_binop (PLUS_EXPR, dataref_offset, bump); + else dataref_ptr = bump_vector_ptr (vinfo, dataref_ptr, ptr_incr, gsi, stmt_info, bump); } - if (memory_access_type == VMAT_LOAD_STORE_LANES) + new_stmt = NULL; + if (grouped_store) + /* Permute. */ + vect_permute_store_chain (vinfo, dr_chain, group_size, stmt_info, gsi, + &result_chain); + + stmt_vec_info next_stmt_info = first_stmt_info; + for (i = 0; i < vec_num; i++) { - tree vec_array; + unsigned misalign; + unsigned HOST_WIDE_INT align; - /* Get an array into which we can store the individual vectors. */ - vec_array = create_vector_array (vectype, vec_num); - - /* Invalidate the current contents of VEC_ARRAY. This should - become an RTL clobber too, which prevents the vector registers - from being upward-exposed. */ - vect_clobber_variable (vinfo, stmt_info, gsi, vec_array); - - /* Store the individual vectors into the array. */ - for (i = 0; i < vec_num; i++) - { - vec_oprnd = dr_chain[i]; - write_vector_array (vinfo, stmt_info, - gsi, vec_oprnd, vec_array, i); - } - - tree final_mask = NULL; + tree final_mask = NULL_TREE; + tree final_len = NULL_TREE; + tree bias = NULL_TREE; if (loop_masks) final_mask = vect_get_loop_mask (loop_vinfo, gsi, loop_masks, - ncopies, vectype, j); + vec_num * ncopies, vectype, + vec_num * j + i); + if (slp && vec_mask) + vec_mask = vec_masks[i]; if (vec_mask) - final_mask = prepare_vec_mask (loop_vinfo, mask_vectype, - final_mask, vec_mask, gsi); + final_mask = prepare_vec_mask (loop_vinfo, mask_vectype, final_mask, + vec_mask, gsi); - gcall *call; - if (final_mask) + if (i > 0) + /* Bump the vector pointer. */ + dataref_ptr = bump_vector_ptr (vinfo, dataref_ptr, ptr_incr, gsi, + stmt_info, bump); + + if (slp) + vec_oprnd = vec_oprnds[i]; + else if (grouped_store) + /* For grouped stores vectorized defs are interleaved in + vect_permute_store_chain(). */ + vec_oprnd = result_chain[i]; + + align = known_alignment (DR_TARGET_ALIGNMENT (first_dr_info)); + if (alignment_support_scheme == dr_aligned) + misalign = 0; + else if (misalignment == DR_MISALIGNMENT_UNKNOWN) { - /* Emit: - MASK_STORE_LANES (DATAREF_PTR, ALIAS_PTR, VEC_MASK, - VEC_ARRAY). */ - unsigned int align = TYPE_ALIGN (TREE_TYPE (vectype)); - tree alias_ptr = build_int_cst (ref_type, align); - call = gimple_build_call_internal (IFN_MASK_STORE_LANES, 4, - dataref_ptr, alias_ptr, - final_mask, vec_array); + align = dr_alignment (vect_dr_behavior (vinfo, first_dr_info)); + misalign = 0; } else - { - /* Emit: - MEM_REF[...all elements...] = STORE_LANES (VEC_ARRAY). */ - data_ref = create_array_ref (aggr_type, dataref_ptr, ref_type); - call = gimple_build_call_internal (IFN_STORE_LANES, 1, - vec_array); - gimple_call_set_lhs (call, data_ref); - } - gimple_call_set_nothrow (call, true); - vect_finish_stmt_generation (vinfo, stmt_info, call, gsi); - new_stmt = call; + misalign = misalignment; + if (dataref_offset == NULL_TREE + && TREE_CODE (dataref_ptr) == SSA_NAME) + set_ptr_info_alignment (get_ptr_info (dataref_ptr), align, + misalign); + align = least_bit_hwi (misalign | align); - /* Record that VEC_ARRAY is now dead. */ - vect_clobber_variable (vinfo, stmt_info, gsi, vec_array); - } - else - { - new_stmt = NULL; - if (grouped_store) + if (memory_access_type == VMAT_CONTIGUOUS_REVERSE) { - if (j == 0) - result_chain.create (group_size); - /* Permute. */ - vect_permute_store_chain (vinfo, dr_chain, group_size, stmt_info, - gsi, &result_chain); + tree perm_mask = perm_mask_for_reverse (vectype); + tree perm_dest + = vect_create_destination_var (vect_get_store_rhs (stmt_info), + vectype); + tree new_temp = make_ssa_name (perm_dest); + + /* Generate the permute statement. */ + gimple *perm_stmt + = gimple_build_assign (new_temp, VEC_PERM_EXPR, vec_oprnd, + vec_oprnd, perm_mask); + vect_finish_stmt_generation (vinfo, stmt_info, perm_stmt, gsi); + + perm_stmt = SSA_NAME_DEF_STMT (new_temp); + vec_oprnd = new_temp; } - stmt_vec_info next_stmt_info = first_stmt_info; - for (i = 0; i < vec_num; i++) + /* Compute IFN when LOOP_LENS or final_mask valid. */ + machine_mode vmode = TYPE_MODE (vectype); + machine_mode new_vmode = vmode; + internal_fn partial_ifn = IFN_LAST; + if (loop_lens) { - unsigned misalign; - unsigned HOST_WIDE_INT align; + opt_machine_mode new_ovmode + = get_len_load_store_mode (vmode, false, &partial_ifn); + new_vmode = new_ovmode.require (); + unsigned factor + = (new_ovmode == vmode) ? 1 : GET_MODE_UNIT_SIZE (vmode); + final_len = vect_get_loop_len (loop_vinfo, gsi, loop_lens, + vec_num * ncopies, vectype, + vec_num * j + i, factor); + } + else if (final_mask) + { + if (!can_vec_mask_load_store_p ( + vmode, TYPE_MODE (TREE_TYPE (final_mask)), false, + &partial_ifn)) + gcc_unreachable (); + } - tree final_mask = NULL_TREE; - tree final_len = NULL_TREE; - tree bias = NULL_TREE; - if (loop_masks) - final_mask = vect_get_loop_mask (loop_vinfo, gsi, loop_masks, - vec_num * ncopies, - vectype, vec_num * j + i); - if (vec_mask) - final_mask = prepare_vec_mask (loop_vinfo, mask_vectype, - final_mask, vec_mask, gsi); - - if (memory_access_type == VMAT_GATHER_SCATTER - && gs_info.ifn != IFN_LAST) + if (partial_ifn == IFN_MASK_LEN_STORE) + { + if (!final_len) { - if (STMT_VINFO_GATHER_SCATTER_P (stmt_info)) - vec_offset = vec_offsets[vec_num * j + i]; - tree scale = size_int (gs_info.scale); - - if (gs_info.ifn == IFN_MASK_LEN_SCATTER_STORE) - { - if (loop_lens) - final_len - = vect_get_loop_len (loop_vinfo, gsi, loop_lens, - vec_num * ncopies, vectype, - vec_num * j + i, 1); - else - final_len - = build_int_cst (sizetype, - TYPE_VECTOR_SUBPARTS (vectype)); - signed char biasval - = LOOP_VINFO_PARTIAL_LOAD_STORE_BIAS (loop_vinfo); - bias = build_int_cst (intQI_type_node, biasval); - if (!final_mask) - { - mask_vectype = truth_type_for (vectype); - final_mask = build_minus_one_cst (mask_vectype); - } - } - - gcall *call; - if (final_len && final_mask) - call - = gimple_build_call_internal (IFN_MASK_LEN_SCATTER_STORE, - 7, dataref_ptr, vec_offset, - scale, vec_oprnd, final_mask, - final_len, bias); - else if (final_mask) - call = gimple_build_call_internal - (IFN_MASK_SCATTER_STORE, 5, dataref_ptr, vec_offset, - scale, vec_oprnd, final_mask); - else - call = gimple_build_call_internal - (IFN_SCATTER_STORE, 4, dataref_ptr, vec_offset, - scale, vec_oprnd); - gimple_call_set_nothrow (call, true); - vect_finish_stmt_generation (vinfo, stmt_info, call, gsi); - new_stmt = call; - break; + /* Pass VF value to 'len' argument of + MASK_LEN_STORE if LOOP_LENS is invalid. */ + final_len = size_int (TYPE_VECTOR_SUBPARTS (vectype)); } - else if (memory_access_type == VMAT_GATHER_SCATTER) + if (!final_mask) { - /* Emulated scatter. */ - gcc_assert (!final_mask); - unsigned HOST_WIDE_INT const_nunits = nunits.to_constant (); - unsigned HOST_WIDE_INT const_offset_nunits - = TYPE_VECTOR_SUBPARTS (gs_info.offset_vectype) - .to_constant (); - vec *ctor_elts; - vec_alloc (ctor_elts, const_nunits); - gimple_seq stmts = NULL; - tree elt_type = TREE_TYPE (vectype); - unsigned HOST_WIDE_INT elt_size - = tree_to_uhwi (TYPE_SIZE (elt_type)); - /* We support offset vectors with more elements - than the data vector for now. */ - unsigned HOST_WIDE_INT factor - = const_offset_nunits / const_nunits; - vec_offset = vec_offsets[j / factor]; - unsigned elt_offset = (j % factor) * const_nunits; - tree idx_type = TREE_TYPE (TREE_TYPE (vec_offset)); - tree scale = size_int (gs_info.scale); - align = get_object_alignment (DR_REF (first_dr_info->dr)); - tree ltype = build_aligned_type (TREE_TYPE (vectype), align); - for (unsigned k = 0; k < const_nunits; ++k) - { - /* Compute the offsetted pointer. */ - tree boff = size_binop (MULT_EXPR, TYPE_SIZE (idx_type), - bitsize_int (k + elt_offset)); - tree idx = gimple_build (&stmts, BIT_FIELD_REF, - idx_type, vec_offset, - TYPE_SIZE (idx_type), boff); - idx = gimple_convert (&stmts, sizetype, idx); - idx = gimple_build (&stmts, MULT_EXPR, - sizetype, idx, scale); - tree ptr = gimple_build (&stmts, PLUS_EXPR, - TREE_TYPE (dataref_ptr), - dataref_ptr, idx); - ptr = gimple_convert (&stmts, ptr_type_node, ptr); - /* Extract the element to be stored. */ - tree elt = gimple_build (&stmts, BIT_FIELD_REF, - TREE_TYPE (vectype), vec_oprnd, - TYPE_SIZE (elt_type), - bitsize_int (k * elt_size)); - gsi_insert_seq_before (gsi, stmts, GSI_SAME_STMT); - stmts = NULL; - tree ref = build2 (MEM_REF, ltype, ptr, - build_int_cst (ref_type, 0)); - new_stmt = gimple_build_assign (ref, elt); - vect_finish_stmt_generation (vinfo, stmt_info, - new_stmt, gsi); - } - break; + /* Pass all ones value to 'mask' argument of + MASK_LEN_STORE if final_mask is invalid. */ + mask_vectype = truth_type_for (vectype); + final_mask = build_minus_one_cst (mask_vectype); } + } + if (final_len) + { + signed char biasval + = LOOP_VINFO_PARTIAL_LOAD_STORE_BIAS (loop_vinfo); - if (i > 0) - /* Bump the vector pointer. */ - dataref_ptr = bump_vector_ptr (vinfo, dataref_ptr, ptr_incr, - gsi, stmt_info, bump); + bias = build_int_cst (intQI_type_node, biasval); + } - if (slp) - vec_oprnd = vec_oprnds[i]; - else if (grouped_store) - /* For grouped stores vectorized defs are interleaved in - vect_permute_store_chain(). */ - vec_oprnd = result_chain[i]; - - align = known_alignment (DR_TARGET_ALIGNMENT (first_dr_info)); - if (alignment_support_scheme == dr_aligned) - misalign = 0; - else if (misalignment == DR_MISALIGNMENT_UNKNOWN) + /* Arguments are ready. Create the new vector stmt. */ + if (final_len) + { + gcall *call; + tree ptr = build_int_cst (ref_type, align * BITS_PER_UNIT); + /* Need conversion if it's wrapped with VnQI. */ + if (vmode != new_vmode) { - align = dr_alignment (vect_dr_behavior (vinfo, first_dr_info)); - misalign = 0; - } - else - misalign = misalignment; - if (dataref_offset == NULL_TREE - && TREE_CODE (dataref_ptr) == SSA_NAME) - set_ptr_info_alignment (get_ptr_info (dataref_ptr), align, - misalign); - align = least_bit_hwi (misalign | align); - - if (memory_access_type == VMAT_CONTIGUOUS_REVERSE) - { - tree perm_mask = perm_mask_for_reverse (vectype); - tree perm_dest = vect_create_destination_var - (vect_get_store_rhs (stmt_info), vectype); - tree new_temp = make_ssa_name (perm_dest); - - /* Generate the permute statement. */ - gimple *perm_stmt - = gimple_build_assign (new_temp, VEC_PERM_EXPR, vec_oprnd, - vec_oprnd, perm_mask); - vect_finish_stmt_generation (vinfo, stmt_info, perm_stmt, gsi); - - perm_stmt = SSA_NAME_DEF_STMT (new_temp); - vec_oprnd = new_temp; - } - - /* Compute IFN when LOOP_LENS or final_mask valid. */ - machine_mode vmode = TYPE_MODE (vectype); - machine_mode new_vmode = vmode; - internal_fn partial_ifn = IFN_LAST; - if (loop_lens) - { - opt_machine_mode new_ovmode - = get_len_load_store_mode (vmode, false, &partial_ifn); - new_vmode = new_ovmode.require (); - unsigned factor - = (new_ovmode == vmode) ? 1 : GET_MODE_UNIT_SIZE (vmode); - final_len = vect_get_loop_len (loop_vinfo, gsi, loop_lens, - vec_num * ncopies, vectype, - vec_num * j + i, factor); - } - else if (final_mask) - { - if (!can_vec_mask_load_store_p (vmode, - TYPE_MODE (TREE_TYPE (final_mask)), - false, &partial_ifn)) - gcc_unreachable (); + tree new_vtype + = build_vector_type_for_mode (unsigned_intQI_type_node, + new_vmode); + tree var = vect_get_new_ssa_name (new_vtype, vect_simple_var); + vec_oprnd = build1 (VIEW_CONVERT_EXPR, new_vtype, vec_oprnd); + gassign *new_stmt + = gimple_build_assign (var, VIEW_CONVERT_EXPR, vec_oprnd); + vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi); + vec_oprnd = var; } if (partial_ifn == IFN_MASK_LEN_STORE) - { - if (!final_len) - { - /* Pass VF value to 'len' argument of - MASK_LEN_STORE if LOOP_LENS is invalid. */ - tree iv_type = LOOP_VINFO_RGROUP_IV_TYPE (loop_vinfo); - final_len - = build_int_cst (iv_type, - TYPE_VECTOR_SUBPARTS (vectype)); - } - if (!final_mask) - { - /* Pass all ones value to 'mask' argument of - MASK_LEN_STORE if final_mask is invalid. */ - mask_vectype = truth_type_for (vectype); - final_mask = build_minus_one_cst (mask_vectype); - } - } - if (final_len) - { - signed char biasval - = LOOP_VINFO_PARTIAL_LOAD_STORE_BIAS (loop_vinfo); - - bias = build_int_cst (intQI_type_node, biasval); - } - - /* Arguments are ready. Create the new vector stmt. */ - if (final_len) - { - gcall *call; - tree ptr = build_int_cst (ref_type, align * BITS_PER_UNIT); - /* Need conversion if it's wrapped with VnQI. */ - if (vmode != new_vmode) - { - tree new_vtype - = build_vector_type_for_mode (unsigned_intQI_type_node, - new_vmode); - tree var - = vect_get_new_ssa_name (new_vtype, vect_simple_var); - vec_oprnd - = build1 (VIEW_CONVERT_EXPR, new_vtype, vec_oprnd); - gassign *new_stmt - = gimple_build_assign (var, VIEW_CONVERT_EXPR, - vec_oprnd); - vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, - gsi); - vec_oprnd = var; - } - - if (partial_ifn == IFN_MASK_LEN_STORE) - call = gimple_build_call_internal (IFN_MASK_LEN_STORE, 6, - dataref_ptr, ptr, - final_mask, final_len, - bias, vec_oprnd); - else - call - = gimple_build_call_internal (IFN_LEN_STORE, 5, - dataref_ptr, ptr, - final_len, bias, - vec_oprnd); - gimple_call_set_nothrow (call, true); - vect_finish_stmt_generation (vinfo, stmt_info, call, gsi); - new_stmt = call; - } - else if (final_mask) - { - tree ptr = build_int_cst (ref_type, align * BITS_PER_UNIT); - gcall *call - = gimple_build_call_internal (IFN_MASK_STORE, 4, - dataref_ptr, ptr, - final_mask, vec_oprnd); - gimple_call_set_nothrow (call, true); - vect_finish_stmt_generation (vinfo, stmt_info, call, gsi); - new_stmt = call; - } + call = gimple_build_call_internal (IFN_MASK_LEN_STORE, 6, + dataref_ptr, ptr, final_mask, + final_len, bias, vec_oprnd); else - { - data_ref = fold_build2 (MEM_REF, vectype, - dataref_ptr, - dataref_offset - ? dataref_offset - : build_int_cst (ref_type, 0)); - if (alignment_support_scheme == dr_aligned) - ; - else - TREE_TYPE (data_ref) - = build_aligned_type (TREE_TYPE (data_ref), - align * BITS_PER_UNIT); - vect_copy_ref_info (data_ref, DR_REF (first_dr_info->dr)); - new_stmt = gimple_build_assign (data_ref, vec_oprnd); - vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi); - } - - if (slp) - continue; - - next_stmt_info = DR_GROUP_NEXT_ELEMENT (next_stmt_info); - if (!next_stmt_info) - break; + call = gimple_build_call_internal (IFN_LEN_STORE, 5, + dataref_ptr, ptr, final_len, + bias, vec_oprnd); + gimple_call_set_nothrow (call, true); + vect_finish_stmt_generation (vinfo, stmt_info, call, gsi); + new_stmt = call; } + else if (final_mask) + { + tree ptr = build_int_cst (ref_type, align * BITS_PER_UNIT); + gcall *call + = gimple_build_call_internal (IFN_MASK_STORE, 4, dataref_ptr, + ptr, final_mask, vec_oprnd); + gimple_call_set_nothrow (call, true); + vect_finish_stmt_generation (vinfo, stmt_info, call, gsi); + new_stmt = call; + } + else + { + data_ref + = fold_build2 (MEM_REF, vectype, dataref_ptr, + dataref_offset ? dataref_offset + : build_int_cst (ref_type, 0)); + if (alignment_support_scheme == dr_aligned) + ; + else + TREE_TYPE (data_ref) + = build_aligned_type (TREE_TYPE (data_ref), + align * BITS_PER_UNIT); + vect_copy_ref_info (data_ref, DR_REF (first_dr_info->dr)); + new_stmt = gimple_build_assign (data_ref, vec_oprnd); + vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi); + } + + if (slp) + continue; + + next_stmt_info = DR_GROUP_NEXT_ELEMENT (next_stmt_info); + if (!next_stmt_info) + break; } if (!slp) { @@ -9182,15 +9361,6 @@ vectorizable_store (vec_info *vinfo, } } - for (i = 0; i < group_size; ++i) - { - vec oprndsi = gvec_oprnds[i]; - oprndsi.release (); - } - oprnds.release (); - result_chain.release (); - vec_oprnds.release (); - return true; } @@ -9405,9 +9575,8 @@ vectorizable_load (vec_info *vinfo, return false; mask_index = internal_fn_mask_index (ifn); - /* ??? For SLP the mask operand is always last. */ if (mask_index >= 0 && slp_node) - mask_index = SLP_TREE_CHILDREN (slp_node).length () - 1; + mask_index = vect_slp_child_index_for_operand (call, mask_index); if (mask_index >= 0 && !vect_check_scalar_mask (vinfo, stmt_info, slp_node, mask_index, &mask, NULL, &mask_dt, &mask_vectype)) @@ -9553,9 +9722,11 @@ vectorizable_load (vec_info *vinfo, enum dr_alignment_support alignment_support_scheme; int misalignment; poly_int64 poffset; + internal_fn lanes_ifn; if (!get_load_store_type (vinfo, stmt_info, vectype, slp_node, mask, VLS_LOAD, ncopies, &memory_access_type, &poffset, - &alignment_support_scheme, &misalignment, &gs_info)) + &alignment_support_scheme, &misalignment, &gs_info, + &lanes_ifn)) return false; if (mask) @@ -10277,7 +10448,368 @@ vectorizable_load (vec_info *vinfo, vect_get_vec_defs_for_operand (vinfo, stmt_info, ncopies, mask, &vec_masks, mask_vectype); } + tree vec_mask = NULL_TREE; + if (memory_access_type == VMAT_LOAD_STORE_LANES) + { + gcc_assert (alignment_support_scheme == dr_aligned + || alignment_support_scheme == dr_unaligned_supported); + gcc_assert (grouped_load && !slp); + + unsigned int inside_cost = 0, prologue_cost = 0; + for (j = 0; j < ncopies; j++) + { + if (costing_p) + { + /* An IFN_LOAD_LANES will load all its vector results, + regardless of which ones we actually need. Account + for the cost of unused results. */ + if (first_stmt_info == stmt_info) + { + unsigned int gaps = DR_GROUP_SIZE (first_stmt_info); + stmt_vec_info next_stmt_info = first_stmt_info; + do + { + gaps -= 1; + next_stmt_info = DR_GROUP_NEXT_ELEMENT (next_stmt_info); + } + while (next_stmt_info); + if (gaps) + { + if (dump_enabled_p ()) + dump_printf_loc (MSG_NOTE, vect_location, + "vect_model_load_cost: %d " + "unused vectors.\n", + gaps); + vect_get_load_cost (vinfo, stmt_info, gaps, + alignment_support_scheme, + misalignment, false, &inside_cost, + &prologue_cost, cost_vec, cost_vec, + true); + } + } + vect_get_load_cost (vinfo, stmt_info, 1, alignment_support_scheme, + misalignment, false, &inside_cost, + &prologue_cost, cost_vec, cost_vec, true); + continue; + } + + /* 1. Create the vector or array pointer update chain. */ + if (j == 0) + dataref_ptr + = vect_create_data_ref_ptr (vinfo, first_stmt_info, aggr_type, + at_loop, offset, &dummy, gsi, + &ptr_incr, false, bump); + else + { + gcc_assert (!LOOP_VINFO_USING_SELECT_VL_P (loop_vinfo)); + dataref_ptr = bump_vector_ptr (vinfo, dataref_ptr, ptr_incr, gsi, + stmt_info, bump); + } + if (mask) + vec_mask = vec_masks[j]; + + tree vec_array = create_vector_array (vectype, vec_num); + + tree final_mask = NULL_TREE; + tree final_len = NULL_TREE; + tree bias = NULL_TREE; + if (loop_masks) + final_mask = vect_get_loop_mask (loop_vinfo, gsi, loop_masks, + ncopies, vectype, j); + if (vec_mask) + final_mask = prepare_vec_mask (loop_vinfo, mask_vectype, final_mask, + vec_mask, gsi); + + if (lanes_ifn == IFN_MASK_LEN_LOAD_LANES) + { + if (loop_lens) + final_len = vect_get_loop_len (loop_vinfo, gsi, loop_lens, + ncopies, vectype, j, 1); + else + final_len = size_int (TYPE_VECTOR_SUBPARTS (vectype)); + signed char biasval + = LOOP_VINFO_PARTIAL_LOAD_STORE_BIAS (loop_vinfo); + bias = build_int_cst (intQI_type_node, biasval); + if (!final_mask) + { + mask_vectype = truth_type_for (vectype); + final_mask = build_minus_one_cst (mask_vectype); + } + } + + gcall *call; + if (final_len && final_mask) + { + /* Emit: + VEC_ARRAY = MASK_LEN_LOAD_LANES (DATAREF_PTR, ALIAS_PTR, + VEC_MASK, LEN, BIAS). */ + unsigned int align = TYPE_ALIGN (TREE_TYPE (vectype)); + tree alias_ptr = build_int_cst (ref_type, align); + call = gimple_build_call_internal (IFN_MASK_LEN_LOAD_LANES, 5, + dataref_ptr, alias_ptr, + final_mask, final_len, bias); + } + else if (final_mask) + { + /* Emit: + VEC_ARRAY = MASK_LOAD_LANES (DATAREF_PTR, ALIAS_PTR, + VEC_MASK). */ + unsigned int align = TYPE_ALIGN (TREE_TYPE (vectype)); + tree alias_ptr = build_int_cst (ref_type, align); + call = gimple_build_call_internal (IFN_MASK_LOAD_LANES, 3, + dataref_ptr, alias_ptr, + final_mask); + } + else + { + /* Emit: + VEC_ARRAY = LOAD_LANES (MEM_REF[...all elements...]). */ + data_ref = create_array_ref (aggr_type, dataref_ptr, ref_type); + call = gimple_build_call_internal (IFN_LOAD_LANES, 1, data_ref); + } + gimple_call_set_lhs (call, vec_array); + gimple_call_set_nothrow (call, true); + vect_finish_stmt_generation (vinfo, stmt_info, call, gsi); + + dr_chain.create (vec_num); + /* Extract each vector into an SSA_NAME. */ + for (i = 0; i < vec_num; i++) + { + new_temp = read_vector_array (vinfo, stmt_info, gsi, scalar_dest, + vec_array, i); + dr_chain.quick_push (new_temp); + } + + /* Record the mapping between SSA_NAMEs and statements. */ + vect_record_grouped_load_vectors (vinfo, stmt_info, dr_chain); + + /* Record that VEC_ARRAY is now dead. */ + vect_clobber_variable (vinfo, stmt_info, gsi, vec_array); + + dr_chain.release (); + + *vec_stmt = STMT_VINFO_VEC_STMTS (stmt_info)[0]; + } + + if (costing_p && dump_enabled_p ()) + dump_printf_loc (MSG_NOTE, vect_location, + "vect_model_load_cost: inside_cost = %u, " + "prologue_cost = %u .\n", + inside_cost, prologue_cost); + + return true; + } + + if (memory_access_type == VMAT_GATHER_SCATTER) + { + gcc_assert (alignment_support_scheme == dr_aligned + || alignment_support_scheme == dr_unaligned_supported); + gcc_assert (!grouped_load && !slp_perm); + + unsigned int inside_cost = 0, prologue_cost = 0; + for (j = 0; j < ncopies; j++) + { + /* 1. Create the vector or array pointer update chain. */ + if (j == 0 && !costing_p) + { + if (STMT_VINFO_GATHER_SCATTER_P (stmt_info)) + vect_get_gather_scatter_ops (loop_vinfo, loop, stmt_info, + slp_node, &gs_info, &dataref_ptr, + &vec_offsets); + else + dataref_ptr + = vect_create_data_ref_ptr (vinfo, first_stmt_info, aggr_type, + at_loop, offset, &dummy, gsi, + &ptr_incr, false, bump); + } + else if (!costing_p) + { + gcc_assert (!LOOP_VINFO_USING_SELECT_VL_P (loop_vinfo)); + if (!STMT_VINFO_GATHER_SCATTER_P (stmt_info)) + dataref_ptr = bump_vector_ptr (vinfo, dataref_ptr, ptr_incr, + gsi, stmt_info, bump); + } + + if (mask && !costing_p) + vec_mask = vec_masks[j]; + + gimple *new_stmt = NULL; + for (i = 0; i < vec_num; i++) + { + tree final_mask = NULL_TREE; + tree final_len = NULL_TREE; + tree bias = NULL_TREE; + if (!costing_p) + { + if (loop_masks) + final_mask + = vect_get_loop_mask (loop_vinfo, gsi, loop_masks, + vec_num * ncopies, vectype, + vec_num * j + i); + if (vec_mask) + final_mask = prepare_vec_mask (loop_vinfo, mask_vectype, + final_mask, vec_mask, gsi); + + if (i > 0 && !STMT_VINFO_GATHER_SCATTER_P (stmt_info)) + dataref_ptr = bump_vector_ptr (vinfo, dataref_ptr, ptr_incr, + gsi, stmt_info, bump); + } + + /* 2. Create the vector-load in the loop. */ + unsigned HOST_WIDE_INT align; + if (gs_info.ifn != IFN_LAST) + { + if (costing_p) + { + unsigned int cnunits = vect_nunits_for_cost (vectype); + inside_cost + = record_stmt_cost (cost_vec, cnunits, scalar_load, + stmt_info, 0, vect_body); + continue; + } + if (STMT_VINFO_GATHER_SCATTER_P (stmt_info)) + vec_offset = vec_offsets[vec_num * j + i]; + tree zero = build_zero_cst (vectype); + tree scale = size_int (gs_info.scale); + + if (gs_info.ifn == IFN_MASK_LEN_GATHER_LOAD) + { + if (loop_lens) + final_len + = vect_get_loop_len (loop_vinfo, gsi, loop_lens, + vec_num * ncopies, vectype, + vec_num * j + i, 1); + else + final_len + = build_int_cst (sizetype, + TYPE_VECTOR_SUBPARTS (vectype)); + signed char biasval + = LOOP_VINFO_PARTIAL_LOAD_STORE_BIAS (loop_vinfo); + bias = build_int_cst (intQI_type_node, biasval); + if (!final_mask) + { + mask_vectype = truth_type_for (vectype); + final_mask = build_minus_one_cst (mask_vectype); + } + } + + gcall *call; + if (final_len && final_mask) + call + = gimple_build_call_internal (IFN_MASK_LEN_GATHER_LOAD, 7, + dataref_ptr, vec_offset, + scale, zero, final_mask, + final_len, bias); + else if (final_mask) + call = gimple_build_call_internal (IFN_MASK_GATHER_LOAD, 5, + dataref_ptr, vec_offset, + scale, zero, final_mask); + else + call = gimple_build_call_internal (IFN_GATHER_LOAD, 4, + dataref_ptr, vec_offset, + scale, zero); + gimple_call_set_nothrow (call, true); + new_stmt = call; + data_ref = NULL_TREE; + } + else + { + /* Emulated gather-scatter. */ + gcc_assert (!final_mask); + unsigned HOST_WIDE_INT const_nunits = nunits.to_constant (); + if (costing_p) + { + /* For emulated gathers N offset vector element + offset add is consumed by the load). */ + inside_cost = record_stmt_cost (cost_vec, const_nunits, + vec_to_scalar, stmt_info, + 0, vect_body); + /* N scalar loads plus gathering them into a + vector. */ + inside_cost + = record_stmt_cost (cost_vec, const_nunits, scalar_load, + stmt_info, 0, vect_body); + inside_cost + = record_stmt_cost (cost_vec, 1, vec_construct, + stmt_info, 0, vect_body); + continue; + } + unsigned HOST_WIDE_INT const_offset_nunits + = TYPE_VECTOR_SUBPARTS (gs_info.offset_vectype) + .to_constant (); + vec *ctor_elts; + vec_alloc (ctor_elts, const_nunits); + gimple_seq stmts = NULL; + /* We support offset vectors with more elements + than the data vector for now. */ + unsigned HOST_WIDE_INT factor + = const_offset_nunits / const_nunits; + vec_offset = vec_offsets[j / factor]; + unsigned elt_offset = (j % factor) * const_nunits; + tree idx_type = TREE_TYPE (TREE_TYPE (vec_offset)); + tree scale = size_int (gs_info.scale); + align = get_object_alignment (DR_REF (first_dr_info->dr)); + tree ltype = build_aligned_type (TREE_TYPE (vectype), align); + for (unsigned k = 0; k < const_nunits; ++k) + { + tree boff = size_binop (MULT_EXPR, TYPE_SIZE (idx_type), + bitsize_int (k + elt_offset)); + tree idx + = gimple_build (&stmts, BIT_FIELD_REF, idx_type, + vec_offset, TYPE_SIZE (idx_type), boff); + idx = gimple_convert (&stmts, sizetype, idx); + idx = gimple_build (&stmts, MULT_EXPR, sizetype, idx, + scale); + tree ptr = gimple_build (&stmts, PLUS_EXPR, + TREE_TYPE (dataref_ptr), + dataref_ptr, idx); + ptr = gimple_convert (&stmts, ptr_type_node, ptr); + tree elt = make_ssa_name (TREE_TYPE (vectype)); + tree ref = build2 (MEM_REF, ltype, ptr, + build_int_cst (ref_type, 0)); + new_stmt = gimple_build_assign (elt, ref); + gimple_set_vuse (new_stmt, gimple_vuse (gsi_stmt (*gsi))); + gimple_seq_add_stmt (&stmts, new_stmt); + CONSTRUCTOR_APPEND_ELT (ctor_elts, NULL_TREE, elt); + } + gsi_insert_seq_before (gsi, stmts, GSI_SAME_STMT); + new_stmt = gimple_build_assign ( + NULL_TREE, build_constructor (vectype, ctor_elts)); + data_ref = NULL_TREE; + } + + vec_dest = vect_create_destination_var (scalar_dest, vectype); + /* DATA_REF is null if we've already built the statement. */ + if (data_ref) + { + vect_copy_ref_info (data_ref, DR_REF (first_dr_info->dr)); + new_stmt = gimple_build_assign (vec_dest, data_ref); + } + new_temp = make_ssa_name (vec_dest, new_stmt); + gimple_set_lhs (new_stmt, new_temp); + vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi); + + /* Store vector loads in the corresponding SLP_NODE. */ + if (slp) + slp_node->push_vec_def (new_stmt); + } + + if (!slp && !costing_p) + STMT_VINFO_VEC_STMTS (stmt_info).safe_push (new_stmt); + } + + if (!slp && !costing_p) + *vec_stmt = STMT_VINFO_VEC_STMTS (stmt_info)[0]; + + if (costing_p && dump_enabled_p ()) + dump_printf_loc (MSG_NOTE, vect_location, + "vect_model_load_cost: inside_cost = %u, " + "prologue_cost = %u .\n", + inside_cost, prologue_cost); + return true; + } + poly_uint64 group_elt = 0; unsigned int inside_cost = 0, prologue_cost = 0; for (j = 0; j < ncopies; j++) @@ -10327,12 +10859,6 @@ vectorizable_load (vec_info *vinfo, gcc_assert (!compute_in_loop); } } - else if (STMT_VINFO_GATHER_SCATTER_P (stmt_info)) - { - vect_get_gather_scatter_ops (loop_vinfo, loop, stmt_info, - slp_node, &gs_info, &dataref_ptr, - &vec_offsets); - } else dataref_ptr = vect_create_data_ref_ptr (vinfo, first_stmt_info, aggr_type, @@ -10348,7 +10874,7 @@ vectorizable_load (vec_info *vinfo, if (dataref_offset) dataref_offset = int_const_binop (PLUS_EXPR, dataref_offset, bump); - else if (!STMT_VINFO_GATHER_SCATTER_P (stmt_info)) + else dataref_ptr = bump_vector_ptr (vinfo, dataref_ptr, ptr_incr, gsi, stmt_info, bump); if (mask) @@ -10359,688 +10885,430 @@ vectorizable_load (vec_info *vinfo, dr_chain.create (vec_num); gimple *new_stmt = NULL; - if (memory_access_type == VMAT_LOAD_STORE_LANES) + for (i = 0; i < vec_num; i++) { + tree final_mask = NULL_TREE; + tree final_len = NULL_TREE; + tree bias = NULL_TREE; + if (!costing_p) + { + if (loop_masks) + final_mask = vect_get_loop_mask (loop_vinfo, gsi, loop_masks, + vec_num * ncopies, vectype, + vec_num * j + i); + if (vec_mask) + final_mask = prepare_vec_mask (loop_vinfo, mask_vectype, + final_mask, vec_mask, gsi); + + if (i > 0) + dataref_ptr = bump_vector_ptr (vinfo, dataref_ptr, ptr_incr, + gsi, stmt_info, bump); + } + + /* 2. Create the vector-load in the loop. */ + switch (alignment_support_scheme) + { + case dr_aligned: + case dr_unaligned_supported: + { + if (costing_p) + break; + + unsigned int misalign; + unsigned HOST_WIDE_INT align; + align = known_alignment (DR_TARGET_ALIGNMENT (first_dr_info)); + if (alignment_support_scheme == dr_aligned) + misalign = 0; + else if (misalignment == DR_MISALIGNMENT_UNKNOWN) + { + align + = dr_alignment (vect_dr_behavior (vinfo, first_dr_info)); + misalign = 0; + } + else + misalign = misalignment; + if (dataref_offset == NULL_TREE + && TREE_CODE (dataref_ptr) == SSA_NAME) + set_ptr_info_alignment (get_ptr_info (dataref_ptr), align, + misalign); + align = least_bit_hwi (misalign | align); + + /* Compute IFN when LOOP_LENS or final_mask valid. */ + machine_mode vmode = TYPE_MODE (vectype); + machine_mode new_vmode = vmode; + internal_fn partial_ifn = IFN_LAST; + if (loop_lens) + { + opt_machine_mode new_ovmode + = get_len_load_store_mode (vmode, true, &partial_ifn); + new_vmode = new_ovmode.require (); + unsigned factor + = (new_ovmode == vmode) ? 1 : GET_MODE_UNIT_SIZE (vmode); + final_len = vect_get_loop_len (loop_vinfo, gsi, loop_lens, + vec_num * ncopies, vectype, + vec_num * j + i, factor); + } + else if (final_mask) + { + if (!can_vec_mask_load_store_p ( + vmode, TYPE_MODE (TREE_TYPE (final_mask)), true, + &partial_ifn)) + gcc_unreachable (); + } + + if (partial_ifn == IFN_MASK_LEN_LOAD) + { + if (!final_len) + { + /* Pass VF value to 'len' argument of + MASK_LEN_LOAD if LOOP_LENS is invalid. */ + final_len = size_int (TYPE_VECTOR_SUBPARTS (vectype)); + } + if (!final_mask) + { + /* Pass all ones value to 'mask' argument of + MASK_LEN_LOAD if final_mask is invalid. */ + mask_vectype = truth_type_for (vectype); + final_mask = build_minus_one_cst (mask_vectype); + } + } + if (final_len) + { + signed char biasval + = LOOP_VINFO_PARTIAL_LOAD_STORE_BIAS (loop_vinfo); + + bias = build_int_cst (intQI_type_node, biasval); + } + + if (final_len) + { + tree ptr = build_int_cst (ref_type, align * BITS_PER_UNIT); + gcall *call; + if (partial_ifn == IFN_MASK_LEN_LOAD) + call = gimple_build_call_internal (IFN_MASK_LEN_LOAD, 5, + dataref_ptr, ptr, + final_mask, final_len, + bias); + else + call = gimple_build_call_internal (IFN_LEN_LOAD, 4, + dataref_ptr, ptr, + final_len, bias); + gimple_call_set_nothrow (call, true); + new_stmt = call; + data_ref = NULL_TREE; + + /* Need conversion if it's wrapped with VnQI. */ + if (vmode != new_vmode) + { + tree new_vtype = build_vector_type_for_mode ( + unsigned_intQI_type_node, new_vmode); + tree var + = vect_get_new_ssa_name (new_vtype, vect_simple_var); + gimple_set_lhs (call, var); + vect_finish_stmt_generation (vinfo, stmt_info, call, + gsi); + tree op = build1 (VIEW_CONVERT_EXPR, vectype, var); + new_stmt = gimple_build_assign (vec_dest, + VIEW_CONVERT_EXPR, op); + } + } + else if (final_mask) + { + tree ptr = build_int_cst (ref_type, align * BITS_PER_UNIT); + gcall *call = gimple_build_call_internal (IFN_MASK_LOAD, 3, + dataref_ptr, ptr, + final_mask); + gimple_call_set_nothrow (call, true); + new_stmt = call; + data_ref = NULL_TREE; + } + else + { + tree ltype = vectype; + tree new_vtype = NULL_TREE; + unsigned HOST_WIDE_INT gap = DR_GROUP_GAP (first_stmt_info); + unsigned int vect_align + = vect_known_alignment_in_bytes (first_dr_info, vectype); + unsigned int scalar_dr_size + = vect_get_scalar_dr_size (first_dr_info); + /* If there's no peeling for gaps but we have a gap + with slp loads then load the lower half of the + vector only. See get_group_load_store_type for + when we apply this optimization. */ + if (slp + && loop_vinfo + && !LOOP_VINFO_PEELING_FOR_GAPS (loop_vinfo) && gap != 0 + && known_eq (nunits, (group_size - gap) * 2) + && known_eq (nunits, group_size) + && gap >= (vect_align / scalar_dr_size)) + { + tree half_vtype; + new_vtype + = vector_vector_composition_type (vectype, 2, + &half_vtype); + if (new_vtype != NULL_TREE) + ltype = half_vtype; + } + tree offset + = (dataref_offset ? dataref_offset + : build_int_cst (ref_type, 0)); + if (ltype != vectype + && memory_access_type == VMAT_CONTIGUOUS_REVERSE) + { + unsigned HOST_WIDE_INT gap_offset + = gap * tree_to_uhwi (TYPE_SIZE_UNIT (elem_type)); + tree gapcst = build_int_cst (ref_type, gap_offset); + offset = size_binop (PLUS_EXPR, offset, gapcst); + } + data_ref + = fold_build2 (MEM_REF, ltype, dataref_ptr, offset); + if (alignment_support_scheme == dr_aligned) + ; + else + TREE_TYPE (data_ref) + = build_aligned_type (TREE_TYPE (data_ref), + align * BITS_PER_UNIT); + if (ltype != vectype) + { + vect_copy_ref_info (data_ref, + DR_REF (first_dr_info->dr)); + tree tem = make_ssa_name (ltype); + new_stmt = gimple_build_assign (tem, data_ref); + vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, + gsi); + data_ref = NULL; + vec *v; + vec_alloc (v, 2); + if (memory_access_type == VMAT_CONTIGUOUS_REVERSE) + { + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, + build_zero_cst (ltype)); + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, tem); + } + else + { + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, tem); + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, + build_zero_cst (ltype)); + } + gcc_assert (new_vtype != NULL_TREE); + if (new_vtype == vectype) + new_stmt = gimple_build_assign ( + vec_dest, build_constructor (vectype, v)); + else + { + tree new_vname = make_ssa_name (new_vtype); + new_stmt = gimple_build_assign ( + new_vname, build_constructor (new_vtype, v)); + vect_finish_stmt_generation (vinfo, stmt_info, + new_stmt, gsi); + new_stmt = gimple_build_assign ( + vec_dest, + build1 (VIEW_CONVERT_EXPR, vectype, new_vname)); + } + } + } + break; + } + case dr_explicit_realign: + { + if (costing_p) + break; + tree ptr, bump; + + tree vs = size_int (TYPE_VECTOR_SUBPARTS (vectype)); + + if (compute_in_loop) + msq = vect_setup_realignment (vinfo, first_stmt_info, gsi, + &realignment_token, + dr_explicit_realign, + dataref_ptr, NULL); + + if (TREE_CODE (dataref_ptr) == SSA_NAME) + ptr = copy_ssa_name (dataref_ptr); + else + ptr = make_ssa_name (TREE_TYPE (dataref_ptr)); + // For explicit realign the target alignment should be + // known at compile time. + unsigned HOST_WIDE_INT align + = DR_TARGET_ALIGNMENT (first_dr_info).to_constant (); + new_stmt = gimple_build_assign ( + ptr, BIT_AND_EXPR, dataref_ptr, + build_int_cst (TREE_TYPE (dataref_ptr), + -(HOST_WIDE_INT) align)); + vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi); + data_ref + = build2 (MEM_REF, vectype, ptr, build_int_cst (ref_type, 0)); + vect_copy_ref_info (data_ref, DR_REF (first_dr_info->dr)); + vec_dest = vect_create_destination_var (scalar_dest, vectype); + new_stmt = gimple_build_assign (vec_dest, data_ref); + new_temp = make_ssa_name (vec_dest, new_stmt); + gimple_assign_set_lhs (new_stmt, new_temp); + gimple_move_vops (new_stmt, stmt_info->stmt); + vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi); + msq = new_temp; + + bump = size_binop (MULT_EXPR, vs, TYPE_SIZE_UNIT (elem_type)); + bump = size_binop (MINUS_EXPR, bump, size_one_node); + ptr = bump_vector_ptr (vinfo, dataref_ptr, NULL, gsi, stmt_info, + bump); + new_stmt = gimple_build_assign ( + NULL_TREE, BIT_AND_EXPR, ptr, + build_int_cst (TREE_TYPE (ptr), -(HOST_WIDE_INT) align)); + if (TREE_CODE (ptr) == SSA_NAME) + ptr = copy_ssa_name (ptr, new_stmt); + else + ptr = make_ssa_name (TREE_TYPE (ptr), new_stmt); + gimple_assign_set_lhs (new_stmt, ptr); + vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi); + data_ref + = build2 (MEM_REF, vectype, ptr, build_int_cst (ref_type, 0)); + break; + } + case dr_explicit_realign_optimized: + { + if (costing_p) + break; + if (TREE_CODE (dataref_ptr) == SSA_NAME) + new_temp = copy_ssa_name (dataref_ptr); + else + new_temp = make_ssa_name (TREE_TYPE (dataref_ptr)); + // We should only be doing this if we know the target + // alignment at compile time. + unsigned HOST_WIDE_INT align + = DR_TARGET_ALIGNMENT (first_dr_info).to_constant (); + new_stmt = gimple_build_assign ( + new_temp, BIT_AND_EXPR, dataref_ptr, + build_int_cst (TREE_TYPE (dataref_ptr), + -(HOST_WIDE_INT) align)); + vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi); + data_ref = build2 (MEM_REF, vectype, new_temp, + build_int_cst (ref_type, 0)); + break; + } + default: + gcc_unreachable (); + } + + /* One common place to cost the above vect load for different + alignment support schemes. */ if (costing_p) { - /* An IFN_LOAD_LANES will load all its vector results, - regardless of which ones we actually need. Account - for the cost of unused results. */ - if (grouped_load && first_stmt_info == stmt_info) - { - unsigned int gaps = DR_GROUP_SIZE (first_stmt_info); - stmt_vec_info next_stmt_info = first_stmt_info; - do - { - gaps -= 1; - next_stmt_info = DR_GROUP_NEXT_ELEMENT (next_stmt_info); - } - while (next_stmt_info); - if (gaps) - { - if (dump_enabled_p ()) - dump_printf_loc (MSG_NOTE, vect_location, - "vect_model_load_cost: %d " - "unused vectors.\n", - gaps); - vect_get_load_cost (vinfo, stmt_info, gaps, - alignment_support_scheme, - misalignment, false, &inside_cost, - &prologue_cost, cost_vec, cost_vec, - true); - } - } - vect_get_load_cost (vinfo, stmt_info, 1, alignment_support_scheme, - misalignment, false, &inside_cost, - &prologue_cost, cost_vec, cost_vec, true); - continue; - } - tree vec_array; - - vec_array = create_vector_array (vectype, vec_num); - - tree final_mask = NULL_TREE; - if (loop_masks) - final_mask = vect_get_loop_mask (loop_vinfo, gsi, loop_masks, - ncopies, vectype, j); - if (vec_mask) - final_mask = prepare_vec_mask (loop_vinfo, mask_vectype, - final_mask, vec_mask, gsi); - - gcall *call; - if (final_mask) - { - /* Emit: - VEC_ARRAY = MASK_LOAD_LANES (DATAREF_PTR, ALIAS_PTR, - VEC_MASK). */ - unsigned int align = TYPE_ALIGN (TREE_TYPE (vectype)); - tree alias_ptr = build_int_cst (ref_type, align); - call = gimple_build_call_internal (IFN_MASK_LOAD_LANES, 3, - dataref_ptr, alias_ptr, - final_mask); + /* For VMAT_CONTIGUOUS_PERMUTE if it's grouped load, we + only need to take care of the first stmt, whose + stmt_info is first_stmt_info, vec_num iterating on it + will cover the cost for the remaining, it's consistent + with transforming. For the prologue cost for realign, + we only need to count it once for the whole group. */ + bool first_stmt_info_p = first_stmt_info == stmt_info; + bool add_realign_cost = first_stmt_info_p && i == 0; + if (memory_access_type == VMAT_CONTIGUOUS + || memory_access_type == VMAT_CONTIGUOUS_REVERSE + || (memory_access_type == VMAT_CONTIGUOUS_PERMUTE + && (!grouped_load || first_stmt_info_p))) + vect_get_load_cost (vinfo, stmt_info, 1, + alignment_support_scheme, misalignment, + add_realign_cost, &inside_cost, + &prologue_cost, cost_vec, cost_vec, true); } else { - /* Emit: - VEC_ARRAY = LOAD_LANES (MEM_REF[...all elements...]). */ - data_ref = create_array_ref (aggr_type, dataref_ptr, ref_type); - call = gimple_build_call_internal (IFN_LOAD_LANES, 1, data_ref); - } - gimple_call_set_lhs (call, vec_array); - gimple_call_set_nothrow (call, true); - vect_finish_stmt_generation (vinfo, stmt_info, call, gsi); - new_stmt = call; - - /* Extract each vector into an SSA_NAME. */ - for (i = 0; i < vec_num; i++) - { - new_temp = read_vector_array (vinfo, stmt_info, gsi, scalar_dest, - vec_array, i); - dr_chain.quick_push (new_temp); + vec_dest = vect_create_destination_var (scalar_dest, vectype); + /* DATA_REF is null if we've already built the statement. */ + if (data_ref) + { + vect_copy_ref_info (data_ref, DR_REF (first_dr_info->dr)); + new_stmt = gimple_build_assign (vec_dest, data_ref); + } + new_temp = make_ssa_name (vec_dest, new_stmt); + gimple_set_lhs (new_stmt, new_temp); + vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi); } - /* Record the mapping between SSA_NAMEs and statements. */ - vect_record_grouped_load_vectors (vinfo, stmt_info, dr_chain); - - /* Record that VEC_ARRAY is now dead. */ - vect_clobber_variable (vinfo, stmt_info, gsi, vec_array); - } - else - { - for (i = 0; i < vec_num; i++) + /* 3. Handle explicit realignment if necessary/supported. + Create in loop: + vec_dest = realign_load (msq, lsq, realignment_token) */ + if (!costing_p + && (alignment_support_scheme == dr_explicit_realign_optimized + || alignment_support_scheme == dr_explicit_realign)) { - tree final_mask = NULL_TREE; - tree final_len = NULL_TREE; - tree bias = NULL_TREE; - if (!costing_p) + lsq = gimple_assign_lhs (new_stmt); + if (!realignment_token) + realignment_token = dataref_ptr; + vec_dest = vect_create_destination_var (scalar_dest, vectype); + new_stmt = gimple_build_assign (vec_dest, REALIGN_LOAD_EXPR, msq, + lsq, realignment_token); + new_temp = make_ssa_name (vec_dest, new_stmt); + gimple_assign_set_lhs (new_stmt, new_temp); + vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi); + + if (alignment_support_scheme == dr_explicit_realign_optimized) { - if (loop_masks && memory_access_type != VMAT_INVARIANT) - final_mask - = vect_get_loop_mask (loop_vinfo, gsi, loop_masks, - vec_num * ncopies, vectype, - vec_num * j + i); - if (vec_mask) - final_mask = prepare_vec_mask (loop_vinfo, mask_vectype, - final_mask, vec_mask, gsi); - - if (i > 0 && !STMT_VINFO_GATHER_SCATTER_P (stmt_info)) - dataref_ptr = bump_vector_ptr (vinfo, dataref_ptr, ptr_incr, - gsi, stmt_info, bump); + gcc_assert (phi); + if (i == vec_num - 1 && j == ncopies - 1) + add_phi_arg (phi, lsq, loop_latch_edge (containing_loop), + UNKNOWN_LOCATION); + msq = lsq; } + } - /* 2. Create the vector-load in the loop. */ - switch (alignment_support_scheme) - { - case dr_aligned: - case dr_unaligned_supported: - { - unsigned int misalign; - unsigned HOST_WIDE_INT align; - - if (memory_access_type == VMAT_GATHER_SCATTER - && gs_info.ifn != IFN_LAST) - { - if (costing_p) - { - unsigned int cnunits - = vect_nunits_for_cost (vectype); - inside_cost - = record_stmt_cost (cost_vec, cnunits, - scalar_load, stmt_info, 0, - vect_body); - break; - } - if (STMT_VINFO_GATHER_SCATTER_P (stmt_info)) - vec_offset = vec_offsets[vec_num * j + i]; - tree zero = build_zero_cst (vectype); - tree scale = size_int (gs_info.scale); - - if (gs_info.ifn == IFN_MASK_LEN_GATHER_LOAD) - { - if (loop_lens) - final_len - = vect_get_loop_len (loop_vinfo, gsi, loop_lens, - vec_num * ncopies, vectype, - vec_num * j + i, 1); - else - final_len = build_int_cst (sizetype, - TYPE_VECTOR_SUBPARTS ( - vectype)); - signed char biasval - = LOOP_VINFO_PARTIAL_LOAD_STORE_BIAS (loop_vinfo); - bias = build_int_cst (intQI_type_node, biasval); - if (!final_mask) - { - mask_vectype = truth_type_for (vectype); - final_mask = build_minus_one_cst (mask_vectype); - } - } - - gcall *call; - if (final_len && final_mask) - call = gimple_build_call_internal ( - IFN_MASK_LEN_GATHER_LOAD, 7, dataref_ptr, - vec_offset, scale, zero, final_mask, final_len, - bias); - else if (final_mask) - call = gimple_build_call_internal - (IFN_MASK_GATHER_LOAD, 5, dataref_ptr, - vec_offset, scale, zero, final_mask); - else - call = gimple_build_call_internal - (IFN_GATHER_LOAD, 4, dataref_ptr, - vec_offset, scale, zero); - gimple_call_set_nothrow (call, true); - new_stmt = call; - data_ref = NULL_TREE; - break; - } - else if (memory_access_type == VMAT_GATHER_SCATTER) - { - /* Emulated gather-scatter. */ - gcc_assert (!final_mask); - unsigned HOST_WIDE_INT const_nunits - = nunits.to_constant (); - if (costing_p) - { - /* For emulated gathers N offset vector element - offset add is consumed by the load). */ - inside_cost - = record_stmt_cost (cost_vec, const_nunits, - vec_to_scalar, stmt_info, 0, - vect_body); - /* N scalar loads plus gathering them into a - vector. */ - inside_cost - = record_stmt_cost (cost_vec, const_nunits, - scalar_load, stmt_info, 0, - vect_body); - inside_cost - = record_stmt_cost (cost_vec, 1, vec_construct, - stmt_info, 0, vect_body); - break; - } - unsigned HOST_WIDE_INT const_offset_nunits - = TYPE_VECTOR_SUBPARTS (gs_info.offset_vectype) - .to_constant (); - vec *ctor_elts; - vec_alloc (ctor_elts, const_nunits); - gimple_seq stmts = NULL; - /* We support offset vectors with more elements - than the data vector for now. */ - unsigned HOST_WIDE_INT factor - = const_offset_nunits / const_nunits; - vec_offset = vec_offsets[j / factor]; - unsigned elt_offset = (j % factor) * const_nunits; - tree idx_type = TREE_TYPE (TREE_TYPE (vec_offset)); - tree scale = size_int (gs_info.scale); - align - = get_object_alignment (DR_REF (first_dr_info->dr)); - tree ltype = build_aligned_type (TREE_TYPE (vectype), - align); - for (unsigned k = 0; k < const_nunits; ++k) - { - tree boff = size_binop (MULT_EXPR, - TYPE_SIZE (idx_type), - bitsize_int - (k + elt_offset)); - tree idx = gimple_build (&stmts, BIT_FIELD_REF, - idx_type, vec_offset, - TYPE_SIZE (idx_type), - boff); - idx = gimple_convert (&stmts, sizetype, idx); - idx = gimple_build (&stmts, MULT_EXPR, - sizetype, idx, scale); - tree ptr = gimple_build (&stmts, PLUS_EXPR, - TREE_TYPE (dataref_ptr), - dataref_ptr, idx); - ptr = gimple_convert (&stmts, ptr_type_node, ptr); - tree elt = make_ssa_name (TREE_TYPE (vectype)); - tree ref = build2 (MEM_REF, ltype, ptr, - build_int_cst (ref_type, 0)); - new_stmt = gimple_build_assign (elt, ref); - gimple_set_vuse (new_stmt, - gimple_vuse (gsi_stmt (*gsi))); - gimple_seq_add_stmt (&stmts, new_stmt); - CONSTRUCTOR_APPEND_ELT (ctor_elts, NULL_TREE, elt); - } - gsi_insert_seq_before (gsi, stmts, GSI_SAME_STMT); - new_stmt = gimple_build_assign (NULL_TREE, - build_constructor - (vectype, ctor_elts)); - data_ref = NULL_TREE; - break; - } - - if (costing_p) - break; - - align = - known_alignment (DR_TARGET_ALIGNMENT (first_dr_info)); - if (alignment_support_scheme == dr_aligned) - misalign = 0; - else if (misalignment == DR_MISALIGNMENT_UNKNOWN) - { - align = dr_alignment - (vect_dr_behavior (vinfo, first_dr_info)); - misalign = 0; - } - else - misalign = misalignment; - if (dataref_offset == NULL_TREE - && TREE_CODE (dataref_ptr) == SSA_NAME) - set_ptr_info_alignment (get_ptr_info (dataref_ptr), - align, misalign); - align = least_bit_hwi (misalign | align); - - /* Compute IFN when LOOP_LENS or final_mask valid. */ - machine_mode vmode = TYPE_MODE (vectype); - machine_mode new_vmode = vmode; - internal_fn partial_ifn = IFN_LAST; - if (loop_lens) - { - opt_machine_mode new_ovmode - = get_len_load_store_mode (vmode, true, - &partial_ifn); - new_vmode = new_ovmode.require (); - unsigned factor = (new_ovmode == vmode) - ? 1 - : GET_MODE_UNIT_SIZE (vmode); - final_len - = vect_get_loop_len (loop_vinfo, gsi, loop_lens, - vec_num * ncopies, vectype, - vec_num * j + i, factor); - } - else if (final_mask) - { - if (!can_vec_mask_load_store_p ( - vmode, TYPE_MODE (TREE_TYPE (final_mask)), true, - &partial_ifn)) - gcc_unreachable (); - } - - if (partial_ifn == IFN_MASK_LEN_LOAD) - { - if (!final_len) - { - /* Pass VF value to 'len' argument of - MASK_LEN_LOAD if LOOP_LENS is invalid. */ - tree iv_type - = LOOP_VINFO_RGROUP_IV_TYPE (loop_vinfo); - final_len - = build_int_cst (iv_type, - TYPE_VECTOR_SUBPARTS (vectype)); - } - if (!final_mask) - { - /* Pass all ones value to 'mask' argument of - MASK_LEN_LOAD if final_mask is invalid. */ - mask_vectype = truth_type_for (vectype); - final_mask = build_minus_one_cst (mask_vectype); - } - } - if (final_len) - { - signed char biasval - = LOOP_VINFO_PARTIAL_LOAD_STORE_BIAS (loop_vinfo); - - bias = build_int_cst (intQI_type_node, biasval); - } - - if (final_len && memory_access_type != VMAT_INVARIANT) - { - tree ptr - = build_int_cst (ref_type, align * BITS_PER_UNIT); - gcall *call; - if (partial_ifn == IFN_MASK_LEN_LOAD) - call = gimple_build_call_internal (IFN_MASK_LEN_LOAD, - 5, dataref_ptr, - ptr, final_mask, - final_len, bias); - else - call = gimple_build_call_internal (IFN_LEN_LOAD, 4, - dataref_ptr, ptr, - final_len, bias); - gimple_call_set_nothrow (call, true); - new_stmt = call; - data_ref = NULL_TREE; - - /* Need conversion if it's wrapped with VnQI. */ - if (vmode != new_vmode) - { - tree new_vtype = build_vector_type_for_mode ( - unsigned_intQI_type_node, new_vmode); - tree var = vect_get_new_ssa_name (new_vtype, - vect_simple_var); - gimple_set_lhs (call, var); - vect_finish_stmt_generation (vinfo, stmt_info, call, - gsi); - tree op = build1 (VIEW_CONVERT_EXPR, vectype, var); - new_stmt - = gimple_build_assign (vec_dest, - VIEW_CONVERT_EXPR, op); - } - } - else if (final_mask) - { - tree ptr = build_int_cst (ref_type, - align * BITS_PER_UNIT); - gcall *call - = gimple_build_call_internal (IFN_MASK_LOAD, 3, - dataref_ptr, ptr, - final_mask); - gimple_call_set_nothrow (call, true); - new_stmt = call; - data_ref = NULL_TREE; - } - else - { - tree ltype = vectype; - tree new_vtype = NULL_TREE; - unsigned HOST_WIDE_INT gap - = DR_GROUP_GAP (first_stmt_info); - unsigned int vect_align - = vect_known_alignment_in_bytes (first_dr_info, - vectype); - unsigned int scalar_dr_size - = vect_get_scalar_dr_size (first_dr_info); - /* If there's no peeling for gaps but we have a gap - with slp loads then load the lower half of the - vector only. See get_group_load_store_type for - when we apply this optimization. */ - if (slp - && loop_vinfo - && !LOOP_VINFO_PEELING_FOR_GAPS (loop_vinfo) - && gap != 0 - && known_eq (nunits, (group_size - gap) * 2) - && known_eq (nunits, group_size) - && gap >= (vect_align / scalar_dr_size)) - { - tree half_vtype; - new_vtype - = vector_vector_composition_type (vectype, 2, - &half_vtype); - if (new_vtype != NULL_TREE) - ltype = half_vtype; - } - tree offset - = (dataref_offset ? dataref_offset - : build_int_cst (ref_type, 0)); - if (ltype != vectype - && memory_access_type == VMAT_CONTIGUOUS_REVERSE) - { - unsigned HOST_WIDE_INT gap_offset - = gap * tree_to_uhwi (TYPE_SIZE_UNIT (elem_type)); - tree gapcst = build_int_cst (ref_type, gap_offset); - offset = size_binop (PLUS_EXPR, offset, gapcst); - } - data_ref - = fold_build2 (MEM_REF, ltype, dataref_ptr, offset); - if (alignment_support_scheme == dr_aligned) - ; - else - TREE_TYPE (data_ref) - = build_aligned_type (TREE_TYPE (data_ref), - align * BITS_PER_UNIT); - if (ltype != vectype) - { - vect_copy_ref_info (data_ref, - DR_REF (first_dr_info->dr)); - tree tem = make_ssa_name (ltype); - new_stmt = gimple_build_assign (tem, data_ref); - vect_finish_stmt_generation (vinfo, stmt_info, - new_stmt, gsi); - data_ref = NULL; - vec *v; - vec_alloc (v, 2); - if (memory_access_type == VMAT_CONTIGUOUS_REVERSE) - { - CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, - build_zero_cst (ltype)); - CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, tem); - } - else - { - CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, tem); - CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, - build_zero_cst (ltype)); - } - gcc_assert (new_vtype != NULL_TREE); - if (new_vtype == vectype) - new_stmt = gimple_build_assign ( - vec_dest, build_constructor (vectype, v)); - else - { - tree new_vname = make_ssa_name (new_vtype); - new_stmt = gimple_build_assign ( - new_vname, build_constructor (new_vtype, v)); - vect_finish_stmt_generation (vinfo, stmt_info, - new_stmt, gsi); - new_stmt = gimple_build_assign ( - vec_dest, build1 (VIEW_CONVERT_EXPR, vectype, - new_vname)); - } - } - } - break; - } - case dr_explicit_realign: - { - if (costing_p) - break; - tree ptr, bump; - - tree vs = size_int (TYPE_VECTOR_SUBPARTS (vectype)); - - if (compute_in_loop) - msq = vect_setup_realignment (vinfo, first_stmt_info, gsi, - &realignment_token, - dr_explicit_realign, - dataref_ptr, NULL); - - if (TREE_CODE (dataref_ptr) == SSA_NAME) - ptr = copy_ssa_name (dataref_ptr); - else - ptr = make_ssa_name (TREE_TYPE (dataref_ptr)); - // For explicit realign the target alignment should be - // known at compile time. - unsigned HOST_WIDE_INT align = - DR_TARGET_ALIGNMENT (first_dr_info).to_constant (); - new_stmt = gimple_build_assign - (ptr, BIT_AND_EXPR, dataref_ptr, - build_int_cst - (TREE_TYPE (dataref_ptr), - -(HOST_WIDE_INT) align)); - vect_finish_stmt_generation (vinfo, stmt_info, - new_stmt, gsi); - data_ref - = build2 (MEM_REF, vectype, ptr, - build_int_cst (ref_type, 0)); - vect_copy_ref_info (data_ref, DR_REF (first_dr_info->dr)); - vec_dest = vect_create_destination_var (scalar_dest, - vectype); - new_stmt = gimple_build_assign (vec_dest, data_ref); - new_temp = make_ssa_name (vec_dest, new_stmt); - gimple_assign_set_lhs (new_stmt, new_temp); - gimple_move_vops (new_stmt, stmt_info->stmt); - vect_finish_stmt_generation (vinfo, stmt_info, - new_stmt, gsi); - msq = new_temp; - - bump = size_binop (MULT_EXPR, vs, - TYPE_SIZE_UNIT (elem_type)); - bump = size_binop (MINUS_EXPR, bump, size_one_node); - ptr = bump_vector_ptr (vinfo, dataref_ptr, NULL, gsi, - stmt_info, bump); - new_stmt = gimple_build_assign - (NULL_TREE, BIT_AND_EXPR, ptr, - build_int_cst - (TREE_TYPE (ptr), -(HOST_WIDE_INT) align)); - if (TREE_CODE (ptr) == SSA_NAME) - ptr = copy_ssa_name (ptr, new_stmt); - else - ptr = make_ssa_name (TREE_TYPE (ptr), new_stmt); - gimple_assign_set_lhs (new_stmt, ptr); - vect_finish_stmt_generation (vinfo, stmt_info, - new_stmt, gsi); - data_ref - = build2 (MEM_REF, vectype, ptr, - build_int_cst (ref_type, 0)); - break; - } - case dr_explicit_realign_optimized: - { - if (costing_p) - break; - if (TREE_CODE (dataref_ptr) == SSA_NAME) - new_temp = copy_ssa_name (dataref_ptr); - else - new_temp = make_ssa_name (TREE_TYPE (dataref_ptr)); - // We should only be doing this if we know the target - // alignment at compile time. - unsigned HOST_WIDE_INT align = - DR_TARGET_ALIGNMENT (first_dr_info).to_constant (); - new_stmt = gimple_build_assign - (new_temp, BIT_AND_EXPR, dataref_ptr, - build_int_cst (TREE_TYPE (dataref_ptr), - -(HOST_WIDE_INT) align)); - vect_finish_stmt_generation (vinfo, stmt_info, - new_stmt, gsi); - data_ref - = build2 (MEM_REF, vectype, new_temp, - build_int_cst (ref_type, 0)); - break; - } - default: - gcc_unreachable (); - } - - /* One common place to cost the above vect load for different - alignment support schemes. */ + if (memory_access_type == VMAT_CONTIGUOUS_REVERSE) + { if (costing_p) - { - /* For VMAT_CONTIGUOUS_PERMUTE if it's grouped load, we - only need to take care of the first stmt, whose - stmt_info is first_stmt_info, vec_num iterating on it - will cover the cost for the remaining, it's consistent - with transforming. For the prologue cost for realign, - we only need to count it once for the whole group. */ - bool first_stmt_info_p = first_stmt_info == stmt_info; - bool add_realign_cost = first_stmt_info_p && i == 0; - if (memory_access_type == VMAT_CONTIGUOUS - || memory_access_type == VMAT_CONTIGUOUS_REVERSE - || (memory_access_type == VMAT_CONTIGUOUS_PERMUTE - && (!grouped_load || first_stmt_info_p))) - vect_get_load_cost (vinfo, stmt_info, 1, - alignment_support_scheme, misalignment, - add_realign_cost, &inside_cost, - &prologue_cost, cost_vec, cost_vec, - true); - } + inside_cost = record_stmt_cost (cost_vec, 1, vec_perm, + stmt_info, 0, vect_body); else { - vec_dest = vect_create_destination_var (scalar_dest, vectype); - /* DATA_REF is null if we've already built the statement. */ - if (data_ref) - { - vect_copy_ref_info (data_ref, DR_REF (first_dr_info->dr)); - new_stmt = gimple_build_assign (vec_dest, data_ref); - } - new_temp = make_ssa_name (vec_dest, new_stmt); - gimple_set_lhs (new_stmt, new_temp); - vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi); - } - - /* 3. Handle explicit realignment if necessary/supported. - Create in loop: - vec_dest = realign_load (msq, lsq, realignment_token) */ - if (!costing_p - && (alignment_support_scheme == dr_explicit_realign_optimized - || alignment_support_scheme == dr_explicit_realign)) - { - lsq = gimple_assign_lhs (new_stmt); - if (!realignment_token) - realignment_token = dataref_ptr; - vec_dest = vect_create_destination_var (scalar_dest, vectype); - new_stmt = gimple_build_assign (vec_dest, REALIGN_LOAD_EXPR, - msq, lsq, realignment_token); - new_temp = make_ssa_name (vec_dest, new_stmt); - gimple_assign_set_lhs (new_stmt, new_temp); - vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi); - - if (alignment_support_scheme == dr_explicit_realign_optimized) - { - gcc_assert (phi); - if (i == vec_num - 1 && j == ncopies - 1) - add_phi_arg (phi, lsq, - loop_latch_edge (containing_loop), - UNKNOWN_LOCATION); - msq = lsq; - } - } - - if (memory_access_type == VMAT_CONTIGUOUS_REVERSE) - { - if (costing_p) - inside_cost = record_stmt_cost (cost_vec, 1, vec_perm, - stmt_info, 0, vect_body); - else - { - tree perm_mask = perm_mask_for_reverse (vectype); - new_temp - = permute_vec_elements (vinfo, new_temp, new_temp, - perm_mask, stmt_info, gsi); - new_stmt = SSA_NAME_DEF_STMT (new_temp); - } - } - - /* Collect vector loads and later create their permutation in - vect_transform_grouped_load (). */ - if (!costing_p && (grouped_load || slp_perm)) - dr_chain.quick_push (new_temp); - - /* Store vector loads in the corresponding SLP_NODE. */ - if (!costing_p && slp && !slp_perm) - slp_node->push_vec_def (new_stmt); - - /* With SLP permutation we load the gaps as well, without - we need to skip the gaps after we manage to fully load - all elements. group_gap_adj is DR_GROUP_SIZE here. */ - group_elt += nunits; - if (!costing_p - && maybe_ne (group_gap_adj, 0U) - && !slp_perm - && known_eq (group_elt, group_size - group_gap_adj)) - { - poly_wide_int bump_val - = (wi::to_wide (TYPE_SIZE_UNIT (elem_type)) - * group_gap_adj); - if (tree_int_cst_sgn - (vect_dr_behavior (vinfo, dr_info)->step) == -1) - bump_val = -bump_val; - tree bump = wide_int_to_tree (sizetype, bump_val); - dataref_ptr = bump_vector_ptr (vinfo, dataref_ptr, ptr_incr, - gsi, stmt_info, bump); - group_elt = 0; + tree perm_mask = perm_mask_for_reverse (vectype); + new_temp = permute_vec_elements (vinfo, new_temp, new_temp, + perm_mask, stmt_info, gsi); + new_stmt = SSA_NAME_DEF_STMT (new_temp); } } - /* Bump the vector pointer to account for a gap or for excess - elements loaded for a permuted SLP load. */ + + /* Collect vector loads and later create their permutation in + vect_transform_grouped_load (). */ + if (!costing_p && (grouped_load || slp_perm)) + dr_chain.quick_push (new_temp); + + /* Store vector loads in the corresponding SLP_NODE. */ + if (!costing_p && slp && !slp_perm) + slp_node->push_vec_def (new_stmt); + + /* With SLP permutation we load the gaps as well, without + we need to skip the gaps after we manage to fully load + all elements. group_gap_adj is DR_GROUP_SIZE here. */ + group_elt += nunits; if (!costing_p && maybe_ne (group_gap_adj, 0U) - && slp_perm) + && !slp_perm + && known_eq (group_elt, group_size - group_gap_adj)) { poly_wide_int bump_val - = (wi::to_wide (TYPE_SIZE_UNIT (elem_type)) - * group_gap_adj); - if (tree_int_cst_sgn - (vect_dr_behavior (vinfo, dr_info)->step) == -1) + = (wi::to_wide (TYPE_SIZE_UNIT (elem_type)) * group_gap_adj); + if (tree_int_cst_sgn (vect_dr_behavior (vinfo, dr_info)->step) + == -1) bump_val = -bump_val; tree bump = wide_int_to_tree (sizetype, bump_val); dataref_ptr = bump_vector_ptr (vinfo, dataref_ptr, ptr_incr, gsi, stmt_info, bump); + group_elt = 0; } } + /* Bump the vector pointer to account for a gap or for excess + elements loaded for a permuted SLP load. */ + if (!costing_p + && maybe_ne (group_gap_adj, 0U) + && slp_perm) + { + poly_wide_int bump_val + = (wi::to_wide (TYPE_SIZE_UNIT (elem_type)) * group_gap_adj); + if (tree_int_cst_sgn (vect_dr_behavior (vinfo, dr_info)->step) == -1) + bump_val = -bump_val; + tree bump = wide_int_to_tree (sizetype, bump_val); + dataref_ptr = bump_vector_ptr (vinfo, dataref_ptr, ptr_incr, gsi, + stmt_info, bump); + } if (slp && !slp_perm) continue; @@ -11068,39 +11336,36 @@ vectorizable_load (vec_info *vinfo, } } else - { - if (grouped_load) - { - if (memory_access_type != VMAT_LOAD_STORE_LANES) + { + if (grouped_load) + { + gcc_assert (memory_access_type == VMAT_CONTIGUOUS_PERMUTE); + /* We assume that the cost of a single load-lanes instruction + is equivalent to the cost of DR_GROUP_SIZE separate loads. + If a grouped access is instead being provided by a + load-and-permute operation, include the cost of the + permutes. */ + if (costing_p && first_stmt_info == stmt_info) { - gcc_assert (memory_access_type == VMAT_CONTIGUOUS_PERMUTE); - /* We assume that the cost of a single load-lanes instruction - is equivalent to the cost of DR_GROUP_SIZE separate loads. - If a grouped access is instead being provided by a - load-and-permute operation, include the cost of the - permutes. */ - if (costing_p && first_stmt_info == stmt_info) - { - /* Uses an even and odd extract operations or shuffle - operations for each needed permute. */ - int group_size = DR_GROUP_SIZE (first_stmt_info); - int nstmts = ceil_log2 (group_size) * group_size; - inside_cost - += record_stmt_cost (cost_vec, nstmts, vec_perm, - stmt_info, 0, vect_body); + /* Uses an even and odd extract operations or shuffle + operations for each needed permute. */ + int group_size = DR_GROUP_SIZE (first_stmt_info); + int nstmts = ceil_log2 (group_size) * group_size; + inside_cost += record_stmt_cost (cost_vec, nstmts, vec_perm, + stmt_info, 0, vect_body); - if (dump_enabled_p ()) - dump_printf_loc ( - MSG_NOTE, vect_location, - "vect_model_load_cost: strided group_size = %d .\n", - group_size); - } - else if (!costing_p) - vect_transform_grouped_load (vinfo, stmt_info, dr_chain, - group_size, gsi); + if (dump_enabled_p ()) + dump_printf_loc (MSG_NOTE, vect_location, + "vect_model_load_cost:" + "strided group_size = %d .\n", + group_size); + } + else if (!costing_p) + { + vect_transform_grouped_load (vinfo, stmt_info, dr_chain, + group_size, gsi); + *vec_stmt = STMT_VINFO_VEC_STMTS (stmt_info)[0]; } - if (!costing_p) - *vec_stmt = STMT_VINFO_VEC_STMTS (stmt_info)[0]; } else if (!costing_p) STMT_VINFO_VEC_STMTS (stmt_info).safe_push (new_stmt); @@ -11112,9 +11377,9 @@ vectorizable_load (vec_info *vinfo, if (costing_p) { - gcc_assert (memory_access_type != VMAT_INVARIANT - && memory_access_type != VMAT_ELEMENTWISE - && memory_access_type != VMAT_STRIDED_SLP); + gcc_assert (memory_access_type == VMAT_CONTIGUOUS + || memory_access_type == VMAT_CONTIGUOUS_REVERSE + || memory_access_type == VMAT_CONTIGUOUS_PERMUTE); if (dump_enabled_p ()) dump_printf_loc (MSG_NOTE, vect_location, "vect_model_load_cost: inside_cost = %u, " @@ -11474,8 +11739,17 @@ vectorizable_condition (vec_info *vinfo, && LOOP_VINFO_CAN_USE_PARTIAL_VECTORS_P (loop_vinfo)) { if (reduction_type == EXTRACT_LAST_REDUCTION) - vect_record_loop_mask (loop_vinfo, &LOOP_VINFO_MASKS (loop_vinfo), - ncopies * vec_num, vectype, NULL); + { + if (direct_internal_fn_supported_p (IFN_LEN_FOLD_EXTRACT_LAST, + vectype, OPTIMIZE_FOR_SPEED)) + vect_record_loop_len (loop_vinfo, + &LOOP_VINFO_LENS (loop_vinfo), + ncopies * vec_num, vectype, 1); + else + vect_record_loop_mask (loop_vinfo, + &LOOP_VINFO_MASKS (loop_vinfo), + ncopies * vec_num, vectype, NULL); + } /* Extra inactive lanes should be safe for vect_nested_cycle. */ else if (STMT_VINFO_DEF_TYPE (reduc_info) != vect_nested_cycle) { @@ -11506,7 +11780,13 @@ vectorizable_condition (vec_info *vinfo, mask to the condition, or to its inverse. */ vec_loop_masks *masks = NULL; - if (loop_vinfo && LOOP_VINFO_FULLY_MASKED_P (loop_vinfo)) + vec_loop_lens *lens = NULL; + if (loop_vinfo && LOOP_VINFO_FULLY_WITH_LENGTH_P (loop_vinfo)) + { + if (reduction_type == EXTRACT_LAST_REDUCTION) + lens = &LOOP_VINFO_LENS (loop_vinfo); + } + else if (loop_vinfo && LOOP_VINFO_FULLY_MASKED_P (loop_vinfo)) { if (reduction_type == EXTRACT_LAST_REDUCTION) masks = &LOOP_VINFO_MASKS (loop_vinfo); @@ -11644,7 +11924,8 @@ vectorizable_condition (vec_info *vinfo, /* Force vec_compare to be an SSA_NAME rather than a comparison, in cases where that's necessary. */ - if (masks || reduction_type == EXTRACT_LAST_REDUCTION) + tree len = NULL_TREE, bias = NULL_TREE; + if (masks || lens || reduction_type == EXTRACT_LAST_REDUCTION) { if (!is_gimple_val (vec_compare)) { @@ -11665,6 +11946,23 @@ vectorizable_condition (vec_info *vinfo, vec_compare = vec_compare_name; } + if (direct_internal_fn_supported_p (IFN_LEN_FOLD_EXTRACT_LAST, + vectype, OPTIMIZE_FOR_SPEED)) + { + if (lens) + { + len = vect_get_loop_len (loop_vinfo, gsi, lens, + vec_num * ncopies, vectype, i, 1); + signed char biasval + = LOOP_VINFO_PARTIAL_LOAD_STORE_BIAS (loop_vinfo); + bias = build_int_cst (intQI_type_node, biasval); + } + else + { + len = size_int (TYPE_VECTOR_SUBPARTS (vectype)); + bias = build_int_cst (intQI_type_node, 0); + } + } if (masks) { tree loop_mask @@ -11684,9 +11982,14 @@ vectorizable_condition (vec_info *vinfo, { gimple *old_stmt = vect_orig_stmt (stmt_info)->stmt; tree lhs = gimple_get_lhs (old_stmt); - new_stmt = gimple_build_call_internal - (IFN_FOLD_EXTRACT_LAST, 3, else_clause, vec_compare, - vec_then_clause); + if (len) + new_stmt = gimple_build_call_internal + (IFN_LEN_FOLD_EXTRACT_LAST, 5, else_clause, vec_compare, + vec_then_clause, len, bias); + else + new_stmt = gimple_build_call_internal + (IFN_FOLD_EXTRACT_LAST, 3, else_clause, vec_compare, + vec_then_clause); gimple_call_set_lhs (new_stmt, lhs); SSA_NAME_DEF_STMT (lhs) = new_stmt; if (old_stmt == gsi_stmt (*gsi)) @@ -11963,11 +12266,10 @@ vectorizable_comparison (vec_info *vinfo, /* If SLP_NODE is nonnull, return true if vectorizable_live_operation can handle all live statements in the node. Otherwise return true if STMT_INFO is not live or if vectorizable_live_operation can handle it. - GSI and VEC_STMT_P are as for vectorizable_live_operation. */ + VEC_STMT_P is as for vectorizable_live_operation. */ static bool -can_vectorize_live_stmts (vec_info *vinfo, - stmt_vec_info stmt_info, gimple_stmt_iterator *gsi, +can_vectorize_live_stmts (vec_info *vinfo, stmt_vec_info stmt_info, slp_tree slp_node, slp_instance slp_node_instance, bool vec_stmt_p, stmt_vector_for_cost *cost_vec) @@ -11979,15 +12281,14 @@ can_vectorize_live_stmts (vec_info *vinfo, FOR_EACH_VEC_ELT (SLP_TREE_SCALAR_STMTS (slp_node), i, slp_stmt_info) { if (STMT_VINFO_LIVE_P (slp_stmt_info) - && !vectorizable_live_operation (vinfo, - slp_stmt_info, gsi, slp_node, + && !vectorizable_live_operation (vinfo, slp_stmt_info, slp_node, slp_node_instance, i, vec_stmt_p, cost_vec)) return false; } } else if (STMT_VINFO_LIVE_P (stmt_info) - && !vectorizable_live_operation (vinfo, stmt_info, gsi, + && !vectorizable_live_operation (vinfo, stmt_info, slp_node, slp_node_instance, -1, vec_stmt_p, cost_vec)) return false; @@ -12222,7 +12523,7 @@ vect_analyze_stmt (vec_info *vinfo, && STMT_VINFO_TYPE (stmt_info) != reduc_vec_info_type && STMT_VINFO_TYPE (stmt_info) != lc_phi_info_type && !can_vectorize_live_stmts (as_a (vinfo), - stmt_info, NULL, node, node_instance, + stmt_info, node, node_instance, false, cost_vec)) return opt_result::failure_at (stmt_info->stmt, "not vectorized:" @@ -12294,21 +12595,22 @@ vect_transform_stmt (vec_info *vinfo, break; case store_vec_info_type: - done = vectorizable_store (vinfo, stmt_info, - gsi, &vec_stmt, slp_node, NULL); - gcc_assert (done); - if (STMT_VINFO_GROUPED_ACCESS (stmt_info) && !slp_node) - { - /* In case of interleaving, the whole chain is vectorized when the - last store in the chain is reached. Store stmts before the last - one are skipped, and there vec_stmt_info shouldn't be freed - meanwhile. */ - stmt_vec_info group_info = DR_GROUP_FIRST_ELEMENT (stmt_info); - if (DR_GROUP_STORE_COUNT (group_info) == DR_GROUP_SIZE (group_info)) - is_store = true; - } + if (STMT_VINFO_GROUPED_ACCESS (stmt_info) + && !slp_node + && (++DR_GROUP_STORE_COUNT (DR_GROUP_FIRST_ELEMENT (stmt_info)) + < DR_GROUP_SIZE (DR_GROUP_FIRST_ELEMENT (stmt_info)))) + /* In case of interleaving, the whole chain is vectorized when the + last store in the chain is reached. Store stmts before the last + one are skipped, and there vec_stmt_info shouldn't be freed + meanwhile. */ + ; else - is_store = true; + { + done = vectorizable_store (vinfo, stmt_info, + gsi, &vec_stmt, slp_node, NULL); + gcc_assert (done); + is_store = true; + } break; case condition_vec_info_type: @@ -12380,7 +12682,7 @@ vect_transform_stmt (vec_info *vinfo, { /* Handle stmts whose DEF is used outside the loop-nest that is being vectorized. */ - done = can_vectorize_live_stmts (vinfo, stmt_info, gsi, slp_node, + done = can_vectorize_live_stmts (vinfo, stmt_info, slp_node, slp_node_instance, true, NULL); gcc_assert (done); } diff --git a/gcc/tree-vectorizer.h b/gcc/tree-vectorizer.h index a65161499ea1..f1d0cd79961a 100644 --- a/gcc/tree-vectorizer.h +++ b/gcc/tree-vectorizer.h @@ -257,6 +257,10 @@ public: from, NULL otherwise. */ vec root_stmts; + /* For slp_inst_kind_bb_reduc the defs that were not vectorized, NULL + otherwise. */ + vec remain_defs; + /* The unrolling factor required to vectorized this SLP instance. */ poly_uint64 unrolling_factor; @@ -285,6 +289,7 @@ public: #define SLP_INSTANCE_UNROLLING_FACTOR(S) (S)->unrolling_factor #define SLP_INSTANCE_LOADS(S) (S)->loads #define SLP_INSTANCE_ROOT_STMTS(S) (S)->root_stmts +#define SLP_INSTANCE_REMAIN_DEFS(S) (S)->remain_defs #define SLP_INSTANCE_KIND(S) (S)->kind #define SLP_TREE_CHILDREN(S) (S)->children @@ -1022,11 +1027,12 @@ loop_vec_info_for_loop (class loop *loop) struct slp_root { slp_root (slp_instance_kind kind_, vec stmts_, - vec roots_) - : kind(kind_), stmts(stmts_), roots(roots_) {} + vec roots_, vec remain_ = vNULL) + : kind(kind_), stmts(stmts_), roots(roots_), remain(remain_) {} slp_instance_kind kind; vec stmts; vec roots; + vec remain; }; typedef class _bb_vec_info : public vec_info @@ -2291,9 +2297,9 @@ extern tree bump_vector_ptr (vec_info *, tree, gimple *, gimple_stmt_iterator *, extern void vect_copy_ref_info (tree, tree); extern tree vect_create_destination_var (tree, tree); extern bool vect_grouped_store_supported (tree, unsigned HOST_WIDE_INT); -extern bool vect_store_lanes_supported (tree, unsigned HOST_WIDE_INT, bool); +extern internal_fn vect_store_lanes_supported (tree, unsigned HOST_WIDE_INT, bool); extern bool vect_grouped_load_supported (tree, bool, unsigned HOST_WIDE_INT); -extern bool vect_load_lanes_supported (tree, unsigned HOST_WIDE_INT, bool); +extern internal_fn vect_load_lanes_supported (tree, unsigned HOST_WIDE_INT, bool); extern void vect_permute_store_chain (vec_info *, vec &, unsigned int, stmt_vec_info, gimple_stmt_iterator *, vec *); @@ -2357,8 +2363,7 @@ extern opt_result vect_analyze_loop_form (class loop *, vect_loop_form_info *); extern loop_vec_info vect_create_loop_vinfo (class loop *, vec_info_shared *, const vect_loop_form_info *, loop_vec_info = nullptr); -extern bool vectorizable_live_operation (vec_info *, - stmt_vec_info, gimple_stmt_iterator *, +extern bool vectorizable_live_operation (vec_info *, stmt_vec_info, slp_tree, slp_instance, int, bool, stmt_vector_for_cost *); extern bool vectorizable_reduction (loop_vec_info, stmt_vec_info, @@ -2424,6 +2429,7 @@ extern int vect_get_place_in_interleaving_chain (stmt_vec_info, stmt_vec_info); extern slp_tree vect_create_new_slp_node (unsigned, tree_code); extern void vect_free_slp_tree (slp_tree); extern bool compatible_calls_p (gcall *, gcall *); +extern int vect_slp_child_index_for_operand (const gimple *, int op); /* In tree-vect-patterns.cc. */ extern void diff --git a/gcc/tree-vrp.cc b/gcc/tree-vrp.cc index d61b087b7303..2d9f62732801 100644 --- a/gcc/tree-vrp.cc +++ b/gcc/tree-vrp.cc @@ -934,10 +934,7 @@ execute_ranger_vrp (struct function *fun, bool warn_array_bounds_p, // Remove tagged builtin-unreachable and maybe update globals. folder.m_unreachable.remove_and_update_globals (final_p); if (dump_file && (dump_flags & TDF_DETAILS)) - { - phi_analysis ().dump (dump_file); - ranger->dump (dump_file); - } + ranger->dump (dump_file); if ((warn_array_bounds || warn_strict_flex_arrays) && warn_array_bounds_p) { diff --git a/gcc/tree.def b/gcc/tree.def index be94b7ece0a7..abba3d764ae4 100644 --- a/gcc/tree.def +++ b/gcc/tree.def @@ -1287,6 +1287,15 @@ DEFTREECODE (OMP_SCAN, "omp_scan", tcc_statement, 2) Operand 0: OMP_SECTION_BODY: Section body. */ DEFTREECODE (OMP_SECTION, "omp_section", tcc_statement, 1) +/* OpenMP structured block sequences that don't correspond to the body + another directive. This is used for code fragments within the body + of a directive that are separately required to be structured block + sequence; in particular, for intervening code sequences in + imperfectly-nested loops. + Operand 0: BODY: contains the statement(s) within the structured block + sequence. */ +DEFTREECODE (OMP_STRUCTURED_BLOCK, "omp_structured_block", tcc_statement, 1) + /* OpenMP - #pragma omp master Operand 0: OMP_MASTER_BODY: Master section body. */ DEFTREECODE (OMP_MASTER, "omp_master", tcc_statement, 1) diff --git a/gcc/tree.h b/gcc/tree.h index 4c04245e2b1b..75bda3fba2f6 100644 --- a/gcc/tree.h +++ b/gcc/tree.h @@ -1530,6 +1530,9 @@ class auto_suppress_location_wrappers #define OMP_SECTION_BODY(NODE) TREE_OPERAND (OMP_SECTION_CHECK (NODE), 0) +#define OMP_STRUCTURED_BLOCK_BODY(NODE) \ + TREE_OPERAND (OMP_STRUCTURED_BLOCK_CHECK (NODE), 0) + #define OMP_SINGLE_BODY(NODE) TREE_OPERAND (OMP_SINGLE_CHECK (NODE), 0) #define OMP_SINGLE_CLAUSES(NODE) TREE_OPERAND (OMP_SINGLE_CHECK (NODE), 1) diff --git a/gcc/value-range.cc b/gcc/value-range.cc index 2abf57bcee80..391cef64cd13 100644 --- a/gcc/value-range.cc +++ b/gcc/value-range.cc @@ -313,6 +313,18 @@ add_vrange (const vrange &v, inchash::hash &hstate, } //namespace inchash +bool +irange::nonnegative_p () const +{ + return wi::ge_p (lower_bound (), 0, TYPE_SIGN (type ())); +} + +bool +irange::nonpositive_p () const +{ + return wi::le_p (upper_bound (), 0, TYPE_SIGN (type ())); +} + bool irange::supports_type_p (const_tree type) const { @@ -540,16 +552,26 @@ frange::union_nans (const frange &r) { gcc_checking_assert (known_isnan () || r.known_isnan ()); - if (known_isnan ()) + bool changed = false; + if (known_isnan () && m_kind != r.m_kind) { m_kind = r.m_kind; m_min = r.m_min; m_max = r.m_max; + changed = true; } - m_pos_nan |= r.m_pos_nan; - m_neg_nan |= r.m_neg_nan; - normalize_kind (); - return true; + if (m_pos_nan != r.m_pos_nan || m_neg_nan != r.m_neg_nan) + { + m_pos_nan |= r.m_pos_nan; + m_neg_nan |= r.m_neg_nan; + changed = true; + } + if (changed) + { + normalize_kind (); + return true; + } + return false; } bool @@ -1876,6 +1898,8 @@ irange::get_bitmask () const // // 3 is in the range endpoints, but is excluded per the known 0 bits // in the mask. + // + // See also the note in irange_bitmask::intersect. irange_bitmask bm = get_bitmask_from_range (); if (!m_bitmask.unknown_p ()) bm.intersect (m_bitmask); @@ -1915,10 +1939,18 @@ irange::intersect_bitmask (const irange &r) return false; irange_bitmask bm = get_bitmask (); + irange_bitmask save = bm; if (!bm.intersect (r.get_bitmask ())) return false; m_bitmask = bm; + + // Updating m_bitmask may still yield a semantic bitmask (as + // returned by get_bitmask) which is functionally equivalent to what + // we originally had. In which case, there's still no change. + if (save == get_bitmask ()) + return false; + if (!set_range_from_bitmask ()) normalize_kind (); if (flag_checking) @@ -1938,10 +1970,18 @@ irange::union_bitmask (const irange &r) return false; irange_bitmask bm = get_bitmask (); + irange_bitmask save = bm; if (!bm.union_ (r.get_bitmask ())) return false; m_bitmask = bm; + + // Updating m_bitmask may still yield a semantic bitmask (as + // returned by get_bitmask) which is functionally equivalent to what + // we originally had. In which case, there's still no change. + if (save == get_bitmask ()) + return false; + // No need to call set_range_from_mask, because we'll never // narrow the range. Besides, it would cause endless recursion // because of the union_ in set_range_from_mask. @@ -2697,6 +2737,22 @@ range_tests_nan () ASSERT_TRUE (real_identical (&r, &r0.upper_bound ())); ASSERT_TRUE (!r0.signbit_p (signbit)); ASSERT_TRUE (r0.maybe_isnan ()); + + // NAN U NAN shouldn't change anything. + r0.set_nan (float_type_node); + r1.set_nan (float_type_node); + ASSERT_FALSE (r0.union_ (r1)); + + // [3,5] NAN U NAN shouldn't change anything. + r0 = frange_float ("3", "5"); + r1.set_nan (float_type_node); + ASSERT_FALSE (r0.union_ (r1)); + + // [3,5] U NAN *does* trigger a change. + r0 = frange_float ("3", "5"); + r0.clear_nan (); + r1.set_nan (float_type_node); + ASSERT_TRUE (r0.union_ (r1)); } static void diff --git a/gcc/value-range.h b/gcc/value-range.h index 622b68863d26..6c5be36d74d2 100644 --- a/gcc/value-range.h +++ b/gcc/value-range.h @@ -288,6 +288,8 @@ public: virtual bool singleton_p (tree *result = NULL) const override; bool singleton_p (wide_int &) const; bool contains_p (const wide_int &) const; + bool nonnegative_p () const; + bool nonpositive_p () const; // In-place operators. virtual bool union_ (const vrange &) override; diff --git a/gcc/vr-values.cc b/gcc/vr-values.cc index ac4a83c6097b..a4fddd628418 100644 --- a/gcc/vr-values.cc +++ b/gcc/vr-values.cc @@ -1139,6 +1139,87 @@ simplify_using_ranges::simplify_cond_using_ranges_1 (gcond *stmt) if (fold_cond (stmt)) return true; + if (simplify_compare_using_ranges_1 (cond_code, op0, op1, stmt)) + { + if (dump_file) + { + fprintf (dump_file, "Simplified relational "); + print_gimple_stmt (dump_file, stmt, 0); + fprintf (dump_file, " into "); + } + + gimple_cond_set_code (stmt, cond_code); + gimple_cond_set_lhs (stmt, op0); + gimple_cond_set_rhs (stmt, op1); + + update_stmt (stmt); + + if (dump_file) + { + print_gimple_stmt (dump_file, stmt, 0); + fprintf (dump_file, "\n"); + } + return true; + } + return false; +} + +/* Like simplify_cond_using_ranges_1 but for assignments rather + than GIMPLE_COND. */ + +bool +simplify_using_ranges::simplify_compare_assign_using_ranges_1 + (gimple_stmt_iterator *gsi, + gimple *stmt) +{ + enum tree_code code = gimple_assign_rhs_code (stmt); + tree op0 = gimple_assign_rhs1 (stmt); + tree op1 = gimple_assign_rhs2 (stmt); + gcc_assert (TREE_CODE_CLASS (code) == tcc_comparison); + bool happened = false; + + if (simplify_compare_using_ranges_1 (code, op0, op1, stmt)) + { + if (dump_file) + { + fprintf (dump_file, "Simplified relational "); + print_gimple_stmt (dump_file, stmt, 0); + fprintf (dump_file, " into "); + } + + gimple_assign_set_rhs_code (stmt, code); + gimple_assign_set_rhs1 (stmt, op0); + gimple_assign_set_rhs2 (stmt, op1); + + update_stmt (stmt); + + if (dump_file) + { + print_gimple_stmt (dump_file, stmt, 0); + fprintf (dump_file, "\n"); + } + happened = true; + } + + /* Transform EQ_EXPR, NE_EXPR into BIT_XOR_EXPR or identity + if the RHS is zero or one, and the LHS are known to be boolean + values. */ + if ((code == EQ_EXPR || code == NE_EXPR) + && INTEGRAL_TYPE_P (TREE_TYPE (op0)) + && simplify_truth_ops_using_ranges (gsi, stmt)) + happened = true; + + return happened; +} + +/* Try to simplify OP0 COND_CODE OP1 using a relational operator to an + equality test if the range information indicates only one value can + satisfy the original conditional. */ + +bool +simplify_using_ranges::simplify_compare_using_ranges_1 (tree_code &cond_code, tree &op0, tree &op1, gimple *stmt) +{ + bool happened = false; if (cond_code != NE_EXPR && cond_code != EQ_EXPR && TREE_CODE (op0) == SSA_NAME @@ -1157,26 +1238,9 @@ simplify_using_ranges::simplify_cond_using_ranges_1 (gcond *stmt) tree new_tree = test_for_singularity (cond_code, op0, op1, &vr); if (new_tree) { - if (dump_file) - { - fprintf (dump_file, "Simplified relational "); - print_gimple_stmt (dump_file, stmt, 0); - fprintf (dump_file, " into "); - } - - gimple_cond_set_code (stmt, EQ_EXPR); - gimple_cond_set_lhs (stmt, op0); - gimple_cond_set_rhs (stmt, new_tree); - - update_stmt (stmt); - - if (dump_file) - { - print_gimple_stmt (dump_file, stmt, 0); - fprintf (dump_file, "\n"); - } - - return true; + cond_code = EQ_EXPR; + op1 = new_tree; + happened = true; } /* Try again after inverting the condition. We only deal @@ -1187,45 +1251,25 @@ simplify_using_ranges::simplify_cond_using_ranges_1 (gcond *stmt) op0, op1, &vr); if (new_tree) { - if (dump_file) - { - fprintf (dump_file, "Simplified relational "); - print_gimple_stmt (dump_file, stmt, 0); - fprintf (dump_file, " into "); - } - - gimple_cond_set_code (stmt, NE_EXPR); - gimple_cond_set_lhs (stmt, op0); - gimple_cond_set_rhs (stmt, new_tree); - - update_stmt (stmt); - - if (dump_file) - { - print_gimple_stmt (dump_file, stmt, 0); - fprintf (dump_file, "\n"); - } - - return true; + cond_code = NE_EXPR; + op1 = new_tree; + happened = true; } } } // Try to simplify casted conditions. - return simplify_casted_cond (stmt); + if (simplify_casted_compare (cond_code, op0, op1)) + happened = true; + return happened; } -/* STMT is a conditional at the end of a basic block. - - If the conditional is of the form SSA_NAME op constant and the SSA_NAME - was set via a type conversion, try to replace the SSA_NAME with the RHS - of the type conversion. Doing so makes the conversion dead which helps - subsequent passes. */ +/* Simplify OP0 code OP1 when OP1 is a constant and OP0 was a SSA_NAME + defined by a type conversion. Replacing OP0 with RHS of the type conversion. + Doing so makes the conversion dead which helps subsequent passes. */ bool -simplify_using_ranges::simplify_casted_cond (gcond *stmt) +simplify_using_ranges::simplify_casted_compare (tree_code &, tree &op0, tree &op1) { - tree op0 = gimple_cond_lhs (stmt); - tree op1 = gimple_cond_rhs (stmt); /* If we have a comparison of an SSA_NAME (OP0) against a constant, see if OP0 was set by a type conversion where the source of @@ -1274,9 +1318,8 @@ simplify_using_ranges::simplify_casted_cond (gcond *stmt) && int_fits_type_p (op1, TREE_TYPE (innerop))) { tree newconst = fold_convert (TREE_TYPE (innerop), op1); - gimple_cond_set_lhs (stmt, innerop); - gimple_cond_set_rhs (stmt, newconst); - update_stmt (stmt); + op0 = innerop; + op1 = newconst; return true; } } @@ -1880,16 +1923,11 @@ simplify_using_ranges::simplify (gimple_stmt_iterator *gsi) } } + if (TREE_CODE_CLASS (rhs_code) == tcc_comparison) + return simplify_compare_assign_using_ranges_1 (gsi, stmt); + switch (rhs_code) { - case EQ_EXPR: - case NE_EXPR: - /* Transform EQ_EXPR, NE_EXPR into BIT_XOR_EXPR or identity - if the RHS is zero or one, and the LHS are known to be boolean - values. */ - if (INTEGRAL_TYPE_P (TREE_TYPE (rhs1))) - return simplify_truth_ops_using_ranges (gsi, stmt); - break; /* Transform TRUNC_DIV_EXPR and TRUNC_MOD_EXPR into RSHIFT_EXPR and BIT_AND_EXPR respectively if the first operand is greater diff --git a/gcc/vr-values.h b/gcc/vr-values.h index df79a3a570b9..bc17aa1af151 100644 --- a/gcc/vr-values.h +++ b/gcc/vr-values.h @@ -38,13 +38,15 @@ private: void legacy_fold_cond (gcond *, edge *); tree legacy_fold_cond_overflow (gimple *stmt); tree fold_cond_with_ops (tree_code, tree, tree, gimple *s); - bool simplify_casted_cond (gcond *); + bool simplify_casted_compare (tree_code &cond_code, tree &op0, tree &op1); bool simplify_truth_ops_using_ranges (gimple_stmt_iterator *, gimple *); bool simplify_div_or_mod_using_ranges (gimple_stmt_iterator *, gimple *); bool simplify_abs_using_ranges (gimple_stmt_iterator *, gimple *); bool simplify_bit_ops_using_ranges (gimple_stmt_iterator *, gimple *); bool simplify_min_or_max_using_ranges (gimple_stmt_iterator *, gimple *); bool simplify_cond_using_ranges_1 (gcond *); + bool simplify_compare_using_ranges_1 (tree_code &, tree &, tree &, gimple *); + bool simplify_compare_assign_using_ranges_1 (gimple_stmt_iterator *, gimple *); bool simplify_switch_using_ranges (gswitch *); bool simplify_float_conversion_using_ranges (gimple_stmt_iterator *, gimple *); diff --git a/include/ChangeLog b/include/ChangeLog index dc3eff19c960..edee0faa493e 100644 --- a/include/ChangeLog +++ b/include/ChangeLog @@ -1,3 +1,26 @@ +2023-08-22 Jason Merrill + + PR c++/109751 + * demangle.h (enum demangle_component_type): Add + DEMANGLE_COMPONENT_FRIEND. + +2023-08-07 Vladimir Mezentsev + + * collectorAPI.h: New file. + * libcollector.h: New file. + * libfcollector.h: New file. + +2023-08-07 Alan Modra + + * xtensa-dynconfig.h (xtensa_isa_internal): Delete unnecessary + forward declaration. + +2023-08-07 Alan Modra + + * plugin-api.h: When handling non-gcc or gcc < 4.6.0 include + necessary header files before testing macros. Make more use + of #elif. Test _LITTLE_ENDIAN and _BIG_ENDIAN in final tests. + 2023-07-29 Tobias Burnus * cuda/cuda.h (CUDA_MEMCPY2D, CUDA_MEMCPY3D, CUDA_MEMCPY3D_PEER): diff --git a/include/demangle.h b/include/demangle.h index 769137e03e54..f062d7731c6b 100644 --- a/include/demangle.h +++ b/include/demangle.h @@ -448,6 +448,8 @@ enum demangle_component_type DEMANGLE_COMPONENT_TRANSACTION_SAFE, /* A cloned function. */ DEMANGLE_COMPONENT_CLONE, + /* A member-like friend function. */ + DEMANGLE_COMPONENT_FRIEND, DEMANGLE_COMPONENT_NOEXCEPT, DEMANGLE_COMPONENT_THROW_SPEC, diff --git a/intl/ChangeLog b/intl/ChangeLog index 52660f631ce8..c7e1983bcc7b 100644 --- a/intl/ChangeLog +++ b/intl/ChangeLog @@ -1,3 +1,7 @@ +2023-08-07 Alan Modra + + * configure: Regenerate. + 2023-06-15 Marek Polacek * Makefile.in: Use @PICFLAG@ in COMPILE as well. diff --git a/libada/ChangeLog b/libada/ChangeLog index 12901d135325..037cdd0344c6 100644 --- a/libada/ChangeLog +++ b/libada/ChangeLog @@ -1,3 +1,7 @@ +2023-08-07 John Ericson + + * configure: Regenerate. + 2022-08-25 Martin Liska * configure: Regenerate. diff --git a/libatomic/ChangeLog b/libatomic/ChangeLog index 942544ab261e..4ea717edec49 100644 --- a/libatomic/ChangeLog +++ b/libatomic/ChangeLog @@ -1,3 +1,27 @@ +2023-08-07 Nick Alcock + + * configure: Regenerate. + +2023-08-07 Alexander von Gluck IV + + * configure: Regenerate. + +2023-08-07 Nick Alcock + + * configure: Regenerate. + +2023-08-07 Nick Alcock + + * configure: Regenerate. + +2023-08-07 H.J. Lu + + * configure: Regenerate. + +2023-08-07 H.J. Lu + + * configure: Regenerate. + 2023-06-10 Xi Ruoyao * configure.tgt: For x86_64, always set try_ifunc=yes. diff --git a/libbacktrace/ChangeLog b/libbacktrace/ChangeLog index 0ab4192522b3..11395da6ea06 100644 --- a/libbacktrace/ChangeLog +++ b/libbacktrace/ChangeLog @@ -1,3 +1,27 @@ +2023-08-07 Nick Alcock + + * configure: Regenerate. + +2023-08-07 Alexander von Gluck IV + + * configure: Regenerate. + +2023-08-07 Nick Alcock + + * configure: Regenerate. + +2023-08-07 Nick Alcock + + * configure: Regenerate. + +2023-08-07 H.J. Lu + + * configure: Regenerate. + +2023-08-07 H.J. Lu + + * configure: Regenerate. + 2023-08-03 Richard Biener * zstdtest.c (test_samples): Properly compute the allocation diff --git a/libcc1/ChangeLog b/libcc1/ChangeLog index 95b523143170..6366a5dc03d8 100644 --- a/libcc1/ChangeLog +++ b/libcc1/ChangeLog @@ -1,3 +1,31 @@ +2023-08-11 Joseph Myers + + * configure: Regenerate. + +2023-08-07 Nick Alcock + + * configure: Regenerate. + +2023-08-07 Alexander von Gluck IV + + * configure: Regenerate. + +2023-08-07 Nick Alcock + + * configure: Regenerate. + +2023-08-07 Nick Alcock + + * configure: Regenerate. + +2023-08-07 H.J. Lu + + * configure: Regenerate. + +2023-08-07 H.J. Lu + + * configure: Regenerate. + 2023-05-18 Bernhard Reutner-Fischer * libcc1plugin.cc (plugin_float_type): Ditto. diff --git a/libcc1/configure b/libcc1/configure index 1a63a0e4e1a8..2a914a0bfc8b 100755 --- a/libcc1/configure +++ b/libcc1/configure @@ -15120,7 +15120,7 @@ fi elif test x$host = x$target; then export_sym_check="$gcc_cv_objdump -T" else - export_sym_check= + export_sym_check="$ac_cv_prog_OBJDUMP -T" fi ;; esac diff --git a/libcpp/ChangeLog b/libcpp/ChangeLog index 3fb8a43f9c6d..6197e498a93e 100644 --- a/libcpp/ChangeLog +++ b/libcpp/ChangeLog @@ -1,3 +1,7 @@ +2023-08-07 Alan Modra + + * configure: Regenerate. + 2023-07-19 Lewis Hyatt PR preprocessor/103902 diff --git a/libffi/ChangeLog b/libffi/ChangeLog index 2d27da4c3d21..e421b0363435 100644 --- a/libffi/ChangeLog +++ b/libffi/ChangeLog @@ -1,3 +1,37 @@ +2023-08-23 Lulu Cheng + + PR libffi/108682 + * configure.host: Add LoongArch support. + * Makefile.am: Likewise. + * Makefile.in: Regenerate. + * src/loongarch64/ffi.c: New file. + * src/loongarch64/ffitarget.h: New file. + * src/loongarch64/sysv.S: New file. + +2023-08-07 Nick Alcock + + * configure: Regenerate. + +2023-08-07 Alexander von Gluck IV + + * configure: Regenerate. + +2023-08-07 Nick Alcock + + * configure: Regenerate. + +2023-08-07 Nick Alcock + + * configure: Regenerate. + +2023-08-07 H.J. Lu + + * configure: Regenerate. + +2023-08-07 H.J. Lu + + * configure: Regenerate. + 2023-05-06 Dan Horák PR libffi/109447 diff --git a/libffi/Makefile.am b/libffi/Makefile.am index c6d6f849c535..2259ddb75f9e 100644 --- a/libffi/Makefile.am +++ b/libffi/Makefile.am @@ -139,7 +139,7 @@ noinst_HEADERS = src/aarch64/ffitarget.h src/aarch64/internal.h \ src/sparc/internal.h src/tile/ffitarget.h src/vax/ffitarget.h \ src/x86/ffitarget.h src/x86/internal.h src/x86/internal64.h \ src/x86/asmnames.h src/xtensa/ffitarget.h src/dlmalloc.c \ - src/kvx/ffitarget.h + src/kvx/ffitarget.h src/loongarch64/ffitarget.h EXTRA_libffi_la_SOURCES = src/aarch64/ffi.c src/aarch64/sysv.S \ src/aarch64/win64_armasm.S src/alpha/ffi.c src/alpha/osf.S \ @@ -169,7 +169,7 @@ EXTRA_libffi_la_SOURCES = src/aarch64/ffi.c src/aarch64/sysv.S \ src/x86/ffiw64.c src/x86/win64.S src/x86/ffi64.c \ src/x86/unix64.S src/x86/sysv_intel.S src/x86/win64_intel.S \ src/xtensa/ffi.c src/xtensa/sysv.S src/kvx/ffi.c \ - src/kvx/sysv.S + src/kvx/sysv.S src/loongarch64/ffi.c src/loongarch64/sysv.S TARGET_OBJ = @TARGET_OBJ@ libffi_la_LIBADD = $(TARGET_OBJ) diff --git a/libffi/Makefile.in b/libffi/Makefile.in index 5524a6a571e6..1d936b5c8a57 100644 --- a/libffi/Makefile.in +++ b/libffi/Makefile.in @@ -550,7 +550,7 @@ noinst_HEADERS = src/aarch64/ffitarget.h src/aarch64/internal.h \ src/sparc/internal.h src/tile/ffitarget.h src/vax/ffitarget.h \ src/x86/ffitarget.h src/x86/internal.h src/x86/internal64.h \ src/x86/asmnames.h src/xtensa/ffitarget.h src/dlmalloc.c \ - src/kvx/ffitarget.h + src/kvx/ffitarget.h src/loongarch64/ffitarget.h EXTRA_libffi_la_SOURCES = src/aarch64/ffi.c src/aarch64/sysv.S \ src/aarch64/win64_armasm.S src/alpha/ffi.c src/alpha/osf.S \ @@ -580,7 +580,7 @@ EXTRA_libffi_la_SOURCES = src/aarch64/ffi.c src/aarch64/sysv.S \ src/x86/ffiw64.c src/x86/win64.S src/x86/ffi64.c \ src/x86/unix64.S src/x86/sysv_intel.S src/x86/win64_intel.S \ src/xtensa/ffi.c src/xtensa/sysv.S src/kvx/ffi.c \ - src/kvx/sysv.S + src/kvx/sysv.S src/loongarch64/ffi.c src/loongarch64/sysv.S libffi_la_LIBADD = $(TARGET_OBJ) libffi_convenience_la_SOURCES = $(libffi_la_SOURCES) @@ -1074,6 +1074,16 @@ src/kvx/ffi.lo: src/kvx/$(am__dirstamp) \ src/kvx/$(DEPDIR)/$(am__dirstamp) src/kvx/sysv.lo: src/kvx/$(am__dirstamp) \ src/kvx/$(DEPDIR)/$(am__dirstamp) +src/loongarch64/$(am__dirstamp): + @$(MKDIR_P) src/loongarch64 + @: > src/loongarch64/$(am__dirstamp) +src/loongarch64/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) src/loongarch64/$(DEPDIR) + @: > src/loongarch64/$(DEPDIR)/$(am__dirstamp) +src/loongarch64/ffi.lo: src/loongarch64/$(am__dirstamp) \ + src/loongarch64/$(DEPDIR)/$(am__dirstamp) +src/loongarch64/sysv.lo: src/loongarch64/$(am__dirstamp) \ + src/loongarch64/$(DEPDIR)/$(am__dirstamp) libffi.la: $(libffi_la_OBJECTS) $(libffi_la_DEPENDENCIES) $(EXTRA_libffi_la_DEPENDENCIES) $(AM_V_CCLD)$(libffi_la_LINK) -rpath $(toolexeclibdir) $(libffi_la_OBJECTS) $(libffi_la_LIBADD) $(LIBS) @@ -1107,6 +1117,8 @@ mostlyclean-compile: -rm -f src/ia64/*.lo -rm -f src/kvx/*.$(OBJEXT) -rm -f src/kvx/*.lo + -rm -f src/loongarch64/*.$(OBJEXT) + -rm -f src/loongarch64/*.lo -rm -f src/m32r/*.$(OBJEXT) -rm -f src/m32r/*.lo -rm -f src/m68k/*.$(OBJEXT) @@ -1182,6 +1194,8 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@src/ia64/$(DEPDIR)/unix.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/kvx/$(DEPDIR)/ffi.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/kvx/$(DEPDIR)/sysv.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/loongarch64/$(DEPDIR)/ffi.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/loongarch64/$(DEPDIR)/sysv.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/m32r/$(DEPDIR)/ffi.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/m32r/$(DEPDIR)/sysv.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/m68k/$(DEPDIR)/ffi.Plo@am__quote@ @@ -1308,6 +1322,7 @@ clean-libtool: -rm -rf src/frv/.libs src/frv/_libs -rm -rf src/ia64/.libs src/ia64/_libs -rm -rf src/kvx/.libs src/kvx/_libs + -rm -rf src/loongarch64/.libs src/loongarch64/_libs -rm -rf src/m32r/.libs src/m32r/_libs -rm -rf src/m68k/.libs src/m68k/_libs -rm -rf src/m88k/.libs src/m88k/_libs @@ -1658,6 +1673,8 @@ distclean-generic: -rm -f src/ia64/$(am__dirstamp) -rm -f src/kvx/$(DEPDIR)/$(am__dirstamp) -rm -f src/kvx/$(am__dirstamp) + -rm -f src/loongarch64/$(DEPDIR)/$(am__dirstamp) + -rm -f src/loongarch64/$(am__dirstamp) -rm -f src/m32r/$(DEPDIR)/$(am__dirstamp) -rm -f src/m32r/$(am__dirstamp) -rm -f src/m68k/$(DEPDIR)/$(am__dirstamp) @@ -1712,7 +1729,7 @@ clean-am: clean-aminfo clean-generic clean-libtool clean-local \ distclean: distclean-recursive -rm -f $(am__CONFIG_DISTCLEAN_FILES) - -rm -rf src/$(DEPDIR) src/aarch64/$(DEPDIR) src/alpha/$(DEPDIR) src/arc/$(DEPDIR) src/arm/$(DEPDIR) src/avr32/$(DEPDIR) src/bfin/$(DEPDIR) src/cris/$(DEPDIR) src/csky/$(DEPDIR) src/frv/$(DEPDIR) src/ia64/$(DEPDIR) src/kvx/$(DEPDIR) src/m32r/$(DEPDIR) src/m68k/$(DEPDIR) src/m88k/$(DEPDIR) src/metag/$(DEPDIR) src/microblaze/$(DEPDIR) src/mips/$(DEPDIR) src/moxie/$(DEPDIR) src/nios2/$(DEPDIR) src/or1k/$(DEPDIR) src/pa/$(DEPDIR) src/powerpc/$(DEPDIR) src/riscv/$(DEPDIR) src/s390/$(DEPDIR) src/sh/$(DEPDIR) src/sh64/$(DEPDIR) src/sparc/$(DEPDIR) src/tile/$(DEPDIR) src/vax/$(DEPDIR) src/x86/$(DEPDIR) src/xtensa/$(DEPDIR) + -rm -rf src/$(DEPDIR) src/aarch64/$(DEPDIR) src/alpha/$(DEPDIR) src/arc/$(DEPDIR) src/arm/$(DEPDIR) src/avr32/$(DEPDIR) src/bfin/$(DEPDIR) src/cris/$(DEPDIR) src/csky/$(DEPDIR) src/frv/$(DEPDIR) src/ia64/$(DEPDIR) src/kvx/$(DEPDIR) src/loongarch64/$(DEPDIR) src/m32r/$(DEPDIR) src/m68k/$(DEPDIR) src/m88k/$(DEPDIR) src/metag/$(DEPDIR) src/microblaze/$(DEPDIR) src/mips/$(DEPDIR) src/moxie/$(DEPDIR) src/nios2/$(DEPDIR) src/or1k/$(DEPDIR) src/pa/$(DEPDIR) src/powerpc/$(DEPDIR) src/riscv/$(DEPDIR) src/s390/$(DEPDIR) src/sh/$(DEPDIR) src/sh64/$(DEPDIR) src/sparc/$(DEPDIR) src/tile/$(DEPDIR) src/vax/$(DEPDIR) src/x86/$(DEPDIR) src/xtensa/$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-hdr distclean-libtool distclean-local distclean-tags @@ -1851,7 +1868,7 @@ installcheck-am: maintainer-clean: maintainer-clean-recursive -rm -f $(am__CONFIG_DISTCLEAN_FILES) -rm -rf $(top_srcdir)/autom4te.cache - -rm -rf src/$(DEPDIR) src/aarch64/$(DEPDIR) src/alpha/$(DEPDIR) src/arc/$(DEPDIR) src/arm/$(DEPDIR) src/avr32/$(DEPDIR) src/bfin/$(DEPDIR) src/cris/$(DEPDIR) src/csky/$(DEPDIR) src/frv/$(DEPDIR) src/ia64/$(DEPDIR) src/kvx/$(DEPDIR) src/m32r/$(DEPDIR) src/m68k/$(DEPDIR) src/m88k/$(DEPDIR) src/metag/$(DEPDIR) src/microblaze/$(DEPDIR) src/mips/$(DEPDIR) src/moxie/$(DEPDIR) src/nios2/$(DEPDIR) src/or1k/$(DEPDIR) src/pa/$(DEPDIR) src/powerpc/$(DEPDIR) src/riscv/$(DEPDIR) src/s390/$(DEPDIR) src/sh/$(DEPDIR) src/sh64/$(DEPDIR) src/sparc/$(DEPDIR) src/tile/$(DEPDIR) src/vax/$(DEPDIR) src/x86/$(DEPDIR) src/xtensa/$(DEPDIR) + -rm -rf src/$(DEPDIR) src/aarch64/$(DEPDIR) src/alpha/$(DEPDIR) src/arc/$(DEPDIR) src/arm/$(DEPDIR) src/avr32/$(DEPDIR) src/bfin/$(DEPDIR) src/cris/$(DEPDIR) src/csky/$(DEPDIR) src/frv/$(DEPDIR) src/ia64/$(DEPDIR) src/kvx/$(DEPDIR) src/loongarch64/$(DEPDIR) src/m32r/$(DEPDIR) src/m68k/$(DEPDIR) src/m88k/$(DEPDIR) src/metag/$(DEPDIR) src/microblaze/$(DEPDIR) src/mips/$(DEPDIR) src/moxie/$(DEPDIR) src/nios2/$(DEPDIR) src/or1k/$(DEPDIR) src/pa/$(DEPDIR) src/powerpc/$(DEPDIR) src/riscv/$(DEPDIR) src/s390/$(DEPDIR) src/sh/$(DEPDIR) src/sh64/$(DEPDIR) src/sparc/$(DEPDIR) src/tile/$(DEPDIR) src/vax/$(DEPDIR) src/x86/$(DEPDIR) src/xtensa/$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-aminfo \ maintainer-clean-generic maintainer-clean-local \ diff --git a/libffi/configure.host b/libffi/configure.host index 268267183a03..9d73f18ee8cb 100644 --- a/libffi/configure.host +++ b/libffi/configure.host @@ -140,6 +140,11 @@ case "${host}" in SOURCES="ffi.c sysv.S" ;; + loongarch64-*-*) + TARGET=LOONGARCH64; TARGETDIR=loongarch64 + SOURCES="ffi.c sysv.S" + ;; + m32r*-*-*) TARGET=M32R; TARGETDIR=m32r SOURCES="ffi.c sysv.S" diff --git a/libffi/src/loongarch64/ffi.c b/libffi/src/loongarch64/ffi.c new file mode 100644 index 000000000000..140be3bc3dc4 --- /dev/null +++ b/libffi/src/loongarch64/ffi.c @@ -0,0 +1,621 @@ +/* ----------------------------------------------------------------------- + ffi.c - Copyright (c) 2022 Xu Chenghua + 2022 Cheng Lulu + Based on RISC-V port + + LoongArch Foreign Function Interface + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. + ----------------------------------------------------------------------- */ + +#include +#include + +#include +#include + +#if defined(__loongarch_soft_float) +# define ABI_FRLEN 0 +#elif defined(__loongarch_single_float) +# define ABI_FRLEN 32 +# define ABI_FLOAT float +#elif defined(__loongarch_double_float) +# define ABI_FRLEN 64 +# define ABI_FLOAT double +#else +#error unsupported LoongArch floating-point ABI +#endif + +#define NARGREG 8 +#define STKALIGN 16 +#define MAXCOPYARG (2 * sizeof (double)) + +/* call_context registers + - 8 floating point parameter/result registers. + - 8 integer parameter/result registers. + - 2 registers used by the assembly code to in-place construct its own + stack frame + - frame register + - return register +*/ +typedef struct call_context +{ + ABI_FLOAT fa[8]; + size_t a[10]; +} call_context; + +typedef struct call_builder +{ + call_context *aregs; + int used_integer; + int used_float; + size_t *used_stack; + size_t *stack; + size_t next_struct_area; +} call_builder; + +/* Integer (not pointer) less than ABI GRLEN. */ +/* FFI_TYPE_INT does not appear to be used. */ +#if __SIZEOF_POINTER__ == 8 +# define IS_INT(type) ((type) >= FFI_TYPE_UINT8 && (type) <= FFI_TYPE_SINT64) +#else +# define IS_INT(type) ((type) >= FFI_TYPE_UINT8 && (type) <= FFI_TYPE_SINT32) +#endif + +#if ABI_FRLEN +typedef struct float_struct_info +{ + char as_elements; + char type1; + char offset2; + char type2; +} float_struct_info; + +#if ABI_FRLEN >= 64 +# define IS_FLOAT(type) ((type) >= FFI_TYPE_FLOAT && (type) <= FFI_TYPE_DOUBLE) +#else +# define IS_FLOAT(type) ((type) == FFI_TYPE_FLOAT) +#endif + +static ffi_type ** +flatten_struct (ffi_type *in, ffi_type **out, ffi_type **out_end) +{ + int i; + + if (out == out_end) + return out; + if (in->type != FFI_TYPE_STRUCT) + *(out++) = in; + else + for (i = 0; in->elements[i]; i++) + out = flatten_struct (in->elements[i], out, out_end); + return out; +} + +/* Structs with at most two fields after flattening, one of which is of + floating point type, are passed in multiple registers if sufficient + registers are available. */ +static float_struct_info +struct_passed_as_elements (call_builder *cb, ffi_type *top) +{ + float_struct_info ret = {0, 0, 0, 0}; + ffi_type *fields[3]; + int num_floats, num_ints; + int num_fields = flatten_struct (top, fields, fields + 3) - fields; + + if (num_fields == 1) + { + if (IS_FLOAT (fields[0]->type)) + { + ret.as_elements = 1; + ret.type1 = fields[0]->type; + } + } + else if (num_fields == 2) + { + num_floats = IS_FLOAT (fields[0]->type) + IS_FLOAT (fields[1]->type); + num_ints = IS_INT (fields[0]->type) + IS_INT (fields[1]->type); + if (num_floats == 0 || num_floats + num_ints != 2) + return ret; + if (cb->used_float + num_floats > NARGREG + || cb->used_integer + (2 - num_floats) > NARGREG) + return ret; + if (!IS_FLOAT (fields[0]->type) && !IS_FLOAT (fields[1]->type)) + return ret; + + ret.type1 = fields[0]->type; + ret.type2 = fields[1]->type; + ret.offset2 = FFI_ALIGN (fields[0]->size, fields[1]->alignment); + ret.as_elements = 1; + } + return ret; +} +#endif + +/* Allocates a single register, float register, or GRLEN-sized stack slot to a + datum. */ +static void +marshal_atom (call_builder *cb, int type, void *data) +{ + size_t value = 0; + switch (type) + { + case FFI_TYPE_UINT8: + value = *(uint8_t *) data; + break; + case FFI_TYPE_SINT8: + value = *(int8_t *) data; + break; + case FFI_TYPE_UINT16: + value = *(uint16_t *) data; + break; + case FFI_TYPE_SINT16: + value = *(int16_t *) data; + break; + /* 32-bit quantities are always sign-extended in the ABI. */ + case FFI_TYPE_UINT32: + value = *(int32_t *) data; + break; + case FFI_TYPE_SINT32: + value = *(int32_t *) data; + break; +#if __SIZEOF_POINTER__ == 8 + case FFI_TYPE_UINT64: + value = *(uint64_t *) data; + break; + case FFI_TYPE_SINT64: + value = *(int64_t *) data; + break; +#endif + case FFI_TYPE_POINTER: + value = *(size_t *) data; + break; + +#if ABI_FRLEN >= 32 + case FFI_TYPE_FLOAT: + *(float *)(cb->aregs->fa + cb->used_float++) = *(float *) data; + return; +#endif +#if ABI_FRLEN >= 64 + case FFI_TYPE_DOUBLE: + (cb->aregs->fa[cb->used_float++]) = *(double *) data; + return; +#endif + default: + FFI_ASSERT (0); + break; + } + + if (cb->used_integer == NARGREG) + *cb->used_stack++ = value; + else + cb->aregs->a[cb->used_integer++] = value; +} + +static void +unmarshal_atom (call_builder *cb, int type, void *data) +{ + size_t value; + switch (type) + { +#if ABI_FRLEN >= 32 + case FFI_TYPE_FLOAT: + *(float *) data = *(float *)(cb->aregs->fa + cb->used_float++); + return; +#endif +#if ABI_FRLEN >= 64 + case FFI_TYPE_DOUBLE: + *(double *) data = cb->aregs->fa[cb->used_float++]; + return; +#endif + } + + if (cb->used_integer == NARGREG) + value = *cb->used_stack++; + else + value = cb->aregs->a[cb->used_integer++]; + + switch (type) + { + case FFI_TYPE_UINT8: + case FFI_TYPE_SINT8: + case FFI_TYPE_UINT16: + case FFI_TYPE_SINT16: + case FFI_TYPE_UINT32: + case FFI_TYPE_SINT32: +#if __SIZEOF_POINTER__ == 8 + case FFI_TYPE_UINT64: + case FFI_TYPE_SINT64: +#endif + case FFI_TYPE_POINTER: + *(ffi_arg *)data = value; + break; + default: + FFI_ASSERT (0); + break; + } +} + +/* Allocate and copy a structure that is passed by value on the stack and + return a pointer to it. */ +static void * +allocate_and_copy_struct_to_stack (call_builder *cb, void *data, + ffi_type *type) +{ + size_t dest = cb->next_struct_area - type->size; + + dest = FFI_ALIGN_DOWN (dest, type->alignment); + cb->next_struct_area = dest; + + return memcpy ((char *)cb->stack + dest, data, type->size); +} + +/* Adds an argument to a call, or a not by reference return value. */ +static void +marshal (call_builder *cb, ffi_type *type, int var, void *data) +{ + size_t realign[2]; + +#if ABI_FRLEN + if (!var && type->type == FFI_TYPE_STRUCT) + { + float_struct_info fsi = struct_passed_as_elements (cb, type); + if (fsi.as_elements) + { + marshal_atom (cb, fsi.type1, data); + if (fsi.offset2) + marshal_atom (cb, fsi.type2, ((char *) data) + fsi.offset2); + return; + } + } + + if (!var && cb->used_float < NARGREG + && IS_FLOAT (type->type)) + { + marshal_atom (cb, type->type, data); + return; + } + + double promoted; + if (var && type->type == FFI_TYPE_FLOAT) + { + /* C standard requires promoting float -> double for variable arg. */ + promoted = *(float *) data; + type = &ffi_type_double; + data = &promoted; + } +#endif + + if (type->size > 2 * __SIZEOF_POINTER__) + /* Pass by reference. */ + { + allocate_and_copy_struct_to_stack (cb, data, type); + data = (char *)cb->stack + cb->next_struct_area; + marshal_atom (cb, FFI_TYPE_POINTER, &data); + } + else if (IS_INT (type->type) || type->type == FFI_TYPE_POINTER) + marshal_atom (cb, type->type, data); + else + { + /* Overlong integers, soft-float floats, and structs without special + float handling are treated identically from this point on. */ + + /* Variadics are aligned even in registers. */ + if (type->alignment > __SIZEOF_POINTER__) + { + if (var) + cb->used_integer = FFI_ALIGN (cb->used_integer, 2); + cb->used_stack + = (size_t *) FFI_ALIGN (cb->used_stack, 2 * __SIZEOF_POINTER__); + } + + memcpy (realign, data, type->size); + if (type->size > 0) + marshal_atom (cb, FFI_TYPE_POINTER, realign); + if (type->size > __SIZEOF_POINTER__) + marshal_atom (cb, FFI_TYPE_POINTER, realign + 1); + } +} + +/* For arguments passed by reference returns the pointer, otherwise the arg + is copied (up to MAXCOPYARG bytes). */ +static void * +unmarshal (call_builder *cb, ffi_type *type, int var, void *data) +{ + size_t realign[2]; + void *pointer; + +#if ABI_FRLEN + if (!var && type->type == FFI_TYPE_STRUCT) + { + float_struct_info fsi = struct_passed_as_elements (cb, type); + if (fsi.as_elements) + { + unmarshal_atom (cb, fsi.type1, data); + if (fsi.offset2) + unmarshal_atom (cb, fsi.type2, ((char *) data) + fsi.offset2); + return data; + } + } + + if (!var && cb->used_float < NARGREG + && IS_FLOAT (type->type)) + { + unmarshal_atom (cb, type->type, data); + return data; + } + + if (var && type->type == FFI_TYPE_FLOAT) + { + int m = cb->used_integer; + void *promoted + = m < NARGREG ? cb->aregs->a + m : cb->used_stack + m - NARGREG + 1; + *(float *) promoted = *(double *) promoted; + } +#endif + + if (type->size > 2 * __SIZEOF_POINTER__) + { + /* Pass by reference. */ + unmarshal_atom (cb, FFI_TYPE_POINTER, (char *) &pointer); + return pointer; + } + else if (IS_INT (type->type) || type->type == FFI_TYPE_POINTER) + { + unmarshal_atom (cb, type->type, data); + return data; + } + else + { + /* Overlong integers, soft-float floats, and structs without special + float handling are treated identically from this point on. */ + + /* Variadics are aligned even in registers. */ + if (type->alignment > __SIZEOF_POINTER__) + { + if (var) + cb->used_integer = FFI_ALIGN (cb->used_integer, 2); + cb->used_stack + = (size_t *) FFI_ALIGN (cb->used_stack, 2 * __SIZEOF_POINTER__); + } + + if (type->size > 0) + unmarshal_atom (cb, FFI_TYPE_POINTER, realign); + if (type->size > __SIZEOF_POINTER__) + unmarshal_atom (cb, FFI_TYPE_POINTER, realign + 1); + memcpy (data, realign, type->size); + return data; + } +} + +static int +passed_by_ref (call_builder *cb, ffi_type *type, int var) +{ +#if ABI_FRLEN + if (!var && type->type == FFI_TYPE_STRUCT) + { + float_struct_info fsi = struct_passed_as_elements (cb, type); + if (fsi.as_elements) + return 0; + } +#endif + + return type->size > 2 * __SIZEOF_POINTER__; +} + +/* Perform machine dependent cif processing. */ +ffi_status +ffi_prep_cif_machdep (ffi_cif *cif) +{ + cif->loongarch_nfixedargs = cif->nargs; + return FFI_OK; +} + +/* Perform machine dependent cif processing when we have a variadic + function. */ +ffi_status +ffi_prep_cif_machdep_var (ffi_cif *cif, unsigned int nfixedargs, + unsigned int ntotalargs) +{ + cif->loongarch_nfixedargs = nfixedargs; + return FFI_OK; +} + +/* Low level routine for calling functions. */ +extern void ffi_call_asm (void *stack, struct call_context *regs, + void (*fn) (void), void *closure) FFI_HIDDEN; + +static void +ffi_call_int (ffi_cif *cif, void (*fn) (void), void *rvalue, void **avalue, + void *closure) +{ + /* This is a conservative estimate, assuming a complex return value and + that all remaining arguments are long long / __int128 */ + size_t arg_bytes = cif->bytes; + size_t rval_bytes = 0; + if (rvalue == NULL && cif->rtype->size > 2 * __SIZEOF_POINTER__) + rval_bytes = FFI_ALIGN (cif->rtype->size, STKALIGN); + size_t alloc_size = arg_bytes + rval_bytes + sizeof (call_context); + + /* The assembly code will deallocate all stack data at lower addresses + than the argument region, so we need to allocate the frame and the + return value after the arguments in a single allocation. */ + size_t alloc_base; + /* Argument region must be 16-byte aligned in LP64 ABIs. */ + if (_Alignof(max_align_t) >= STKALIGN) + /* Since sizeof long double is normally 16, the compiler will + guarantee alloca alignment to at least that much. */ + alloc_base = (size_t) alloca (alloc_size); + else + alloc_base = FFI_ALIGN (alloca (alloc_size + STKALIGN - 1), STKALIGN); + + if (rval_bytes) + rvalue = (void *) (alloc_base + arg_bytes); + + call_builder cb; + cb.used_float = cb.used_integer = 0; + cb.aregs = (call_context *) (alloc_base + arg_bytes + rval_bytes); + cb.used_stack = (void *) alloc_base; + cb.stack = (void *) alloc_base; + cb.next_struct_area = arg_bytes; + + int return_by_ref = passed_by_ref (&cb, cif->rtype, 0); + if (return_by_ref) + cb.aregs->a[cb.used_integer++] = (size_t)rvalue; + + int i; + for (i = 0; i < cif->nargs; i++) + marshal (&cb, cif->arg_types[i], i >= cif->loongarch_nfixedargs, + avalue[i]); + + ffi_call_asm ((void *) alloc_base, cb.aregs, fn, closure); + + cb.used_float = cb.used_integer = 0; + if (!return_by_ref && rvalue) + unmarshal (&cb, cif->rtype, 0, rvalue); +} + +void +ffi_call (ffi_cif *cif, void (*fn) (void), void *rvalue, void **avalue) +{ + ffi_call_int (cif, fn, rvalue, avalue, NULL); +} + +void +ffi_call_go (ffi_cif *cif, void (*fn) (void), void *rvalue, void **avalue, + void *closure) +{ + ffi_call_int (cif, fn, rvalue, avalue, closure); +} + +extern void ffi_closure_asm (void) FFI_HIDDEN; + +ffi_status +ffi_prep_closure_loc (ffi_closure *closure, ffi_cif *cif, + void (*fun) (ffi_cif *, void *, void **, void *), + void *user_data, void *codeloc) +{ + uint32_t *tramp = (uint32_t *) &closure->tramp[0]; + uint64_t fn = (uint64_t) (uintptr_t) ffi_closure_asm; + + if (cif->abi <= FFI_FIRST_ABI || cif->abi >= FFI_LAST_ABI) + return FFI_BAD_ABI; + +#if defined(FFI_EXEC_STATIC_TRAMP) + if (ffi_tramp_is_present(closure)) + { + ffi_tramp_set_parms (closure->ftramp, ffi_closure_asm, closure); + goto out; + } +#endif + + /* Fill the dynamic trampoline. We will call ffi_closure_inner with codeloc, + not closure, but as long as the memory is readable it should work. */ + tramp[0] = 0x1800000c; /* pcaddi $t0, 0 (i.e. $t0 <- tramp) */ + tramp[1] = 0x28c0418d; /* ld.d $t1, $t0, 16 */ + tramp[2] = 0x4c0001a0; /* jirl $zero, $t1, 0 */ + tramp[3] = 0x03400000; /* nop */ + tramp[4] = fn; + tramp[5] = fn >> 32; + + __builtin___clear_cache (codeloc, codeloc + FFI_TRAMPOLINE_SIZE); + +#if defined(FFI_EXEC_STATIC_TRAMP) +out: +#endif + closure->cif = cif; + closure->fun = fun; + closure->user_data = user_data; + + return FFI_OK; +} + +extern void ffi_go_closure_asm (void) FFI_HIDDEN; + +ffi_status +ffi_prep_go_closure (ffi_go_closure *closure, ffi_cif *cif, + void (*fun) (ffi_cif *, void *, void **, void *)) +{ + if (cif->abi <= FFI_FIRST_ABI || cif->abi >= FFI_LAST_ABI) + return FFI_BAD_ABI; + + closure->tramp = (void *) ffi_go_closure_asm; + closure->cif = cif; + closure->fun = fun; + return FFI_OK; +} + +/* Called by the assembly code with aregs pointing to saved argument registers + and stack pointing to the stacked arguments. Return values passed in + registers will be reloaded from aregs. */ +void FFI_HIDDEN +ffi_closure_inner (ffi_cif *cif, + void (*fun) (ffi_cif *, void *, void **, void *), + void *user_data, size_t *stack, call_context *aregs) +{ + void **avalue = alloca (cif->nargs * sizeof (void *)); + /* Storage for arguments which will be copied by unmarshal(). We could + theoretically avoid the copies in many cases and use at most 128 bytes + of memory, but allocating disjoint storage for each argument is + simpler. */ + char *astorage = alloca (cif->nargs * MAXCOPYARG); + void *rvalue; + call_builder cb; + int return_by_ref; + int i; + + cb.aregs = aregs; + cb.used_integer = cb.used_float = 0; + cb.used_stack = stack; + + return_by_ref = passed_by_ref (&cb, cif->rtype, 0); + if (return_by_ref) + unmarshal (&cb, &ffi_type_pointer, 0, &rvalue); + else + rvalue = alloca (cif->rtype->size); + + for (i = 0; i < cif->nargs; i++) + avalue[i] + = unmarshal (&cb, cif->arg_types[i], i >= cif->loongarch_nfixedargs, + astorage + i * MAXCOPYARG); + + fun (cif, rvalue, avalue, user_data); + + if (!return_by_ref && cif->rtype->type != FFI_TYPE_VOID) + { + cb.used_integer = cb.used_float = 0; + marshal (&cb, cif->rtype, 0, rvalue); + } +} + +#if defined(FFI_EXEC_STATIC_TRAMP) +void * +ffi_tramp_arch (size_t *tramp_size, size_t *map_size) +{ + extern void *trampoline_code_table; + + *tramp_size = 16; + /* A mapping size of 64K is chosen to cover the page sizes of 4K, 16K, and + 64K. */ + *map_size = 1 << 16; + return &trampoline_code_table; +} +#endif diff --git a/libffi/src/loongarch64/ffitarget.h b/libffi/src/loongarch64/ffitarget.h new file mode 100644 index 000000000000..5a4698af308d --- /dev/null +++ b/libffi/src/loongarch64/ffitarget.h @@ -0,0 +1,82 @@ +/* -----------------------------------------------------------------*-C-*- + ffitarget.h - Copyright (c) 2022 Xu Chenghua + 2022 Cheng Lulu + + Target configuration macros for LoongArch. + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. + + ----------------------------------------------------------------------- */ + +#ifndef LIBFFI_TARGET_H +#define LIBFFI_TARGET_H + +#ifndef LIBFFI_H +#error \ + "Please do not include ffitarget.h directly into your source. Use ffi.h instead." +#endif + +#ifndef __loongarch__ +#error \ + "libffi was configured for a LoongArch target but this does not appear to be a LoongArch compiler." +#endif + +#ifndef LIBFFI_ASM + +typedef unsigned long ffi_arg; +typedef signed long ffi_sarg; + +typedef enum ffi_abi +{ + FFI_FIRST_ABI = 0, + FFI_LP64S, + FFI_LP64F, + FFI_LP64D, + FFI_LAST_ABI, + +#if defined(__loongarch64) +#if defined(__loongarch_soft_float) + FFI_DEFAULT_ABI = FFI_LP64S +#elif defined(__loongarch_single_float) + FFI_DEFAULT_ABI = FFI_LP64F +#elif defined(__loongarch_double_float) + FFI_DEFAULT_ABI = FFI_LP64D +#else +#error unsupported LoongArch floating-point ABI +#endif +#else +#error unsupported LoongArch base architecture +#endif +} ffi_abi; + +#endif /* LIBFFI_ASM */ + +/* ---- Definitions for closures ----------------------------------------- */ + +#define FFI_CLOSURES 1 +#define FFI_GO_CLOSURES 1 +#define FFI_TRAMPOLINE_SIZE 24 +#define FFI_NATIVE_RAW_API 0 +#define FFI_EXTRA_CIF_FIELDS \ + unsigned loongarch_nfixedargs; \ + unsigned loongarch_unused; +#define FFI_TARGET_SPECIFIC_VARIADIC +#endif diff --git a/libffi/src/loongarch64/sysv.S b/libffi/src/loongarch64/sysv.S new file mode 100644 index 000000000000..aa7bde2c1efc --- /dev/null +++ b/libffi/src/loongarch64/sysv.S @@ -0,0 +1,327 @@ +/* ----------------------------------------------------------------------- + sysv.S - Copyright (c) 2022 Xu Chenghua + 2022 Cheng Lulu + + LoongArch Foreign Function Interface + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. + ----------------------------------------------------------------------- */ + +#define LIBFFI_ASM +#include +#include + +/* Define aliases so that we can handle all ABIs uniformly. */ + +#if __SIZEOF_POINTER__ == 8 +# define PTRS 8 +# define LARG ld.d +# define SARG st.d +#else +# define PTRS 4 +# define LARG ld.w +# define SARG st.w +#endif + +#if defined(__loongarch_single_float) +# define FLTS 4 +# define FLD fld.w +# define FST fst.w +#elif defined(__loongarch_double_float) +# define FLTS 8 +# define FLARG fld.d +# define FSARG fst.d +#elif defined(__loongarch_soft_float) +# define FLTS 0 +#else +#error unsupported LoongArch floating-point ABI +#endif + + .text + .globl ffi_call_asm + .type ffi_call_asm, @function + .hidden ffi_call_asm +/* struct call_context + { + ABI_FLOAT fa[8]; + size_t a[10]; + } + + - 8 floating point parameter/result registers (fa[0] - fa[7]) + - 8 integer parameter/result registers (a[0] - a[7]) + - 2 registers used by the assembly code to in-place construct its own stack + frame. + - frame pointer (a[8]) + - return address (a[9]) + + void ffi_call_asm (size_t *stackargs, struct call_context *regargs, + void (*fn)(void), void *closure); */ + +#define FRAME_LEN (8 * FLTS + 10 * PTRS) + +ffi_call_asm: + .cfi_startproc + + /* We are NOT going to set up an ordinary stack frame. In order to pass + the stacked args to the called function, we adjust our stack pointer + to a0, which is in the _caller's_ alloca area. We establish our own + stack frame at the end of the call_context. + + Anything below the arguments will be freed at this point, although + we preserve the call_context so that it can be read back in the + caller. */ + + .cfi_def_cfa 5, FRAME_LEN # Interim CFA based on a1. + SARG $fp, $a1, FRAME_LEN - 2*PTRS + .cfi_offset 22, -2*PTRS + SARG $ra, $a1, FRAME_LEN - 1*PTRS + .cfi_offset 1, -1*PTRS + + addi.d $fp, $a1, FRAME_LEN + move $sp, $a0 + .cfi_def_cfa 22, 0 # Our frame is fully set up. + + # Load arguments. + move $t1, $a2 + move $t2, $a3 + +#if FLTS + FLARG $fa0, $fp, -FRAME_LEN+0*FLTS + FLARG $fa1, $fp, -FRAME_LEN+1*FLTS + FLARG $fa2, $fp, -FRAME_LEN+2*FLTS + FLARG $fa3, $fp, -FRAME_LEN+3*FLTS + FLARG $fa4, $fp, -FRAME_LEN+4*FLTS + FLARG $fa5, $fp, -FRAME_LEN+5*FLTS + FLARG $fa6, $fp, -FRAME_LEN+6*FLTS + FLARG $fa7, $fp, -FRAME_LEN+7*FLTS +#endif + + LARG $a0, $fp, -FRAME_LEN+8*FLTS+0*PTRS + LARG $a1, $fp, -FRAME_LEN+8*FLTS+1*PTRS + LARG $a2, $fp, -FRAME_LEN+8*FLTS+2*PTRS + LARG $a3, $fp, -FRAME_LEN+8*FLTS+3*PTRS + LARG $a4, $fp, -FRAME_LEN+8*FLTS+4*PTRS + LARG $a5, $fp, -FRAME_LEN+8*FLTS+5*PTRS + LARG $a6, $fp, -FRAME_LEN+8*FLTS+6*PTRS + LARG $a7, $fp, -FRAME_LEN+8*FLTS+7*PTRS + + /* Call */ + jirl $ra, $t1, 0 + +#if FLTS + /* Save return values - only a0/a1 (fa0/fa1) are used. */ + FSARG $fa0, $fp, -FRAME_LEN+0*FLTS + FSARG $fa1, $fp, -FRAME_LEN+1*FLTS +#endif + + SARG $a0, $fp, -FRAME_LEN+8*FLTS+0*PTRS + SARG $a1, $fp, -FRAME_LEN+8*FLTS+1*PTRS + + /* Restore and return. */ + addi.d $sp, $fp, -FRAME_LEN + .cfi_def_cfa 3, FRAME_LEN + LARG $ra, $fp, -1*PTRS + .cfi_restore 1 + LARG $fp, $fp, -2*PTRS + .cfi_restore 22 + jr $ra + .cfi_endproc + .size ffi_call_asm, .-ffi_call_asm + + +/* ffi_closure_asm. Expects address of the passed-in ffi_closure in t0. + void ffi_closure_inner (ffi_cif *cif, + void (*fun)(ffi_cif *, void *, void **, void *), + void *user_data, + size_t *stackargs, struct call_context *regargs) */ + + .globl ffi_closure_asm + .hidden ffi_closure_asm + .type ffi_closure_asm, @function + +ffi_closure_asm: + .cfi_startproc + addi.d $sp, $sp, -FRAME_LEN + .cfi_def_cfa_offset FRAME_LEN + + /* Make a frame. */ + SARG $fp, $sp, FRAME_LEN - 2*PTRS + .cfi_offset 22, -2*PTRS + SARG $ra, $sp, FRAME_LEN - 1*PTRS + .cfi_offset 1, -1*PTRS + addi.d $fp, $sp, FRAME_LEN + + /* Save arguments. */ +#if FLTS + FSARG $fa0, $sp, 0*FLTS + FSARG $fa1, $sp, 1*FLTS + FSARG $fa2, $sp, 2*FLTS + FSARG $fa3, $sp, 3*FLTS + FSARG $fa4, $sp, 4*FLTS + FSARG $fa5, $sp, 5*FLTS + FSARG $fa6, $sp, 6*FLTS + FSARG $fa7, $sp, 7*FLTS +#endif + + SARG $a0, $sp, 8*FLTS+0*PTRS + SARG $a1, $sp, 8*FLTS+1*PTRS + SARG $a2, $sp, 8*FLTS+2*PTRS + SARG $a3, $sp, 8*FLTS+3*PTRS + SARG $a4, $sp, 8*FLTS+4*PTRS + SARG $a5, $sp, 8*FLTS+5*PTRS + SARG $a6, $sp, 8*FLTS+6*PTRS + SARG $a7, $sp, 8*FLTS+7*PTRS + + /* Enter C */ + LARG $a0, $t0, FFI_TRAMPOLINE_SIZE+0*PTRS + LARG $a1, $t0, FFI_TRAMPOLINE_SIZE+1*PTRS + LARG $a2, $t0, FFI_TRAMPOLINE_SIZE+2*PTRS + addi.d $a3, $sp, FRAME_LEN + move $a4, $sp + + bl ffi_closure_inner + + /* Return values. */ +#if FLTS + FLARG $fa0, $sp, 0*FLTS + FLARG $fa1, $sp, 1*FLTS +#endif + + LARG $a0, $sp, 8*FLTS+0*PTRS + LARG $a1, $sp, 8*FLTS+1*PTRS + + /* Restore and return. */ + LARG $ra, $sp, FRAME_LEN-1*PTRS + .cfi_restore 1 + LARG $fp, $sp, FRAME_LEN-2*PTRS + .cfi_restore 22 + addi.d $sp, $sp, FRAME_LEN + .cfi_def_cfa_offset 0 + jr $ra + .cfi_endproc + .size ffi_closure_asm, .-ffi_closure_asm + +/* Static trampoline code table, in which each element is a trampoline. + + The trampoline clobbers t0 and t1, but we don't save them on the stack + because our psABI explicitly says they are scratch registers, at least for + ELF. Our dynamic trampoline is already clobbering them anyway. + + The trampoline has two parameters - target code to jump to and data for + the target code. The trampoline extracts the parameters from its parameter + block (see tramp_table_map()). The trampoline saves the data address in + t0 and jumps to the target code. As ffi_closure_asm() already expects the + data address to be in t0, we don't need a "ffi_closure_asm_alt". */ + +#if defined(FFI_EXEC_STATIC_TRAMP) + .align 16 + .globl trampoline_code_table + .hidden trampoline_code_table + .type trampoline_code_table, @function + +trampoline_code_table: + + .rept 65536 / 16 + pcaddu12i $t1, 16 # 65536 >> 12 + ld.d $t0, $t1, 0 + ld.d $t1, $t1, 8 + jirl $zero, $t1, 0 + .endr + .size trampoline_code_table, .-trampoline_code_table + + .align 2 +#endif + +/* ffi_go_closure_asm. Expects address of the passed-in ffi_go_closure in t2. + void ffi_closure_inner (ffi_cif *cif, + void (*fun)(ffi_cif *, void *, void **, void *), + void *user_data, + size_t *stackargs, struct call_context *regargs) */ + + .globl ffi_go_closure_asm + .hidden ffi_go_closure_asm + .type ffi_go_closure_asm, @function + +ffi_go_closure_asm: + .cfi_startproc + addi.d $sp, $sp, -FRAME_LEN + .cfi_def_cfa_offset FRAME_LEN + + /* Make a frame. */ + SARG $fp, $sp, FRAME_LEN - 2*PTRS + .cfi_offset 22, -2*PTRS + SARG $ra, $sp, FRAME_LEN - 1*PTRS + .cfi_offset 1, -1*PTRS + addi.d $fp, $sp, FRAME_LEN + + /* Save arguments. */ +#if FLTS + FSARG $fa0, $sp, 0*FLTS + FSARG $fa1, $sp, 1*FLTS + FSARG $fa2, $sp, 2*FLTS + FSARG $fa3, $sp, 3*FLTS + FSARG $fa4, $sp, 4*FLTS + FSARG $fa5, $sp, 5*FLTS + FSARG $fa6, $sp, 6*FLTS + FSARG $fa7, $sp, 7*FLTS +#endif + + SARG $a0, $sp, 8*FLTS+0*PTRS + SARG $a1, $sp, 8*FLTS+1*PTRS + SARG $a2, $sp, 8*FLTS+2*PTRS + SARG $a3, $sp, 8*FLTS+3*PTRS + SARG $a4, $sp, 8*FLTS+4*PTRS + SARG $a5, $sp, 8*FLTS+5*PTRS + SARG $a6, $sp, 8*FLTS+6*PTRS + SARG $a7, $sp, 8*FLTS+7*PTRS + + /* Enter C */ + LARG $a0, $t2, 1*PTRS + LARG $a1, $t2, 2*PTRS + move $a2, $t2 + addi.d $a3, $sp, FRAME_LEN + move $a4, $sp + + bl ffi_closure_inner + + /* Return values. */ +#if FLTS + FLARG $fa0, $sp, 0*FLTS + FLARG $fa1, $sp, 1*FLTS +#endif + + LARG $a0, $sp, 8*FLTS+0*PTRS + LARG $a1, $sp, 8*FLTS+1*PTRS + + /* Restore and return. */ + LARG $ra, $sp, FRAME_LEN-1*PTRS + .cfi_restore 1 + LARG $fp, $sp, FRAME_LEN-2*PTRS + .cfi_restore 22 + addi.d $sp, $sp, FRAME_LEN + .cfi_def_cfa_offset 0 + jr $ra + .cfi_endproc + .size ffi_go_closure_asm, .-ffi_go_closure_asm + +#if defined __ELF__ && defined __linux__ + .section .note.GNU-stack,"",%progbits +#endif diff --git a/libgcc/ChangeLog b/libgcc/ChangeLog index 1c9b44fc4e21..53c48ee8cd7a 100644 --- a/libgcc/ChangeLog +++ b/libgcc/ChangeLog @@ -1,3 +1,17 @@ +2023-08-11 Thomas Neumann + + PR libgcc/110956 + * unwind-dw2-fde.c: Associate object with address of unwinding + table. + +2023-08-07 John Ericson + + * configure: Regenerate. + +2023-08-07 Alan Modra + + * configure: Regenerate. + 2023-07-23 Andrew Pinski * config.host (riscv*-*-linux*): Add t-crtstuff to tmake_file. diff --git a/libgcc/unwind-dw2-fde.c b/libgcc/unwind-dw2-fde.c index d7c4a4677548..51129906fac0 100644 --- a/libgcc/unwind-dw2-fde.c +++ b/libgcc/unwind-dw2-fde.c @@ -124,6 +124,9 @@ __register_frame_info_bases (const void *begin, struct object *ob, #endif #ifdef ATOMIC_FDE_FAST_PATH + // Register the object itself to know the base pointer on deregistration. + btree_insert (®istered_frames, (uintptr_type) begin, 1, ob); + // Register the frame in the b-tree uintptr_type range[2]; get_pc_range (ob, range); @@ -175,6 +178,9 @@ __register_frame_info_table_bases (void *begin, struct object *ob, ob->s.b.encoding = DW_EH_PE_omit; #ifdef ATOMIC_FDE_FAST_PATH + // Register the object itself to know the base pointer on deregistration. + btree_insert (®istered_frames, (uintptr_type) begin, 1, ob); + // Register the frame in the b-tree uintptr_type range[2]; get_pc_range (ob, range); @@ -225,22 +231,17 @@ __deregister_frame_info_bases (const void *begin) return ob; #ifdef ATOMIC_FDE_FAST_PATH - // Find the corresponding PC range - struct object lookupob; - lookupob.tbase = 0; - lookupob.dbase = 0; - lookupob.u.single = begin; - lookupob.s.i = 0; - lookupob.s.b.encoding = DW_EH_PE_omit; -#ifdef DWARF2_OBJECT_END_PTR_EXTENSION - lookupob.fde_end = NULL; -#endif - uintptr_type range[2]; - get_pc_range (&lookupob, range); + // Find the originally registered object to get the base pointer. + ob = btree_remove (®istered_frames, (uintptr_type) begin); - // And remove - ob = btree_remove (®istered_frames, range[0]); - bool empty_table = (range[1] - range[0]) == 0; + // Remove the corresponding PC range. + if (ob) + { + uintptr_type range[2]; + get_pc_range (ob, range); + if (range[0] != range[1]) + btree_remove (®istered_frames, range[0]); + } // Deallocate the sort array if any. if (ob && ob->s.b.sorted) @@ -283,12 +284,11 @@ __deregister_frame_info_bases (const void *begin) out: __gthread_mutex_unlock (&object_mutex); - const int empty_table = 0; // The non-atomic path stores all tables. #endif // If we didn't find anything in the lookup data structures then they // were either already destroyed or we tried to remove an empty range. - gcc_assert (in_shutdown || (empty_table || ob)); + gcc_assert (in_shutdown || ob); return (void *) ob; } diff --git a/libgfortran/ChangeLog b/libgfortran/ChangeLog index e780c66c3f69..b63929921eaa 100644 --- a/libgfortran/ChangeLog +++ b/libgfortran/ChangeLog @@ -1,3 +1,27 @@ +2023-08-07 Nick Alcock + + * configure: Regenerate. + +2023-08-07 Alexander von Gluck IV + + * configure: Regenerate. + +2023-08-07 Nick Alcock + + * configure: Regenerate. + +2023-08-07 Nick Alcock + + * configure: Regenerate. + +2023-08-07 H.J. Lu + + * configure: Regenerate. + +2023-08-07 H.J. Lu + + * configure: Regenerate. + 2023-07-21 Andrew Pinski PR libfortran/110759 diff --git a/libgm2/ChangeLog b/libgm2/ChangeLog index b7381e1a9163..221384603c4f 100644 --- a/libgm2/ChangeLog +++ b/libgm2/ChangeLog @@ -1,3 +1,68 @@ +2023-08-12 Gaius Mulley + + PR modula2/110779 + * configure: Regenerate. + * configure.ac: Provide special case test for Darwin cross + configuration. + (GLIBCXX_CONFIGURE): New statement. + (GLIBCXX_CHECK_GETTIMEOFDAY): New statement. + (GLIBCXX_ENABLE_LIBSTDCXX_TIME): New statement. + * libm2iso/wrapclock.cc: New sys/time.h conditional include. + (sys/syscall.h): Conditional include. + (unistd.h): Conditional include. + (GetTimeRealtime): Re-implement. + (SetTimeRealtime): Re-implement. + (timezone): Re-implement. + (istimezone): New function. + (daylight): Re-implement. + (isdst): Re-implement. + (tzname): Re-implement. + +2023-08-09 Gaius Mulley + + PR modula2/110779 + * config.h.in: Regenerate. + * configure: Regenerate. + * configure.ac (AC_CACHE_CHECK): Check for tm_gmtoff field in + struct tm. + (GM2_CHECK_LIB): Check for daylight, timezone and tzname. + * libm2iso/wrapclock.cc (timezone): Guard against absence of + struct tm and tm_gmtoff. + (daylight): Check for daylight. + (timezone): Check for timezone. + (isdst): Check for isdst. + (tzname): Check for tzname. + (GetTimeRealtime): Check for struct timespec. + (SetTimeRealtime): Check for struct timespec. + (InitTimespec): Check for struct timespec. + (KillTimespec): Check for struct timespec. + (SetTimespec): Check for struct timespec. + (GetTimespec): Check for struct timespec. + +2023-08-07 Nick Alcock + + * configure: Regenerate. + +2023-08-07 Alexander von Gluck IV + + * configure: Regenerate. + +2023-08-07 Nick Alcock + + * configure: Regenerate. + +2023-08-07 Nick Alcock + + * configure: Regenerate. + +2023-08-07 H.J. Lu + + * configure: Regenerate. + +2023-08-07 H.J. Lu + + * configure: Regenerate. + 2023-08-05 Gaius Mulley PR modula2/110779 diff --git a/libgm2/config.h.in b/libgm2/config.h.in index 8372055a47a3..f91f5a42f1ec 100644 --- a/libgm2/config.h.in +++ b/libgm2/config.h.in @@ -24,6 +24,9 @@ /* function ctime exists */ #undef HAVE_CTIME +/* function daylight exists */ +#undef HAVE_DAYLIGHT + /* Define to 1 if you have the header file. */ #undef HAVE_DIRECT_H @@ -195,6 +198,9 @@ /* Define to 1 if the system has the type `struct timezone'. */ #undef HAVE_STRUCT_TIMEZONE +/* Define to 1 if the system has the type `struct tm'. */ +#undef HAVE_STRUCT_TM + /* Define to 1 if you have the header file. */ #undef HAVE_SYS_ERRNO_H @@ -240,9 +246,18 @@ /* function times exists */ #undef HAVE_TIMES +/* function timezone exists */ +#undef HAVE_TIMEZONE + /* Define to 1 if you have the header file. */ #undef HAVE_TIME_H +/* Define if struct tm has a tm_gmtoff field. */ +#undef HAVE_TM_TM_GMTOFF + +/* function tzname exists */ +#undef HAVE_TZNAME + /* Define to 1 if you have the header file. */ #undef HAVE_UNISTD_H diff --git a/libgm2/configure b/libgm2/configure index ee5d86ed2875..072d584544ec 100755 --- a/libgm2/configure +++ b/libgm2/configure @@ -3976,6 +3976,42 @@ test -n "$target_alias" && target_alias=${target_alias-$host_alias} +if test "$build" != "$host"; then + # We are being configured with some form of cross compiler. + GLIBCXX_IS_NATIVE=false + case "$host","$target" in + # Darwin crosses can use the host system's libraries and headers, + # because of the fat library support. Of course, it must be the + # same version of Darwin on both sides. Allow the user to + # just say --target=foo-darwin without a version number to mean + # "the version on this system". + *-*-darwin*,*-*-darwin*) + hostos=`echo $host | sed 's/.*-darwin/darwin/'` + targetos=`echo $target | sed 's/.*-darwin/darwin/'` + if test $hostos = $targetos || test $targetos = darwin ; then + GLIBCXX_IS_NATIVE=true + fi + ;; + + *) + + ;; + esac +else + GLIBCXX_IS_NATIVE=true +fi + +# Runs configure.host, and assorted other critical bits. Sets +# up critical shell variables. +GLIBCXX_CONFIGURE + +# For gettimeofday support. +GLIBCXX_CHECK_GETTIMEOFDAY + +# For clock_gettime, nanosleep and sched_yield support. +GLIBCXX_ENABLE_LIBSTDCXX_TIME + + am__api_version='1.15' # Find a good install program. We prefer a C program (faster), @@ -12702,7 +12738,7 @@ else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF -#line 12705 "configure" +#line 12741 "configure" #include "confdefs.h" #if HAVE_DLFCN_H @@ -12808,7 +12844,7 @@ else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF -#line 12811 "configure" +#line 12847 "configure" #include "confdefs.h" #if HAVE_DLFCN_H @@ -16130,7 +16166,58 @@ _ACEOF fi +ac_fn_c_check_type "$LINENO" "struct tm" "ac_cv_type_struct_tm" "$ac_includes_default" +if test "x$ac_cv_type_struct_tm" = xyes; then : +cat >>confdefs.h <<_ACEOF +#define HAVE_STRUCT_TM 1 +_ACEOF + + +fi + + +# Check if struct tm contains the tm_gmtoff field. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for tm_gmtoff in struct tm" >&5 +$as_echo_n "checking for tm_gmtoff in struct tm... " >&6; } +if ${ac_cv_struct_tm_gmtoff+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + #include + +int +main () +{ + + struct tm tm; + tm.tm_gmtoff = 1; + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_struct_tm_gmtoff=yes +else + ac_cv_struct_tm_gmtoff=no + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_struct_tm_gmtoff" >&5 +$as_echo "$ac_cv_struct_tm_gmtoff" >&6; } + +if (test "$ac_cv_struct_tm_gmtoff" = "yes"); then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking m2 front end detects struct tm with the tm_gmtoff field." >&5 +$as_echo_n "checking m2 front end detects struct tm with the tm_gmtoff field.... " >&6; } + +$as_echo "#define HAVE_TM_TM_GMTOFF 1" >>confdefs.h + +fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' @@ -17305,6 +17392,75 @@ $as_echo "#define HAVE_CREAT 1" >>confdefs.h fi + { $as_echo "$as_me:${as_lineno-$LINENO}: checking m2 front end checking c library for daylight" >&5 +$as_echo_n "checking m2 front end checking c library for daylight... " >&6; } + if test x$gcc_no_link != xyes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for daylight in -lc" >&5 +$as_echo_n "checking for daylight in -lc... " >&6; } +if ${ac_cv_lib_c_daylight+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lc $LIBS" +if test x$gcc_no_link = xyes; then + as_fn_error $? "Link tests are not allowed after GCC_NO_EXECUTABLES." "$LINENO" 5 +fi +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char daylight (); +int +main () +{ +return daylight (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_c_daylight=yes +else + ac_cv_lib_c_daylight=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_c_daylight" >&5 +$as_echo "$ac_cv_lib_c_daylight" >&6; } +if test "x$ac_cv_lib_c_daylight" = xyes; then : + +$as_echo "#define HAVE_DAYLIGHT 1" >>confdefs.h + +else + + $as_echo "#undef HAVE_DAYLIGHT" >>confdefs.h + +fi + + else + if test "x$ac_cv_lib_c_daylight" = xyes; then + +$as_echo "#define HAVE_DAYLIGHT 1" >>confdefs.h + + elif test "x$ac_cv_func_daylight" = xyes; then + +$as_echo "#define HAVE_DAYLIGHT 1" >>confdefs.h + + else + + $as_echo "#undef HAVE_DAYLIGHT" >>confdefs.h + + fi + fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking m2 front end checking c library for dup" >&5 $as_echo_n "checking m2 front end checking c library for dup... " >&6; } if test x$gcc_no_link != xyes; then @@ -19237,6 +19393,144 @@ $as_echo "#define HAVE_TIMES 1" >>confdefs.h fi + { $as_echo "$as_me:${as_lineno-$LINENO}: checking m2 front end checking c library for timezone" >&5 +$as_echo_n "checking m2 front end checking c library for timezone... " >&6; } + if test x$gcc_no_link != xyes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for timezone in -lc" >&5 +$as_echo_n "checking for timezone in -lc... " >&6; } +if ${ac_cv_lib_c_timezone+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lc $LIBS" +if test x$gcc_no_link = xyes; then + as_fn_error $? "Link tests are not allowed after GCC_NO_EXECUTABLES." "$LINENO" 5 +fi +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char timezone (); +int +main () +{ +return timezone (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_c_timezone=yes +else + ac_cv_lib_c_timezone=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_c_timezone" >&5 +$as_echo "$ac_cv_lib_c_timezone" >&6; } +if test "x$ac_cv_lib_c_timezone" = xyes; then : + +$as_echo "#define HAVE_TIMEZONE 1" >>confdefs.h + +else + + $as_echo "#undef HAVE_TIMEZONE" >>confdefs.h + +fi + + else + if test "x$ac_cv_lib_c_timezone" = xyes; then + +$as_echo "#define HAVE_TIMEZONE 1" >>confdefs.h + + elif test "x$ac_cv_func_timezone" = xyes; then + +$as_echo "#define HAVE_TIMEZONE 1" >>confdefs.h + + else + + $as_echo "#undef HAVE_TIMEZONE" >>confdefs.h + + fi + fi + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking m2 front end checking c library for tzname" >&5 +$as_echo_n "checking m2 front end checking c library for tzname... " >&6; } + if test x$gcc_no_link != xyes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for tzname in -lc" >&5 +$as_echo_n "checking for tzname in -lc... " >&6; } +if ${ac_cv_lib_c_tzname+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lc $LIBS" +if test x$gcc_no_link = xyes; then + as_fn_error $? "Link tests are not allowed after GCC_NO_EXECUTABLES." "$LINENO" 5 +fi +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char tzname (); +int +main () +{ +return tzname (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_c_tzname=yes +else + ac_cv_lib_c_tzname=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_c_tzname" >&5 +$as_echo "$ac_cv_lib_c_tzname" >&6; } +if test "x$ac_cv_lib_c_tzname" = xyes; then : + +$as_echo "#define HAVE_TZNAME 1" >>confdefs.h + +else + + $as_echo "#undef HAVE_TZNAME" >>confdefs.h + +fi + + else + if test "x$ac_cv_lib_c_tzname" = xyes; then + +$as_echo "#define HAVE_TZNAME 1" >>confdefs.h + + elif test "x$ac_cv_func_tzname" = xyes; then + +$as_echo "#define HAVE_TZNAME 1" >>confdefs.h + + else + + $as_echo "#undef HAVE_TZNAME" >>confdefs.h + + fi + fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking m2 front end checking c library for unlink" >&5 $as_echo_n "checking m2 front end checking c library for unlink... " >&6; } if test x$gcc_no_link != xyes; then diff --git a/libgm2/configure.ac b/libgm2/configure.ac index d64a8ee80a9f..92e76c9346c9 100644 --- a/libgm2/configure.ac +++ b/libgm2/configure.ac @@ -42,6 +42,42 @@ AC_CANONICAL_SYSTEM target_alias=${target_alias-$host_alias} AC_SUBST(target_alias) +if test "$build" != "$host"; then + # We are being configured with some form of cross compiler. + GLIBCXX_IS_NATIVE=false + case "$host","$target" in + # Darwin crosses can use the host system's libraries and headers, + # because of the fat library support. Of course, it must be the + # same version of Darwin on both sides. Allow the user to + # just say --target=foo-darwin without a version number to mean + # "the version on this system". + *-*-darwin*,*-*-darwin*) + hostos=`echo $host | sed 's/.*-darwin/darwin/'` + targetos=`echo $target | sed 's/.*-darwin/darwin/'` + if test $hostos = $targetos || test $targetos = darwin ; then + GLIBCXX_IS_NATIVE=true + fi + ;; + + *) + GCC_NO_EXECUTABLES + ;; + esac +else + GLIBCXX_IS_NATIVE=true +fi + +# Runs configure.host, and assorted other critical bits. Sets +# up critical shell variables. +GLIBCXX_CONFIGURE + +# For gettimeofday support. +GLIBCXX_CHECK_GETTIMEOFDAY + +# For clock_gettime, nanosleep and sched_yield support. +GLIBCXX_ENABLE_LIBSTDCXX_TIME + + AM_INIT_AUTOMAKE([1.15.1 no-define foreign no-dist -Wall -Wno-portability]) AH_TEMPLATE(PACKAGE, [Name of package]) @@ -187,7 +223,25 @@ else multilib_arg= fi -AC_CHECK_TYPES([struct timezone, struct stat, struct timespec, struct timeval]) +AC_CHECK_TYPES([struct timezone, struct stat, struct timespec, struct timeval, struct tm]) + +# Check if struct tm contains the tm_gmtoff field. +AC_CACHE_CHECK(for tm_gmtoff in struct tm, ac_cv_struct_tm_gmtoff, + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([ + #include + ], [ + struct tm tm; + tm.tm_gmtoff = 1; + ])], + [ac_cv_struct_tm_gmtoff=yes], + [ac_cv_struct_tm_gmtoff=no] + ) +) + +if (test "$ac_cv_struct_tm_gmtoff" = "yes"); then + AC_MSG_CHECKING([m2 front end detects struct tm with the tm_gmtoff field.]) + AC_DEFINE(HAVE_TM_TM_GMTOFF, 1, [Define if struct tm has a tm_gmtoff field.]) +fi AC_LANG_C # Check the compiler. @@ -230,6 +284,7 @@ GM2_CHECK_LIB([c],[clock_settime],[CLOCK_SETTIME]) GM2_CHECK_LIB([c],[close],[CLOSE]) GM2_CHECK_LIB([c],[ctime],[CTIME]) GM2_CHECK_LIB([c],[creat],[CREAT]) +GM2_CHECK_LIB([c],[daylight],[DAYLIGHT]) GM2_CHECK_LIB([c],[dup],[DUP]) GM2_CHECK_LIB([c],[execve],[EXECVE]) GM2_CHECK_LIB([c],[exit],[EXIT]) @@ -258,6 +313,8 @@ GM2_CHECK_LIB([c],[strsignal],[STRSIGNAL]) GM2_CHECK_LIB([c],[strtod],[STRTOD]) GM2_CHECK_LIB([c],[strtold],[STRTOLD]) GM2_CHECK_LIB([c],[times],[TIMES]) +GM2_CHECK_LIB([c],[timezone],[TIMEZONE]) +GM2_CHECK_LIB([c],[tzname],[TZNAME]) GM2_CHECK_LIB([c],[unlink],[UNLINK]) GM2_CHECK_LIB([c],[wait],[WAIT]) GM2_CHECK_LIB([c],[write],[WRITE]) diff --git a/libgm2/libm2iso/wrapclock.cc b/libgm2/libm2iso/wrapclock.cc index 7ee1f25c2fb8..1f4ca8c325d0 100644 --- a/libgm2/libm2iso/wrapclock.cc +++ b/libgm2/libm2iso/wrapclock.cc @@ -51,6 +51,18 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see #include "time.h" #endif +// Conditional inclusion of sys/time.h for gettimeofday +#if !defined(_GLIBCXX_USE_CLOCK_MONOTONIC) && \ + !defined(_GLIBCXX_USE_CLOCK_REALTIME) && \ + defined(_GLIBCXX_USE_GETTIMEOFDAY) +#include +#endif + +#if defined(_GLIBCXX_USE_CLOCK_GETTIME_SYSCALL) +#include +#include +#endif + #if defined(HAVE_MALLOC_H) #include "malloc.h" #endif @@ -64,103 +76,82 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see #endif -extern "C" long int -EXPORT(timezone) (void) -{ - struct tm result; - struct timespec ts; - - if (clock_gettime (CLOCK_REALTIME, &ts) == 0) - { - time_t time = ts.tv_sec; - localtime_r (&time, &result); - return result.tm_gmtoff; - } - else - return timezone; -} - - -extern "C" int -EXPORT(daylight) (void) -{ - return daylight; -} - - -/* isdst returns 1 if daylight saving time is currently in effect and - returns 0 if it is not. */ - -extern "C" int -EXPORT(isdst) (void) -{ - struct tm result; - struct timespec ts; - - if (clock_gettime (CLOCK_REALTIME, &ts) == 0) - { - time_t time = ts.tv_sec; - localtime_r (&time, &result); - return result.tm_isdst; - } - else - return 0; -} - - -/* tzname returns the string associated with the local timezone. - The daylight value is 0 or 1. The value 0 returns the non - daylight saving timezone string and the value of 1 returns the - daylight saving timezone string. */ - -extern "C" char * -EXPORT(tzname) (int daylight) -{ - return tzname[daylight]; -} - - /* GetTimeRealtime performs return gettime (CLOCK_REALTIME, ts). gettime returns 0 on success and -1 on failure. If the underlying system does not have gettime then GetTimeRealtime returns 1. */ +#if defined(HAVE_STRUCT_TIMESPEC) && defined(_GLIBCXX_USE_CLOCK_REALTIME) extern "C" int EXPORT(GetTimeRealtime) (struct timespec *ts) { -#if defined(HAVE_CLOCK_GETTIME) - return clock_gettime (CLOCK_REALTIME, ts); + timespec tp; +#if defined(_GLIBCXX_USE_CLOCK_GETTIME_SYSCALL) + return syscall (SYS_clock_gettime, CLOCK_REALTIME, ts); #else - return 1; + return clock_gettime (CLOCK_REALTIME, ts); #endif } +#else + +extern "C" int +EXPORT(GetTimeRealtime) (void *ts) +{ + return 1; +} +#endif /* SetTimeRealtime performs return settime (CLOCK_REALTIME, ts). gettime returns 0 on success and -1 on failure. If the underlying system does not have gettime then GetTimeRealtime returns 1. */ +#if defined(HAVE_STRUCT_TIMESPEC) && defined(_GLIBCXX_USE_CLOCK_REALTIME) extern "C" int EXPORT(SetTimeRealtime) (struct timespec *ts) { -#if defined(HAVE_CLOCK_GETTIME) +#if defined(_GLIBCXX_USE_CLOCK_SETTIME_SYSCALL) + return syscall (SYS_clock_settime, CLOCK_REALTIME, ts); +#elif defined(HAVE_CLOCK_SETTIME) return clock_settime (CLOCK_REALTIME, ts); #else return 1; #endif } +#else + +extern "C" int +EXPORT(SetTimeRealtime) (void *ts) +{ + return 1; +} +#endif /* InitTimespec returns a newly created opaque type. */ +#if defined(HAVE_STRUCT_TIMESPEC) extern "C" struct timespec * EXPORT(InitTimespec) (void) { +#if defined(HAVE_STRUCT_TIMESPEC) && defined(HAVE_MALLOC_H) return (struct timespec *)malloc (sizeof (struct timespec)); +#else + return NULL; +#endif } +#else + +extern "C" void * +EXPORT(InitTimespec) (void) +{ + return NULL; +} +#endif /* KillTimeval deallocates the memory associated with an opaque type. */ +#if defined(HAVE_STRUCT_TIMESPEC) extern "C" struct timespec * EXPORT(KillTimespec) (void *ts) { @@ -170,27 +161,155 @@ EXPORT(KillTimespec) (void *ts) return NULL; } +#else + +extern "C" void * +EXPORT(KillTimespec) (void *ts) +{ + return NULL; +} +#endif /* GetTimespec retrieves the number of seconds and nanoseconds from the - timespec. */ + timespec. 1 is returned if successful and 0 otherwise. */ -extern "C" void +#if defined(HAVE_STRUCT_TIMESPEC) +extern "C" int EXPORT(GetTimespec) (timespec *ts, unsigned long *sec, unsigned long *nano) { +#if defined(HAVE_STRUCT_TIMESPEC) *sec = ts->tv_sec; *nano = ts->tv_nsec; + return 1; +#else + return 0; +#endif } +#else +extern "C" int +EXPORT(GetTimespec) (void *ts, unsigned long *sec, unsigned long *nano) +{ + return 0; +} +#endif -/* SetTimespec sets the number of seconds and nanoseconds into timespec. */ +/* SetTimespec sets the number of seconds and nanoseconds into timespec. + 1 is returned if successful and 0 otherwise. */ -extern "C" void +#if defined(HAVE_STRUCT_TIMESPEC) +extern "C" int EXPORT(SetTimespec) (timespec *ts, unsigned long sec, unsigned long nano) { +#if defined(HAVE_STRUCT_TIMESPEC) ts->tv_sec = sec; ts->tv_nsec = nano; + return 1; +#else + return 0; +#endif } +#else + +extern "C" int +EXPORT(SetTimespec) (void *ts, unsigned long sec, unsigned long nano) +{ + return 0; +} +#endif + +extern "C" long int +EXPORT(timezone) (void) +{ +#if defined(HAVE_STRUCT_TIMESPEC) + struct tm result; + struct timespec ts; + +#if defined(HAVE_TM_TM_GMTOFF) + if (EXPORT(GetTimeRealtime) (&ts) == 0) + { + time_t time = ts.tv_sec; + localtime_r (&time, &result); + return result.tm_gmtoff; + } + else +#endif +#endif + { +#if defined(HAVE_TIMEZONE) + return timezone; +#else + return 0; +#endif + } +} + +/* istimezone returns 1 if timezone in wrapclock.cc can resolve the + timezone value using the timezone C library call or by using + clock_gettime, localtime_r and tm_gmtoff. */ + +extern "C" int +EXPORT(istimezone) (void) +{ +#if defined(HAVE_STRUCT_TIMESPEC) +#if defined(HAVE_TM_TM_GMTOFF) +#if defined(_GLIBCXX_USE_CLOCK_REALTIME) + return 1; +#endif +#endif +#endif + return 0; +} + +extern "C" int +EXPORT(daylight) (void) +{ +#if defined(HAVE_DAYLIGHT) + return daylight; +#else + return 0; +#endif +} + +/* isdst returns 1 if daylight saving time is currently in effect and + returns 0 if it is not. */ + +extern "C" int +EXPORT(isdst) (void) +{ +#if defined(HAVE_STRUCT_TIMESPEC) + struct tm result; + struct timespec ts; + + if (EXPORT(GetTimeRealtime) (&ts) == 0) + { + time_t time = ts.tv_sec; + localtime_r (&time, &result); + return result.tm_isdst; + } + else + return 0; +#else + return 0; +#endif +} + +/* tzname returns the string associated with the local timezone. + The daylight value is 0 or 1. The value 0 returns the non + daylight saving timezone string and the value of 1 returns the + daylight saving timezone string. It returns NULL if tzname is + unavailable. */ + +extern "C" char * +EXPORT(tzname) (int daylight) +{ +#if defined(HAVE_TZNAME) + return tzname[daylight]; +#else + return NULL; +#endif +} /* init - init/finish functions for the module */ diff --git a/libgomp/ChangeLog b/libgomp/ChangeLog index 034472963246..6742cb79074c 100644 --- a/libgomp/ChangeLog +++ b/libgomp/ChangeLog @@ -1,3 +1,95 @@ +2023-08-25 Sandra Loosemore + + * libgomp.texi (OpenMP 5.0): Imperfectly-nested loops are done. + +2023-08-25 Sandra Loosemore + + * testsuite/libgomp.fortran/imperfect-destructor.f90: New. + * testsuite/libgomp.fortran/imperfect1.f90: New. + * testsuite/libgomp.fortran/imperfect2.f90: New. + * testsuite/libgomp.fortran/imperfect3.f90: New. + * testsuite/libgomp.fortran/imperfect4.f90: New. + * testsuite/libgomp.fortran/target-imperfect1.f90: New. + * testsuite/libgomp.fortran/target-imperfect2.f90: New. + * testsuite/libgomp.fortran/target-imperfect3.f90: New. + * testsuite/libgomp.fortran/target-imperfect4.f90: New. + +2023-08-25 Sandra Loosemore + + * testsuite/libgomp.c-c++-common/imperfect1.c: New. + * testsuite/libgomp.c-c++-common/imperfect2.c: New. + * testsuite/libgomp.c-c++-common/imperfect3.c: New. + * testsuite/libgomp.c-c++-common/imperfect4.c: New. + * testsuite/libgomp.c-c++-common/imperfect5.c: New. + * testsuite/libgomp.c-c++-common/imperfect6.c: New. + * testsuite/libgomp.c-c++-common/target-imperfect1.c: New. + * testsuite/libgomp.c-c++-common/target-imperfect2.c: New. + * testsuite/libgomp.c-c++-common/target-imperfect3.c: New. + * testsuite/libgomp.c-c++-common/target-imperfect4.c: New. + +2023-08-25 Sandra Loosemore + + * testsuite/libgomp.c++/attrs-imperfect1.C: New test. + * testsuite/libgomp.c++/attrs-imperfect2.C: New test. + * testsuite/libgomp.c++/attrs-imperfect3.C: New test. + * testsuite/libgomp.c++/attrs-imperfect4.C: New test. + * testsuite/libgomp.c++/attrs-imperfect5.C: New test. + * testsuite/libgomp.c++/attrs-imperfect6.C: New test. + * testsuite/libgomp.c++/imperfect-class-1.C: New test. + * testsuite/libgomp.c++/imperfect-class-2.C: New test. + * testsuite/libgomp.c++/imperfect-class-3.C: New test. + * testsuite/libgomp.c++/imperfect-destructor.C: New test. + * testsuite/libgomp.c++/imperfect-template-1.C: New test. + * testsuite/libgomp.c++/imperfect-template-2.C: New test. + * testsuite/libgomp.c++/imperfect-template-3.C: New test. + +2023-08-22 Francois-Xavier Coudert + + * testsuite/lib/libgomp.exp: Add effective target. + * testsuite/libgomp.c/simd-math-1.c: Avoid calling nonstandard + functions. + +2023-08-22 Tobias Burnus + + * libgomp.texi (OpenMP 5.2 status): Add depobj with + destroy-var argument as 'N'. Mark defaultmap with + 'all' category as 'Y'. + +2023-08-19 Tobias Burnus + + PR middle-end/111017 + * testsuite/libgomp.c-c++-common/non-rect-loop-1.c: New test. + +2023-08-17 Tobias Burnus + + PR libgomp/111024 + * allocator.c (gomp_init_libnuma): Call numa_available; if + not available or not returning 0, disable libnuma usage. + +2023-08-07 Nick Alcock + + * configure: Regenerate. + +2023-08-07 Alexander von Gluck IV + + * configure: Regenerate. + +2023-08-07 Nick Alcock + + * configure: Regenerate. + +2023-08-07 Nick Alcock + + * configure: Regenerate. + +2023-08-07 H.J. Lu + + * configure: Regenerate. + +2023-08-07 H.J. Lu + + * configure: Regenerate. + 2023-07-29 Tobias Burnus * target.c (omp_target_memcpy_rect_worker): Undo dim=1 change for diff --git a/libgomp/allocator.c b/libgomp/allocator.c index 90f2dcb60d64..b4e50e2ad72a 100644 --- a/libgomp/allocator.c +++ b/libgomp/allocator.c @@ -118,6 +118,17 @@ gomp_init_libnuma (void) dlclose (handle); return; } + if (handle) + { + int (*numa_available) (void); + numa_available + = (__typeof (numa_available)) dlsym (handle, "numa_available"); + if (!numa_available || numa_available () != 0) + { + dlclose (handle); + handle = NULL; + } + } if (!handle) { __atomic_store_n (&libnuma_data, data, MEMMODEL_RELEASE); diff --git a/libgomp/libgomp.texi b/libgomp/libgomp.texi index 073c181f6273..4aad8cc52f47 100644 --- a/libgomp/libgomp.texi +++ b/libgomp/libgomp.texi @@ -200,7 +200,7 @@ The OpenMP 4.5 specification is fully supported. @item @code{!=} as relational-op in canonical loop form for C/C++ @tab Y @tab @item @code{nonmonotonic} as default loop schedule modifier for worksharing-loop constructs @tab Y @tab -@item Collapse of associated loops that are imperfectly nested loops @tab N @tab +@item Collapse of associated loops that are imperfectly nested loops @tab Y @tab @item Clauses @code{if}, @code{nontemporal} and @code{order(concurrent)} in @code{simd} construct @tab Y @tab @item @code{atomic} constructs in @code{simd} @tab Y @tab @@ -378,6 +378,8 @@ to address of matching mapped list item per 5.1, Sect. 2.21.7.2 @tab N @tab sentinel is warned for with with @code{-Wsurprising} (enabled by @code{-Wall}). Unknown clauses are always rejected with an error.} @item Clauses on @code{end} directive can be on directive @tab Y @tab +@item @code{destroy} clause with destroy-var argument on @code{depobj} + @tab N @tab @item Deprecation of no-argument @code{destroy} clause on @code{depobj} @tab N @tab @item @code{linear} clause syntax changes and @code{step} modifier @tab Y @tab @@ -426,7 +428,7 @@ to address of matching mapped list item per 5.1, Sect. 2.21.7.2 @tab N @tab @code{omp_invalid_device} enum/PARAMETER @tab Y @tab @item Initial value of @var{default-device-var} ICV with @code{OMP_TARGET_OFFLOAD=mandatory} @tab Y @tab -@item @code{all} as @emph{implicit-behavior} for @code{defaultmap} @tab N @tab +@item @code{all} as @emph{implicit-behavior} for @code{defaultmap} @tab Y @tab @item @emph{interop_types} in any position of the modifier list for the @code{init} clause of the @code{interop} construct @tab N @tab @end multitable diff --git a/libgomp/testsuite/lib/libgomp.exp b/libgomp/testsuite/lib/libgomp.exp index 2f9e538278fd..a143b5d0defa 100644 --- a/libgomp/testsuite/lib/libgomp.exp +++ b/libgomp/testsuite/lib/libgomp.exp @@ -377,6 +377,25 @@ proc offload_target_to_openacc_device_type { offload_target } { } } +# Return 1 if certain nonstandard math functions are available +# on the target: gamma, scalb, significand, and their float variants. +proc check_effective_target_nonstandard_math_functions { } { + return [check_no_compiler_messages nonstandard_math_functions executable { + #include + int main() { + float x = 42; + double y = 42; + x = gammaf (x); + x = __builtin_scalbf (x, 2.f); + x =__builtin_significandf (x); + y = gamma (y); + y = __builtin_scalb (y, 2.); + y =__builtin_significand (y); + return 0; + } + } "-lm" ] +} + # Return 1 if compiling for the specified offload target # Takes -foffload=... into account by checking OFFLOAD_TARGET_NAMES= # in the -v compiler output. diff --git a/libgomp/testsuite/libgomp.c++/attrs-imperfect1.C b/libgomp/testsuite/libgomp.c++/attrs-imperfect1.C new file mode 100644 index 000000000000..4cbea6280ccb --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/attrs-imperfect1.C @@ -0,0 +1,76 @@ +/* { dg-do run } */ + +static int f1count[3], f2count[3]; + +#ifndef __cplusplus +extern void abort (void); +#else +extern "C" void abort (void); +#endif + +int f1 (int depth, int iter) +{ + f1count[depth]++; + return iter; +} + +int f2 (int depth, int iter) +{ + f2count[depth]++; + return iter; +} + +void s1 (int a1, int a2, int a3) +{ + int i, j, k; + + [[ omp :: directive (for, collapse(3)) ]] + for (i = 0; i < a1; i++) + { + f1 (0, i); + for (j = 0; j < a2; j++) + { + f1 (1, j); + for (k = 0; k < a3; k++) + { + f1 (2, k); + f2 (2, k); + } + f2 (1, j); + } + f2 (0, i); + } +} + +int +main (void) +{ + f1count[0] = 0; + f1count[1] = 0; + f1count[2] = 0; + f2count[0] = 0; + f2count[1] = 0; + f2count[2] = 0; + + s1 (3, 4, 5); + + /* All intervening code at the same depth must be executed the same + number of times. */ + if (f1count[0] != f2count[0]) abort (); + if (f1count[1] != f2count[1]) abort (); + if (f1count[2] != f2count[2]) abort (); + + /* Intervening code must be executed at least as many times as the loop + that encloses it. */ + if (f1count[0] < 3) abort (); + if (f1count[1] < 3 * 4) abort (); + + /* Intervening code must not be executed more times than the number + of logical iterations. */ + if (f1count[0] > 3 * 4 * 5) abort (); + if (f1count[1] > 3 * 4 * 5) abort (); + + /* Check that the innermost loop body is executed exactly the number + of logical iterations expected. */ + if (f1count[2] != 3 * 4 * 5) abort (); +} diff --git a/libgomp/testsuite/libgomp.c++/attrs-imperfect2.C b/libgomp/testsuite/libgomp.c++/attrs-imperfect2.C new file mode 100644 index 000000000000..9fb82d9c817b --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/attrs-imperfect2.C @@ -0,0 +1,114 @@ +/* { dg-do run } */ + +static int f1count[3], f2count[3]; +static int g1count[3], g2count[3]; + +#ifndef __cplusplus +extern void abort (void); +#else +extern "C" void abort (void); +#endif + +int f1 (int depth, int iter) +{ + f1count[depth]++; + return iter; +} + +int f2 (int depth, int iter) +{ + f2count[depth]++; + return iter; +} + +int g1 (int depth, int iter) +{ + g1count[depth]++; + return iter; +} + +int g2 (int depth, int iter) +{ + g2count[depth]++; + return iter; +} + +void s1 (int a1, int a2, int a3) +{ + int i, j, k; + + [[ omp :: directive (for, collapse(3)) ]] + for (i = 0; i < a1; i++) + { + f1 (0, i); + { + g1 (0, i); + for (j = 0; j < a2; j++) + { + f1 (1, j); + { + g1 (1, j); + for (k = 0; k < a3; k++) + { + f1 (2, k); + { + g1 (2, k); + g2 (2, k); + } + f2 (2, k); + } + g2 (1, j); + } + f2 (1, j); + } + g2 (0, i); + } + f2 (0, i); + } +} + +int +main (void) +{ + f1count[0] = 0; + f1count[1] = 0; + f1count[2] = 0; + f2count[0] = 0; + f2count[1] = 0; + f2count[2] = 0; + + g1count[0] = 0; + g1count[1] = 0; + g1count[2] = 0; + g2count[0] = 0; + g2count[1] = 0; + g2count[2] = 0; + + s1 (3, 4, 5); + + /* All intervening code at the same depth must be executed the same + number of times. */ + if (f1count[0] != f2count[0]) abort (); + if (f1count[1] != f2count[1]) abort (); + if (f1count[2] != f2count[2]) abort (); + if (g1count[0] != f1count[0]) abort (); + if (g2count[0] != f1count[0]) abort (); + if (g1count[1] != f1count[1]) abort (); + if (g2count[1] != f1count[1]) abort (); + if (g1count[2] != f1count[2]) abort (); + if (g2count[2] != f1count[2]) abort (); + + /* Intervening code must be executed at least as many times as the loop + that encloses it. */ + if (f1count[0] < 3) abort (); + if (f1count[1] < 3 * 4) abort (); + + /* Intervening code must not be executed more times than the number + of logical iterations. */ + if (f1count[0] > 3 * 4 * 5) abort (); + if (f1count[1] > 3 * 4 * 5) abort (); + + /* Check that the innermost loop body is executed exactly the number + of logical iterations expected. */ + if (f1count[2] != 3 * 4 * 5) abort (); +} diff --git a/libgomp/testsuite/libgomp.c++/attrs-imperfect3.C b/libgomp/testsuite/libgomp.c++/attrs-imperfect3.C new file mode 100644 index 000000000000..51cb23aa02db --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/attrs-imperfect3.C @@ -0,0 +1,119 @@ +/* { dg-do run } */ + +/* Like imperfect2.c, but includes bindings in the blocks. */ + +static int f1count[3], f2count[3]; +static int g1count[3], g2count[3]; + +#ifndef __cplusplus +extern void abort (void); +#else +extern "C" void abort (void); +#endif + +int f1 (int depth, int iter) +{ + f1count[depth]++; + return iter; +} + +int f2 (int depth, int iter) +{ + f2count[depth]++; + return iter; +} + +int g1 (int depth, int iter) +{ + g1count[depth]++; + return iter; +} + +int g2 (int depth, int iter) +{ + g2count[depth]++; + return iter; +} + +void s1 (int a1, int a2, int a3) +{ + int i, j, k; + + [[ omp :: directive (for, collapse(3)) ]] + for (i = 0; i < a1; i++) + { + int local0 = 0; + f1 (local0, i); + { + g1 (local0, i); + for (j = 0; j < a2; j++) + { + int local1 = 1; + f1 (local1, j); + { + g1 (local1, j); + for (k = 0; k < a3; k++) + { + int local2 = 2; + f1 (local2, k); + { + g1 (local2, k); + g2 (local2, k); + } + f2 (local2, k); + } + g2 (local1, j); + } + f2 (local1, j); + } + g2 (local0, i); + } + f2 (local0, i); + } +} + +int +main (void) +{ + f1count[0] = 0; + f1count[1] = 0; + f1count[2] = 0; + f2count[0] = 0; + f2count[1] = 0; + f2count[2] = 0; + + g1count[0] = 0; + g1count[1] = 0; + g1count[2] = 0; + g2count[0] = 0; + g2count[1] = 0; + g2count[2] = 0; + + s1 (3, 4, 5); + + /* All intervening code at the same depth must be executed the same + number of times. */ + if (f1count[0] != f2count[0]) abort (); + if (f1count[1] != f2count[1]) abort (); + if (f1count[2] != f2count[2]) abort (); + if (g1count[0] != f1count[0]) abort (); + if (g2count[0] != f1count[0]) abort (); + if (g1count[1] != f1count[1]) abort (); + if (g2count[1] != f1count[1]) abort (); + if (g1count[2] != f1count[2]) abort (); + if (g2count[2] != f1count[2]) abort (); + + /* Intervening code must be executed at least as many times as the loop + that encloses it. */ + if (f1count[0] < 3) abort (); + if (f1count[1] < 3 * 4) abort (); + + /* Intervening code must not be executed more times than the number + of logical iterations. */ + if (f1count[0] > 3 * 4 * 5) abort (); + if (f1count[1] > 3 * 4 * 5) abort (); + + /* Check that the innermost loop body is executed exactly the number + of logical iterations expected. */ + if (f1count[2] != 3 * 4 * 5) abort (); +} diff --git a/libgomp/testsuite/libgomp.c++/attrs-imperfect4.C b/libgomp/testsuite/libgomp.c++/attrs-imperfect4.C new file mode 100644 index 000000000000..cc0a034bbedd --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/attrs-imperfect4.C @@ -0,0 +1,117 @@ +/* { dg-do run } */ + +/* Like imperfect2.c, but includes blocks that are themselves intervening + code. */ + +static int f1count[3], f2count[3]; +static int g1count[3], g2count[3]; + +#ifndef __cplusplus +extern void abort (void); +#else +extern "C" void abort (void); +#endif + +int f1 (int depth, int iter) +{ + f1count[depth]++; + return iter; +} + +int f2 (int depth, int iter) +{ + f2count[depth]++; + return iter; +} + +int g1 (int depth, int iter) +{ + g1count[depth]++; + return iter; +} + +int g2 (int depth, int iter) +{ + g2count[depth]++; + return iter; +} + +void s1 (int a1, int a2, int a3) +{ + int i, j, k; + + [[ omp :: directive (for, collapse(3)) ]] + for (i = 0; i < a1; i++) + { + { f1 (0, i); } + { + g1 (0, i); + for (j = 0; j < a2; j++) + { + { f1 (1, j); } + { + { g1 (1, j); } + for (k = 0; k < a3; k++) + { + f1 (2, k); + { + g1 (2, k); + g2 (2, k); + } + f2 (2, k); + } + { g2 (1, j); } + } + { f2 (1, j); } + } + { g2 (0, i); } + } + { f2 (0, i); } + } +} + +int +main (void) +{ + f1count[0] = 0; + f1count[1] = 0; + f1count[2] = 0; + f2count[0] = 0; + f2count[1] = 0; + f2count[2] = 0; + + g1count[0] = 0; + g1count[1] = 0; + g1count[2] = 0; + g2count[0] = 0; + g2count[1] = 0; + g2count[2] = 0; + + s1 (3, 4, 5); + + /* All intervening code at the same depth must be executed the same + number of times. */ + if (f1count[0] != f2count[0]) abort (); + if (f1count[1] != f2count[1]) abort (); + if (f1count[2] != f2count[2]) abort (); + if (g1count[0] != f1count[0]) abort (); + if (g2count[0] != f1count[0]) abort (); + if (g1count[1] != f1count[1]) abort (); + if (g2count[1] != f1count[1]) abort (); + if (g1count[2] != f1count[2]) abort (); + if (g2count[2] != f1count[2]) abort (); + + /* Intervening code must be executed at least as many times as the loop + that encloses it. */ + if (f1count[0] < 3) abort (); + if (f1count[1] < 3 * 4) abort (); + + /* Intervening code must not be executed more times than the number + of logical iterations. */ + if (f1count[0] > 3 * 4 * 5) abort (); + if (f1count[1] > 3 * 4 * 5) abort (); + + /* Check that the innermost loop body is executed exactly the number + of logical iterations expected. */ + if (f1count[2] != 3 * 4 * 5) abort (); +} diff --git a/libgomp/testsuite/libgomp.c++/attrs-imperfect5.C b/libgomp/testsuite/libgomp.c++/attrs-imperfect5.C new file mode 100644 index 000000000000..89a969db8ccd --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/attrs-imperfect5.C @@ -0,0 +1,49 @@ +/* { dg-do run } */ + +#ifndef __cplusplus +extern void abort (void); +#else +extern "C" void abort (void); +#endif + +static int inner_loop_count = 0; +static int intervening_code_count = 0; + +void +g (int x, int y) +{ + inner_loop_count++; +} + +int +foo (int imax, int jmax) +{ + int j = 0; + + [[ omp :: directive (for, collapse(2)) ]] + for (int i = 0; i < imax; ++i) + { + /* All the intervening code at the same level must be executed + the same number of times. */ + ++intervening_code_count; + for (int j = 0; j < jmax; ++j) + { + g (i, j); + } + /* This is the outer j, not the one from the inner collapsed loop. */ + ++j; + } + return j; +} + +int +main (void) +{ + int j = foo (5, 3); + if (j != intervening_code_count) + abort (); + if (inner_loop_count != 5 * 3) + abort (); + if (intervening_code_count < 5 || intervening_code_count > 5 * 3) + abort (); +} diff --git a/libgomp/testsuite/libgomp.c++/attrs-imperfect6.C b/libgomp/testsuite/libgomp.c++/attrs-imperfect6.C new file mode 100644 index 000000000000..01f9be123a65 --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/attrs-imperfect6.C @@ -0,0 +1,115 @@ +/* { dg-do run } */ + +/* Like imperfect4.c, but bind the iteration variables in the loops. */ + +static int f1count[3], f2count[3]; +static int g1count[3], g2count[3]; + +#ifndef __cplusplus +extern void abort (void); +#else +extern "C" void abort (void); +#endif + +int f1 (int depth, int iter) +{ + f1count[depth]++; + return iter; +} + +int f2 (int depth, int iter) +{ + f2count[depth]++; + return iter; +} + +int g1 (int depth, int iter) +{ + g1count[depth]++; + return iter; +} + +int g2 (int depth, int iter) +{ + g2count[depth]++; + return iter; +} + +void s1 (int a1, int a2, int a3) +{ + + [[ omp :: directive (for, collapse(3)) ]] + for (int i = 0; i < a1; i++) + { + { f1 (0, i); } + { + g1 (0, i); + for (int j = 0; j < a2; j++) + { + { f1 (1, j); } + { + { g1 (1, j); } + for (int k = 0; k < a3; k++) + { + f1 (2, k); + { + g1 (2, k); + g2 (2, k); + } + f2 (2, k); + } + { g2 (1, j); } + } + { f2 (1, j); } + } + { g2 (0, i); } + } + { f2 (0, i); } + } +} + +int +main (void) +{ + f1count[0] = 0; + f1count[1] = 0; + f1count[2] = 0; + f2count[0] = 0; + f2count[1] = 0; + f2count[2] = 0; + + g1count[0] = 0; + g1count[1] = 0; + g1count[2] = 0; + g2count[0] = 0; + g2count[1] = 0; + g2count[2] = 0; + + s1 (3, 4, 5); + + /* All intervening code at the same depth must be executed the same + number of times. */ + if (f1count[0] != f2count[0]) abort (); + if (f1count[1] != f2count[1]) abort (); + if (f1count[2] != f2count[2]) abort (); + if (g1count[0] != f1count[0]) abort (); + if (g2count[0] != f1count[0]) abort (); + if (g1count[1] != f1count[1]) abort (); + if (g2count[1] != f1count[1]) abort (); + if (g1count[2] != f1count[2]) abort (); + if (g2count[2] != f1count[2]) abort (); + + /* Intervening code must be executed at least as many times as the loop + that encloses it. */ + if (f1count[0] < 3) abort (); + if (f1count[1] < 3 * 4) abort (); + + /* Intervening code must not be executed more times than the number + of logical iterations. */ + if (f1count[0] > 3 * 4 * 5) abort (); + if (f1count[1] > 3 * 4 * 5) abort (); + + /* Check that the innermost loop body is executed exactly the number + of logical iterations expected. */ + if (f1count[2] != 3 * 4 * 5) abort (); +} diff --git a/libgomp/testsuite/libgomp.c++/imperfect-class-1.C b/libgomp/testsuite/libgomp.c++/imperfect-class-1.C new file mode 100644 index 000000000000..3c39c42c1075 --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/imperfect-class-1.C @@ -0,0 +1,169 @@ +// { dg-do run } +// Test that class iterators and imperfectly-nested loops work together. +// This variant tests initialization by assignment. + +typedef __PTRDIFF_TYPE__ ptrdiff_t; +typedef int T; +typedef int S; + +class I +{ +public: + typedef ptrdiff_t difference_type; + I (); + ~I (); + I (T *); + I (const I &); + T &operator * (); + T *operator -> (); + T &operator [] (const difference_type &) const; + I &operator = (const I &); + I &operator ++ (); + I operator ++ (int); + I &operator -- (); + I operator -- (int); + I &operator += (const difference_type &); + I &operator -= (const difference_type &); + I operator + (const difference_type &) const; + I operator - (const difference_type &) const; + friend bool operator == (I &, I &); + friend bool operator == (const I &, const I &); + friend bool operator < (I &, I &); + friend bool operator < (const I &, const I &); + friend bool operator <= (I &, I &); + friend bool operator <= (const I &, const I &); + friend bool operator > (I &, I &); + friend bool operator > (const I &, const I &); + friend bool operator >= (I &, I &); + friend bool operator >= (const I &, const I &); + friend typename I::difference_type operator - (I &, I &); + friend typename I::difference_type operator - (const I &, const I &); + friend I operator + (typename I::difference_type , const I &); +private: + T *p; +}; + I::I () : p (0) {} + I::~I () { p = (T *) 0; } + I::I (T *x) : p (x) {} + I::I (const I &x) : p (x.p) {} + T &I::operator * () { return *p; } + T *I::operator -> () { return p; } + T &I::operator [] (const difference_type &x) const { return p[x]; } + I &I::operator = (const I &x) { p = x.p; return *this; } + I &I::operator ++ () { ++p; return *this; } + I I::operator ++ (int) { return I (p++); } + I &I::operator -- () { --p; return *this; } + I I::operator -- (int) { return I (p--); } + I &I::operator += (const difference_type &x) { p += x; return *this; } + I &I::operator -= (const difference_type &x) { p -= x; return *this; } + I I::operator + (const difference_type &x) const { return I (p + x); } + I I::operator - (const difference_type &x) const { return I (p - x); } + bool operator == (I &x, I &y) { return x.p == y.p; } + bool operator == (const I &x, const I &y) { return x.p == y.p; } + bool operator != (I &x, I &y) { return !(x == y); } + bool operator != (const I &x, const I &y) { return !(x == y); } + bool operator < (I &x, I &y) { return x.p < y.p; } + bool operator < (const I &x, const I &y) { return x.p < y.p; } + bool operator <= (I &x, I &y) { return x.p <= y.p; } + bool operator <= (const I &x, const I &y) { return x.p <= y.p; } + bool operator > (I &x, I &y) { return x.p > y.p; } + bool operator > (const I &x, const I &y) { return x.p > y.p; } + bool operator >= (I &x, I &y) { return x.p >= y.p; } + bool operator >= (const I &x, const I &y) { return x.p >= y.p; } + typename I::difference_type operator - (I &x, I &y) { return x.p - y.p; } + typename I::difference_type operator - (const I &x, const I &y) { return x.p - y.p; } + I operator + (typename I::difference_type x, const I &y) { return I (x + y.p); } + +class J +{ + public: + J(const I &x, const I &y) : b (x), e (y) {} + const I &begin (); + const I &end (); + private: + I b, e; +}; + +const I &J::begin () { return b; } +const I &J::end () { return e; } + +static int f1count[3], f2count[3]; + +#ifndef __cplusplus +extern void abort (void); +#else +extern "C" void abort (void); +#endif + +void f1 (int depth) +{ + f1count[depth]++; +} + +void f2 (int depth) +{ + f2count[depth]++; +} + +void s1 (J a1, J a2, J a3) +{ + I i, j, k; + +#pragma omp for collapse(3) + for (i = a1.begin (); i < a1.end (); i++) + { + f1 (0); + for (j = a2.begin (); j < a2.end (); j++) + { + f1 (1); + for (k = a3.begin (); k < a3.end (); k++) + { + f1 (2); + f2 (2); + } + f2 (1); + } + f2 (0); + } +} + + +int +main (void) +{ + + int index[] = {0, 1, 2, 3, 4, 5}; + + J x (&index[0], &index[3]); + J y (&index[0], &index[4]); + J z (&index[0], &index[5]); + + f1count[0] = 0; + f1count[1] = 0; + f1count[2] = 0; + f2count[0] = 0; + f2count[1] = 0; + f2count[2] = 0; + + s1 (x, y, z); + + /* All intervening code at the same depth must be executed the same + number of times. */ + if (f1count[0] != f2count[0]) abort (); + if (f1count[1] != f2count[1]) abort (); + if (f1count[2] != f2count[2]) abort (); + + /* Intervening code must be executed at least as many times as the loop + that encloses it. */ + if (f1count[0] < 3) abort (); + if (f1count[1] < 3 * 4) abort (); + + /* Intervening code must not be executed more times than the number + of logical iterations. */ + if (f1count[0] > 3 * 4 * 5) abort (); + if (f1count[1] > 3 * 4 * 5) abort (); + + /* Check that the innermost loop body is executed exactly the number + of logical iterations expected. */ + if (f1count[2] != 3 * 4 * 5) abort (); +} diff --git a/libgomp/testsuite/libgomp.c++/imperfect-class-2.C b/libgomp/testsuite/libgomp.c++/imperfect-class-2.C new file mode 100644 index 000000000000..c6b657cabbae --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/imperfect-class-2.C @@ -0,0 +1,167 @@ +// { dg-do run } +// Test that class iterators and imperfectly-nested loops work together. +// This variant tests loop initialization by declaration. + +typedef __PTRDIFF_TYPE__ ptrdiff_t; +typedef int T; +typedef int S; + +class I +{ +public: + typedef ptrdiff_t difference_type; + I (); + ~I (); + I (T *); + I (const I &); + T &operator * (); + T *operator -> (); + T &operator [] (const difference_type &) const; + I &operator = (const I &); + I &operator ++ (); + I operator ++ (int); + I &operator -- (); + I operator -- (int); + I &operator += (const difference_type &); + I &operator -= (const difference_type &); + I operator + (const difference_type &) const; + I operator - (const difference_type &) const; + friend bool operator == (I &, I &); + friend bool operator == (const I &, const I &); + friend bool operator < (I &, I &); + friend bool operator < (const I &, const I &); + friend bool operator <= (I &, I &); + friend bool operator <= (const I &, const I &); + friend bool operator > (I &, I &); + friend bool operator > (const I &, const I &); + friend bool operator >= (I &, I &); + friend bool operator >= (const I &, const I &); + friend typename I::difference_type operator - (I &, I &); + friend typename I::difference_type operator - (const I &, const I &); + friend I operator + (typename I::difference_type , const I &); +private: + T *p; +}; + I::I () : p (0) {} + I::~I () { p = (T *) 0; } + I::I (T *x) : p (x) {} + I::I (const I &x) : p (x.p) {} + T &I::operator * () { return *p; } + T *I::operator -> () { return p; } + T &I::operator [] (const difference_type &x) const { return p[x]; } + I &I::operator = (const I &x) { p = x.p; return *this; } + I &I::operator ++ () { ++p; return *this; } + I I::operator ++ (int) { return I (p++); } + I &I::operator -- () { --p; return *this; } + I I::operator -- (int) { return I (p--); } + I &I::operator += (const difference_type &x) { p += x; return *this; } + I &I::operator -= (const difference_type &x) { p -= x; return *this; } + I I::operator + (const difference_type &x) const { return I (p + x); } + I I::operator - (const difference_type &x) const { return I (p - x); } + bool operator == (I &x, I &y) { return x.p == y.p; } + bool operator == (const I &x, const I &y) { return x.p == y.p; } + bool operator != (I &x, I &y) { return !(x == y); } + bool operator != (const I &x, const I &y) { return !(x == y); } + bool operator < (I &x, I &y) { return x.p < y.p; } + bool operator < (const I &x, const I &y) { return x.p < y.p; } + bool operator <= (I &x, I &y) { return x.p <= y.p; } + bool operator <= (const I &x, const I &y) { return x.p <= y.p; } + bool operator > (I &x, I &y) { return x.p > y.p; } + bool operator > (const I &x, const I &y) { return x.p > y.p; } + bool operator >= (I &x, I &y) { return x.p >= y.p; } + bool operator >= (const I &x, const I &y) { return x.p >= y.p; } + typename I::difference_type operator - (I &x, I &y) { return x.p - y.p; } + typename I::difference_type operator - (const I &x, const I &y) { return x.p - y.p; } + I operator + (typename I::difference_type x, const I &y) { return I (x + y.p); } + +class J +{ + public: + J(const I &x, const I &y) : b (x), e (y) {} + const I &begin (); + const I &end (); + private: + I b, e; +}; + +const I &J::begin () { return b; } +const I &J::end () { return e; } + +static int f1count[3], f2count[3]; + +#ifndef __cplusplus +extern void abort (void); +#else +extern "C" void abort (void); +#endif + +void f1 (int depth) +{ + f1count[depth]++; +} + +void f2 (int depth) +{ + f2count[depth]++; +} + +void s1 (J a1, J a2, J a3) +{ +#pragma omp for collapse(3) + for (I i = a1.begin (); i < a1.end (); i++) + { + f1 (0); + for (I j = a2.begin (); j < a2.end (); j++) + { + f1 (1); + for (I k = a3.begin (); k < a3.end (); k++) + { + f1 (2); + f2 (2); + } + f2 (1); + } + f2 (0); + } +} + + +int +main (void) +{ + + int index[] = {0, 1, 2, 3, 4, 5}; + + J x (&index[0], &index[3]); + J y (&index[0], &index[4]); + J z (&index[0], &index[5]); + + f1count[0] = 0; + f1count[1] = 0; + f1count[2] = 0; + f2count[0] = 0; + f2count[1] = 0; + f2count[2] = 0; + + s1 (x, y, z); + + /* All intervening code at the same depth must be executed the same + number of times. */ + if (f1count[0] != f2count[0]) abort (); + if (f1count[1] != f2count[1]) abort (); + if (f1count[2] != f2count[2]) abort (); + + /* Intervening code must be executed at least as many times as the loop + that encloses it. */ + if (f1count[0] < 3) abort (); + if (f1count[1] < 3 * 4) abort (); + + /* Intervening code must not be executed more times than the number + of logical iterations. */ + if (f1count[0] > 3 * 4 * 5) abort (); + if (f1count[1] > 3 * 4 * 5) abort (); + + /* Check that the innermost loop body is executed exactly the number + of logical iterations expected. */ + if (f1count[2] != 3 * 4 * 5) abort (); +} diff --git a/libgomp/testsuite/libgomp.c++/imperfect-class-3.C b/libgomp/testsuite/libgomp.c++/imperfect-class-3.C new file mode 100644 index 000000000000..c33826a6b362 --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/imperfect-class-3.C @@ -0,0 +1,167 @@ +// { dg-do run } +// Test that class iterators and imperfectly-nested loops work together. +// This variant tests range for. + +typedef __PTRDIFF_TYPE__ ptrdiff_t; +typedef int T; +typedef int S; + +class I +{ +public: + typedef ptrdiff_t difference_type; + I (); + ~I (); + I (T *); + I (const I &); + T &operator * (); + T *operator -> (); + T &operator [] (const difference_type &) const; + I &operator = (const I &); + I &operator ++ (); + I operator ++ (int); + I &operator -- (); + I operator -- (int); + I &operator += (const difference_type &); + I &operator -= (const difference_type &); + I operator + (const difference_type &) const; + I operator - (const difference_type &) const; + friend bool operator == (I &, I &); + friend bool operator == (const I &, const I &); + friend bool operator < (I &, I &); + friend bool operator < (const I &, const I &); + friend bool operator <= (I &, I &); + friend bool operator <= (const I &, const I &); + friend bool operator > (I &, I &); + friend bool operator > (const I &, const I &); + friend bool operator >= (I &, I &); + friend bool operator >= (const I &, const I &); + friend typename I::difference_type operator - (I &, I &); + friend typename I::difference_type operator - (const I &, const I &); + friend I operator + (typename I::difference_type , const I &); +private: + T *p; +}; + I::I () : p (0) {} + I::~I () { p = (T *) 0; } + I::I (T *x) : p (x) {} + I::I (const I &x) : p (x.p) {} + T &I::operator * () { return *p; } + T *I::operator -> () { return p; } + T &I::operator [] (const difference_type &x) const { return p[x]; } + I &I::operator = (const I &x) { p = x.p; return *this; } + I &I::operator ++ () { ++p; return *this; } + I I::operator ++ (int) { return I (p++); } + I &I::operator -- () { --p; return *this; } + I I::operator -- (int) { return I (p--); } + I &I::operator += (const difference_type &x) { p += x; return *this; } + I &I::operator -= (const difference_type &x) { p -= x; return *this; } + I I::operator + (const difference_type &x) const { return I (p + x); } + I I::operator - (const difference_type &x) const { return I (p - x); } + bool operator == (I &x, I &y) { return x.p == y.p; } + bool operator == (const I &x, const I &y) { return x.p == y.p; } + bool operator != (I &x, I &y) { return !(x == y); } + bool operator != (const I &x, const I &y) { return !(x == y); } + bool operator < (I &x, I &y) { return x.p < y.p; } + bool operator < (const I &x, const I &y) { return x.p < y.p; } + bool operator <= (I &x, I &y) { return x.p <= y.p; } + bool operator <= (const I &x, const I &y) { return x.p <= y.p; } + bool operator > (I &x, I &y) { return x.p > y.p; } + bool operator > (const I &x, const I &y) { return x.p > y.p; } + bool operator >= (I &x, I &y) { return x.p >= y.p; } + bool operator >= (const I &x, const I &y) { return x.p >= y.p; } + typename I::difference_type operator - (I &x, I &y) { return x.p - y.p; } + typename I::difference_type operator - (const I &x, const I &y) { return x.p - y.p; } + I operator + (typename I::difference_type x, const I &y) { return I (x + y.p); } + +class J +{ + public: + J(const I &x, const I &y) : b (x), e (y) {} + const I &begin (); + const I &end (); + private: + I b, e; +}; + +const I &J::begin () { return b; } +const I &J::end () { return e; } + +static int f1count[3], f2count[3]; + +#ifndef __cplusplus +extern void abort (void); +#else +extern "C" void abort (void); +#endif + +void f1 (int depth) +{ + f1count[depth]++; +} + +void f2 (int depth) +{ + f2count[depth]++; +} + +void s1 (J a1, J a2, J a3) +{ +#pragma omp for collapse(3) + for (auto i : a1) + { + f1 (0); + for (auto j : a2) + { + f1 (1); + for (auto k : a3) + { + f1 (2); + f2 (2); + } + f2 (1); + } + f2 (0); + } +} + + +int +main (void) +{ + + int index[] = {0, 1, 2, 3, 4, 5}; + + J x (&index[0], &index[3]); + J y (&index[0], &index[4]); + J z (&index[0], &index[5]); + + f1count[0] = 0; + f1count[1] = 0; + f1count[2] = 0; + f2count[0] = 0; + f2count[1] = 0; + f2count[2] = 0; + + s1 (x, y, z); + + /* All intervening code at the same depth must be executed the same + number of times. */ + if (f1count[0] != f2count[0]) abort (); + if (f1count[1] != f2count[1]) abort (); + if (f1count[2] != f2count[2]) abort (); + + /* Intervening code must be executed at least as many times as the loop + that encloses it. */ + if (f1count[0] < 3) abort (); + if (f1count[1] < 3 * 4) abort (); + + /* Intervening code must not be executed more times than the number + of logical iterations. */ + if (f1count[0] > 3 * 4 * 5) abort (); + if (f1count[1] > 3 * 4 * 5) abort (); + + /* Check that the innermost loop body is executed exactly the number + of logical iterations expected. */ + if (f1count[2] != 3 * 4 * 5) abort (); +} diff --git a/libgomp/testsuite/libgomp.c++/imperfect-destructor.C b/libgomp/testsuite/libgomp.c++/imperfect-destructor.C new file mode 100644 index 000000000000..bd87760e076b --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/imperfect-destructor.C @@ -0,0 +1,135 @@ +/* { dg-do run } */ + +/* Make sure destructors are called for class variables bound + in intervening code. */ + +static int f1count[3], f2count[3]; +static int g1count[3], g2count[3]; + +static int ccount[3], dcount[3]; + +class C { + public: + int n; + C (int nn) { n = nn; ccount[n]++; } + ~C () { dcount[n]++; n = 0; } +}; + +#ifndef __cplusplus +extern void abort (void); +#else +extern "C" void abort (void); +#endif + +int f1 (int depth, int iter) +{ + f1count[depth]++; + return iter; +} + +int f2 (int depth, int iter) +{ + f2count[depth]++; + return iter; +} + +int g1 (int depth, int iter) +{ + g1count[depth]++; + return iter; +} + +int g2 (int depth, int iter) +{ + g2count[depth]++; + return iter; +} + +void s1 (int a1, int a2, int a3) +{ + int i, j, k; + +#pragma omp for collapse(3) + for (i = 0; i < a1; i++) + { + C local0(0); + f1 (local0.n, i); + { + g1 (local0.n, i); + for (j = 0; j < a2; j++) + { + C local1(1); + f1 (local1.n, j); + { + g1 (local1.n, j); + for (k = 0; k < a3; k++) + { + C local2(2); + f1 (local2.n, k); + { + g1 (local2.n, k); + g2 (local2.n, k); + } + f2 (local2.n, k); + } + g2 (local1.n, j); + } + f2 (local1.n, j); + } + g2 (local0.n, i); + } + f2 (local0.n, i); + } +} + +int +main (void) +{ + f1count[0] = 0; + f1count[1] = 0; + f1count[2] = 0; + f2count[0] = 0; + f2count[1] = 0; + f2count[2] = 0; + + g1count[0] = 0; + g1count[1] = 0; + g1count[2] = 0; + g2count[0] = 0; + g2count[1] = 0; + g2count[2] = 0; + + s1 (3, 4, 5); + + /* All intervening code at the same depth must be executed the same + number of times. */ + if (f1count[0] != f2count[0]) abort (); + if (f1count[1] != f2count[1]) abort (); + if (f1count[2] != f2count[2]) abort (); + if (g1count[0] != f1count[0]) abort (); + if (g2count[0] != f1count[0]) abort (); + if (g1count[1] != f1count[1]) abort (); + if (g2count[1] != f1count[1]) abort (); + if (g1count[2] != f1count[2]) abort (); + if (g2count[2] != f1count[2]) abort (); + + /* Intervening code must be executed at least as many times as the loop + that encloses it. */ + if (f1count[0] < 3) abort (); + if (f1count[1] < 3 * 4) abort (); + + /* Intervening code must not be executed more times than the number + of logical iterations. */ + if (f1count[0] > 3 * 4 * 5) abort (); + if (f1count[1] > 3 * 4 * 5) abort (); + + /* Check that the innermost loop body is executed exactly the number + of logical iterations expected. */ + if (f1count[2] != 3 * 4 * 5) abort (); + + /* Check that each class object declared in intervening code was + constructed and destructed an equal number of times. */ + if (ccount[0] != dcount[0]) abort (); + if (ccount[1] != dcount[1]) abort (); + if (ccount[2] != dcount[2]) abort (); +} diff --git a/libgomp/testsuite/libgomp.c++/imperfect-template-1.C b/libgomp/testsuite/libgomp.c++/imperfect-template-1.C new file mode 100644 index 000000000000..4ed96c8319bb --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/imperfect-template-1.C @@ -0,0 +1,172 @@ +// { dg-do run } +// Test that template class iterators and imperfectly-nested loops +// work together. +// This variant tests initialization by assignment. + +typedef __PTRDIFF_TYPE__ ptrdiff_t; +extern "C" void abort (); + +template +class I +{ +public: + typedef ptrdiff_t difference_type; + I (); + ~I (); + I (T *); + I (const I &); + T &operator * (); + T *operator -> (); + T &operator [] (const difference_type &) const; + I &operator = (const I &); + I &operator ++ (); + I operator ++ (int); + I &operator -- (); + I operator -- (int); + I &operator += (const difference_type &); + I &operator -= (const difference_type &); + I operator + (const difference_type &) const; + I operator - (const difference_type &) const; + template friend bool operator == (I &, I &); + template friend bool operator == (const I &, const I &); + template friend bool operator < (I &, I &); + template friend bool operator < (const I &, const I &); + template friend bool operator <= (I &, I &); + template friend bool operator <= (const I &, const I &); + template friend bool operator > (I &, I &); + template friend bool operator > (const I &, const I &); + template friend bool operator >= (I &, I &); + template friend bool operator >= (const I &, const I &); + template friend typename I::difference_type operator - (I &, I &); + template friend typename I::difference_type operator - (const I &, const I &); + template friend I operator + (typename I::difference_type , const I &); +private: + T *p; +}; +template I::I () : p (0) {} +template I::~I () { p = (T *) 0; } +template I::I (T *x) : p (x) {} +template I::I (const I &x) : p (x.p) {} +template T &I::operator * () { return *p; } +template T *I::operator -> () { return p; } +template T &I::operator [] (const difference_type &x) const { return p[x]; } +template I &I::operator = (const I &x) { p = x.p; return *this; } +template I &I::operator ++ () { ++p; return *this; } +template I I::operator ++ (int) { return I (p++); } +template I &I::operator -- () { --p; return *this; } +template I I::operator -- (int) { return I (p--); } +template I &I::operator += (const difference_type &x) { p += x; return *this; } +template I &I::operator -= (const difference_type &x) { p -= x; return *this; } +template I I::operator + (const difference_type &x) const { return I (p + x); } +template I I::operator - (const difference_type &x) const { return I (p - x); } +template bool operator == (I &x, I &y) { return x.p == y.p; } +template bool operator == (const I &x, const I &y) { return x.p == y.p; } +template bool operator != (I &x, I &y) { return !(x == y); } +template bool operator != (const I &x, const I &y) { return !(x == y); } +template bool operator < (I &x, I &y) { return x.p < y.p; } +template bool operator < (const I &x, const I &y) { return x.p < y.p; } +template bool operator <= (I &x, I &y) { return x.p <= y.p; } +template bool operator <= (const I &x, const I &y) { return x.p <= y.p; } +template bool operator > (I &x, I &y) { return x.p > y.p; } +template bool operator > (const I &x, const I &y) { return x.p > y.p; } +template bool operator >= (I &x, I &y) { return x.p >= y.p; } +template bool operator >= (const I &x, const I &y) { return x.p >= y.p; } +template typename I::difference_type operator - (I &x, I &y) { return x.p - y.p; } +template typename I::difference_type operator - (const I &x, const I &y) { return x.p - y.p; } +template I operator + (typename I::difference_type x, const I &y) { return I (x + y.p); } + +template +class J +{ +public: + J(const I &x, const I &y) : b (x), e (y) {} + const I &begin (); + const I &end (); +private: + I b, e; +}; + +template const I &J::begin () { return b; } +template const I &J::end () { return e; } + +static int f1count[3], f2count[3]; + +#ifndef __cplusplus +extern void abort (void); +#else +extern "C" void abort (void); +#endif + +void f1 (int depth) +{ + f1count[depth]++; +} + +void f2 (int depth) +{ + f2count[depth]++; +} + +template +void s1 (J a1, J a2, J a3) +{ + I i, j, k; + +#pragma omp for collapse(3) + for (i = a1.begin (); i < a1.end (); i++) + { + f1 (0); + for (j = a2.begin (); j < a2.end (); j++) + { + f1 (1); + for (k = a3.begin (); k < a3.end (); k++) + { + f1 (2); + f2 (2); + } + f2 (1); + } + f2 (0); + } +} + + +int +main (void) +{ + + int index[] = {0, 1, 2, 3, 4, 5}; + + J x (&index[0], &index[3]); + J y (&index[0], &index[4]); + J z (&index[0], &index[5]); + + f1count[0] = 0; + f1count[1] = 0; + f1count[2] = 0; + f2count[0] = 0; + f2count[1] = 0; + f2count[2] = 0; + + s1 (x, y, z); + + /* All intervening code at the same depth must be executed the same + number of times. */ + if (f1count[0] != f2count[0]) abort (); + if (f1count[1] != f2count[1]) abort (); + if (f1count[2] != f2count[2]) abort (); + + /* Intervening code must be executed at least as many times as the loop + that encloses it. */ + if (f1count[0] < 3) abort (); + if (f1count[1] < 3 * 4) abort (); + + /* Intervening code must not be executed more times than the number + of logical iterations. */ + if (f1count[0] > 3 * 4 * 5) abort (); + if (f1count[1] > 3 * 4 * 5) abort (); + + /* Check that the innermost loop body is executed exactly the number + of logical iterations expected. */ + if (f1count[2] != 3 * 4 * 5) abort (); +} diff --git a/libgomp/testsuite/libgomp.c++/imperfect-template-2.C b/libgomp/testsuite/libgomp.c++/imperfect-template-2.C new file mode 100644 index 000000000000..a41c87c481f9 --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/imperfect-template-2.C @@ -0,0 +1,170 @@ +// { dg-do run } +// Test that template class iterators and imperfectly-nested loops +// work together. +// This variant tests initialization by declaration. + +typedef __PTRDIFF_TYPE__ ptrdiff_t; +extern "C" void abort (); + +template +class I +{ +public: + typedef ptrdiff_t difference_type; + I (); + ~I (); + I (T *); + I (const I &); + T &operator * (); + T *operator -> (); + T &operator [] (const difference_type &) const; + I &operator = (const I &); + I &operator ++ (); + I operator ++ (int); + I &operator -- (); + I operator -- (int); + I &operator += (const difference_type &); + I &operator -= (const difference_type &); + I operator + (const difference_type &) const; + I operator - (const difference_type &) const; + template friend bool operator == (I &, I &); + template friend bool operator == (const I &, const I &); + template friend bool operator < (I &, I &); + template friend bool operator < (const I &, const I &); + template friend bool operator <= (I &, I &); + template friend bool operator <= (const I &, const I &); + template friend bool operator > (I &, I &); + template friend bool operator > (const I &, const I &); + template friend bool operator >= (I &, I &); + template friend bool operator >= (const I &, const I &); + template friend typename I::difference_type operator - (I &, I &); + template friend typename I::difference_type operator - (const I &, const I &); + template friend I operator + (typename I::difference_type , const I &); +private: + T *p; +}; +template I::I () : p (0) {} +template I::~I () { p = (T *) 0; } +template I::I (T *x) : p (x) {} +template I::I (const I &x) : p (x.p) {} +template T &I::operator * () { return *p; } +template T *I::operator -> () { return p; } +template T &I::operator [] (const difference_type &x) const { return p[x]; } +template I &I::operator = (const I &x) { p = x.p; return *this; } +template I &I::operator ++ () { ++p; return *this; } +template I I::operator ++ (int) { return I (p++); } +template I &I::operator -- () { --p; return *this; } +template I I::operator -- (int) { return I (p--); } +template I &I::operator += (const difference_type &x) { p += x; return *this; } +template I &I::operator -= (const difference_type &x) { p -= x; return *this; } +template I I::operator + (const difference_type &x) const { return I (p + x); } +template I I::operator - (const difference_type &x) const { return I (p - x); } +template bool operator == (I &x, I &y) { return x.p == y.p; } +template bool operator == (const I &x, const I &y) { return x.p == y.p; } +template bool operator != (I &x, I &y) { return !(x == y); } +template bool operator != (const I &x, const I &y) { return !(x == y); } +template bool operator < (I &x, I &y) { return x.p < y.p; } +template bool operator < (const I &x, const I &y) { return x.p < y.p; } +template bool operator <= (I &x, I &y) { return x.p <= y.p; } +template bool operator <= (const I &x, const I &y) { return x.p <= y.p; } +template bool operator > (I &x, I &y) { return x.p > y.p; } +template bool operator > (const I &x, const I &y) { return x.p > y.p; } +template bool operator >= (I &x, I &y) { return x.p >= y.p; } +template bool operator >= (const I &x, const I &y) { return x.p >= y.p; } +template typename I::difference_type operator - (I &x, I &y) { return x.p - y.p; } +template typename I::difference_type operator - (const I &x, const I &y) { return x.p - y.p; } +template I operator + (typename I::difference_type x, const I &y) { return I (x + y.p); } + +template +class J +{ +public: + J(const I &x, const I &y) : b (x), e (y) {} + const I &begin (); + const I &end (); +private: + I b, e; +}; + +template const I &J::begin () { return b; } +template const I &J::end () { return e; } + +static int f1count[3], f2count[3]; + +#ifndef __cplusplus +extern void abort (void); +#else +extern "C" void abort (void); +#endif + +void f1 (int depth) +{ + f1count[depth]++; +} + +void f2 (int depth) +{ + f2count[depth]++; +} + +template +void s1 (J a1, J a2, J a3) +{ +#pragma omp for collapse(3) + for (I i = a1.begin (); i < a1.end (); i++) + { + f1 (0); + for (I j = a2.begin (); j < a2.end (); j++) + { + f1 (1); + for (I k = a3.begin (); k < a3.end (); k++) + { + f1 (2); + f2 (2); + } + f2 (1); + } + f2 (0); + } +} + + +int +main (void) +{ + + int index[] = {0, 1, 2, 3, 4, 5}; + + J x (&index[0], &index[3]); + J y (&index[0], &index[4]); + J z (&index[0], &index[5]); + + f1count[0] = 0; + f1count[1] = 0; + f1count[2] = 0; + f2count[0] = 0; + f2count[1] = 0; + f2count[2] = 0; + + s1 (x, y, z); + + /* All intervening code at the same depth must be executed the same + number of times. */ + if (f1count[0] != f2count[0]) abort (); + if (f1count[1] != f2count[1]) abort (); + if (f1count[2] != f2count[2]) abort (); + + /* Intervening code must be executed at least as many times as the loop + that encloses it. */ + if (f1count[0] < 3) abort (); + if (f1count[1] < 3 * 4) abort (); + + /* Intervening code must not be executed more times than the number + of logical iterations. */ + if (f1count[0] > 3 * 4 * 5) abort (); + if (f1count[1] > 3 * 4 * 5) abort (); + + /* Check that the innermost loop body is executed exactly the number + of logical iterations expected. */ + if (f1count[2] != 3 * 4 * 5) abort (); +} diff --git a/libgomp/testsuite/libgomp.c++/imperfect-template-3.C b/libgomp/testsuite/libgomp.c++/imperfect-template-3.C new file mode 100644 index 000000000000..2e464ed55100 --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/imperfect-template-3.C @@ -0,0 +1,170 @@ +// { dg-do run } +// Test that template class iterators and imperfectly-nested loops +// work together. +// This variant tests range for syntax. + +typedef __PTRDIFF_TYPE__ ptrdiff_t; +extern "C" void abort (); + +template +class I +{ +public: + typedef ptrdiff_t difference_type; + I (); + ~I (); + I (T *); + I (const I &); + T &operator * (); + T *operator -> (); + T &operator [] (const difference_type &) const; + I &operator = (const I &); + I &operator ++ (); + I operator ++ (int); + I &operator -- (); + I operator -- (int); + I &operator += (const difference_type &); + I &operator -= (const difference_type &); + I operator + (const difference_type &) const; + I operator - (const difference_type &) const; + template friend bool operator == (I &, I &); + template friend bool operator == (const I &, const I &); + template friend bool operator < (I &, I &); + template friend bool operator < (const I &, const I &); + template friend bool operator <= (I &, I &); + template friend bool operator <= (const I &, const I &); + template friend bool operator > (I &, I &); + template friend bool operator > (const I &, const I &); + template friend bool operator >= (I &, I &); + template friend bool operator >= (const I &, const I &); + template friend typename I::difference_type operator - (I &, I &); + template friend typename I::difference_type operator - (const I &, const I &); + template friend I operator + (typename I::difference_type , const I &); +private: + T *p; +}; +template I::I () : p (0) {} +template I::~I () { p = (T *) 0; } +template I::I (T *x) : p (x) {} +template I::I (const I &x) : p (x.p) {} +template T &I::operator * () { return *p; } +template T *I::operator -> () { return p; } +template T &I::operator [] (const difference_type &x) const { return p[x]; } +template I &I::operator = (const I &x) { p = x.p; return *this; } +template I &I::operator ++ () { ++p; return *this; } +template I I::operator ++ (int) { return I (p++); } +template I &I::operator -- () { --p; return *this; } +template I I::operator -- (int) { return I (p--); } +template I &I::operator += (const difference_type &x) { p += x; return *this; } +template I &I::operator -= (const difference_type &x) { p -= x; return *this; } +template I I::operator + (const difference_type &x) const { return I (p + x); } +template I I::operator - (const difference_type &x) const { return I (p - x); } +template bool operator == (I &x, I &y) { return x.p == y.p; } +template bool operator == (const I &x, const I &y) { return x.p == y.p; } +template bool operator != (I &x, I &y) { return !(x == y); } +template bool operator != (const I &x, const I &y) { return !(x == y); } +template bool operator < (I &x, I &y) { return x.p < y.p; } +template bool operator < (const I &x, const I &y) { return x.p < y.p; } +template bool operator <= (I &x, I &y) { return x.p <= y.p; } +template bool operator <= (const I &x, const I &y) { return x.p <= y.p; } +template bool operator > (I &x, I &y) { return x.p > y.p; } +template bool operator > (const I &x, const I &y) { return x.p > y.p; } +template bool operator >= (I &x, I &y) { return x.p >= y.p; } +template bool operator >= (const I &x, const I &y) { return x.p >= y.p; } +template typename I::difference_type operator - (I &x, I &y) { return x.p - y.p; } +template typename I::difference_type operator - (const I &x, const I &y) { return x.p - y.p; } +template I operator + (typename I::difference_type x, const I &y) { return I (x + y.p); } + +template +class J +{ +public: + J(const I &x, const I &y) : b (x), e (y) {} + const I &begin (); + const I &end (); +private: + I b, e; +}; + +template const I &J::begin () { return b; } +template const I &J::end () { return e; } + +static int f1count[3], f2count[3]; + +#ifndef __cplusplus +extern void abort (void); +#else +extern "C" void abort (void); +#endif + +void f1 (int depth) +{ + f1count[depth]++; +} + +void f2 (int depth) +{ + f2count[depth]++; +} + +template +void s1 (J a1, J a2, J a3) +{ +#pragma omp for collapse(3) + for (auto i : a1) + { + f1 (0); + for (auto j : a2) + { + f1 (1); + for (auto k : a3) + { + f1 (2); + f2 (2); + } + f2 (1); + } + f2 (0); + } +} + + +int +main (void) +{ + + int index[] = {0, 1, 2, 3, 4, 5}; + + J x (&index[0], &index[3]); + J y (&index[0], &index[4]); + J z (&index[0], &index[5]); + + f1count[0] = 0; + f1count[1] = 0; + f1count[2] = 0; + f2count[0] = 0; + f2count[1] = 0; + f2count[2] = 0; + + s1 (x, y, z); + + /* All intervening code at the same depth must be executed the same + number of times. */ + if (f1count[0] != f2count[0]) abort (); + if (f1count[1] != f2count[1]) abort (); + if (f1count[2] != f2count[2]) abort (); + + /* Intervening code must be executed at least as many times as the loop + that encloses it. */ + if (f1count[0] < 3) abort (); + if (f1count[1] < 3 * 4) abort (); + + /* Intervening code must not be executed more times than the number + of logical iterations. */ + if (f1count[0] > 3 * 4 * 5) abort (); + if (f1count[1] > 3 * 4 * 5) abort (); + + /* Check that the innermost loop body is executed exactly the number + of logical iterations expected. */ + if (f1count[2] != 3 * 4 * 5) abort (); +} diff --git a/libgomp/testsuite/libgomp.c-c++-common/imperfect1.c b/libgomp/testsuite/libgomp.c-c++-common/imperfect1.c new file mode 100644 index 000000000000..cafdcaf25b0e --- /dev/null +++ b/libgomp/testsuite/libgomp.c-c++-common/imperfect1.c @@ -0,0 +1,76 @@ +/* { dg-do run } */ + +static int f1count[3], f2count[3]; + +#ifndef __cplusplus +extern void abort (void); +#else +extern "C" void abort (void); +#endif + +int f1 (int depth, int iter) +{ + f1count[depth]++; + return iter; +} + +int f2 (int depth, int iter) +{ + f2count[depth]++; + return iter; +} + +void s1 (int a1, int a2, int a3) +{ + int i, j, k; + +#pragma omp for collapse(3) + for (i = 0; i < a1; i++) + { + f1 (0, i); + for (j = 0; j < a2; j++) + { + f1 (1, j); + for (k = 0; k < a3; k++) + { + f1 (2, k); + f2 (2, k); + } + f2 (1, j); + } + f2 (0, i); + } +} + +int +main (void) +{ + f1count[0] = 0; + f1count[1] = 0; + f1count[2] = 0; + f2count[0] = 0; + f2count[1] = 0; + f2count[2] = 0; + + s1 (3, 4, 5); + + /* All intervening code at the same depth must be executed the same + number of times. */ + if (f1count[0] != f2count[0]) abort (); + if (f1count[1] != f2count[1]) abort (); + if (f1count[2] != f2count[2]) abort (); + + /* Intervening code must be executed at least as many times as the loop + that encloses it. */ + if (f1count[0] < 3) abort (); + if (f1count[1] < 3 * 4) abort (); + + /* Intervening code must not be executed more times than the number + of logical iterations. */ + if (f1count[0] > 3 * 4 * 5) abort (); + if (f1count[1] > 3 * 4 * 5) abort (); + + /* Check that the innermost loop body is executed exactly the number + of logical iterations expected. */ + if (f1count[2] != 3 * 4 * 5) abort (); +} diff --git a/libgomp/testsuite/libgomp.c-c++-common/imperfect2.c b/libgomp/testsuite/libgomp.c-c++-common/imperfect2.c new file mode 100644 index 000000000000..e2098006eabc --- /dev/null +++ b/libgomp/testsuite/libgomp.c-c++-common/imperfect2.c @@ -0,0 +1,114 @@ +/* { dg-do run } */ + +static int f1count[3], f2count[3]; +static int g1count[3], g2count[3]; + +#ifndef __cplusplus +extern void abort (void); +#else +extern "C" void abort (void); +#endif + +int f1 (int depth, int iter) +{ + f1count[depth]++; + return iter; +} + +int f2 (int depth, int iter) +{ + f2count[depth]++; + return iter; +} + +int g1 (int depth, int iter) +{ + g1count[depth]++; + return iter; +} + +int g2 (int depth, int iter) +{ + g2count[depth]++; + return iter; +} + +void s1 (int a1, int a2, int a3) +{ + int i, j, k; + +#pragma omp for collapse(3) + for (i = 0; i < a1; i++) + { + f1 (0, i); + { + g1 (0, i); + for (j = 0; j < a2; j++) + { + f1 (1, j); + { + g1 (1, j); + for (k = 0; k < a3; k++) + { + f1 (2, k); + { + g1 (2, k); + g2 (2, k); + } + f2 (2, k); + } + g2 (1, j); + } + f2 (1, j); + } + g2 (0, i); + } + f2 (0, i); + } +} + +int +main (void) +{ + f1count[0] = 0; + f1count[1] = 0; + f1count[2] = 0; + f2count[0] = 0; + f2count[1] = 0; + f2count[2] = 0; + + g1count[0] = 0; + g1count[1] = 0; + g1count[2] = 0; + g2count[0] = 0; + g2count[1] = 0; + g2count[2] = 0; + + s1 (3, 4, 5); + + /* All intervening code at the same depth must be executed the same + number of times. */ + if (f1count[0] != f2count[0]) abort (); + if (f1count[1] != f2count[1]) abort (); + if (f1count[2] != f2count[2]) abort (); + if (g1count[0] != f1count[0]) abort (); + if (g2count[0] != f1count[0]) abort (); + if (g1count[1] != f1count[1]) abort (); + if (g2count[1] != f1count[1]) abort (); + if (g1count[2] != f1count[2]) abort (); + if (g2count[2] != f1count[2]) abort (); + + /* Intervening code must be executed at least as many times as the loop + that encloses it. */ + if (f1count[0] < 3) abort (); + if (f1count[1] < 3 * 4) abort (); + + /* Intervening code must not be executed more times than the number + of logical iterations. */ + if (f1count[0] > 3 * 4 * 5) abort (); + if (f1count[1] > 3 * 4 * 5) abort (); + + /* Check that the innermost loop body is executed exactly the number + of logical iterations expected. */ + if (f1count[2] != 3 * 4 * 5) abort (); +} diff --git a/libgomp/testsuite/libgomp.c-c++-common/imperfect3.c b/libgomp/testsuite/libgomp.c-c++-common/imperfect3.c new file mode 100644 index 000000000000..feb5e32d1d65 --- /dev/null +++ b/libgomp/testsuite/libgomp.c-c++-common/imperfect3.c @@ -0,0 +1,119 @@ +/* { dg-do run } */ + +/* Like imperfect2.c, but includes bindings in the blocks. */ + +static int f1count[3], f2count[3]; +static int g1count[3], g2count[3]; + +#ifndef __cplusplus +extern void abort (void); +#else +extern "C" void abort (void); +#endif + +int f1 (int depth, int iter) +{ + f1count[depth]++; + return iter; +} + +int f2 (int depth, int iter) +{ + f2count[depth]++; + return iter; +} + +int g1 (int depth, int iter) +{ + g1count[depth]++; + return iter; +} + +int g2 (int depth, int iter) +{ + g2count[depth]++; + return iter; +} + +void s1 (int a1, int a2, int a3) +{ + int i, j, k; + +#pragma omp for collapse(3) + for (i = 0; i < a1; i++) + { + int local0 = 0; + f1 (local0, i); + { + g1 (local0, i); + for (j = 0; j < a2; j++) + { + int local1 = 1; + f1 (local1, j); + { + g1 (local1, j); + for (k = 0; k < a3; k++) + { + int local2 = 2; + f1 (local2, k); + { + g1 (local2, k); + g2 (local2, k); + } + f2 (local2, k); + } + g2 (local1, j); + } + f2 (local1, j); + } + g2 (local0, i); + } + f2 (local0, i); + } +} + +int +main (void) +{ + f1count[0] = 0; + f1count[1] = 0; + f1count[2] = 0; + f2count[0] = 0; + f2count[1] = 0; + f2count[2] = 0; + + g1count[0] = 0; + g1count[1] = 0; + g1count[2] = 0; + g2count[0] = 0; + g2count[1] = 0; + g2count[2] = 0; + + s1 (3, 4, 5); + + /* All intervening code at the same depth must be executed the same + number of times. */ + if (f1count[0] != f2count[0]) abort (); + if (f1count[1] != f2count[1]) abort (); + if (f1count[2] != f2count[2]) abort (); + if (g1count[0] != f1count[0]) abort (); + if (g2count[0] != f1count[0]) abort (); + if (g1count[1] != f1count[1]) abort (); + if (g2count[1] != f1count[1]) abort (); + if (g1count[2] != f1count[2]) abort (); + if (g2count[2] != f1count[2]) abort (); + + /* Intervening code must be executed at least as many times as the loop + that encloses it. */ + if (f1count[0] < 3) abort (); + if (f1count[1] < 3 * 4) abort (); + + /* Intervening code must not be executed more times than the number + of logical iterations. */ + if (f1count[0] > 3 * 4 * 5) abort (); + if (f1count[1] > 3 * 4 * 5) abort (); + + /* Check that the innermost loop body is executed exactly the number + of logical iterations expected. */ + if (f1count[2] != 3 * 4 * 5) abort (); +} diff --git a/libgomp/testsuite/libgomp.c-c++-common/imperfect4.c b/libgomp/testsuite/libgomp.c-c++-common/imperfect4.c new file mode 100644 index 000000000000..e29301bfbad2 --- /dev/null +++ b/libgomp/testsuite/libgomp.c-c++-common/imperfect4.c @@ -0,0 +1,117 @@ +/* { dg-do run } */ + +/* Like imperfect2.c, but includes blocks that are themselves intervening + code. */ + +static int f1count[3], f2count[3]; +static int g1count[3], g2count[3]; + +#ifndef __cplusplus +extern void abort (void); +#else +extern "C" void abort (void); +#endif + +int f1 (int depth, int iter) +{ + f1count[depth]++; + return iter; +} + +int f2 (int depth, int iter) +{ + f2count[depth]++; + return iter; +} + +int g1 (int depth, int iter) +{ + g1count[depth]++; + return iter; +} + +int g2 (int depth, int iter) +{ + g2count[depth]++; + return iter; +} + +void s1 (int a1, int a2, int a3) +{ + int i, j, k; + +#pragma omp for collapse(3) + for (i = 0; i < a1; i++) + { + { f1 (0, i); } + { + g1 (0, i); + for (j = 0; j < a2; j++) + { + { f1 (1, j); } + { + { g1 (1, j); } + for (k = 0; k < a3; k++) + { + f1 (2, k); + { + g1 (2, k); + g2 (2, k); + } + f2 (2, k); + } + { g2 (1, j); } + } + { f2 (1, j); } + } + { g2 (0, i); } + } + { f2 (0, i); } + } +} + +int +main (void) +{ + f1count[0] = 0; + f1count[1] = 0; + f1count[2] = 0; + f2count[0] = 0; + f2count[1] = 0; + f2count[2] = 0; + + g1count[0] = 0; + g1count[1] = 0; + g1count[2] = 0; + g2count[0] = 0; + g2count[1] = 0; + g2count[2] = 0; + + s1 (3, 4, 5); + + /* All intervening code at the same depth must be executed the same + number of times. */ + if (f1count[0] != f2count[0]) abort (); + if (f1count[1] != f2count[1]) abort (); + if (f1count[2] != f2count[2]) abort (); + if (g1count[0] != f1count[0]) abort (); + if (g2count[0] != f1count[0]) abort (); + if (g1count[1] != f1count[1]) abort (); + if (g2count[1] != f1count[1]) abort (); + if (g1count[2] != f1count[2]) abort (); + if (g2count[2] != f1count[2]) abort (); + + /* Intervening code must be executed at least as many times as the loop + that encloses it. */ + if (f1count[0] < 3) abort (); + if (f1count[1] < 3 * 4) abort (); + + /* Intervening code must not be executed more times than the number + of logical iterations. */ + if (f1count[0] > 3 * 4 * 5) abort (); + if (f1count[1] > 3 * 4 * 5) abort (); + + /* Check that the innermost loop body is executed exactly the number + of logical iterations expected. */ + if (f1count[2] != 3 * 4 * 5) abort (); +} diff --git a/libgomp/testsuite/libgomp.c-c++-common/imperfect5.c b/libgomp/testsuite/libgomp.c-c++-common/imperfect5.c new file mode 100644 index 000000000000..7bd4f12d472b --- /dev/null +++ b/libgomp/testsuite/libgomp.c-c++-common/imperfect5.c @@ -0,0 +1,49 @@ +/* { dg-do run } */ + +#ifndef __cplusplus +extern void abort (void); +#else +extern "C" void abort (void); +#endif + +static int inner_loop_count = 0; +static int intervening_code_count = 0; + +void +g (int x, int y) +{ + inner_loop_count++; +} + +int +foo (int imax, int jmax) +{ + int j = 0; + +#pragma omp for collapse(2) + for (int i = 0; i < imax; ++i) + { + /* All the intervening code at the same level must be executed + the same number of times. */ + ++intervening_code_count; + for (int j = 0; j < jmax; ++j) + { + g (i, j); + } + /* This is the outer j, not the one from the inner collapsed loop. */ + ++j; + } + return j; +} + +int +main (void) +{ + int j = foo (5, 3); + if (j != intervening_code_count) + abort (); + if (inner_loop_count != 5 * 3) + abort (); + if (intervening_code_count < 5 || intervening_code_count > 5 * 3) + abort (); +} diff --git a/libgomp/testsuite/libgomp.c-c++-common/imperfect6.c b/libgomp/testsuite/libgomp.c-c++-common/imperfect6.c new file mode 100644 index 000000000000..808c65408900 --- /dev/null +++ b/libgomp/testsuite/libgomp.c-c++-common/imperfect6.c @@ -0,0 +1,115 @@ +/* { dg-do run } */ + +/* Like imperfect4.c, but bind the iteration variables in the loops. */ + +static int f1count[3], f2count[3]; +static int g1count[3], g2count[3]; + +#ifndef __cplusplus +extern void abort (void); +#else +extern "C" void abort (void); +#endif + +int f1 (int depth, int iter) +{ + f1count[depth]++; + return iter; +} + +int f2 (int depth, int iter) +{ + f2count[depth]++; + return iter; +} + +int g1 (int depth, int iter) +{ + g1count[depth]++; + return iter; +} + +int g2 (int depth, int iter) +{ + g2count[depth]++; + return iter; +} + +void s1 (int a1, int a2, int a3) +{ + +#pragma omp for collapse(3) + for (int i = 0; i < a1; i++) + { + { f1 (0, i); } + { + g1 (0, i); + for (int j = 0; j < a2; j++) + { + { f1 (1, j); } + { + { g1 (1, j); } + for (int k = 0; k < a3; k++) + { + f1 (2, k); + { + g1 (2, k); + g2 (2, k); + } + f2 (2, k); + } + { g2 (1, j); } + } + { f2 (1, j); } + } + { g2 (0, i); } + } + { f2 (0, i); } + } +} + +int +main (void) +{ + f1count[0] = 0; + f1count[1] = 0; + f1count[2] = 0; + f2count[0] = 0; + f2count[1] = 0; + f2count[2] = 0; + + g1count[0] = 0; + g1count[1] = 0; + g1count[2] = 0; + g2count[0] = 0; + g2count[1] = 0; + g2count[2] = 0; + + s1 (3, 4, 5); + + /* All intervening code at the same depth must be executed the same + number of times. */ + if (f1count[0] != f2count[0]) abort (); + if (f1count[1] != f2count[1]) abort (); + if (f1count[2] != f2count[2]) abort (); + if (g1count[0] != f1count[0]) abort (); + if (g2count[0] != f1count[0]) abort (); + if (g1count[1] != f1count[1]) abort (); + if (g2count[1] != f1count[1]) abort (); + if (g1count[2] != f1count[2]) abort (); + if (g2count[2] != f1count[2]) abort (); + + /* Intervening code must be executed at least as many times as the loop + that encloses it. */ + if (f1count[0] < 3) abort (); + if (f1count[1] < 3 * 4) abort (); + + /* Intervening code must not be executed more times than the number + of logical iterations. */ + if (f1count[0] > 3 * 4 * 5) abort (); + if (f1count[1] > 3 * 4 * 5) abort (); + + /* Check that the innermost loop body is executed exactly the number + of logical iterations expected. */ + if (f1count[2] != 3 * 4 * 5) abort (); +} diff --git a/libgomp/testsuite/libgomp.c-c++-common/non-rect-loop-1.c b/libgomp/testsuite/libgomp.c-c++-common/non-rect-loop-1.c new file mode 100644 index 000000000000..fbd462b36831 --- /dev/null +++ b/libgomp/testsuite/libgomp.c-c++-common/non-rect-loop-1.c @@ -0,0 +1,72 @@ +/* PR middle-end/111017 */ + +#include + +#define DIM 32 +#define N (DIM*DIM) + +int +main () +{ + int a[N], b[N], c[N]; + int dim = DIM; + + for (int i = 0; i < N; i++) + { + a[i] = 3*i; + b[i] = 7*i; + c[i] = 42; + } + + #pragma omp parallel for collapse(2) + for (int i = 0; i < DIM; i++) + for (int j = (i*DIM); j < (i*DIM + DIM); j++) + c[j] = a[j] + b[j]; + + for (int i = 0; i < DIM; i++) + for (int j = (i*DIM); j < (i*DIM + DIM); j++) + if (c[j] != a[j] + b[j] || c[j] != 3*j +7*j) + __builtin_abort (); + for (int i = 0; i < N; i++) + c[i] = 42; + + #pragma omp parallel for collapse(2) + for (int i = 0; i < dim; i++) + for (int j = (i*dim); j < (i*dim + dim); j++) + c[j] = a[j] + b[j]; + + for (int i = 0; i < DIM; i++) + for (int j = (i*DIM); j < (i*DIM + DIM); j++) + if (c[j] != a[j] + b[j] || c[j] != 3*j +7*j) + __builtin_abort (); + for (int i = 0; i < N; i++) + c[i] = 42; + + for (int dev = 0; dev <= omp_get_num_devices(); dev++) + { + #pragma omp target teams loop device(dev) map(to:a,b) map(from:c) + for (int i = 0; i < DIM; i++) + for (int j = (i*DIM); j < (i*DIM + DIM); j++) + c[j] = a[j] + b[j]; + + for (int i = 0; i < DIM; i++) + for (int j = (i*DIM); j < (i*DIM + DIM); j++) + if (c[j] != a[j] + b[j] || c[j] != 3*j +7*j) + __builtin_abort (); + for (int i = 0; i < N; i++) + c[i] = 42; + + #pragma omp target teams loop device(dev) map(to:a,b) map(from:c) + for (int i = 0; i < dim; i++) + for (int j = (i*dim); j < (i*dim + dim); j++) + c[j] = a[j] + b[j]; + + for (int i = 0; i < DIM; i++) + for (int j = (i*DIM); j < (i*DIM + DIM); j++) + if (c[j] != a[j] + b[j] || c[j] != 3*j +7*j) + __builtin_abort (); + for (int i = 0; i < N; i++) + c[i] = 42; + } + return 0; +} diff --git a/libgomp/testsuite/libgomp.c-c++-common/pr100059-1.c b/libgomp/testsuite/libgomp.c-c++-common/pr100059-1.c new file mode 100644 index 000000000000..af12295541a2 --- /dev/null +++ b/libgomp/testsuite/libgomp.c-c++-common/pr100059-1.c @@ -0,0 +1,55 @@ +/* Based on sollve_vv's tests/5.0/declare_target/test_nested_declare_target.c. */ + +#define N 1024 +int a[N], b[N], c[N]; +int i = 0; + +void +update () +{ + for (i = 0; i < N; i++) + { + a[i] += 1; + b[i] += 2; + c[i] += 3; + } +} + +#pragma omp declare target +#pragma omp declare target link(a,c,b,i) +#pragma omp declare target to(update) +#pragma omp end declare target + +int +main () +{ + for (i = 0; i < N; i++) + { + a[i] = i; + b[i] = i + 1; + c[i] = i + 2; + } + + //__builtin_printf("i=5: A=%d, B=%d, C=%d\n", a[5], b[5], c[5]); + + #pragma omp target map(to: i) map(tofrom: a, b, c) + { + update(); /* Device. */ + } + + //__builtin_printf("i=5: A=%d, B=%d, C=%d\n", a[5], b[5], c[5]); + + for (i = 0; i < N; i++) + if ( a[i] != i + 1 || b[i] != i + 3 || c[i] != i + 5) + __builtin_abort(); + + update(); /* Host. */ + + //__builtin_printf("i=5: A=%d, B=%d, C=%d\n", a[5], b[5], c[5]); + + for (i = 0; i < N; i++) + if ( a[i] != i + 2 || b[i] != i + 5 || c[i] != i + 8) + __builtin_abort (); + + return 0; +} diff --git a/libgomp/testsuite/libgomp.c-c++-common/target-imperfect1.c b/libgomp/testsuite/libgomp.c-c++-common/target-imperfect1.c new file mode 100644 index 000000000000..53bc611ace3a --- /dev/null +++ b/libgomp/testsuite/libgomp.c-c++-common/target-imperfect1.c @@ -0,0 +1,81 @@ +/* { dg-do run } */ + +/* Like imperfect1.c, but enables offloading. */ + +static int f1count[3], f2count[3]; +#pragma omp declare target enter (f1count, f2count) + +#ifndef __cplusplus +extern void abort (void); +#else +extern "C" void abort (void); +#endif + +int f1 (int depth, int iter) +{ + #pragma omp atomic + f1count[depth]++; + return iter; +} + +int f2 (int depth, int iter) +{ + #pragma omp atomic + f2count[depth]++; + return iter; +} + +void s1 (int a1, int a2, int a3) +{ + int i, j, k; + +#pragma omp target parallel for collapse(3) map(always, tofrom:f1count, f2count) + for (i = 0; i < a1; i++) + { + f1 (0, i); + for (j = 0; j < a2; j++) + { + f1 (1, j); + for (k = 0; k < a3; k++) + { + f1 (2, k); + f2 (2, k); + } + f2 (1, j); + } + f2 (0, i); + } +} + +int +main (void) +{ + f1count[0] = 0; + f1count[1] = 0; + f1count[2] = 0; + f2count[0] = 0; + f2count[1] = 0; + f2count[2] = 0; + + s1 (3, 4, 5); + + /* All intervening code at the same depth must be executed the same + number of times. */ + if (f1count[0] != f2count[0]) abort (); + if (f1count[1] != f2count[1]) abort (); + if (f1count[2] != f2count[2]) abort (); + + /* Intervening code must be executed at least as many times as the loop + that encloses it. */ + if (f1count[0] < 3) abort (); + if (f1count[1] < 3 * 4) abort (); + + /* Intervening code must not be executed more times than the number + of logical iterations. */ + if (f1count[0] > 3 * 4 * 5) abort (); + if (f1count[1] > 3 * 4 * 5) abort (); + + /* Check that the innermost loop body is executed exactly the number + of logical iterations expected. */ + if (f1count[2] != 3 * 4 * 5) abort (); +} diff --git a/libgomp/testsuite/libgomp.c-c++-common/target-imperfect2.c b/libgomp/testsuite/libgomp.c-c++-common/target-imperfect2.c new file mode 100644 index 000000000000..bc2901a517e6 --- /dev/null +++ b/libgomp/testsuite/libgomp.c-c++-common/target-imperfect2.c @@ -0,0 +1,122 @@ +/* { dg-do run } */ + +/* Like imperfect2.c, but enables offloading. */ + +static int f1count[3], f2count[3]; +static int g1count[3], g2count[3]; +#pragma omp declare target enter (f1count, f2count) +#pragma omp declare target enter (g1count, g2count) + +#ifndef __cplusplus +extern void abort (void); +#else +extern "C" void abort (void); +#endif + +int f1 (int depth, int iter) +{ + #pragma omp atomic + f1count[depth]++; + return iter; +} + +int f2 (int depth, int iter) +{ + #pragma omp atomic + f2count[depth]++; + return iter; +} + +int g1 (int depth, int iter) +{ + #pragma omp atomic + g1count[depth]++; + return iter; +} + +int g2 (int depth, int iter) +{ + #pragma omp atomic + g2count[depth]++; + return iter; +} + +void s1 (int a1, int a2, int a3) +{ + int i, j, k; + +#pragma omp target parallel for collapse(3) map(always, tofrom:f1count, f2count, g1count, g2count) + for (i = 0; i < a1; i++) + { + f1 (0, i); + { + g1 (0, i); + for (j = 0; j < a2; j++) + { + f1 (1, j); + { + g1 (1, j); + for (k = 0; k < a3; k++) + { + f1 (2, k); + { + g1 (2, k); + g2 (2, k); + } + f2 (2, k); + } + g2 (1, j); + } + f2 (1, j); + } + g2 (0, i); + } + f2 (0, i); + } +} + +int +main (void) +{ + f1count[0] = 0; + f1count[1] = 0; + f1count[2] = 0; + f2count[0] = 0; + f2count[1] = 0; + f2count[2] = 0; + + g1count[0] = 0; + g1count[1] = 0; + g1count[2] = 0; + g2count[0] = 0; + g2count[1] = 0; + g2count[2] = 0; + + s1 (3, 4, 5); + + /* All intervening code at the same depth must be executed the same + number of times. */ + if (f1count[0] != f2count[0]) abort (); + if (f1count[1] != f2count[1]) abort (); + if (f1count[2] != f2count[2]) abort (); + if (g1count[0] != f1count[0]) abort (); + if (g2count[0] != f1count[0]) abort (); + if (g1count[1] != f1count[1]) abort (); + if (g2count[1] != f1count[1]) abort (); + if (g1count[2] != f1count[2]) abort (); + if (g2count[2] != f1count[2]) abort (); + + /* Intervening code must be executed at least as many times as the loop + that encloses it. */ + if (f1count[0] < 3) abort (); + if (f1count[1] < 3 * 4) abort (); + + /* Intervening code must not be executed more times than the number + of logical iterations. */ + if (f1count[0] > 3 * 4 * 5) abort (); + if (f1count[1] > 3 * 4 * 5) abort (); + + /* Check that the innermost loop body is executed exactly the number + of logical iterations expected. */ + if (f1count[2] != 3 * 4 * 5) abort (); +} diff --git a/libgomp/testsuite/libgomp.c-c++-common/target-imperfect3.c b/libgomp/testsuite/libgomp.c-c++-common/target-imperfect3.c new file mode 100644 index 000000000000..ddcfcf4b7ebc --- /dev/null +++ b/libgomp/testsuite/libgomp.c-c++-common/target-imperfect3.c @@ -0,0 +1,125 @@ +/* { dg-do run } */ + +/* Like imperfect3.c, but enables offloading. */ + +static int f1count[3], f2count[3]; +static int g1count[3], g2count[3]; +#pragma omp declare target enter (f1count, f2count) +#pragma omp declare target enter (g1count, g2count) + +#ifndef __cplusplus +extern void abort (void); +#else +extern "C" void abort (void); +#endif + +int f1 (int depth, int iter) +{ + #pragma omp atomic + f1count[depth]++; + return iter; +} + +int f2 (int depth, int iter) +{ + #pragma omp atomic + f2count[depth]++; + return iter; +} + +int g1 (int depth, int iter) +{ + #pragma omp atomic + g1count[depth]++; + return iter; +} + +int g2 (int depth, int iter) +{ + #pragma omp atomic + g2count[depth]++; + return iter; +} + +void s1 (int a1, int a2, int a3) +{ + int i, j, k; + +#pragma omp target parallel for collapse(3) map(always, tofrom:f1count, f2count, g1count, g2count) + for (i = 0; i < a1; i++) + { + int local0 = 0; + f1 (local0, i); + { + g1 (local0, i); + for (j = 0; j < a2; j++) + { + int local1 = 1; + f1 (local1, j); + { + g1 (local1, j); + for (k = 0; k < a3; k++) + { + int local2 = 2; + f1 (local2, k); + { + g1 (local2, k); + g2 (local2, k); + } + f2 (local2, k); + } + g2 (local1, j); + } + f2 (local1, j); + } + g2 (local0, i); + } + f2 (local0, i); + } +} + +int +main (void) +{ + f1count[0] = 0; + f1count[1] = 0; + f1count[2] = 0; + f2count[0] = 0; + f2count[1] = 0; + f2count[2] = 0; + + g1count[0] = 0; + g1count[1] = 0; + g1count[2] = 0; + g2count[0] = 0; + g2count[1] = 0; + g2count[2] = 0; + + s1 (3, 4, 5); + + /* All intervening code at the same depth must be executed the same + number of times. */ + if (f1count[0] != f2count[0]) abort (); + if (f1count[1] != f2count[1]) abort (); + if (f1count[2] != f2count[2]) abort (); + if (g1count[0] != f1count[0]) abort (); + if (g2count[0] != f1count[0]) abort (); + if (g1count[1] != f1count[1]) abort (); + if (g2count[1] != f1count[1]) abort (); + if (g1count[2] != f1count[2]) abort (); + if (g2count[2] != f1count[2]) abort (); + + /* Intervening code must be executed at least as many times as the loop + that encloses it. */ + if (f1count[0] < 3) abort (); + if (f1count[1] < 3 * 4) abort (); + + /* Intervening code must not be executed more times than the number + of logical iterations. */ + if (f1count[0] > 3 * 4 * 5) abort (); + if (f1count[1] > 3 * 4 * 5) abort (); + + /* Check that the innermost loop body is executed exactly the number + of logical iterations expected. */ + if (f1count[2] != 3 * 4 * 5) abort (); +} diff --git a/libgomp/testsuite/libgomp.c-c++-common/target-imperfect4.c b/libgomp/testsuite/libgomp.c-c++-common/target-imperfect4.c new file mode 100644 index 000000000000..ede488977b88 --- /dev/null +++ b/libgomp/testsuite/libgomp.c-c++-common/target-imperfect4.c @@ -0,0 +1,122 @@ +/* { dg-do run } */ + +/* Like imperfect4.c, but enables offloading. */ + +static int f1count[3], f2count[3]; +static int g1count[3], g2count[3]; +#pragma omp declare target enter (f1count, f2count) +#pragma omp declare target enter (g1count, g2count) + +#ifndef __cplusplus +extern void abort (void); +#else +extern "C" void abort (void); +#endif + +int f1 (int depth, int iter) +{ + #pragma omp atomic + f1count[depth]++; + return iter; +} + +int f2 (int depth, int iter) +{ + #pragma omp atomic + f2count[depth]++; + return iter; +} + +int g1 (int depth, int iter) +{ + #pragma omp atomic + g1count[depth]++; + return iter; +} + +int g2 (int depth, int iter) +{ + #pragma omp atomic + g2count[depth]++; + return iter; +} + +void s1 (int a1, int a2, int a3) +{ + int i, j, k; + +#pragma omp target parallel for collapse(3) map(always, tofrom:f1count, f2count, g1count, g2count) + for (i = 0; i < a1; i++) + { + { f1 (0, i); } + { + g1 (0, i); + for (j = 0; j < a2; j++) + { + { f1 (1, j); } + { + { g1 (1, j); } + for (k = 0; k < a3; k++) + { + f1 (2, k); + { + g1 (2, k); + g2 (2, k); + } + f2 (2, k); + } + { g2 (1, j); } + } + { f2 (1, j); } + } + { g2 (0, i); } + } + { f2 (0, i); } + } +} + +int +main (void) +{ + f1count[0] = 0; + f1count[1] = 0; + f1count[2] = 0; + f2count[0] = 0; + f2count[1] = 0; + f2count[2] = 0; + + g1count[0] = 0; + g1count[1] = 0; + g1count[2] = 0; + g2count[0] = 0; + g2count[1] = 0; + g2count[2] = 0; + + s1 (3, 4, 5); + + /* All intervening code at the same depth must be executed the same + number of times. */ + if (f1count[0] != f2count[0]) abort (); + if (f1count[1] != f2count[1]) abort (); + if (f1count[2] != f2count[2]) abort (); + if (g1count[0] != f1count[0]) abort (); + if (g2count[0] != f1count[0]) abort (); + if (g1count[1] != f1count[1]) abort (); + if (g2count[1] != f1count[1]) abort (); + if (g1count[2] != f1count[2]) abort (); + if (g2count[2] != f1count[2]) abort (); + + /* Intervening code must be executed at least as many times as the loop + that encloses it. */ + if (f1count[0] < 3) abort (); + if (f1count[1] < 3 * 4) abort (); + + /* Intervening code must not be executed more times than the number + of logical iterations. */ + if (f1count[0] > 3 * 4 * 5) abort (); + if (f1count[1] > 3 * 4 * 5) abort (); + + /* Check that the innermost loop body is executed exactly the number + of logical iterations expected. */ + if (f1count[2] != 3 * 4 * 5) abort (); +} diff --git a/libgomp/testsuite/libgomp.c/simd-math-1.c b/libgomp/testsuite/libgomp.c/simd-math-1.c index dd2077cc5973..42a008c80fc8 100644 --- a/libgomp/testsuite/libgomp.c/simd-math-1.c +++ b/libgomp/testsuite/libgomp.c/simd-math-1.c @@ -4,6 +4,7 @@ /* { dg-do run } */ /* { dg-options "-O2 -ftree-vectorize -fno-math-errno" } */ /* { dg-additional-options -foffload-options=amdgcn-amdhsa=-mstack-size=3000000 { target offload_target_amdgcn } } */ +/* { dg-additional-options "-DNONSTDFUNC=1" { target nonstandard_math_functions } } */ #undef PRINT_RESULT #define VERBOSE 0 @@ -160,7 +161,9 @@ int main (void) TEST_FUN (float, -10.0, 10.0, expf); TEST_FUN (float, -10.0, 10.0, exp2f); TEST_FUN2 (float, -10.0, 10.0, 100.0, -25.0, fmodf); +#ifdef NONSTDFUNC TEST_FUN (float, -10.0, 10.0, gammaf); +#endif TEST_FUN2 (float, -10.0, 10.0, 15.0, -5.0,hypotf); TEST_FUN (float, -10.0, 10.0, lgammaf); TEST_FUN (float, -1.0, 50.0, logf); @@ -169,8 +172,10 @@ int main (void) TEST_FUN2 (float, -100.0, 100.0, 100.0, -100.0, powf); TEST_FUN2 (float, -50.0, 100.0, -2.0, 40.0, remainderf); TEST_FUN (float, -50.0, 50.0, rintf); +#ifdef NONSTDFUNC TEST_FUN2 (float, -50.0, 50.0, -10.0, 32.0, __builtin_scalbf); TEST_FUN (float, -10.0, 10.0, __builtin_significandf); +#endif TEST_FUN (float, -3.14159265359, 3.14159265359, sinf); TEST_FUN (float, -3.14159265359, 3.14159265359, sinhf); TEST_FUN (float, -0.1, 10000.0, sqrtf); @@ -193,7 +198,9 @@ int main (void) TEST_FUN (double, -10.0, 10.0, exp); TEST_FUN (double, -10.0, 10.0, exp2); TEST_FUN2 (double, -10.0, 10.0, 100.0, -25.0, fmod); +#ifdef NONSTDFUNC TEST_FUN (double, -10.0, 10.0, gamma); +#endif TEST_FUN2 (double, -10.0, 10.0, 15.0, -5.0, hypot); TEST_FUN (double, -10.0, 10.0, lgamma); TEST_FUN (double, -1.0, 50.0, log); @@ -202,8 +209,10 @@ int main (void) TEST_FUN2 (double, -100.0, 100.0, 100.0, -100.0, pow); TEST_FUN2 (double, -50.0, 100.0, -2.0, 40.0, remainder); TEST_FUN (double, -50.0, 50.0, rint); +#ifdef NONSTDFUNC TEST_FUN2 (double, -50.0, 50.0, -10.0, 32.0, __builtin_scalb); TEST_FUN (double, -10.0, 10.0, __builtin_significand); +#endif TEST_FUN (double, -3.14159265359, 3.14159265359, sin); TEST_FUN (double, -3.14159265359, 3.14159265359, sinh); TEST_FUN (double, -0.1, 10000.0, sqrt); diff --git a/libgomp/testsuite/libgomp.fortran/imperfect-destructor.f90 b/libgomp/testsuite/libgomp.fortran/imperfect-destructor.f90 new file mode 100644 index 000000000000..664d27fe9684 --- /dev/null +++ b/libgomp/testsuite/libgomp.fortran/imperfect-destructor.f90 @@ -0,0 +1,142 @@ +! { dg-do run } + +! Like imperfect2.f90, but adds bindings to the blocks. + +module m + implicit none + type t + integer :: i + contains + final :: fini + end type t + + integer :: ccount(3), dcount(3) + + contains + + subroutine init(x, n) + type(t) :: x + integer :: n + x%i = n + ccount(x%i) = ccount(x%i) + 1 + end subroutine init + + subroutine fini(x) + type(t) :: x + dcount(x%i) = dcount(x%i) + 1 + end subroutine fini +end module m + +program foo + use m + + integer :: f1count(3), f2count(3), g1count(3), g2count(3) + + f1count(1) = 0 + f1count(2) = 0 + f1count(3) = 0 + f2count(1) = 0 + f2count(2) = 0 + f2count(3) = 0 + + g1count(1) = 0 + g1count(2) = 0 + g1count(3) = 0 + g2count(1) = 0 + g2count(2) = 0 + g2count(3) = 0 + + call s1 (3, 4, 5) + + ! All intervening code at the same depth must be executed the same + ! number of times. + if (f1count(1) /= f2count(1)) error stop 101 + if (f1count(2) /= f2count(2)) error stop 102 + if (f1count(3) /= f2count(3)) error stop 103 + if (g1count(1) /= f1count(1)) error stop 104 + if (g2count(1) /= f1count(1)) error stop 105 + if (g1count(2) /= f1count(2)) error stop 106 + if (g2count(2) /= f1count(2)) error stop 107 + if (g1count(3) /= f1count(3)) error stop 108 + if (g2count(3) /= f1count(3)) error stop 109 + + ! Intervening code must be executed at least as many times as the loop + ! that encloses it. + if (f1count(1) < 3) error stop 111 + if (f1count(2) < 3 * 4) error stop 112 + + ! Intervening code must not be executed more times than the number + ! of logical iterations. + if (f1count(1) > 3 * 4 * 5) error stop 121 + if (f1count(2) > 3 * 4 * 5) error stop 122 + + ! Check that the innermost loop body is executed exactly the number + ! of logical iterations expected. + if (f1count(3) /= 3 * 4 * 5) error stop 131 + + ! Check that constructors and destructors are called equal number of times. + if (ccount(1) /= dcount(1)) error stop 141 + if (ccount(2) /= dcount(2)) error stop 142 + if (ccount(3) /= dcount(3)) error stop 143 + +contains + +subroutine f1 (depth, iter) + integer :: depth, iter + f1count(depth) = f1count(depth) + 1 +end subroutine + +subroutine f2 (depth, iter) + integer :: depth, iter + f2count(depth) = f2count(depth) + 1 +end subroutine + +subroutine g1 (depth, iter) + integer :: depth, iter + g1count(depth) = g1count(depth) + 1 +end subroutine + +subroutine g2 (depth, iter) + integer :: depth, iter + g2count(depth) = g2count(depth) + 1 +end subroutine + +subroutine s1 (a1, a2, a3) + integer :: a1, a2, a3 + integer :: i, j, k + + !$omp do collapse(3) + do i = 1, a1 + call f1 (1, i) + block + type (t) :: local1 + call init (local1, 1) + call g1 (local1%i, i) + do j = 1, a2 + call f1 (2, j) + block + type (t) :: local2 + call init (local2, 2) + call g1 (local2%i, j) + do k = 1, a3 + call f1 (3, k) + block + type (t) :: local3 + call init (local3, 3) + call g1 (local3%i, k) + call g2 (local3%i, k) + end block + call f2 (3, k) + end do + call g2 (local2%i, j) + end block + call f2 (2, j) + end do + call g2 (local1%i, i) + end block + call f2 (1, i) + end do + +end subroutine + +end program diff --git a/libgomp/testsuite/libgomp.fortran/imperfect1.f90 b/libgomp/testsuite/libgomp.fortran/imperfect1.f90 new file mode 100644 index 000000000000..8c483c2a4e5e --- /dev/null +++ b/libgomp/testsuite/libgomp.fortran/imperfect1.f90 @@ -0,0 +1,67 @@ +! { dg-do run } + +program foo + integer, save :: f1count(3), f2count(3) + + f1count(1) = 0 + f1count(2) = 0 + f1count(3) = 0 + f2count(1) = 0 + f2count(2) = 0 + f2count(3) = 0 + + call s1 (3, 4, 5) + + ! All intervening code at the same depth must be executed the same + ! number of times. + if (f1count(1) /= f2count(1)) error stop 101 + if (f1count(2) /= f2count(2)) error stop 102 + if (f1count(3) /= f2count(3)) error stop 103 + + ! Intervening code must be executed at least as many times as the loop + ! that encloses it. + if (f1count(1) < 3) error stop 111 + if (f1count(2) < 3 * 4) error stop 112 + + ! Intervening code must not be executed more times than the number + ! of logical iterations. + if (f1count(1) > 3 * 4 * 5) error stop 121 + if (f1count(2) > 3 * 4 * 5) error stop 122 + + ! Check that the innermost loop body is executed exactly the number + ! of logical iterations expected. + if (f1count(3) /= 3 * 4 * 5) error stop 131 + +contains + +subroutine f1 (depth, iter) + integer :: depth, iter + f1count(depth) = f1count(depth) + 1 +end subroutine + +subroutine f2 (depth, iter) + integer :: depth, iter + f2count(depth) = f2count(depth) + 1 +end subroutine + +subroutine s1 (a1, a2, a3) + integer :: a1, a2, a3 + integer :: i, j, k + + !$omp do collapse(3) + do i = 1, a1 + call f1 (1, i) + do j = 1, a2 + call f1 (2, j) + do k = 1, a3 + call f1 (3, k) + call f2 (3, k) + end do + call f2 (2, j) + end do + call f2 (1, i) + end do + +end subroutine + +end program diff --git a/libgomp/testsuite/libgomp.fortran/imperfect2.f90 b/libgomp/testsuite/libgomp.fortran/imperfect2.f90 new file mode 100644 index 000000000000..e42cb08031b1 --- /dev/null +++ b/libgomp/testsuite/libgomp.fortran/imperfect2.f90 @@ -0,0 +1,102 @@ +! { dg-do run } + +program foo + integer, save :: f1count(3), f2count(3), g1count(3), g2count(3) + + f1count(1) = 0 + f1count(2) = 0 + f1count(3) = 0 + f2count(1) = 0 + f2count(2) = 0 + f2count(3) = 0 + + g1count(1) = 0 + g1count(2) = 0 + g1count(3) = 0 + g2count(1) = 0 + g2count(2) = 0 + g2count(3) = 0 + + call s1 (3, 4, 5) + + ! All intervening code at the same depth must be executed the same + ! number of times. + if (f1count(1) /= f2count(1)) error stop 101 + if (f1count(2) /= f2count(2)) error stop 102 + if (f1count(3) /= f2count(3)) error stop 103 + if (g1count(1) /= f1count(1)) error stop 104 + if (g2count(1) /= f1count(1)) error stop 105 + if (g1count(2) /= f1count(2)) error stop 106 + if (g2count(2) /= f1count(2)) error stop 107 + if (g1count(3) /= f1count(3)) error stop 108 + if (g2count(3) /= f1count(3)) error stop 109 + + ! Intervening code must be executed at least as many times as the loop + ! that encloses it. + if (f1count(1) < 3) error stop 111 + if (f1count(2) < 3 * 4) error stop 112 + + ! Intervening code must not be executed more times than the number + ! of logical iterations. + if (f1count(1) > 3 * 4 * 5) error stop 121 + if (f1count(2) > 3 * 4 * 5) error stop 122 + + ! Check that the innermost loop body is executed exactly the number + ! of logical iterations expected. + if (f1count(3) /= 3 * 4 * 5) error stop 131 + +contains + +subroutine f1 (depth, iter) + integer :: depth, iter + f1count(depth) = f1count(depth) + 1 +end subroutine + +subroutine f2 (depth, iter) + integer :: depth, iter + f2count(depth) = f2count(depth) + 1 +end subroutine + +subroutine g1 (depth, iter) + integer :: depth, iter + g1count(depth) = g1count(depth) + 1 +end subroutine + +subroutine g2 (depth, iter) + integer :: depth, iter + g2count(depth) = g2count(depth) + 1 +end subroutine + +subroutine s1 (a1, a2, a3) + integer :: a1, a2, a3 + integer :: i, j, k + + !$omp do collapse(3) + do i = 1, a1 + call f1 (1, i) + block + call g1 (1, i) + do j = 1, a2 + call f1 (2, j) + block + call g1 (2, j) + do k = 1, a3 + call f1 (3, k) + block + call g1 (3, k) + call g2 (3, k) + end block + call f2 (3, k) + end do + call g2 (2, j) + end block + call f2 (2, j) + end do + call g2 (1, i) + end block + call f2 (1, i) + end do + +end subroutine + +end program diff --git a/libgomp/testsuite/libgomp.fortran/imperfect3.f90 b/libgomp/testsuite/libgomp.fortran/imperfect3.f90 new file mode 100644 index 000000000000..da0946123328 --- /dev/null +++ b/libgomp/testsuite/libgomp.fortran/imperfect3.f90 @@ -0,0 +1,110 @@ +! { dg-do run } + +! Like imperfect2.f90, but adds bindings to the blocks. + +program foo + integer, save :: f1count(3), f2count(3), g1count(3), g2count(3) + + f1count(1) = 0 + f1count(2) = 0 + f1count(3) = 0 + f2count(1) = 0 + f2count(2) = 0 + f2count(3) = 0 + + g1count(1) = 0 + g1count(2) = 0 + g1count(3) = 0 + g2count(1) = 0 + g2count(2) = 0 + g2count(3) = 0 + + call s1 (3, 4, 5) + + ! All intervening code at the same depth must be executed the same + ! number of times. + if (f1count(1) /= f2count(1)) error stop 101 + if (f1count(2) /= f2count(2)) error stop 102 + if (f1count(3) /= f2count(3)) error stop 103 + if (g1count(1) /= f1count(1)) error stop 104 + if (g2count(1) /= f1count(1)) error stop 105 + if (g1count(2) /= f1count(2)) error stop 106 + if (g2count(2) /= f1count(2)) error stop 107 + if (g1count(3) /= f1count(3)) error stop 108 + if (g2count(3) /= f1count(3)) error stop 109 + + ! Intervening code must be executed at least as many times as the loop + ! that encloses it. + if (f1count(1) < 3) error stop 111 + if (f1count(2) < 3 * 4) error stop 112 + + ! Intervening code must not be executed more times than the number + ! of logical iterations. + if (f1count(1) > 3 * 4 * 5) error stop 121 + if (f1count(2) > 3 * 4 * 5) error stop 122 + + ! Check that the innermost loop body is executed exactly the number + ! of logical iterations expected. + if (f1count(3) /= 3 * 4 * 5) error stop 131 + +contains + +subroutine f1 (depth, iter) + integer :: depth, iter + f1count(depth) = f1count(depth) + 1 +end subroutine + +subroutine f2 (depth, iter) + integer :: depth, iter + f2count(depth) = f2count(depth) + 1 +end subroutine + +subroutine g1 (depth, iter) + integer :: depth, iter + g1count(depth) = g1count(depth) + 1 +end subroutine + +subroutine g2 (depth, iter) + integer :: depth, iter + g2count(depth) = g2count(depth) + 1 +end subroutine + +subroutine s1 (a1, a2, a3) + integer :: a1, a2, a3 + integer :: i, j, k + + !$omp do collapse(3) + do i = 1, a1 + call f1 (1, i) + block + integer :: local1 + local1 = 1 + call g1 (local1, i) + do j = 1, a2 + call f1 (2, j) + block + integer :: local2 + local2 = 2 + call g1 (local2, j) + do k = 1, a3 + call f1 (3, k) + block + integer :: local3 + local3 = 3 + call g1 (local3, k) + call g2 (local3, k) + end block + call f2 (3, k) + end do + call g2 (local2, j) + end block + call f2 (2, j) + end do + call g2 (local1, i) + end block + call f2 (1, i) + end do + +end subroutine + +end program diff --git a/libgomp/testsuite/libgomp.fortran/imperfect4.f90 b/libgomp/testsuite/libgomp.fortran/imperfect4.f90 new file mode 100644 index 000000000000..1679c8c5b92b --- /dev/null +++ b/libgomp/testsuite/libgomp.fortran/imperfect4.f90 @@ -0,0 +1,121 @@ +! { dg-do run } + +! Like imperfect2.f90, but includes blocks that are themselves wholly +! intervening code and not containers for nested loops. + +program foo + integer, save :: f1count(3), f2count(3), g1count(3), g2count(3) + + f1count(1) = 0 + f1count(2) = 0 + f1count(3) = 0 + f2count(1) = 0 + f2count(2) = 0 + f2count(3) = 0 + + g1count(1) = 0 + g1count(2) = 0 + g1count(3) = 0 + g2count(1) = 0 + g2count(2) = 0 + g2count(3) = 0 + + call s1 (3, 4, 5) + + ! All intervening code at the same depth must be executed the same + ! number of times. + if (f1count(1) /= f2count(1)) error stop 101 + if (f1count(2) /= f2count(2)) error stop 102 + if (f1count(3) /= f2count(3)) error stop 103 + if (g1count(1) /= f1count(1)) error stop 104 + if (g2count(1) /= f1count(1)) error stop 105 + if (g1count(2) /= f1count(2)) error stop 106 + if (g2count(2) /= f1count(2)) error stop 107 + if (g1count(3) /= f1count(3)) error stop 108 + if (g2count(3) /= f1count(3)) error stop 109 + + ! Intervening code must be executed at least as many times as the loop + ! that encloses it. + if (f1count(1) < 3) error stop 111 + if (f1count(2) < 3 * 4) error stop 112 + + ! Intervening code must not be executed more times than the number + ! of logical iterations. + if (f1count(1) > 3 * 4 * 5) error stop 121 + if (f1count(2) > 3 * 4 * 5) error stop 122 + + ! Check that the innermost loop body is executed exactly the number + ! of logical iterations expected. + if (f1count(3) /= 3 * 4 * 5) error stop 131 + +contains + +subroutine f1 (depth, iter) + integer :: depth, iter + f1count(depth) = f1count(depth) + 1 +end subroutine + +subroutine f2 (depth, iter) + integer :: depth, iter + f2count(depth) = f2count(depth) + 1 +end subroutine + +subroutine g1 (depth, iter) + integer :: depth, iter + g1count(depth) = g1count(depth) + 1 +end subroutine + +subroutine g2 (depth, iter) + integer :: depth, iter + g2count(depth) = g2count(depth) + 1 +end subroutine + +subroutine s1 (a1, a2, a3) + integer :: a1, a2, a3 + integer :: i, j, k + + !$omp do collapse(3) + do i = 1, a1 + block + call f1 (1, i) + end block + block + block + call g1 (1, i) + end block + do j = 1, a2 + block + call f1 (2, j) + end block + block + block + call g1 (2, j) + end block + do k = 1, a3 + call f1 (3, k) + block + call g1 (3, k) + call g2 (3, k) + end block + call f2 (3, k) + end do + block + call g2 (2, j) + end block + end block + block + call f2 (2, j) + end block + end do + block + call g2 (1, i) + end block + end block + block + call f2 (1, i) + end block + end do + +end subroutine + +end program diff --git a/libgomp/testsuite/libgomp.fortran/target-imperfect1.f90 b/libgomp/testsuite/libgomp.fortran/target-imperfect1.f90 new file mode 100644 index 000000000000..608eee7e4241 --- /dev/null +++ b/libgomp/testsuite/libgomp.fortran/target-imperfect1.f90 @@ -0,0 +1,72 @@ +! { dg-do run } + +! Like imperfect1.f90, but enables offloading. + +program foo + integer, save :: f1count(3), f2count(3) + !$omp declare target enter (f1count, f2count) + + f1count(1) = 0 + f1count(2) = 0 + f1count(3) = 0 + f2count(1) = 0 + f2count(2) = 0 + f2count(3) = 0 + + call s1 (3, 4, 5) + + ! All intervening code at the same depth must be executed the same + ! number of times. + if (f1count(1) /= f2count(1)) error stop 101 + if (f1count(2) /= f2count(2)) error stop 102 + if (f1count(3) /= f2count(3)) error stop 103 + + ! Intervening code must be executed at least as many times as the loop + ! that encloses it. + if (f1count(1) < 3) error stop 111 + if (f1count(2) < 3 * 4) error stop 112 + + ! Intervening code must not be executed more times than the number + ! of logical iterations. + if (f1count(1) > 3 * 4 * 5) error stop 121 + if (f1count(2) > 3 * 4 * 5) error stop 122 + + ! Check that the innermost loop body is executed exactly the number + ! of logical iterations expected. + if (f1count(3) /= 3 * 4 * 5) error stop 131 + +contains + +subroutine f1 (depth, iter) + integer :: depth, iter + !$omp atomic + f1count(depth) = f1count(depth) + 1 +end subroutine + +subroutine f2 (depth, iter) + integer :: depth, iter + !$omp atomic + f2count(depth) = f2count(depth) + 1 +end subroutine + +subroutine s1 (a1, a2, a3) + integer :: a1, a2, a3 + integer :: i, j, k + + !$omp target parallel do collapse(3) map(always, tofrom:f1count, f2count) + do i = 1, a1 + call f1 (1, i) + do j = 1, a2 + call f1 (2, j) + do k = 1, a3 + call f1 (3, k) + call f2 (3, k) + end do + call f2 (2, j) + end do + call f2 (1, i) + end do + +end subroutine + +end program diff --git a/libgomp/testsuite/libgomp.fortran/target-imperfect2.f90 b/libgomp/testsuite/libgomp.fortran/target-imperfect2.f90 new file mode 100644 index 000000000000..982661c278a2 --- /dev/null +++ b/libgomp/testsuite/libgomp.fortran/target-imperfect2.f90 @@ -0,0 +1,110 @@ +! { dg-do run } + +! Like imperfect2.f90, but enables offloading. + +program foo + integer, save :: f1count(3), f2count(3), g1count(3), g2count(3) + !$omp declare target enter (f1count, f2count) + !$omp declare target enter (g1count, g2count) + + f1count(1) = 0 + f1count(2) = 0 + f1count(3) = 0 + f2count(1) = 0 + f2count(2) = 0 + f2count(3) = 0 + + g1count(1) = 0 + g1count(2) = 0 + g1count(3) = 0 + g2count(1) = 0 + g2count(2) = 0 + g2count(3) = 0 + + call s1 (3, 4, 5) + + ! All intervening code at the same depth must be executed the same + ! number of times. + if (f1count(1) /= f2count(1)) error stop 101 + if (f1count(2) /= f2count(2)) error stop 102 + if (f1count(3) /= f2count(3)) error stop 103 + if (g1count(1) /= f1count(1)) error stop 104 + if (g2count(1) /= f1count(1)) error stop 105 + if (g1count(2) /= f1count(2)) error stop 106 + if (g2count(2) /= f1count(2)) error stop 107 + if (g1count(3) /= f1count(3)) error stop 108 + if (g2count(3) /= f1count(3)) error stop 109 + + ! Intervening code must be executed at least as many times as the loop + ! that encloses it. + if (f1count(1) < 3) error stop 111 + if (f1count(2) < 3 * 4) error stop 112 + + ! Intervening code must not be executed more times than the number + ! of logical iterations. + if (f1count(1) > 3 * 4 * 5) error stop 121 + if (f1count(2) > 3 * 4 * 5) error stop 122 + + ! Check that the innermost loop body is executed exactly the number + ! of logical iterations expected. + if (f1count(3) /= 3 * 4 * 5) error stop 131 + +contains + +subroutine f1 (depth, iter) + integer :: depth, iter + !$omp atomic + f1count(depth) = f1count(depth) + 1 +end subroutine + +subroutine f2 (depth, iter) + integer :: depth, iter + !$omp atomic + f2count(depth) = f2count(depth) + 1 +end subroutine + +subroutine g1 (depth, iter) + integer :: depth, iter + !$omp atomic + g1count(depth) = g1count(depth) + 1 +end subroutine + +subroutine g2 (depth, iter) + integer :: depth, iter + !$omp atomic + g2count(depth) = g2count(depth) + 1 +end subroutine + +subroutine s1 (a1, a2, a3) + integer :: a1, a2, a3 + integer :: i, j, k + + !$omp target parallel do collapse(3) map(always, tofrom:f1count, f2count, g1count, g2count) + do i = 1, a1 + call f1 (1, i) + block + call g1 (1, i) + do j = 1, a2 + call f1 (2, j) + block + call g1 (2, j) + do k = 1, a3 + call f1 (3, k) + block + call g1 (3, k) + call g2 (3, k) + end block + call f2 (3, k) + end do + call g2 (2, j) + end block + call f2 (2, j) + end do + call g2 (1, i) + end block + call f2 (1, i) + end do + +end subroutine + +end program diff --git a/libgomp/testsuite/libgomp.fortran/target-imperfect3.f90 b/libgomp/testsuite/libgomp.fortran/target-imperfect3.f90 new file mode 100644 index 000000000000..6f4f92d6f3fd --- /dev/null +++ b/libgomp/testsuite/libgomp.fortran/target-imperfect3.f90 @@ -0,0 +1,116 @@ +! { dg-do run } + +! Like imperfect3.f90, but enables offloading. + +program foo + integer, save :: f1count(3), f2count(3), g1count(3), g2count(3) + !$omp declare target enter (f1count, f2count) + !$omp declare target enter (g1count, g2count) + + f1count(1) = 0 + f1count(2) = 0 + f1count(3) = 0 + f2count(1) = 0 + f2count(2) = 0 + f2count(3) = 0 + + g1count(1) = 0 + g1count(2) = 0 + g1count(3) = 0 + g2count(1) = 0 + g2count(2) = 0 + g2count(3) = 0 + + call s1 (3, 4, 5) + + ! All intervening code at the same depth must be executed the same + ! number of times. + if (f1count(1) /= f2count(1)) error stop 101 + if (f1count(2) /= f2count(2)) error stop 102 + if (f1count(3) /= f2count(3)) error stop 103 + if (g1count(1) /= f1count(1)) error stop 104 + if (g2count(1) /= f1count(1)) error stop 105 + if (g1count(2) /= f1count(2)) error stop 106 + if (g2count(2) /= f1count(2)) error stop 107 + if (g1count(3) /= f1count(3)) error stop 108 + if (g2count(3) /= f1count(3)) error stop 109 + + ! Intervening code must be executed at least as many times as the loop + ! that encloses it. + if (f1count(1) < 3) error stop 111 + if (f1count(2) < 3 * 4) error stop 112 + + ! Intervening code must not be executed more times than the number + ! of logical iterations. + if (f1count(1) > 3 * 4 * 5) error stop 121 + if (f1count(2) > 3 * 4 * 5) error stop 122 + + ! Check that the innermost loop body is executed exactly the number + ! of logical iterations expected. + if (f1count(3) /= 3 * 4 * 5) error stop 131 + +contains + +subroutine f1 (depth, iter) + integer :: depth, iter + !$omp atomic + f1count(depth) = f1count(depth) + 1 +end subroutine + +subroutine f2 (depth, iter) + integer :: depth, iter + !$omp atomic + f2count(depth) = f2count(depth) + 1 +end subroutine + +subroutine g1 (depth, iter) + integer :: depth, iter + !$omp atomic + g1count(depth) = g1count(depth) + 1 +end subroutine + +subroutine g2 (depth, iter) + integer :: depth, iter + !$omp atomic + g2count(depth) = g2count(depth) + 1 +end subroutine + +subroutine s1 (a1, a2, a3) + integer :: a1, a2, a3 + integer :: i, j, k + + !$omp target parallel do collapse(3) map(always, tofrom:f1count, f2count, g1count, g2count) + do i = 1, a1 + call f1 (1, i) + block + integer :: local1 + local1 = 1 + call g1 (local1, i) + do j = 1, a2 + call f1 (2, j) + block + integer :: local2 + local2 = 2 + call g1 (local2, j) + do k = 1, a3 + call f1 (3, k) + block + integer :: local3 + local3 = 3 + call g1 (local3, k) + call g2 (local3, k) + end block + call f2 (3, k) + end do + call g2 (local2, j) + end block + call f2 (2, j) + end do + call g2 (local1, i) + end block + call f2 (1, i) + end do + +end subroutine + +end program diff --git a/libgomp/testsuite/libgomp.fortran/target-imperfect4.f90 b/libgomp/testsuite/libgomp.fortran/target-imperfect4.f90 new file mode 100644 index 000000000000..59ec0e92b05d --- /dev/null +++ b/libgomp/testsuite/libgomp.fortran/target-imperfect4.f90 @@ -0,0 +1,126 @@ +! { dg-do run } + +! Like imperfect4.f90, but enables offloading. + +program foo + integer, save :: f1count(3), f2count(3), g1count(3), g2count(3) + !$omp declare target enter (f1count, f2count) + !$omp declare target enter (g1count, g2count) + + f1count(1) = 0 + f1count(2) = 0 + f1count(3) = 0 + f2count(1) = 0 + f2count(2) = 0 + f2count(3) = 0 + + g1count(1) = 0 + g1count(2) = 0 + g1count(3) = 0 + g2count(1) = 0 + g2count(2) = 0 + g2count(3) = 0 + + call s1 (3, 4, 5) + + ! All intervening code at the same depth must be executed the same + ! number of times. + if (f1count(1) /= f2count(1)) error stop 101 + if (f1count(2) /= f2count(2)) error stop 102 + if (f1count(3) /= f2count(3)) error stop 103 + if (g1count(1) /= f1count(1)) error stop 104 + if (g2count(1) /= f1count(1)) error stop 105 + if (g1count(2) /= f1count(2)) error stop 106 + if (g2count(2) /= f1count(2)) error stop 107 + if (g1count(3) /= f1count(3)) error stop 108 + if (g2count(3) /= f1count(3)) error stop 109 + + ! Intervening code must be executed at least as many times as the loop + ! that encloses it. + if (f1count(1) < 3) error stop 111 + if (f1count(2) < 3 * 4) error stop 112 + + ! Intervening code must not be executed more times than the number + ! of logical iterations. + if (f1count(1) > 3 * 4 * 5) error stop 121 + if (f1count(2) > 3 * 4 * 5) error stop 122 + + ! Check that the innermost loop body is executed exactly the number + ! of logical iterations expected. + if (f1count(3) /= 3 * 4 * 5) error stop 131 + +contains + +subroutine f1 (depth, iter) + integer :: depth, iter + !$omp atomic + f1count(depth) = f1count(depth) + 1 +end subroutine + +subroutine f2 (depth, iter) + integer :: depth, iter + !$omp atomic + f2count(depth) = f2count(depth) + 1 +end subroutine + +subroutine g1 (depth, iter) + integer :: depth, iter + !$omp atomic + g1count(depth) = g1count(depth) + 1 +end subroutine + +subroutine g2 (depth, iter) + integer :: depth, iter + !$omp atomic + g2count(depth) = g2count(depth) + 1 +end subroutine + +subroutine s1 (a1, a2, a3) + integer :: a1, a2, a3 + integer :: i, j, k + + !$omp target parallel do collapse(3) map(always, tofrom:f1count, f2count, g1count, g2count) + do i = 1, a1 + block + call f1 (1, i) + end block + block + block + call g1 (1, i) + end block + do j = 1, a2 + block + call f1 (2, j) + end block + block + block + call g1 (2, j) + end block + do k = 1, a3 + call f1 (3, k) + block + call g1 (3, k) + call g2 (3, k) + end block + call f2 (3, k) + end do + block + call g2 (2, j) + end block + end block + block + call f2 (2, j) + end block + end do + block + call g2 (1, i) + end block + end block + block + call f2 (1, i) + end block + end do + +end subroutine + +end program diff --git a/libiberty/ChangeLog b/libiberty/ChangeLog index 3424fef99ba2..71b6dec118ab 100644 --- a/libiberty/ChangeLog +++ b/libiberty/ChangeLog @@ -1,3 +1,30 @@ +2023-08-22 Jason Merrill + + PR c++/109751 + * cp-demangle.c (d_make_comp): Handle DEMANGLE_COMPONENT_FRIEND. + (d_count_templates_scopes): Likewise. + (d_print_comp_inner): Likewise. + (d_unqualified_name): Handle member-like friend mangling. + * testsuite/demangle-expected: Add test. + +2023-08-07 John Ericson + + * configure: Regenerate. + +2023-08-07 H.J. Lu + + * configure: Regenerate. + +2023-08-07 H.J. Lu + + * Makefile.in (AR): Add @AR_PLUGIN_OPTION@ + (RANLIB): Add @RANLIB_PLUGIN_OPTION@. + (configure_deps): Depend on ../config/gcc-plugin.m4. + * configure.ac: AC_SUBST AR_PLUGIN_OPTION and + RANLIB_PLUGIN_OPTION. + * aclocal.m4: Regenerated. + * configure: Likewise. + 2023-06-15 Marek Polacek * configure.ac: Also set shared when enable_host_pie. diff --git a/libiberty/cp-demangle.c b/libiberty/cp-demangle.c index 3bd303a75445..2ce984f85cf4 100644 --- a/libiberty/cp-demangle.c +++ b/libiberty/cp-demangle.c @@ -1036,6 +1036,7 @@ d_make_comp (struct d_info *di, enum demangle_component_type type, case DEMANGLE_COMPONENT_TEMPLATE_NON_TYPE_PARM: case DEMANGLE_COMPONENT_TEMPLATE_TEMPLATE_PARM: case DEMANGLE_COMPONENT_TEMPLATE_PACK_PARM: + case DEMANGLE_COMPONENT_FRIEND: if (left == NULL) return NULL; break; @@ -1681,6 +1682,7 @@ d_maybe_module_name (struct d_info *di, struct demangle_component **name) /* ::= [] [] ::= [] [] ::= [] [] + ::= [] F [] ::= [] [] ::= [] DC + E [] ::= L [] @@ -1692,11 +1694,18 @@ d_unqualified_name (struct d_info *di, struct demangle_component *scope, { struct demangle_component *ret; char peek; + int member_like_friend = 0; if (!d_maybe_module_name (di, &module)) return NULL; peek = d_peek_char (di); + if (peek == 'F') + { + member_like_friend = 1; + d_advance (di, 1); + peek = d_peek_char (di); + } if (IS_DIGIT (peek)) ret = d_source_name (di); else if (IS_LOWER (peek)) @@ -1773,6 +1782,8 @@ d_unqualified_name (struct d_info *di, struct demangle_component *scope, ret = d_make_comp (di, DEMANGLE_COMPONENT_MODULE_ENTITY, ret, module); if (d_peek_char (di) == 'B') ret = d_abi_tags (di, ret); + if (member_like_friend) + ret = d_make_comp (di, DEMANGLE_COMPONENT_FRIEND, ret, NULL); if (scope) ret = d_make_comp (di, DEMANGLE_COMPONENT_QUAL_NAME, scope, ret); @@ -4459,6 +4470,7 @@ d_count_templates_scopes (struct d_print_info *dpi, case DEMANGLE_COMPONENT_GLOBAL_CONSTRUCTORS: case DEMANGLE_COMPONENT_GLOBAL_DESTRUCTORS: case DEMANGLE_COMPONENT_MODULE_ENTITY: + case DEMANGLE_COMPONENT_FRIEND: d_count_templates_scopes (dpi, d_left (dc)); break; @@ -6197,6 +6209,11 @@ d_print_comp_inner (struct d_print_info *dpi, int options, d_append_char (dpi, ']'); return; + case DEMANGLE_COMPONENT_FRIEND: + d_print_comp (dpi, options, d_left (dc)); + d_append_string (dpi, "[friend]"); + return; + case DEMANGLE_COMPONENT_TEMPLATE_HEAD: { d_append_char (dpi, '<'); diff --git a/libiberty/testsuite/demangle-expected b/libiberty/testsuite/demangle-expected index 0acd2d635db0..01ca22278cd3 100644 --- a/libiberty/testsuite/demangle-expected +++ b/libiberty/testsuite/demangle-expected @@ -1689,3 +1689,6 @@ X::operator Z()::y _ZZN1XIfEcv1ZIT_EIiEEvE1y X::operator Z()::y + +_ZN1SILi1EEF3barIiEEiR4Base +int S<1>::bar[friend](Base&) diff --git a/libitm/ChangeLog b/libitm/ChangeLog index 20fce42c1ab8..d8e6febfd859 100644 --- a/libitm/ChangeLog +++ b/libitm/ChangeLog @@ -1,3 +1,27 @@ +2023-08-07 Nick Alcock + + * configure: Regenerate. + +2023-08-07 Alexander von Gluck IV + + * configure: Regenerate. + +2023-08-07 Nick Alcock + + * configure: Regenerate. + +2023-08-07 Nick Alcock + + * configure: Regenerate. + +2023-08-07 H.J. Lu + + * configure: Regenerate. + +2023-08-07 H.J. Lu + + * configure: Regenerate. + 2023-06-02 Thomas Schwinge * configure.ac (PERL): Remove. diff --git a/libobjc/ChangeLog b/libobjc/ChangeLog index 73ee1144a71e..b797888464d8 100644 --- a/libobjc/ChangeLog +++ b/libobjc/ChangeLog @@ -1,3 +1,27 @@ +2023-08-07 Nick Alcock + + * configure: Regenerate. + +2023-08-07 Alexander von Gluck IV + + * configure: Regenerate. + +2023-08-07 Nick Alcock + + * configure: Regenerate. + +2023-08-07 Nick Alcock + + * configure: Regenerate. + +2023-08-07 H.J. Lu + + * configure: Regenerate. + +2023-08-07 H.J. Lu + + * configure: Regenerate. + 2023-05-22 Iain Sandoe Andrew Pinski diff --git a/libphobos/ChangeLog b/libphobos/ChangeLog index 2e7c1ee3457a..a4d80657993a 100644 --- a/libphobos/ChangeLog +++ b/libphobos/ChangeLog @@ -1,3 +1,32 @@ +2023-08-20 Iain Buclaw + + * libdruntime/MERGE: Merge upstream druntime 26f049fb26. + * src/MERGE: Merge upstream phobos 330d6a4fd. + +2023-08-07 Nick Alcock + + * configure: Regenerate. + +2023-08-07 Alexander von Gluck IV + + * configure: Regenerate. + +2023-08-07 Nick Alcock + + * configure: Regenerate. + +2023-08-07 Nick Alcock + + * configure: Regenerate. + +2023-08-07 H.J. Lu + + * configure: Regenerate. + +2023-08-07 H.J. Lu + + * configure: Regenerate. + 2023-07-10 Iain Buclaw * libdruntime/MERGE: Merge upstream druntime a88e1335f7. diff --git a/libphobos/libdruntime/MERGE b/libphobos/libdruntime/MERGE index 308d51b55d08..a02a8cbaba5f 100644 --- a/libphobos/libdruntime/MERGE +++ b/libphobos/libdruntime/MERGE @@ -1,4 +1,4 @@ -a88e1335f7ea767ef438c34998f5d1f26008c586 +26f049fb26e755096dea3f1474decea7c0fef187 The first line of this file holds the git revision number of the last merge done from the dlang/dmd repository. diff --git a/libphobos/libdruntime/core/int128.d b/libphobos/libdruntime/core/int128.d index 20fa7dea1705..4c88f15abfb6 100644 --- a/libphobos/libdruntime/core/int128.d +++ b/libphobos/libdruntime/core/int128.d @@ -14,8 +14,8 @@ nothrow: @safe: @nogc: -alias I = long; -alias U = ulong; +private alias I = long; +private alias U = ulong; enum Ubits = uint(U.sizeof * 8); version (DigitalMars) @@ -36,6 +36,10 @@ else else private enum Cent_alignment = (size_t.sizeof * 2); } +/** + * 128 bit integer type. + * See_also: $(REF Int128, std,int128). + */ align(Cent_alignment) struct Cent { version (LittleEndian) diff --git a/libphobos/libdruntime/core/internal/array/comparison.d b/libphobos/libdruntime/core/internal/array/comparison.d index 821f96e25c0d..94fa2433da8c 100644 --- a/libphobos/libdruntime/core/internal/array/comparison.d +++ b/libphobos/libdruntime/core/internal/array/comparison.d @@ -83,7 +83,7 @@ int __cmp(T)(scope const T[] lhs, scope const T[] rhs) @trusted // This function is called by the compiler when dealing with array // comparisons in the semantic analysis phase of CmpExp. The ordering // comparison is lowered to a call to this template. -int __cmp(T1, T2)(T1[] s1, T2[] s2) +auto __cmp(T1, T2)(T1[] s1, T2[] s2) if (!__traits(isScalar, T1) && !__traits(isScalar, T2)) { import core.internal.traits : Unqual; @@ -237,3 +237,26 @@ if (!__traits(isScalar, T1) && !__traits(isScalar, T2)) auto vb = [cast(void[])b[0], b[1]]; assert(less2(va, vb)); } + +// custom aggregate types +@safe unittest +{ + // https://issues.dlang.org/show_bug.cgi?id=24044 + // Support float opCmp(...) with array + static struct F + { + float f; + float opCmp(F other) const { return this.f - other.f; } + } + + F[2] a = [F(1.0f), F(float.nan)]; + F[2] b = [F(1.0f), F(1.0f)]; + F[1] c = [F(1.0f)]; + + bool isNan(float f) { return f != f; } + + assert(isNan(__cmp(a, b))); + assert(isNan(__cmp(a, a))); + assert(__cmp(b, b) == 0); + assert(__cmp(a, c) > 0); +} diff --git a/libphobos/libdruntime/core/lifetime.d b/libphobos/libdruntime/core/lifetime.d index 89236dbf4c11..3a55ca916c26 100644 --- a/libphobos/libdruntime/core/lifetime.d +++ b/libphobos/libdruntime/core/lifetime.d @@ -1570,7 +1570,11 @@ template forward(args...) alias fwd = arg; // (r)value else - @property auto fwd(){ pragma(inline, true); return move(arg); } + @property auto fwd() + { + version (DigitalMars) { /* @@BUG 23890@@ */ } else pragma(inline, true); + return move(arg); + } } alias Result = AliasSeq!(); diff --git a/libphobos/src/MERGE b/libphobos/src/MERGE index e0011d7e7f70..a5414f16cd3a 100644 --- a/libphobos/src/MERGE +++ b/libphobos/src/MERGE @@ -1,4 +1,4 @@ -1921d29df25f2b44d6014c224e2018ce63ac2b71 +330d6a4fdbe82683e081959d0aeb53597b025bc4 The first line of this file holds the git revision number of the last merge done from the dlang/phobos repository. diff --git a/libphobos/src/std/algorithm/searching.d b/libphobos/src/std/algorithm/searching.d index f061915d582d..37a08de7a8ff 100644 --- a/libphobos/src/std/algorithm/searching.d +++ b/libphobos/src/std/algorithm/searching.d @@ -1528,6 +1528,23 @@ if (isInputRange!Range && !isInfinite!Range && assert([S(5), S(6)].extremum!"a.value" == S(5)); } +// https://issues.dlang.org/show_bug.cgi?id=24027 +@safe nothrow unittest +{ + class A + { + int a; + this(int a) + { + this.a = a; + } + } + + auto test = new A(5); + A[] arr = [test]; + assert(maxElement!"a.a"(arr) is test); +} + // find /** Finds an individual element in an $(REF_ALTTEXT input range, isInputRange, std,range,primitives). diff --git a/libphobos/src/std/bigint.d b/libphobos/src/std/bigint.d index 50f88da60558..0240ea1d179a 100644 --- a/libphobos/src/std/bigint.d +++ b/libphobos/src/std/bigint.d @@ -323,7 +323,15 @@ public: else static if (op=="^^") { sign = (y & 1) ? sign : false; - data = BigUint.pow(data, u); + if (y < 0) + { + checkDivByZero(); + data = cast(ulong) (data == 1); + } + else + { + data = BigUint.pow(data, u); + } } else static if (op=="&") { @@ -411,6 +419,19 @@ public: )); } + // https://issues.dlang.org/show_bug.cgi?id=24028 + @system unittest + { + import std.exception : assertThrown; + import core.exception : AssertError; + + assert(BigInt(100) ^^ -1 == BigInt(0)); + assert(BigInt(1) ^^ -1 == BigInt(1)); + assert(BigInt(-1) ^^ -1 == BigInt(-1)); + assert(BigInt(-1) ^^ -2 == BigInt(1)); + assertThrown!AssertError(BigInt(0) ^^ -1); + } + /** * Implements assignment operators of the form `BigInt op= BigInt`. */ diff --git a/libphobos/src/std/json.d b/libphobos/src/std/json.d index 219af7143731..7d48890501fb 100644 --- a/libphobos/src/std/json.d +++ b/libphobos/src/std/json.d @@ -6,6 +6,10 @@ Implements functionality to read and write JavaScript Object Notation values. JavaScript Object Notation is a lightweight data interchange format commonly used in web services and configuration files. It's easy for humans to read and write, and it's easy for machines to parse and generate. +$(RED Warning: While $(LREF JSONValue) is fine for small-scale use, at the range of hundreds of megabytes it is +known to cause and exacerbate GC problems. If you encounter problems, try replacing it with a stream parser. See +also $(LINK https://forum.dlang.org/post/dzfyaxypmkdrpakmycjv@forum.dlang.org).) + Copyright: Copyright Jeremie Pelletier 2008 - 2009. License: $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0). Authors: Jeremie Pelletier, David Herberth diff --git a/libphobos/src/std/math/package.d b/libphobos/src/std/math/package.d index 19982ec216a5..b5f914acf7cb 100644 --- a/libphobos/src/std/math/package.d +++ b/libphobos/src/std/math/package.d @@ -168,12 +168,6 @@ public import std.math.rounding; public import std.math.traits; public import std.math.trigonometry; -// @@@DEPRECATED_2.102@@@ -// Note: Exposed accidentally, should be deprecated / removed -deprecated("std.meta.AliasSeq was unintentionally available from std.math " - ~ "and will be removed after 2.102. Please import std.meta instead") -public import std.meta : AliasSeq; - package(std): // Not public yet /* Return the value that lies halfway between x and y on the IEEE number line. * diff --git a/libphobos/src/std/stdio.d b/libphobos/src/std/stdio.d index 19ce9880b893..d9291b11bde4 100644 --- a/libphobos/src/std/stdio.d +++ b/libphobos/src/std/stdio.d @@ -425,21 +425,6 @@ private extern (C) @nogc nothrow pragma(mangle, _FPUTWC.mangleof) int trustedFPUTWC(wchar_t ch, _iobuf* h) @trusted; } -static if (__traits(compiles, core.sys.posix.stdio.getdelim)) -{ - extern(C) nothrow @nogc - { - // @@@DEPRECATED_2.104@@@ - deprecated("To be removed after 2.104. Use core.sys.posix.stdio.getdelim instead.") - ptrdiff_t getdelim(char**, size_t*, int, FILE*); - - // @@@DEPRECATED_2.104@@@ - // getline() always comes together with getdelim() - deprecated("To be removed after 2.104. Use core.sys.posix.stdio.getline instead.") - ptrdiff_t getline(char**, size_t*, FILE*); - } -} - //------------------------------------------------------------------------------ private struct ByRecordImpl(Fields...) { diff --git a/libquadmath/ChangeLog b/libquadmath/ChangeLog index 3003c7a84a7a..458e610237fd 100644 --- a/libquadmath/ChangeLog +++ b/libquadmath/ChangeLog @@ -1,3 +1,27 @@ +2023-08-07 Nick Alcock + + * configure: Regenerate. + +2023-08-07 Alexander von Gluck IV + + * configure: Regenerate. + +2023-08-07 Nick Alcock + + * configure: Regenerate. + +2023-08-07 Nick Alcock + + * configure: Regenerate. + +2023-08-07 H.J. Lu + + * configure: Regenerate. + +2023-08-07 H.J. Lu + + * configure: Regenerate. + 2023-03-02 niXman Jakub Jelinek diff --git a/libsanitizer/ChangeLog b/libsanitizer/ChangeLog index 57b2a5cf646f..692e06b1e243 100644 --- a/libsanitizer/ChangeLog +++ b/libsanitizer/ChangeLog @@ -1,3 +1,33 @@ +2023-08-07 Nick Alcock + + * configure: Regenerate. + +2023-08-07 Alexander von Gluck IV + + * configure: Regenerate. + +2023-08-07 Nick Alcock + + * configure: Regenerate. + +2023-08-07 Nick Alcock + + * configure: Regenerate. + +2023-08-07 H.J. Lu + + * configure: Regenerate. + +2023-08-07 H.J. Lu + + * configure: Regenerate. + +2023-08-07 Rainer Orth + + * sanitizer_common/sanitizer_stacktrace_sparc.cpp, + sanitizer_common/sanitizer_unwind_linux_libcdep.cpp: Cherry-pick + llvm-project revision 679c076ae446af81eba81ce9b94203a273d4b88a. + 2023-04-30 Martin Liska PR sanitizer/109674 diff --git a/libssp/ChangeLog b/libssp/ChangeLog index 2a303b85b39c..1b0c4f9ba81d 100644 --- a/libssp/ChangeLog +++ b/libssp/ChangeLog @@ -1,3 +1,27 @@ +2023-08-07 Nick Alcock + + * configure: Regenerate. + +2023-08-07 Alexander von Gluck IV + + * configure: Regenerate. + +2023-08-07 Nick Alcock + + * configure: Regenerate. + +2023-08-07 Nick Alcock + + * configure: Regenerate. + +2023-08-07 H.J. Lu + + * configure: Regenerate. + +2023-08-07 H.J. Lu + + * configure: Regenerate. + 2023-01-07 LIU Hao PR middle-end/108300 diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index cdd26b9c6577..3941569c7bb8 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,3 +1,1065 @@ +2023-09-01 Jonathan Wakely + + * testsuite/25_algorithms/copy/debug/constexpr_neg.cc: Adjust + expected errors. + * testsuite/25_algorithms/equal/debug/constexpr_neg.cc: + Likewise. + +2023-09-01 Jonathan Wakely + + * testsuite/27_io/filesystem/iterators/91067.cc: Add + -Wno-self-move to options. + * testsuite/27_io/filesystem/path/assign/copy.cc: Likewise. + +2023-09-01 Vladimir Palevich + + PR libstdc++/110879 + * include/bits/vector.tcc (_M_realloc_insert): End guard + lifetime just before assignment to class members. + (_M_default_append): Likewise. + +2023-09-01 Jonathan Wakely + + * src/c++17/fs_ops.cc (fs::absolute) [FILESYSTEM_IS_WINDOWS]: + Use __resize_and_overwrite to fill buffer. + (fs::read_symlink) [HAVE_READLINK]: Likewise. + * src/filesystem/ops-common.h (get_temp_directory_from_env) + [FILESYSTEM_IS_WINDOWS]: Likewise. + +2023-09-01 Jonathan Wakely + + PR libstdc++/111077 + * include/bits/atomic_base.h (__atomic_impl::__compare_exchange): + Add _AtomicRef non-type template parameter and use a loop if it + is true. + (__atomic_impl::compare_exchange_weak): Add _AtomicRef NTTP. + (__atomic_impl::compare_exchange_strong): Likewise. + (atomic_ref::compare_exchange_weak): Use true for NTTP. + (atomic_ref::compare_exchange_strong): Use true for NTTP. + * testsuite/29_atomics/atomic_ref/compare_exchange_padding.cc: + Fix test to not rely on atomic_ref::load() to return an object + with padding preserved. + +2023-09-01 Jonathan Wakely + + * testsuite/27_io/filesystem/path/108636.cc: Add dg-require for + filesystem support. + +2023-09-01 Jonathan Wakely + + * src/c++20/tzdb.cc (tzdb::current_zone): Check configure macros + for POSIX readlink before using filesystem::read_symlink. + +2023-09-01 Jonathan Wakely + + * acinclude.m4 (GLIBCXX_ENABLE_BACKTRACE): Default to yes. + * configure: Regenerate. + +2023-09-01 Jonathan Wakely + + * include/bits/chrono_io.h (_Parser::operator()): Set failbit + early if invalid values are read when _M_need & _TimeOfDay is + non-zero. + * testsuite/std/time/parse.cc: Check that "25:59" cannot be + parsed for "%H:%M". + +2023-09-01 Jonathan Wakely + + PR libstdc++/111162 + * include/bits/chrono_io.h (_Parser::Operator()): Check %C + values are in range of year::min() to year::max(). + * testsuite/std/time/parse.cc: Check out of range centuries. + +2023-09-01 Jonathan Wakely + + * include/std/format (__format::_Sink::_M_reset): Change second + argument from iterator to offset. + +2023-08-24 Paul Dreik + + PR libstdc++/111102 + * testsuite/std/format/string.cc: Check wide character format + strings with out-of-range widths. + +2023-08-24 Paul Dreik + + PR libstdc++/111102 + * include/std/format (__format::__parse_integer): Check for + non-null pointer. + +2023-08-24 Jonathan Wakely + + * testsuite/std/format/functions/format_to.cc: Avoid warning for + unused variables. + +2023-08-24 Jonathan Wakely + + * include/std/atomic: Add comment to #ifdef and fix indentation. + * include/std/ostream: Check __glibcxx_syncbuf instead of + __cplusplus and _GLIBCXX_HOSTED. + * include/std/thread: Add comment to #ifdef. + +2023-08-24 Jonathan Wakely + + * include/bits/version.def (__cpp_lib_ratio): Define. + * include/bits/version.h: Regenerate. + * include/std/ratio (quecto, ronto, yocto, zepto) + (zetta, yotta, ronna, quetta): Define. + * testsuite/20_util/ratio/operations/ops_overflow_neg.cc: Adjust + dg-error line numbers. + +2023-08-24 Jonathan Wakely + + * python/libstdcxx/v6/printers.py (StdLocalePrinter): New + printer class. + * testsuite/libstdc++-prettyprinters/locale.cc: New test. + +2023-08-24 Jonathan Wakely + + PR libstdc++/110944 + * python/libstdcxx/v6/printers.py (StdExpOptionalPrinter): Do + not show template arguments. + (StdVariantPrinter): Likewise. + * testsuite/libstdc++-prettyprinters/compat.cc: Adjust expected + output. + * testsuite/libstdc++-prettyprinters/cxx17.cc: Likewise. + * testsuite/libstdc++-prettyprinters/libfundts.cc: Likewise. + +2023-08-23 François Dumont + + * testsuite/util/replacement_memory_operators.h + (counter::scope): New, capture and reset counter count at construction and + restore it at destruction. + (counter::check_new): Add scope instantiation. + * testsuite/23_containers/unordered_map/96088.cc (main): + Add counter::scope instantiation. + * testsuite/23_containers/unordered_multimap/96088.cc (main): Likewise. + * testsuite/23_containers/unordered_multiset/96088.cc (main): Likewise. + * testsuite/23_containers/unordered_set/96088.cc (main): Likewise. + * testsuite/ext/malloc_allocator/deallocate_local.cc (main): Likewise. + * testsuite/ext/new_allocator/deallocate_local.cc (main): Likewise. + * testsuite/ext/throw_allocator/deallocate_local.cc (main): Likewise. + * testsuite/ext/pool_allocator/allocate_chunk.cc (started): New global. + (operator new(size_t)): Check started. + (main): Set/Unset started. + * testsuite/17_intro/no_library_allocation.cc: New test case. + +2023-08-21 Jonathan Wakely + + * testsuite/18_support/nested_exception/rethrow_if_nested-term.cc: + Call std::set_terminate before throwing the nested exception. + +2023-08-18 Jonathan Wakely + + PR target/111060 + * include/std/format (formatter): Only define specializations + for 16-bit floating-point types for C++23. + * include/std/limits (numeric_limits): Likewise. + +2023-08-18 Jonathan Wakely + + * include/bits/chrono_io.h (operator<<): Make uses of wide + strings with streams and std::format type-dependent on _CharT. + * include/std/format [!_GLIBCXX_USE_WCHAR_T] Do not use + __to_wstring_numeric. + +2023-08-18 Jonathan Wakely + + * include/bits/chrono_io.h (operator<<): Use __format_context. + * include/std/format (__format::__format_context): New alias + template. + [!_GLIBCXX_USE_WCHAR_T] (wformat_args, make_wformat_arg): + Disable. + +2023-08-17 Jonathan Wakely + + Revert: + 2023-08-17 Jonathan Wakely + + * config/locale/generic/c_locale.cc (__convert_to_v): Reuse + double overload for long double if possible. + +2023-08-17 Jonathan Wakely + + * src/c++20/tzdb.cc (tzdata_file, leaps_file): Change type to + std::string_view. + +2023-08-17 Jonathan Wakely + + * config/locale/generic/c_locale.cc (__convert_to_v): Reuse + double overload for long double if possible. + +2023-08-17 Jonathan Wakely + + * src/c++98/localename.cc (is_C_locale): New function. + (locale::locale(const char*)): Use is_C_locale. + +2023-08-17 Jonathan Wakely + + PR libstdc++/110945 + * include/bits/basic_string.h (basic_string::assign(Iter, Iter)): + Dispatch to _M_replace or move assignment from a temporary, + based on the iterator type. + +2023-08-17 Jonathan Wakely + + * include/std/format (formatter): Add partial specializations + for extended floating-point types. + * testsuite/std/format/functions/format.cc: Move test_float128() + to ... + * testsuite/std/format/formatter/ext_float.cc: New test. + +2023-08-17 Jonathan Wakely + + * include/bits/c++config (__gnu_cxx::__bfloat16_t): Define + whenever __BFLT16_DIG__ is defined, not only for C++23. + * include/std/limits (numeric_limits): Likewise. + (numeric_limits<_Float16>, numeric_limits<_Float32>) + (numeric_limits<_Float64>): Likewise for other extended + floating-point types. + +2023-08-17 Jonathan Wakely + + * include/experimental/internet (address_v4::to_string): Remove + unused parameter name. + +2023-08-17 Jonathan Wakely + + * libsupc++/compare (__cmp_cat::__unseq): Make ctor consteval. + * testsuite/18_support/comparisons/categories/zero_neg.cc: Prune + excess errors caused by invalid consteval calls. + +2023-08-17 Jonathan Wakely + + * include/bits/chrono_io.h (__units_suffix_misc): Remove. + (__units_suffix): Return a known suffix as string view, do not + write unknown suffixes to a buffer. + (__fmt_units_suffix): New function that formats the suffix using + std::format_to. + (operator<<, __chrono_formatter::_M_q): Use __fmt_units_suffix. + (__chrono_formatter::_M_Z): Correct lifetime of wstring. + +2023-08-17 Jonathan Wakely + + * include/std/format [_GLIBCXX_USE_WCHAR_T]: Guard all wide + string formatters with this macro. + (__formatter_int::_M_format_int, __formatter_fp::format) + (formatter::format): Use __to_wstring_numeric + instead of std::ctype::widen. + (__formatter_fp::_M_localize): Use hardcoded wchar_t values + instead of std::ctype::widen. + * testsuite/std/format/functions/format.cc: Add more checks for + wstring formatting of arithmetic types. + +2023-08-17 Jonathan Wakely + + * include/bits/basic_string.h (to_string(floating-point-type)): + Implement using std::to_chars for C++26. + * include/bits/version.def (__cpp_lib_to_string): Define. + * include/bits/version.h: Regenerate. + * testsuite/21_strings/basic_string/numeric_conversions/char/dr1261.cc: + Adjust expected result in C++26 mode. + * testsuite/21_strings/basic_string/numeric_conversions/char/to_string.cc: + Likewise. + * testsuite/21_strings/basic_string/numeric_conversions/wchar_t/dr1261.cc: + Likewise. + * testsuite/21_strings/basic_string/numeric_conversions/wchar_t/to_wstring.cc: + Likewise. + * testsuite/21_strings/basic_string/numeric_conversions/char/to_string_float.cc: + New test. + * testsuite/21_strings/basic_string/numeric_conversions/wchar_t/to_wstring_float.cc: + New test. + * testsuite/21_strings/basic_string/numeric_conversions/version.cc: + New test. + +2023-08-17 Jonathan Wakely + + * include/bits/basic_string.h (to_string(integral-type)): Use + resize_and_overwrite when available. + (__to_wstring_numeric): New helper functions. + (to_wstring): Use std::to_string then __to_wstring_numeric. + * testsuite/21_strings/basic_string/numeric_conversions/char/to_string_int.cc: + Remove check for no excess capacity. + +2023-08-17 Jonathan Wakely + + * include/bits/basic_string.h (__resize_and_overwrite): New + function. + * include/bits/basic_string.tcc (__resize_and_overwrite): New + function. + (resize_and_overwrite): Simplify by using reserve instead of + growing the string manually. Adjust for C++11 compatibility. + * include/bits/cow_string.h (resize_and_overwrite): New + function. + (__resize_and_overwrite): New function. + * include/bits/version.def (__cpp_lib_string_resize_and_overwrite): + Do not depend on cxx11abi. + * include/bits/version.h: Regenerate. + * include/std/format (__formatter_fp::_S_resize_and_overwrite): + Remove. + (__formatter_fp::format, __formatter_fp::_M_localize): Use + __resize_and_overwrite instead of _S_resize_and_overwrite. + * testsuite/21_strings/basic_string/capacity/char/resize_and_overwrite.cc: + Adjust for C++11 compatibility when included by ... + * testsuite/21_strings/basic_string/capacity/char/resize_and_overwrite_ext.cc: + New test. + +2023-08-17 Patrick Palka + + * include/bits/regex.h (regex_iterator::iterator_concept): + Define for C++20 as per P2770R0. + (regex_token_iterator::iterator_concept): Likewise. + * include/std/ranges (__detail::__as_lvalue): Define. + (join_view::_Iterator): Befriend join_view. + (join_view::_Iterator::_M_satisfy): Use _M_get_outer + instead of _M_outer. + (join_view::_Iterator::_M_get_outer): Define. + (join_view::_Iterator::_Iterator): Split constructor taking + _Parent argument into two as per P2770R0. Remove constraint on + default constructor. + (join_view::_Iterator::_M_outer): Make this data member present + only when the underlying range is forward. + (join_view::_Iterator::operator++): Use _M_get_outer instead of + _M_outer. + (join_view::_Iterator::operator--): Use __as_lvalue helper. + (join_view::_Iterator::operator==): Adjust constraints as per + P2770R0. + (join_view::_Sentinel::__equal): Use _M_get_outer instead of + _M_outer. + (join_view::_M_outer): New data member when the underlying range + is non-forward. + (join_view::begin): Adjust definition as per P2770R0. + (join_view::end): Likewise. + (join_with_view::_M_outer_it): New data member when the + underlying range is non-forward. + (join_with_view::begin): Adjust definition as per P2770R0. + (join_with_view::end): Likewise. + (join_with_view::_Iterator::_M_outer_it): Make this data member + present only when the underlying range is forward. + (join_with_view::_Iterator::_M_get_outer): Define. + (join_with_view::_Iterator::_Iterator): Split constructor + taking _Parent argument into two as per P2770R0. Remove + constraint on default constructor. + (join_with_view::_Iterator::_M_update_inner): Adjust definition + as per P2770R0. + (join_with_view::_Iterator::_M_get_inner): Likewise. + (join_with_view::_Iterator::_M_satisfy): Adjust calls to + _M_get_inner. Use _M_get_outer instead of _M_outer_it. + (join_with_view::_Iterator::operator==): Adjust constraints + as per P2770R0. + (join_with_view::_Sentinel::operator==): Use _M_get_outer + instead of _M_outer_it. + * testsuite/std/ranges/adaptors/p2770r0.cc: New test. + +2023-08-17 Patrick Palka + + PR libstdc++/108827 + * include/std/ranges (__adaptor::_RangeAdaptorClosure): + Convert into a CRTP class template. Move hidden operator| + friends into namespace scope and adjust their constraints. + (__closure::__is_range_adaptor_closure_fn): Define. + (__closure::__is_range_adaptor_closure): Define. + (__adaptor::_Partial): Adjust use of _RangeAdaptorClosure. + (__adaptor::_Pipe): Likewise. + (views::_All): Likewise. + (views::_Join): Likewise. + (views::_Common): Likewise. + (views::_Reverse): Likewise. + (views::_Elements): Likewise. + (views::_Adjacent): Likewise. + (views::_AsRvalue): Likewise. + (views::_Enumerate): Likewise. + (views::_AsConst): Likewise. + * testsuite/std/ranges/adaptors/all.cc: Reinstate assertion + expecting that adding empty range adaptor closure objects to a + pipeline doesn't increase the size of a pipeline. + +2023-08-17 Jonathan Wakely + + * include/std/format (__format::_Pres_type): Add _Pres_F. + (__formatter_fp::parse): Use _Pres_F for 'F'. + (__formatter_fp::format): Set __upper for _Pres_F. + * testsuite/std/format/functions/format.cc: Check formatting of + infinity and NaN for each presentation type. + +2023-08-17 Jonathan Wakely + + * include/Makefile.in: Regenerate. + +2023-08-17 Jonathan Wakely + + * testsuite/24_iterators/move_iterator/p2520r0.cc: Add no_pch. + * testsuite/std/format/functions/format.cc: Likewise. + * testsuite/std/format/functions/format_c++23.cc: Likewise. + +2023-08-17 Jonathan Wakely + + * testsuite/lib/dg-options.exp (add_options_for_no_pch): Remove + any "-include bits/stdc++.h" from options and add the macro to + the existing options instead of replacing them. + +2023-08-16 Jonathan Wakely + + * include/bits/basic_string.tcc (resize_and_overwrite): Invoke + the callable with the same size as resize_and_overwrite was + called with. + * testsuite/21_strings/basic_string/capacity/char/resize_and_overwrite.cc: + Check with small values for the new size. + * testsuite/std/format/functions/format.cc: Check wide + formatting of double values that produce small strings. + * testsuite/std/format/functions/format_c++23.cc: New test. + +2023-08-16 Jonathan Wakely + + * include/bits/version.def (stds): Update value for C++23. + * include/bits/version.h: Regenerate. + +2023-08-16 Jonathan Wakely + + * testsuite/25_algorithms/pstl/alg_sorting/set_difference.cc: + Fix name of upstream file this was derived from. + * testsuite/25_algorithms/pstl/alg_sorting/set_intersection.cc: + Likewise. + * testsuite/25_algorithms/pstl/alg_sorting/set_symmetric_difference.cc: + Likewise. + * testsuite/25_algorithms/pstl/alg_sorting/set_union.cc: + Likewise. + * testsuite/25_algorithms/pstl/alg_sorting/set_util.h: Likewise. + +2023-08-16 Arsen Arsenović + + * libsupc++/typeinfo: Switch to bits/version.h for + __cpp_lib_constexpr_typeinfo. + * libsupc++/new: Switch to bits/version.h for + __cpp_lib_{launder,hardware_interference_size,destroying_delete}. + (launder): Guard behind __cpp_lib_launder. + (hardware_destructive_interference_size) + (hardware_constructive_interference_size): Guard behind + __cpp_lib_hardware_interference_size. + * libsupc++/exception: Switch to bits/version.h for + __cpp_lib_uncaught_exceptions. + (uncaught_exceptions): Guard behind __cpp_lib_uncaught_exceptions. + * libsupc++/compare: Switch to bits/version.h for + __cpp_lib_three_way_comparison. + (three_way_comparable, three_way_comparable_with) + (compare_three_way, weak_order, strong_order, partial_order): + Guard behind __cpp_lib_three_way_comparison >= 201907L. + * include/std/chrono: Drop __cpp_lib_chrono definition. + * include/std/vector: Switch to bits/version.h for + __cpp_lib_erase_if. + (erase, erase_if): Guard behind __cpp_lib_erase_if. + * include/std/variant: Switch to bits/version.h for + __cpp_lib_variant. Guard whole header behind that FTM. + * include/std/utility: Switch to bits/version.h for + __cpp_lib_{exchange_function,constexpr_algorithms,as_const}, + __cpp_lib_{integer_comparison_functions,to_underlying}, and + __cpp_lib_unreachable. + (exchange): Guard behind __cpp_lib_exchange_function. + (cmp_equal, cmp_not_equal, cmp_less, cmp_greater, cmp_less_equal) + (cmp_greater_equal, in_range): Guard behind + __cpp_lib_integer_comparison_functions. + (to_underlying): Guard behind __cpp_lib_to_underlying. + (unreachable): Guard behind __cpp_lib_unreachable. + * include/std/type_traits: Switch to bits/version.h for + __cpp_lib_is_{null_pointer,final,nothrow_convertible,aggregate}, + __cpp_lib_is_{constant_evaluated,invocable,layout_compatible}, + __cpp_lib_is_{pointer_interconvertible,scoped_enum,swappable}, + __cpp_lib_{logical_traits,reference_from_temporary,remove_cvref}, + __cpp_lib_{result_of_sfinae,transformation_trait_aliases}, + __cpp_lib_{type_identity,type_trait_variable_templates}, + __cpp_lib_{unwrap_ref,void_t,integral_constant_callable}, + __cpp_lib_{bool_constant,bounded_array_traits}, and + __cpp_lib_has_unique_object_representations. + (integral_constant::operator()): Guard behind + __cpp_lib_integral_constant_callable. + (bool_constant): Guard behind __cpp_lib_bool_constant. + (conjunction, disjunction, negation, conjunction_v, disjunction_v) + (negation_v): Guard behind __cpp_lib_logical_traits. + (is_null_pointer): Guard behind __cpp_lib_is_null_pointer. + (is_final): Guard behind __cpp_lib_is_final. + (is_nothrow_convertible, is_nothrow_convertible_v): Guard behind + __cpp_lib_is_nothrow_convertible. + (remove_const_t, remove_volatile_t, remove_cv_t) + (add_const_t, add_volatile_t, add_cv_t): Guard behind + __cpp_lib_transformation_trait_aliases. + (void_t): Guard behind __cpp_lib_void_t. + (is_swappable_with_v, is_nothrow_swappable_with_v) + (is_swappable_with, is_nothrow_swappable_with): Guard behind + __cpp_lib_is_swappable. + (is_nothrow_invocable_r, is_invocable_r, invoke_result) + (is_invocable, invoke_result_t): Guard behind + __cpp_lib_is_invocable. + (alignment_of_v, extent_v, has_virtual_destructor_v) + (is_abstract_v, is_arithmetic_v, is_array_v) + (is_assignable_v, is_base_of_v, is_class_v, is_compound_v) + (is_constructible_v, is_const_v, is_convertible_v) + (is_copy_assignable_v, is_copy_constructible_v) + (is_default_constructible_v, is_destructible_v) + (is_empty_v, is_enum_v, is_final_v, is_floating_point_v) + (is_function_v, is_fundamental_v, is_integral_v) + (is_invocable_r_v, is_invocable_v, is_literal_type_v) + (is_lvalue_reference_v, is_member_function_pointer_v) + (is_member_object_pointer_v, is_member_pointer_v) + (is_move_assignable_v, is_move_constructible_v) + (is_nothrow_assignable_v, is_nothrow_constructible_v) + (is_nothrow_copy_assignable_v, is_nothrow_copy_constructible_v) + (is_nothrow_default_constructible_v, is_nothrow_destructible_v) + (is_nothrow_invocable_r_v, is_nothrow_invocable_v) + (is_nothrow_move_assignable_v, is_nothrow_move_constructible_v) + (is_null_pointer_v, is_object_v, is_pod_v, is_pointer_v) + (is_polymorphic_v, is_reference_v, is_rvalue_reference_v) + (is_same_v, is_scalar_v, is_signed_v, is_standard_layout_v) + (is_trivially_assignable_v, is_trivially_constructible_v) + (is_trivially_copyable_v, is_trivially_copy_assignable_v) + (is_trivially_copy_constructible_v) + (is_trivially_default_constructible_v) + (is_trivially_destructible_v, is_trivially_move_assignable_v) + (is_trivially_move_constructible_v, is_trivial_v, is_union_v) + (is_unsigned_v, is_void_v, is_volatile_v, rank_v, as variadic): + Guard behind __cpp_lib_type_trait_variable_templates. + (has_unique_object_representations) + (has_unique_object_representations_v): Guard behind + __cpp_lib_has_unique_object_representation. + (is_aggregate): Guard behind __cpp_lib_is_aggregate. + (remove_cvref, remove_cvref_t): Guard behind + __cpp_lib_remove_cvref. + (type_identity, type_identity_t): Guard behind + __cpp_lib_type_identity. + (unwrap_reference, unwrap_reference_t, unwrap_ref_decay) + (unwrap_ref_decay_t): Guard behind __cpp_lib_unwrap_ref. + (is_bounded_array_v, is_unbounded_array_v, is_bounded_array) + (is_unbounded_array): Guard behind __cpp_lib_bounded_array_traits. + (is_scoped_enum, is_scoped_enum_v): Guard behind + __cpp_lib_is_scoped_enum. + (reference_constructs_from_temporary) + (reference_constructs_from_temporary_v): Guard behind + __cpp_lib_reference_from_temporary. + * include/std/tuple: Switch to bits/version.h for + __cpp_lib_{constexpr_tuple,tuple_by_type,apply_make_from_tuple}. + (get): Guard behind __cpp_lib_tuple_by_type. + (apply): Guard behind __cpp_lib_apply. + (make_from_tuple): Guard behind __cpp_lib_make_from_tuple. + * include/std/syncstream: Switch to bits/version.h for + __cpp_lib_syncbuf. Guard header behind that FTM. + * include/std/string_view: Switch to bits/version.h for + __cpp_lib_{string_{view,contains},constexpr_string_view} and + __cpp_lib_starts_ends_with. + (basic_string_view::starts_with, basic_string_view::ends_with): + Guard behind __cpp_lib_starts_ends_with. + [C++23 && _GLIBCXX_HOSTED && !defined(__cpp_lib_string_contains)]: + Assert as impossible ithout a bug in C++23. + * include/std/string: Switch to bits/version.h for + __cpp_lib_erase_if. + (erase, erase_if): Guard behind __cpp_lib_erase_if. + * include/std/thread: Switch to bits/version.h for + __cpp_lib_jthread. + * include/std/stop_token: Switch to bits/version.h for + __cpp_lib_jthread. + * include/std/spanstream: Switch to bits/version.h for + __cpp_lib_spanstream. Guard header behind that FTM. + * include/std/span: Switch to bits/version.h for __cpp_lib_span. + Guard header behind that FTM. + * include/std/source_location: Switch to bits/version.h for + __cpp_lib_source_location. Guard header with that FTM. + * include/std/shared_mutex: Switch to bits/version.h for + __cpp_lib_shared{,_timed}_mutex. + (shared_mutex): Guard behind __cpp_lib_shared_mutex. + * include/std/semaphore: Switch to bits/version.h for + __cpp_lib_semaphore. Guard header behind that FTM. + * include/std/ranges: Switch to bits/version.h for + __cpp_lib_ranges_{zip,chunk{,_by},slide,join_with}, + __cpp_lib_ranges_{repeat_stride,cartesian_product,as_rvalue}, + and __cpp_lib_ranges_{as_const,enumerate,iota}. + (ranges::zip et al, ranges::chunk et al, ranges::slide et al) + (ranges::chunk_by et al, ranges::join_with et al) + (ranges::stride et al, ranges::cartesian_product et al) + (ranges::as_rvalue et al, ranges::as_const et al) + (ranges::enumerate et al): Guard behind appropriate FTM. + * include/std/optional: Switch to bits/version.h for + __cpp_lib_optional. Guard header behind that FTM. + * include/std/numeric: Switch to bits/version.h for + __cpp_lib_{gcd{,_lcm},lcm,constexpr_numeric,interpolate} + and __cpp_lib_parallel_algorithm. + (gcd, lcm): Guard behind __cpp_lib_gcd_lcm. + (midpoint): Guard behind __cpp_lib_interpolate. + * include/std/numbers: Switch to bits/version.h for + __cpp_lib_math_constants. Guard header behind that FTM. + * include/std/mutex: Switch to bits/version.h for + __cpp_lib_scoped_lock. + (scoped_Lock): Guard behind __cpp_lib_scoped_lock. + * include/std/memory_resource: Switch to bits/version.h for + __cpp_lib_{polymorphic_allocator,memory_resource}. + (synchronized_pool_resource): Guard behind + __cpp_lib_memory_resource >= 201603L. + (polymorphic_allocator): Guard behind + __cpp_lib_polymorphic_allocator. + * include/std/memory: Switch to bits/version.h for + __cpp_lib_{parallel_algorithm,atomic_value_initialization}. + * include/std/list: Switch to bits/version.h for + __cpp_lib_erase_if. + (erase, erase_if): Guard behind __cpp_lib_erase_if. + * include/std/latch: Switch to bits/version.h for __cpp_lib_latch. + Guard header behind that FTM. + * include/std/iterator: Switch to bits/version.h for + __cpp_lib_null_iterators. + * include/std/iomanip: Switch to bits/version.h for + __cpp_lib_quoted_string_io. + (quoted): Guard behind __cpp_lib_quoted_string_io. + * include/std/functional: Switch to bits/version.h for + __cpp_lib_{invoke{,_r},constexpr_functional,bind_front} and + __cpp_lib_{not_fn,booyer_moore_searcher}. + (invoke): Guard behind __cpp_lib_invoke. + (invoke_r): Guard behind __cpp_lib_invoke_r. + (bind_front): Guard behind __cpp_lib_bind_front. + (not_fn): Guard behind __cpp_lib_not_fn. + (boyer_moore_searcher, boyer_moore_horspool_searcher): Guard + definition behind __cpp_lib_boyer_moore_searcher. + * include/std/forward_list: Switch to bits/version.h for + __cpp_lib_erase_if. + (erase, erase_if): Guard behind __cpp_lib_erase_if. + * include/std/format: Switch to bits/version.h for + __cpp_lib_format. Guard header behind that FTM. + * include/std/filesystem: Switch to bits/version.h for + __cpp_lib_filesystem. Guard header behind that FTM. + * include/std/expected: Switch to bits/version.h for + __cpp_lib_expected. Guard header behind it. + * include/std/execution: Switch to bits/version.h for + __cpp_lib_{execution,parallel_algorithm}. Guard header behind + either. + * include/std/deque: Switch to bits/version.h for + __cpp_lib_erase_if. + (erase, erase_if): Guard behind __cpp_lib_erase_if. + * include/std/coroutine: Switch to bits/version.h for + __cpp_lib_coroutine. Guard header behind that FTM. + * include/std/concepts: Switch to bits/version.h for + __cpp_lib_concepts. Guard header behind that FTM. + * include/std/complex: Switch to bits/version.h for + __cpp_lib_{complex_udls,constexpr_complex}. + (operator""if, operator""i, operator""il): Guard behind + __cpp_lib_complex_udls. + * include/std/charconv: Swtich to bits/version.h for + __cpp_lib_{to_chars,constexpr_charconv}. + * include/std/bitset: Switch to bits/version.h for + __cpp_lib_constexpr_bitset. + * include/std/bit: Switch to bits/version.h for + __cpp_lib_{bit_cast,byteswap,bitops,int_pow2,endian}. + (bit_cast): Guard behind __cpp_lib_bit_cast. + (byteswap): Guard behind __cpp_lib_byteswap. + (rotl, rotr, countl_zero, countl_one, countr_zero, countr_one) + (popcount): Guard behind __cpp_lib_bitops. + (has_single_bit, bit_ceil, bit_floor, bit_width): Guard behind + __cpp_lib_int_pow2. + (endian): Guard behind __cpp_lib_endian. + * include/std/barrier: Switch to bits/version.h for + __cpp_lib_barrier. Guard header behind that FTM. + * include/std/atomic: Switch to bits/version.h for + __cpp_lib_atomic_{is_always_lock_free,float,ref} + and __cpp_lib_lock_free_type_aliases. + (*::is_always_lock_free): Guard behind + __cpp_lib_atomic_is_always_lock_free. + (atomic): Guard behind __cpp_lib_atomic_float. + (atomic_ref): Guard behind __cpp_lib_atomic_ref. + (atomic_signed_lock_free, atomic_unsigned_lock_free): Guard behind + __cpp_lib_atomic_lock_free_type_aliases. + * include/std/array: Switch to bits/version.h for + __cpp_lib_to_array. + (to_array): Guard behind __cpp_lib_to_array. + * include/std/any: Switch to bits/version.h for __cpp_lib_any. + Guard header behind that FTM. + * include/std/algorithm: Switch to bits/version.h for + __cpp_lib_parallel_algorithm. + * include/c_global/cstddef: Switch to bits/version.h for + __cpp_lib_byte. + (byte): Guard behind __cpp_lib_byte. + * include/c_global/cmath: Switch to bits/version.h for + __cpp_lib_{hypot,interpolate}. + (hypot3): Guard behind __cpp_lib_hypot. + (lerp): Guard behind __cpp_lib_interpolate. + * include/c_compatibility/stdatomic.h: Switch to + bits/stl_version.h for __cpp_lib_atomic. Guard header behind that + FTM. + * include/bits/utility.h: Switch to bits/version.h for + __cpp_lib_{tuple_element_t,integer_sequence,ranges_zip}. + (tuple_element_t): Guard behind __cpp_lib_tuple_element_t. + (integer_sequence et al): Guard behind __cpp_lib_integer_sequence. + * include/bits/uses_allocator_args.h: Switch to bits/version.h for + __cpp_lib_make_obj_using_allocator. Guard header behind that FTM. + * include/bits/unordered_map.h: Switch to bits/version.h for + __cpp_lib_unordered_map_try_emplace. + (try_emplace): Guard behind __cpp_lib_unordered_map_try_emplace. + * include/bits/unique_ptr.h: Switch to bits/version.h for + __cpp_lib_{constexpr_memory,make_unique}. + (make_unique): Guard behind __cpp_lib_make_unique. + * include/bits/stl_vector.h: Switch to bits/version.h for + __cpp_lib_constexpr_vector. + * include/bits/stl_uninitialized.h: Switch to bits/version.h for + __cpp_lib_raw_memory_algorithms. + (uninitialized_default_construct) + (uninitialized_default_construct_n, uninitialized_move) + (uninitialized_move_n, uninitialized_value_construct) + (uninitialized_value_construct_n): Guard behind + __cpp_lib_raw_memory_algorithms. + * include/bits/stl_tree.h: Switch to bits/version.h for + __cpp_lib_generic_associative_lookup. + * include/bits/stl_stack.h: Switch to bits/version.h for + __cpp_lib_adaptor_iterator_pair_constructor. + (stack): Guard iterator-pair constructor behind + __cpp_lib_adaptor_iterator_pair_constructor. + * include/bits/stl_queue.h: Switch to bits/version.h for + __cpp_lib_adaptor_iterator_pair_constructor. + (queue): Guard iterator-pair constructor behind + __cpp_lib_adaptor_iterator_pair_constructor. + * include/bits/stl_pair.h: Switch to bits/version.h for + __cpp_lib_{concepts,tuples_by_type}. + (get): Guard type-getting overloads behind + __cpp_lib_tuples_by_type. + * include/bits/stl_map.h: Switch to bits/version.h for + __cpp_lib_map_try_emplace. + (map<>::try_emplace): Guard behind __cpp_lib_map_try_emplace. + * include/bits/stl_list.h: Switch to bits/version.h for + __cpp_lib_list_remove_return_type. + (__remove_return_type, _GLIBCXX_LIST_REMOVE_RETURN_TYPE_TAG) + [C++20]: guard behind __cpp_lib_list_remove_return_type instead. + * include/bits/stl_iterator.h: Switch to bits/version.h for + __cpp_lib_{constexpr_iterator,array_constexpr} and + __cpp_lib_{make_reverse_iterator,move_iterator_concept}. + (make_reverse_iterator): Guard behind + __cpp_lib_make_reverse_iterator. + (iterator_concept et al): Guard __cpp_lib_move_iterator_concept + changes behind that FTM. + * include/bits/stl_function.h: Switch to bits/version.h for + __cpp_lib_transparent_operators. + (equal_to, not_equal_to, greater, less, greater_equal) + (less_equal, bit_and, bit_or, bit_xor, bit_not, logical_and) + (logical_or, logical_not, plus, minus, multiplies, divides) + (modulus, negate): Guard '= void' fwdecls behind + __cpp_lib_transparent_operators. + (plus, minus, multiplies, divides) + (modulus, negate, logical_and, logical_or) + (logical_not, bit_and, bit_or, bit_xor) + (equal_to, not_equal_to, greater, less) + (greater_equal, less_equal, bit_not) + (__has_is_transparent): Guard behind + __cpp_lib_transparent_operators. + * include/bits/stl_algobase.h: Switch to bits/version.h for + __cpp_lib_robust_nonmodifying_seq_ops. + (robust equal, mismatch): Guard behind + __cpp_lib_nonmember_container_access. + * include/bits/stl_algo.h: Swtich to bits/version.h for + __cpp_lib_{clamp,sample}. + (clamp): Guard behind __cpp_lib_clamp. + (sample): Guard behind __cpp_lib_sample. + * include/bits/specfun.h: Switch to bits/version.h for + __cpp_lib_math_special_functions and __STDCPP_MATH_SPEC_FUNCS__. + * include/bits/shared_ptr_base.h: Switch to bits/version.h for + __cpp_lib_{smart_ptr_for_overwrite,shared_ptr_arrays}. + (_Sp_overwrite_tag): Guard behind + __cpp_lib_smart_ptr_for_overwrite. + * include/bits/shared_ptr_atomic.h: Switch to bits/version.h for + __cpp_lib_atomic_shared_ptr. + * include/bits/shared_ptr.h: Switch to bits/version.h for + __cpp_lib_{enable_shared_from_this,shared_ptr_weak_type}. + (shared_ptr::weak_type): Guard behind + __cpp_lib_shared_ptr_weak_type. + (enable_shared_from_this::weak_from_this): Guard behind + __cpp_lib_enable_shared_from_this. + * include/bits/ranges_cmp.h: Switch to bits/version.h for + __cpp_lib_ranges. + * include/bits/ranges_algo.h: Switch to bits/version.h for + __cpp_lib_{shift,ranges_{contains,find_last,fold,iota}}. + * include/bits/range_access.h: Switch to bits/version.h for + __cpp_lib_nonmember_container_access + (size, empty, data): Guard behind + __cpp_lib_nonmember_container_access. + (ssize): Guard behind __cpp_lib_ssize. + * include/bits/ptr_traits.h: Switch to bits/version.h. for + __cpp_lib_{constexpr_memory,to_address}. + (to_address): Guard behind __cpp_lib_to_address. + * include/bits/node_handle.h: Switch to bits/version.h for + __cpp_lib_node_extract. Guard header behind that FTM. + * include/bits/move_only_function.h: Switch to bits/version.h for + __cpp_lib_move_only_function. Guard header behind that FTM. + * include/bits/move.h: Switch to bits/version.h for + __cpp_lib_addressof_constexpr. + * include/bits/ios_base.h: Switch to bits/version.h for + __cpp_lib_ios_noreplace. + (noreplace): Guard with __cpp_lib_ios_noreplace. + * include/bits/hashtable.h: Switch to bits/version.h for + __cpp_lib_generic_unordered_lookup. + (_M_equal_range_tr, _M_count_tr, _M_find_tr): Guard behind + __cpp_lib_generic_unordered_lookup. + * include/bits/forward_list.h: Switch to bits/version.h for + __cpp_lib_list_remove_return_type. + (__remove_return_type): Guard behind + __cpp_lib_list_remove_return_type. + * include/bits/erase_if.h: Switch to bits/version.h for + __cpp_lib_erase_if. + * include/bits/cow_string.h: Switch to bits/version.h for + __cpp_lib_constexpr_string. + * include/bits/chrono.h: Swtich to bits/version.h for + __cpp_lib_chrono{,_udls}. + (ceil): Guard behind __cpp_lib_chrono. + (operator""ns et al): Guard behind __cpp_lib_chrono_udls. + * include/bits/char_traits.h: Switch to bits/version.h for + __cpp_lib_constexpr_char_traits. + * include/bits/basic_string.h: Switch to bits/version.h for + __cpp_lib_{constexpr_string,string_{resize_and_overwrite,udls}}. + (resize_and_overwrite): Guard behind + __cpp_lib_string_resize_and_overwrite. + (operator""s): Guard behind __cpp_lib_string_udls. + * include/bits/atomic_wait.h: Switch to bits/version.h for + __cpp_lib_atomic_wait. Guard header behind that FTM. + * include/bits/atomic_base.h: Switch to bits/version.h for + __cpp_lib_atomic_value_initialization and + __cpp_lib_atomic_flag_test. + (atomic_flag::test): Guard behind __cpp_lib_atomic_flag_test, + rather than C++20. + * include/bits/allocator.h: Switch to bits/version.h for + __cpp_lib_incomplete_container_elements. + * include/bits/alloc_traits.h: Switch to using bits/version.h for + __cpp_lib_constexpr_dynamic_alloc and + __cpp_lib_allocator_traits_is_always_equal. + * include/bits/align.h: Switch to bits/version.h for defining + __cpp_lib_assume_aligned. + (assume_aligned): Guard with __cpp_lib_assume_aligned. + * include/bits/algorithmfwd.h: Switch to bits/version.h for + defining __cpp_lib_constexpr_algorithms. + * include/std/stacktrace: Switch to bits/version.h for + __cpp_lib_stacktrace. Guard header behind that FTM. + * testsuite/23_containers/array/tuple_interface/get_neg.cc: + Update line numbers. + +2023-08-16 Arsen Arsenović + + * include/Makefile.am (bits_freestanding): Add version.h. + (allcreated): Add version.h. + (${bits_srcdir}/version.h): New rule. Regenerates + version.h out of version.{def,tpl}. + * include/Makefile.in: Regenerate. + * include/bits/version.def: New file. Declares a list of + all feature test macros, their values and their preconditions. + * include/bits/version.tpl: New file. Turns version.def + into a sequence of #if blocks. + * include/bits/version.h: New file. Generated from + version.def. + * include/std/version: Replace with a __glibcxx_want_all define + and bits/version.h include. + +2023-08-14 Paul Dreik + + PR libstdc++/110860 + * include/std/format (__formatter_fp::format): Use frexp instead + of log10. + +2023-08-12 Ken Matsui + + * include/std/type_traits (true_type): Use __bool_constant + instead. + (false_type): Likewise. + (bool_constant): Likewise. + +2023-08-11 Jonathan Wakely + + PR libstdc++/110990 + * include/std/format (_Seq_sink::get): Only call _M_overflow if + its precondition is met. + (_Iter_sink::_M_finish): Likewise. + (_Iter_sink::_M_overflow): Only switch to the + internal buffer after running out of space. + (_Iter_sink::_M_finish): Do not use _M_overflow. + (_Counting_sink::count): Likewise. + * testsuite/std/format/functions/format_to_n.cc: Check cases + where the output fits into the buffer. + +2023-08-11 Jonathan Wakely + + PR libstdc++/104167 + * include/bits/chrono_io.h (operator|=, operator|): Add noexcept + to _ChronoParts operators. + (from_stream, parse): Define new functions. + (__detail::_Parse, __detail::_Parser): New class templates. + * include/std/chrono (__cpp_lib_chrono): Define to 201907L for + C++20. + * include/std/version (__cpp_lib_chrono): Likewise. + * testsuite/20_util/duration/arithmetic/constexpr_c++17.cc: + Adjust expected value of feature test macro. + * testsuite/20_util/duration/io.cc: Test parsing. + * testsuite/std/time/clock/file/io.cc: Likewise. + * testsuite/std/time/clock/gps/io.cc: Likewise. + * testsuite/std/time/clock/system/io.cc: Likewise. + * testsuite/std/time/clock/tai/io.cc: Likewise. + * testsuite/std/time/clock/utc/io.cc: Likewise. + * testsuite/std/time/day/io.cc: Likewise. + * testsuite/std/time/month/io.cc: Likewise. + * testsuite/std/time/month_day/io.cc: Likewise. + * testsuite/std/time/weekday/io.cc: Likewise. + * testsuite/std/time/year/io.cc: Likewise. + * testsuite/std/time/year_month/io.cc: Likewise. + * testsuite/std/time/year_month_day/io.cc: Likewise. + * testsuite/std/time/syn_c++20.cc: Check value of macro and for + the existence of parse and from_stream in namespace chrono. + * testsuite/std/time/clock/local/io.cc: New test. + * testsuite/std/time/parse.cc: New test. + +2023-08-11 Jonathan Wakely + + PR libstdc++/110860 + * include/std/format (__formatter_fp::format): Do not call log10 + with zero values. + +2023-08-11 Jonathan Wakely + + * python/libstdcxx/v6/printers.py (StdChronoCalendarPrinter): + Check for out-of-range month an weekday indices. + * testsuite/libstdc++-prettyprinters/chrono.cc: Check invalid + month and weekday values. + +2023-08-11 Jonathan Wakely + + * include/bits/stl_iterator.h (__clamped_iter_cat_t): Remove. + +2023-08-10 Jonathan Wakely + + PR libstdc++/110974 + * include/std/format (_Spec::_S_parse_width_or_precision): Check + for empty range before dereferencing iterator. + * testsuite/std/format/string.cc: Check for expected exception. + Fix expected exception message in test_pr110862() and actually + call it. + +2023-08-10 Jonathan Wakely + + PR libstdc++/110968 + * include/std/format (__formatter_fp::format): Check return + value of _M_localize. + * testsuite/std/format/functions/format.cc: Check classic + locale. + +2023-08-10 Jonathan Wakely + + PR libstdc++/110970 + * include/bits/stl_iterator.h (__detail::__move_iter_cat): Use + __iter_category_t. + (iterator_traits>::_S_iter_cat): Likewise. + (__detail::__basic_const_iterator_iter_cat): Likewise. + * include/bits/stl_iterator_base_types.h (__iterator_category_t): + Rename to __iter_category_t. + +2023-08-09 Jonathan Wakely + + * include/bits/chrono.h (duration_cast): Do not use braces + around statements for C++11 constexpr rules. + * include/bits/stl_algobase.h (__lg): Rewrite as a single + statement for C++11 constexpr rules. + * include/experimental/bits/fs_path.h (path::string): Use + _GLIBCXX17_CONSTEXPR not _GLIBCXX_CONSTEXPR for 'if constexpr'. + * include/std/charconv (__to_chars_8): Initialize variable for + C++17 constexpr rules. + +2023-08-09 Jonathan Wakely + + * include/bits/list.tcc (list::sort(Cmp)): Fix -Wsign-compare + warning for loop condition. + +2023-08-09 Jonathan Wakely + + * include/std/complex: Add diagnostic pragma for clang. + +2023-08-09 Jonathan Wakely + + * include/bits/shared_ptr_atomic.h (atomic): Change class-head + to struct. + * include/bits/stl_tree.h (_Rb_tree_merge_helper): Change + class-head to struct in friend declaration. + * include/std/chrono (tzdb_list::_Node): Likewise. + * include/std/future (_Task_state_base, _Task_state): Likewise. + * include/std/scoped_allocator (__inner_type_impl): Likewise. + * include/std/valarray (_BinClos, _SClos, _GClos, _IClos) + (_ValFunClos, _RefFunClos): Change class-head to struct. + +2023-08-09 Jonathan Wakely + + * include/bits/alloc_traits.h (allocate): Add [[maybe_unused]] + attribute. + * include/bits/regex_executor.tcc: Remove name of unused + parameter. + * include/bits/shared_ptr_atomic.h (atomic_is_lock_free): + Likewise. + * include/bits/stl_uninitialized.h: Likewise. + * include/bits/streambuf_iterator.h (operator==): Likewise. + * include/bits/uses_allocator.h: Likewise. + * include/c_global/cmath (isfinite, isinf, isnan): Likewise. + * include/std/chrono (zoned_time): Likewise. + * include/std/future (__future_base::_S_allocate_result): + Likewise. + (packaged_task): Likewise. + * include/std/optional (_Optional_payload_base): Likewise. + * include/std/scoped_allocator (__inner_type_impl): Likewise. + * include/std/tuple (_Tuple_impl): Likewise. + +2023-08-09 Jonathan Wakely + + * include/bits/new_allocator.h (__new_allocator): Define copy + assignment operator as defaulted. + * include/std/complex (complex, complex) + (complex): Define copy constructor as defaulted. + +2023-08-09 Jonathan Wakely + + * include/std/format: Fix some warnings. + (__format::__write(Ctx&, basic_string_view)): Remove + unused function template. + +2023-08-07 Jonathan Wakely + + PR libstdc++/110860 + * include/std/format (__formatter_fp::format): Do not use + __builtin_abs and __builtin_log10 with arbitrary floating-point + types. + +2023-08-07 Jonathan Wakely + + PR libstdc++/110917 + * include/std/format (__format::_Iter_sink): + Constrain partial specialization for contiguous iterators to + require the value type to be CharT. + * testsuite/std/format/functions/format_to.cc: New test. + +2023-08-07 Jonathan Wakely + + PR libstdc++/110862 + * include/std/format (_Scanner::_M_on_replacement_field): + Check for expected '}' before incrementing iterator. + * testsuite/std/format/string.cc: Check "{0:{0}" format string. + +2023-08-07 Nick Alcock + + * configure: Regenerate. + +2023-08-07 Alan Modra + + * configure: Regenerate. + +2023-08-07 Alexander von Gluck IV + + * configure: Regenerate. + +2023-08-07 Nick Alcock + + * configure: Regenerate. + +2023-08-07 Nick Alcock + + * configure: Regenerate. + +2023-08-07 H.J. Lu + + * configure: Regenerate. + +2023-08-07 H.J. Lu + + * configure: Regenerate. + 2023-08-06 François Dumont * config/abi/pre/gnu-versioned-namespace.ver: Add __cxa_call_terminate diff --git a/libstdc++-v3/acinclude.m4 b/libstdc++-v3/acinclude.m4 index b25378eaacec..50c808c6b2d6 100644 --- a/libstdc++-v3/acinclude.m4 +++ b/libstdc++-v3/acinclude.m4 @@ -5481,7 +5481,7 @@ BACKTRACE_CPPFLAGS="$BACKTRACE_CPPFLAGS -DBACKTRACE_ELF_SIZE=$elfsize" AC_MSG_CHECKING([whether to build libbacktrace support]) if test "$enable_libstdcxx_backtrace" = "auto"; then - enable_libstdcxx_backtrace=no + enable_libstdcxx_backtrace=yes fi AC_MSG_RESULT($enable_libstdcxx_backtrace) if test "$enable_libstdcxx_backtrace" = "yes"; then diff --git a/libstdc++-v3/configure b/libstdc++-v3/configure index c4da56c3042f..db1932300c01 100755 --- a/libstdc++-v3/configure +++ b/libstdc++-v3/configure @@ -73156,7 +73156,7 @@ BACKTRACE_CPPFLAGS="$BACKTRACE_CPPFLAGS -DBACKTRACE_ELF_SIZE=$elfsize" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build libbacktrace support" >&5 $as_echo_n "checking whether to build libbacktrace support... " >&6; } if test "$enable_libstdcxx_backtrace" = "auto"; then - enable_libstdcxx_backtrace=no + enable_libstdcxx_backtrace=yes fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_libstdcxx_backtrace" >&5 $as_echo "$enable_libstdcxx_backtrace" >&6; } diff --git a/libstdc++-v3/include/Makefile.am b/libstdc++-v3/include/Makefile.am index a880e8ee2275..9c71c75393aa 100644 --- a/libstdc++-v3/include/Makefile.am +++ b/libstdc++-v3/include/Makefile.am @@ -154,6 +154,7 @@ bits_freestanding = \ ${bits_srcdir}/stl_raw_storage_iter.h \ ${bits_srcdir}/stl_relops.h \ ${bits_srcdir}/stl_uninitialized.h \ + ${bits_srcdir}/version.h \ ${bits_srcdir}/string_view.tcc \ ${bits_srcdir}/uniform_int_dist.h \ ${bits_srcdir}/unique_ptr.h \ @@ -1113,7 +1114,8 @@ allcreated = \ ${host_builddir}/c++config.h \ ${host_builddir}/largefile-config.h \ ${thread_host_headers} \ - ${pch_build} + ${pch_build} \ + ${bits_srcdir}/version.h # Here are the rules for building the headers all-local: ${allstamped} ${allcreated} @@ -1463,6 +1465,12 @@ ${pch3_output}: ${pch3_source} ${pch2_output} -mkdir -p ${pch3_output_builddir} $(CXX) $(PCHFLAGS) $(AM_CPPFLAGS) -O2 -g ${pch3_source} -o $@ +# AutoGen . +.PHONY: update-version +update-version: + cd ${bits_srcdir} && \ + autogen version.def + # The real deal. install-data-local: install-headers install-headers: diff --git a/libstdc++-v3/include/Makefile.in b/libstdc++-v3/include/Makefile.in index 0ff875b280be..d2c95ee0b95b 100644 --- a/libstdc++-v3/include/Makefile.in +++ b/libstdc++-v3/include/Makefile.in @@ -509,6 +509,7 @@ bits_freestanding = \ ${bits_srcdir}/stl_raw_storage_iter.h \ ${bits_srcdir}/stl_relops.h \ ${bits_srcdir}/stl_uninitialized.h \ + ${bits_srcdir}/version.h \ ${bits_srcdir}/string_view.tcc \ ${bits_srcdir}/uniform_int_dist.h \ ${bits_srcdir}/unique_ptr.h \ @@ -1441,7 +1442,8 @@ allcreated = \ ${host_builddir}/c++config.h \ ${host_builddir}/largefile-config.h \ ${thread_host_headers} \ - ${pch_build} + ${pch_build} \ + ${bits_srcdir}/version.h # Host includes for threads @@ -1937,6 +1939,12 @@ ${pch3_output}: ${pch3_source} ${pch2_output} -mkdir -p ${pch3_output_builddir} $(CXX) $(PCHFLAGS) $(AM_CPPFLAGS) -O2 -g ${pch3_source} -o $@ +# AutoGen . +.PHONY: update-version +update-version: + cd ${bits_srcdir} && \ + autogen version.def + # The real deal. install-data-local: install-headers install-headers: diff --git a/libstdc++-v3/include/bits/algorithmfwd.h b/libstdc++-v3/include/bits/algorithmfwd.h index 130943d23406..bc757c340a43 100644 --- a/libstdc++-v3/include/bits/algorithmfwd.h +++ b/libstdc++-v3/include/bits/algorithmfwd.h @@ -39,6 +39,9 @@ #include #endif +#define __glibcxx_want_constexpr_algorithms +#include + namespace std _GLIBCXX_VISIBILITY(default) { _GLIBCXX_BEGIN_NAMESPACE_VERSION @@ -191,10 +194,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION // adjacent_find -#if __cplusplus > 201703L -# define __cpp_lib_constexpr_algorithms 201806L -#endif - #if __cplusplus >= 201103L template _GLIBCXX20_CONSTEXPR diff --git a/libstdc++-v3/include/bits/align.h b/libstdc++-v3/include/bits/align.h index 32d9349ee252..4152639622e6 100644 --- a/libstdc++-v3/include/bits/align.h +++ b/libstdc++-v3/include/bits/align.h @@ -32,6 +32,9 @@ #include +#define __glibcxx_want_assume_aligned +#include + #include // std::has_single_bit #include // uintptr_t #include // _GLIBCXX_DEBUG_ASSERT @@ -75,8 +78,7 @@ align(size_t __align, size_t __size, void*& __ptr, size_t& __space) noexcept } } -#if __cplusplus > 201703L -#define __cpp_lib_assume_aligned 201811L +#ifdef __cpp_lib_assume_aligned // C++ >= 20 /** @brief Inform the compiler that a pointer is aligned. * * @tparam _Align An alignment value (i.e. a power of two) @@ -103,7 +105,7 @@ align(size_t __align, size_t __size, void*& __ptr, size_t& __space) noexcept return static_cast<_Tp*>(__builtin_assume_aligned(__ptr, _Align)); } } -#endif // C++2a +#endif // __cpp_lib_assume_aligned _GLIBCXX_END_NAMESPACE_VERSION } // namespace diff --git a/libstdc++-v3/include/bits/alloc_traits.h b/libstdc++-v3/include/bits/alloc_traits.h index 182c3e23eeda..453278e5348d 100644 --- a/libstdc++-v3/include/bits/alloc_traits.h +++ b/libstdc++-v3/include/bits/alloc_traits.h @@ -40,13 +40,15 @@ # endif #endif +#define __glibcxx_want_constexpr_dynamic_alloc +#define __glibcxx_want_allocator_traits_is_always_equal +#include + namespace std _GLIBCXX_VISIBILITY(default) { _GLIBCXX_BEGIN_NAMESPACE_VERSION #if __cplusplus >= 201103L -#define __cpp_lib_allocator_traits_is_always_equal 201411L - /// @cond undocumented struct __allocator_traits_base { @@ -418,11 +420,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION }; #if _GLIBCXX_HOSTED - -#if __cplusplus > 201703L -# define __cpp_lib_constexpr_dynamic_alloc 201907L -#endif - /// Partial specialization for std::allocator. template struct allocator_traits> @@ -493,7 +490,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION */ [[__nodiscard__,__gnu__::__always_inline__]] static _GLIBCXX20_CONSTEXPR pointer - allocate(allocator_type& __a, size_type __n, const_void_pointer __hint) + allocate(allocator_type& __a, size_type __n, + [[maybe_unused]] const_void_pointer __hint) { #if __cplusplus <= 201703L return __a.allocate(__n, __hint); diff --git a/libstdc++-v3/include/bits/allocator.h b/libstdc++-v3/include/bits/allocator.h index abbd753d33d6..41e35f876f00 100644 --- a/libstdc++-v3/include/bits/allocator.h +++ b/libstdc++-v3/include/bits/allocator.h @@ -49,7 +49,8 @@ #include #endif -#define __cpp_lib_incomplete_container_elements 201505L +#define __glibcxx_want_incomplete_container_elements +#include namespace std _GLIBCXX_VISIBILITY(default) { diff --git a/libstdc++-v3/include/bits/atomic_base.h b/libstdc++-v3/include/bits/atomic_base.h index 3af618818955..974872ad7a63 100644 --- a/libstdc++-v3/include/bits/atomic_base.h +++ b/libstdc++-v3/include/bits/atomic_base.h @@ -46,6 +46,10 @@ #define _GLIBCXX_ALWAYS_INLINE inline __attribute__((__always_inline__)) #endif +#define __glibcxx_want_atomic_value_initialization +#define __glibcxx_want_atomic_flag_test +#include + namespace std _GLIBCXX_VISIBILITY(default) { _GLIBCXX_BEGIN_NAMESPACE_VERSION @@ -156,10 +160,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION return __ret; } -#if __cplusplus >= 202002L -# define __cpp_lib_atomic_value_initialization 201911L -#endif - /// @cond undocumented #if __cpp_lib_atomic_value_initialization # define _GLIBCXX20_INIT(I) = I @@ -234,9 +234,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION return __atomic_test_and_set (&_M_i, int(__m)); } -#if __cplusplus > 201703L -#define __cpp_lib_atomic_flag_test 201907L - +#ifdef __cpp_lib_atomic_flag_test // C++ >= 20 _GLIBCXX_ALWAYS_INLINE bool test(memory_order __m = memory_order_seq_cst) const noexcept { @@ -252,8 +250,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION __atomic_load(&_M_i, &__v, int(__m)); return __v == __GCC_ATOMIC_TEST_AND_SET_TRUEVAL; } +#endif -#if __cpp_lib_atomic_wait +#if __cpp_lib_atomic_wait // C++ >= 20 && (linux_futex || gthread) _GLIBCXX_ALWAYS_INLINE void wait(bool __old, memory_order __m = memory_order_seq_cst) const noexcept @@ -279,7 +278,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION // TODO add const volatile overload #endif // __cpp_lib_atomic_wait -#endif // C++20 _GLIBCXX_ALWAYS_INLINE void clear(memory_order __m = memory_order_seq_cst) noexcept @@ -987,7 +985,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template using _Val = typename remove_volatile<_Tp>::type; - template +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wc++17-extensions" + + template _GLIBCXX_ALWAYS_INLINE bool __compare_exchange(_Tp& __val, _Val<_Tp>& __e, _Val<_Tp>& __i, bool __is_weak, @@ -996,27 +997,79 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION __glibcxx_assert(__is_valid_cmpexch_failure_order(__f)); using _Vp = _Val<_Tp>; + _Tp* const __pval = std::__addressof(__val); - if _GLIBCXX17_CONSTEXPR (__atomic_impl::__maybe_has_padding<_Vp>()) + if constexpr (!__atomic_impl::__maybe_has_padding<_Vp>()) { - // We must not modify __e on success, so cannot clear its padding. - // Copy into a buffer and clear that, then copy back on failure. - alignas(_Vp) unsigned char __buf[sizeof(_Vp)]; - _Vp* __exp = ::new((void*)__buf) _Vp(__e); - __atomic_impl::__clear_padding(*__exp); - if (__atomic_compare_exchange(std::__addressof(__val), __exp, - __atomic_impl::__clear_padding(__i), + return __atomic_compare_exchange(__pval, std::__addressof(__e), + std::__addressof(__i), __is_weak, + int(__s), int(__f)); + } + else if constexpr (!_AtomicRef) // std::atomic + { + // Clear padding of the value we want to set: + _Vp* const __pi = __atomic_impl::__clear_padding(__i); + // Only allowed to modify __e on failure, so make a copy: + _Vp __exp = __e; + // Clear padding of the expected value: + _Vp* const __pexp = __atomic_impl::__clear_padding(__exp); + + // For std::atomic we know that the contained value will already + // have zeroed padding, so trivial memcmp semantics are OK. + if (__atomic_compare_exchange(__pval, __pexp, __pi, __is_weak, int(__s), int(__f))) return true; - __builtin_memcpy(std::__addressof(__e), __exp, sizeof(_Vp)); + // Value bits must be different, copy from __exp back to __e: + __builtin_memcpy(std::__addressof(__e), __pexp, sizeof(_Vp)); return false; } - else - return __atomic_compare_exchange(std::__addressof(__val), - std::__addressof(__e), - std::__addressof(__i), - __is_weak, int(__s), int(__f)); + else // std::atomic_ref where T has padding bits. + { + // Clear padding of the value we want to set: + _Vp* const __pi = __atomic_impl::__clear_padding(__i); + + // Only allowed to modify __e on failure, so make a copy: + _Vp __exp = __e; + // Optimistically assume that a previous store had zeroed padding + // so that zeroing it in the expected value will match first time. + _Vp* const __pexp = __atomic_impl::__clear_padding(__exp); + + // compare_exchange is specified to compare value representations. + // Need to check whether a failure is 'real' or just due to + // differences in padding bits. This loop should run no more than + // three times, because the worst case scenario is: + // First CAS fails because the actual value has non-zero padding. + // Second CAS fails because another thread stored the same value, + // but now with padding cleared. Third CAS succeeds. + // We will never need to loop a fourth time, because any value + // written by another thread (whether via store, exchange or + // compare_exchange) will have had its padding cleared. + while (true) + { + // Copy of the expected value so we can clear its padding. + _Vp __orig = __exp; + + if (__atomic_compare_exchange(__pval, __pexp, __pi, + __is_weak, int(__s), int(__f))) + return true; + + // Copy of the actual value so we can clear its padding. + _Vp __curr = __exp; + + // Compare value representations (i.e. ignoring padding). + if (__builtin_memcmp(__atomic_impl::__clear_padding(__orig), + __atomic_impl::__clear_padding(__curr), + sizeof(_Vp))) + { + // Value representations compare unequal, real failure. + __builtin_memcpy(std::__addressof(__e), __pexp, + sizeof(_Vp)); + return false; + } + } + } } +#pragma GCC diagnostic pop } // namespace __atomic_impl #if __cplusplus > 201703L @@ -1063,24 +1116,26 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION return *__dest; } - template + template _GLIBCXX_ALWAYS_INLINE bool compare_exchange_weak(_Tp* __ptr, _Val<_Tp>& __expected, _Val<_Tp> __desired, memory_order __success, - memory_order __failure) noexcept + memory_order __failure, + bool __check_padding = false) noexcept { - return __atomic_impl::__compare_exchange(*__ptr, __expected, __desired, - true, __success, __failure); + return __atomic_impl::__compare_exchange<_AtomicRef>( + *__ptr, __expected, __desired, true, __success, __failure); } - template + template _GLIBCXX_ALWAYS_INLINE bool compare_exchange_strong(_Tp* __ptr, _Val<_Tp>& __expected, _Val<_Tp> __desired, memory_order __success, - memory_order __failure) noexcept + memory_order __failure, + bool __ignore_padding = false) noexcept { - return __atomic_impl::__compare_exchange(*__ptr, __expected, __desired, - false, __success, __failure); + return __atomic_impl::__compare_exchange<_AtomicRef>( + *__ptr, __expected, __desired, false, __success, __failure); } #if __cpp_lib_atomic_wait @@ -1487,9 +1542,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION memory_order __success, memory_order __failure) const noexcept { - return __atomic_impl::compare_exchange_weak(_M_ptr, - __expected, __desired, - __success, __failure); + return __atomic_impl::compare_exchange_weak( + _M_ptr, __expected, __desired, __success, __failure); } bool @@ -1497,9 +1551,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION memory_order __success, memory_order __failure) const noexcept { - return __atomic_impl::compare_exchange_strong(_M_ptr, - __expected, __desired, - __success, __failure); + return __atomic_impl::compare_exchange_strong( + _M_ptr, __expected, __desired, __success, __failure); } bool @@ -1602,9 +1655,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION memory_order __success, memory_order __failure) const noexcept { - return __atomic_impl::compare_exchange_weak(_M_ptr, - __expected, __desired, - __success, __failure); + return __atomic_impl::compare_exchange_weak( + _M_ptr, __expected, __desired, __success, __failure); } bool @@ -1612,9 +1664,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION memory_order __success, memory_order __failure) const noexcept { - return __atomic_impl::compare_exchange_strong(_M_ptr, - __expected, __desired, - __success, __failure); + return __atomic_impl::compare_exchange_strong( + _M_ptr, __expected, __desired, __success, __failure); } bool @@ -1777,19 +1828,17 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION memory_order __success, memory_order __failure) const noexcept { - return __atomic_impl::compare_exchange_weak(_M_ptr, - __expected, __desired, - __success, __failure); + return __atomic_impl::compare_exchange_weak( + _M_ptr, __expected, __desired, __success, __failure); } bool compare_exchange_strong(_Fp& __expected, _Fp __desired, - memory_order __success, - memory_order __failure) const noexcept + memory_order __success, + memory_order __failure) const noexcept { - return __atomic_impl::compare_exchange_strong(_M_ptr, - __expected, __desired, - __success, __failure); + return __atomic_impl::compare_exchange_strong( + _M_ptr, __expected, __desired, __success, __failure); } bool @@ -1906,9 +1955,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION memory_order __success, memory_order __failure) const noexcept { - return __atomic_impl::compare_exchange_weak(_M_ptr, - __expected, __desired, - __success, __failure); + return __atomic_impl::compare_exchange_weak( + _M_ptr, __expected, __desired, __success, __failure); } bool @@ -1916,9 +1964,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION memory_order __success, memory_order __failure) const noexcept { - return __atomic_impl::compare_exchange_strong(_M_ptr, - __expected, __desired, - __success, __failure); + return __atomic_impl::compare_exchange_strong( + _M_ptr, __expected, __desired, __success, __failure); } bool diff --git a/libstdc++-v3/include/bits/atomic_wait.h b/libstdc++-v3/include/bits/atomic_wait.h index 67c0e3bf56b7..9cbfb99a7c22 100644 --- a/libstdc++-v3/include/bits/atomic_wait.h +++ b/libstdc++-v3/include/bits/atomic_wait.h @@ -32,8 +32,10 @@ #pragma GCC system_header -#include -#if defined _GLIBCXX_HAS_GTHREADS || defined _GLIBCXX_HAVE_LINUX_FUTEX +#define __glibcxx_want_atomic_wait +#include + +#if __cpp_lib_atomic_wait #include #include #include @@ -48,8 +50,6 @@ # include // std::mutex, std::__condvar -#define __cpp_lib_atomic_wait 201907L - namespace std _GLIBCXX_VISIBILITY(default) { _GLIBCXX_BEGIN_NAMESPACE_VERSION @@ -476,5 +476,5 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } _GLIBCXX_END_NAMESPACE_VERSION } // namespace std -#endif // GTHREADS || LINUX_FUTEX +#endif // __cpp_lib_atomic_wait #endif // _GLIBCXX_ATOMIC_WAIT_H diff --git a/libstdc++-v3/include/bits/basic_string.h b/libstdc++-v3/include/bits/basic_string.h index 170a43664c97..09fd62afa665 100644 --- a/libstdc++-v3/include/bits/basic_string.h +++ b/libstdc++-v3/include/bits/basic_string.h @@ -47,22 +47,25 @@ # include #endif +#if __cplusplus > 202302L +# include +#endif + +#define __glibcxx_want_constexpr_string +#define __glibcxx_want_string_resize_and_overwrite +#define __glibcxx_want_string_udls +#define __glibcxx_want_to_string +#include + #if ! _GLIBCXX_USE_CXX11_ABI # include "cow_string.h" #else + namespace std _GLIBCXX_VISIBILITY(default) { _GLIBCXX_BEGIN_NAMESPACE_VERSION _GLIBCXX_BEGIN_NAMESPACE_CXX11 -#ifdef __cpp_lib_is_constant_evaluated -// Support P0980R1 in C++20. -# define __cpp_lib_constexpr_string 201907L -#elif __cplusplus >= 201703L && _GLIBCXX_HAVE_IS_CONSTANT_EVALUATED -// Support P0426R1 changes to char_traits in C++17. -# define __cpp_lib_constexpr_string 201611L -#endif - /** * @class basic_string basic_string.h * @brief Managing sequences of characters and character-like objects. @@ -1118,8 +1121,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 #pragma GCC diagnostic pop #endif -#if __cplusplus > 202002L -#define __cpp_lib_string_resize_and_overwrite 202110L +#ifdef __cpp_lib_string_resize_and_overwrite // C++ >= 23 /** Resize the string and call a function to fill it. * * @param __n The maximum size requested. @@ -1154,6 +1156,13 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 resize_and_overwrite(size_type __n, _Operation __op); #endif +#if __cplusplus >= 201103L + /// Non-standard version of resize_and_overwrite for C++11 and above. + template + _GLIBCXX20_CONSTEXPR void + __resize_and_overwrite(size_type __n, _Operation __op); +#endif + /** * Returns the total number of characters that the %string can hold * before needing to allocate more memory. @@ -1702,15 +1711,36 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 * Sets value of string to characters in the range [__first,__last). */ #if __cplusplus >= 201103L +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wc++17-extensions" template> _GLIBCXX20_CONSTEXPR + basic_string& + assign(_InputIterator __first, _InputIterator __last) + { +#if __cplusplus >= 202002L + if constexpr (contiguous_iterator<_InputIterator> + && is_same_v, _CharT>) +#else + if constexpr (__is_one_of<_InputIterator, const_iterator, iterator, + const _CharT*, _CharT*>::value) +#endif + { + __glibcxx_requires_valid_range(__first, __last); + return _M_replace(size_type(0), size(), + std::__to_address(__first), __last - __first); + } + else + return *this = basic_string(__first, __last, get_allocator()); + } +#pragma GCC diagnostic pop #else template + basic_string& + assign(_InputIterator __first, _InputIterator __last) + { return this->replace(begin(), end(), __first, __last); } #endif - basic_string& - assign(_InputIterator __first, _InputIterator __last) - { return this->replace(begin(), end(), __first, __last); } #if __cplusplus >= 201103L /** @@ -1721,7 +1751,20 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 _GLIBCXX20_CONSTEXPR basic_string& assign(initializer_list<_CharT> __l) - { return this->assign(__l.begin(), __l.size()); } + { + // The initializer_list array cannot alias the characters in *this + // so we don't need to use replace to that case. + const size_type __n = __l.size(); + if (__n > capacity()) + *this = basic_string(__l.begin(), __l.end(), get_allocator()); + else + { + if (__n) + _S_copy(_M_data(), __l.begin(), __n); + _M_set_length(__n); + } + return *this; + } #endif // C++11 #if __cplusplus >= 201703L @@ -4181,6 +4224,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 { return std::stod(__str, __idx); } #endif + // _GLIBCXX_RESOLVE_LIB_DEFECTS // DR 1261. Insufficent overloads for to_string / to_wstring _GLIBCXX_NODISCARD @@ -4193,8 +4237,12 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 const bool __neg = __val < 0; const unsigned __uval = __neg ? (unsigned)~__val + 1u : __val; const auto __len = __detail::__to_chars_len(__uval); - string __str(__neg + __len, '-'); - __detail::__to_chars_10_impl(&__str[__neg], __len, __uval); + string __str; + __str.__resize_and_overwrite(__neg + __len, [=](char* __p, size_t __n) { + __p[0] = '-'; + __detail::__to_chars_10_impl(__p + (int)__neg, __len, __uval); + return __n; + }); return __str; } @@ -4205,8 +4253,12 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 noexcept // any 32-bit value fits in the SSO buffer #endif { - string __str(__detail::__to_chars_len(__val), '\0'); - __detail::__to_chars_10_impl(&__str[0], __str.size(), __val); + const auto __len = __detail::__to_chars_len(__val); + string __str; + __str.__resize_and_overwrite(__len, [__val](char* __p, size_t __n) { + __detail::__to_chars_10_impl(__p, __n, __val); + return __n; + }); return __str; } @@ -4220,8 +4272,12 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 const bool __neg = __val < 0; const unsigned long __uval = __neg ? (unsigned long)~__val + 1ul : __val; const auto __len = __detail::__to_chars_len(__uval); - string __str(__neg + __len, '-'); - __detail::__to_chars_10_impl(&__str[__neg], __len, __uval); + string __str; + __str.__resize_and_overwrite(__neg + __len, [=](char* __p, size_t __n) { + __p[0] = '-'; + __detail::__to_chars_10_impl(__p + (int)__neg, __len, __uval); + return __n; + }); return __str; } @@ -4232,8 +4288,12 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 noexcept // any 32-bit value fits in the SSO buffer #endif { - string __str(__detail::__to_chars_len(__val), '\0'); - __detail::__to_chars_10_impl(&__str[0], __str.size(), __val); + const auto __len = __detail::__to_chars_len(__val); + string __str; + __str.__resize_and_overwrite(__len, [__val](char* __p, size_t __n) { + __detail::__to_chars_10_impl(__p, __n, __val); + return __n; + }); return __str; } @@ -4245,8 +4305,12 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 const unsigned long long __uval = __neg ? (unsigned long long)~__val + 1ull : __val; const auto __len = __detail::__to_chars_len(__uval); - string __str(__neg + __len, '-'); - __detail::__to_chars_10_impl(&__str[__neg], __len, __uval); + string __str; + __str.__resize_and_overwrite(__neg + __len, [=](char* __p, size_t __n) { + __p[0] = '-'; + __detail::__to_chars_10_impl(__p + (int)__neg, __len, __uval); + return __n; + }); return __str; } @@ -4254,12 +4318,74 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 inline string to_string(unsigned long long __val) { - string __str(__detail::__to_chars_len(__val), '\0'); - __detail::__to_chars_10_impl(&__str[0], __str.size(), __val); + const auto __len = __detail::__to_chars_len(__val); + string __str; + __str.__resize_and_overwrite(__len, [__val](char* __p, size_t __n) { + __detail::__to_chars_10_impl(__p, __n, __val); + return __n; + }); return __str; } -#if _GLIBCXX_USE_C99_STDIO +#if __cpp_lib_to_string >= 202306L + + [[nodiscard]] + inline string + to_string(float __val) + { + string __str; + size_t __len = 15; + do { + __str.resize_and_overwrite(__len, + [__val, &__len] (char* __p, size_t __n) { + auto [__end, __err] = std::to_chars(__p, __p + __n, __val); + if (__err == errc{}) [[likely]] + return __end - __p; + __len *= 2; + return __p - __p;; + }); + } while (__str.empty()); + return __str; + } + + [[nodiscard]] + inline string + to_string(double __val) + { + string __str; + size_t __len = 15; + do { + __str.resize_and_overwrite(__len, + [__val, &__len] (char* __p, size_t __n) { + auto [__end, __err] = std::to_chars(__p, __p + __n, __val); + if (__err == errc{}) [[likely]] + return __end - __p; + __len *= 2; + return __p - __p;; + }); + } while (__str.empty()); + return __str; + } + + [[nodiscard]] + inline string + to_string(long double __val) + { + string __str; + size_t __len = 15; + do { + __str.resize_and_overwrite(__len, + [__val, &__len] (char* __p, size_t __n) { + auto [__end, __err] = std::to_chars(__p, __p + __n, __val); + if (__err == errc{}) [[likely]] + return __end - __p; + __len *= 2; + return __p - __p;; + }); + } while (__str.empty()); + return __str; + } +#elif _GLIBCXX_USE_C99_STDIO // NB: (v)snprintf vs sprintf. _GLIBCXX_NODISCARD @@ -4331,80 +4457,129 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 inline long double stold(const wstring& __str, size_t* __idx = 0) { return __gnu_cxx::__stoa(&std::wcstold, "stold", __str.c_str(), __idx); } +#endif + +#ifdef _GLIBCXX_USE_WCHAR_T +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wc++17-extensions" + _GLIBCXX20_CONSTEXPR + inline void + __to_wstring_numeric(const char* __s, int __len, wchar_t* __wout) + { + // This condition is true if exec-charset and wide-exec-charset share the + // same values for the ASCII subset or the EBCDIC invariant character set. + if constexpr (wchar_t('0') == L'0' && wchar_t('-') == L'-' + && wchar_t('.') == L'.' && wchar_t('e') == L'e') + { + for (int __i = 0; __i < __len; ++__i) + __wout[__i] = (wchar_t) __s[__i]; + } + else + { + wchar_t __wc[256]; + for (int __i = '0'; __i <= '9'; ++__i) + __wc[__i] = L'0' + __i; + __wc['.'] = L'.'; + __wc['+'] = L'+'; + __wc['-'] = L'-'; + __wc['a'] = L'a'; + __wc['b'] = L'b'; + __wc['c'] = L'c'; + __wc['d'] = L'd'; + __wc['e'] = L'e'; + __wc['f'] = L'f'; + __wc['n'] = L'n'; // for "nan" and "inf" + __wc['p'] = L'p'; // for hexfloats "0x1p1" + __wc['x'] = L'x'; + __wc['A'] = L'A'; + __wc['B'] = L'B'; + __wc['C'] = L'C'; + __wc['D'] = L'D'; + __wc['E'] = L'E'; + __wc['F'] = L'F'; + __wc['N'] = L'N'; + __wc['P'] = L'P'; + __wc['X'] = L'X'; + + for (int __i = 0; __i < __len; ++__i) + __wout[__i] = __wc[(int)__s[__i]]; + } + } + +#if __cpp_lib_constexpr_string >= 201907L + constexpr +#endif + inline wstring +#if __cplusplus >= 201703L + __to_wstring_numeric(string_view __s) +#else + __to_wstring_numeric(const string& __s) +#endif + { + if constexpr (wchar_t('0') == L'0' && wchar_t('-') == L'-' + && wchar_t('.') == L'.' && wchar_t('e') == L'e') + return wstring(__s.data(), __s.data() + __s.size()); + else + { + wstring __ws; + auto __f = __s.data(); + __ws.__resize_and_overwrite(__s.size(), + [__f] (wchar_t* __to, int __n) { + std::__to_wstring_numeric(__f, __n, __to); + return __n; + }); + return __ws; + } + } +#pragma GCC diagnostic pop -#ifndef _GLIBCXX_HAVE_BROKEN_VSWPRINTF - // DR 1261. _GLIBCXX_NODISCARD inline wstring to_wstring(int __val) - { return __gnu_cxx::__to_xstring(&std::vswprintf, 4 * sizeof(int), - L"%d", __val); } + { return std::__to_wstring_numeric(std::to_string(__val)); } _GLIBCXX_NODISCARD inline wstring to_wstring(unsigned __val) - { return __gnu_cxx::__to_xstring(&std::vswprintf, - 4 * sizeof(unsigned), - L"%u", __val); } + { return std::__to_wstring_numeric(std::to_string(__val)); } _GLIBCXX_NODISCARD inline wstring to_wstring(long __val) - { return __gnu_cxx::__to_xstring(&std::vswprintf, 4 * sizeof(long), - L"%ld", __val); } + { return std::__to_wstring_numeric(std::to_string(__val)); } _GLIBCXX_NODISCARD inline wstring to_wstring(unsigned long __val) - { return __gnu_cxx::__to_xstring(&std::vswprintf, - 4 * sizeof(unsigned long), - L"%lu", __val); } + { return std::__to_wstring_numeric(std::to_string(__val)); } _GLIBCXX_NODISCARD inline wstring to_wstring(long long __val) - { return __gnu_cxx::__to_xstring(&std::vswprintf, - 4 * sizeof(long long), - L"%lld", __val); } + { return std::__to_wstring_numeric(std::to_string(__val)); } _GLIBCXX_NODISCARD inline wstring to_wstring(unsigned long long __val) - { return __gnu_cxx::__to_xstring(&std::vswprintf, - 4 * sizeof(unsigned long long), - L"%llu", __val); } + { return std::__to_wstring_numeric(std::to_string(__val)); } +#if __cpp_lib_to_string || _GLIBCXX_USE_C99_STDIO _GLIBCXX_NODISCARD inline wstring to_wstring(float __val) - { - const int __n = - __gnu_cxx::__numeric_traits::__max_exponent10 + 20; - return __gnu_cxx::__to_xstring(&std::vswprintf, __n, - L"%f", __val); - } + { return std::__to_wstring_numeric(std::to_string(__val)); } _GLIBCXX_NODISCARD inline wstring to_wstring(double __val) - { - const int __n = - __gnu_cxx::__numeric_traits::__max_exponent10 + 20; - return __gnu_cxx::__to_xstring(&std::vswprintf, __n, - L"%f", __val); - } + { return std::__to_wstring_numeric(std::to_string(__val)); } _GLIBCXX_NODISCARD inline wstring to_wstring(long double __val) - { - const int __n = - __gnu_cxx::__numeric_traits::__max_exponent10 + 20; - return __gnu_cxx::__to_xstring(&std::vswprintf, __n, - L"%Lf", __val); - } -#endif // _GLIBCXX_HAVE_BROKEN_VSWPRINTF -#endif // _GLIBCXX_USE_WCHAR_T && _GLIBCXX_USE_C99_WCHAR + { return std::__to_wstring_numeric(std::to_string(__val)); } +#endif +#endif // _GLIBCXX_USE_WCHAR_T _GLIBCXX_END_NAMESPACE_CXX11 _GLIBCXX_END_NAMESPACE_VERSION @@ -4491,10 +4666,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { }; #endif -#if __cplusplus >= 201402L - -#define __cpp_lib_string_udls 201304L - +#ifdef __cpp_lib_string_udls // C++ >= 14 inline namespace literals { inline namespace string_literals @@ -4539,6 +4711,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION #pragma GCC diagnostic pop } // inline namespace string_literals } // inline namespace literals +#endif // __cpp_lib_string_udls #if __cplusplus >= 201703L namespace __detail::__variant @@ -4556,7 +4729,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { }; } // namespace __detail::__variant #endif // C++17 -#endif // C++14 _GLIBCXX_END_NAMESPACE_VERSION } // namespace std diff --git a/libstdc++-v3/include/bits/basic_string.tcc b/libstdc++-v3/include/bits/basic_string.tcc index d8a279fc9edb..104a517f7941 100644 --- a/libstdc++-v3/include/bits/basic_string.tcc +++ b/libstdc++-v3/include/bits/basic_string.tcc @@ -561,43 +561,52 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION return __n; } -#if __cplusplus > 202002L +#ifdef __cpp_lib_string_resize_and_overwrite // C++ >= 23 template template + [[__gnu__::__always_inline__]] constexpr void basic_string<_CharT, _Traits, _Alloc>:: - resize_and_overwrite(size_type __n, _Operation __op) - { - const size_type __capacity = capacity(); - _CharT* __p; - if (__n > __capacity) - { - __p = _M_create(__n, __capacity); - this->_S_copy(__p, _M_data(), length()); // exclude trailing null -#if __cpp_lib_is_constant_evaluated - if (std::is_constant_evaluated()) - traits_type::assign(__p + length(), __n - length(), _CharT()); + __resize_and_overwrite(const size_type __n, _Operation __op) + { resize_and_overwrite<_Operation&>(__n, __op); } +#endif + +#if __cplusplus >= 201103L + template + template + _GLIBCXX20_CONSTEXPR void + basic_string<_CharT, _Traits, _Alloc>:: +#ifdef __cpp_lib_string_resize_and_overwrite // C++ >= 23 + resize_and_overwrite(const size_type __n, _Operation __op) +#else + __resize_and_overwrite(const size_type __n, _Operation __op) +#endif + { + reserve(__n); + _CharT* const __p = _M_data(); +#if __cpp_lib_is_constant_evaluated + if (std::__is_constant_evaluated() && __n > size()) + traits_type::assign(__p + size(), __n - size(), _CharT()); #endif - _M_dispose(); - _M_data(__p); - _M_capacity(__n); - } - else - __p = _M_data(); struct _Terminator { - constexpr ~_Terminator() { _M_this->_M_set_length(_M_r); } + _GLIBCXX20_CONSTEXPR ~_Terminator() { _M_this->_M_set_length(_M_r); } basic_string* _M_this; size_type _M_r; }; - _Terminator __term{this}; - auto __r = std::move(__op)(auto(__p), auto(__n)); + _Terminator __term{this, 0}; + auto __r = std::move(__op)(__p + 0, __n + 0); +#ifdef __cpp_lib_concepts static_assert(ranges::__detail::__is_integer_like); +#else + static_assert(__gnu_cxx::__is_integer_nonstrict::__value, + "resize_and_overwrite operation must return an integer"); +#endif _GLIBCXX_DEBUG_ASSERT(__r >= 0 && __r <= __n); __term._M_r = size_type(__r); if (__term._M_r > __n) __builtin_unreachable(); } -#endif // C++23 +#endif // C++11 #endif // _GLIBCXX_USE_CXX11_ABI diff --git a/libstdc++-v3/include/bits/c++config b/libstdc++-v3/include/bits/c++config index dd47f274d5ff..0a41cdd29a9a 100644 --- a/libstdc++-v3/include/bits/c++config +++ b/libstdc++-v3/include/bits/c++config @@ -822,10 +822,10 @@ namespace std # define _GLIBCXX_LDOUBLE_IS_IEEE_BINARY128 1 #endif -#ifdef __STDCPP_BFLOAT16_T__ +#if defined __cplusplus && defined __BFLT16_DIG__ namespace __gnu_cxx { - using __bfloat16_t = decltype(0.0bf16); + typedef __decltype(0.0bf16) __bfloat16_t; } #endif diff --git a/libstdc++-v3/include/bits/char_traits.h b/libstdc++-v3/include/bits/char_traits.h index 0928137854bb..e9b4e84af994 100644 --- a/libstdc++-v3/include/bits/char_traits.h +++ b/libstdc++-v3/include/bits/char_traits.h @@ -61,6 +61,9 @@ # define _GLIBCXX_ALWAYS_INLINE inline __attribute__((__always_inline__)) #endif +#define __glibcxx_want_constexpr_char_traits +#include + namespace __gnu_cxx _GLIBCXX_VISIBILITY(default) { _GLIBCXX_BEGIN_NAMESPACE_VERSION @@ -316,14 +319,6 @@ namespace std _GLIBCXX_VISIBILITY(default) { _GLIBCXX_BEGIN_NAMESPACE_VERSION -#ifdef __cpp_lib_is_constant_evaluated -// Unofficial macro indicating P1032R1 support in C++20 -# define __cpp_lib_constexpr_char_traits 201811L -#elif __cplusplus >= 201703L && _GLIBCXX_HAVE_IS_CONSTANT_EVALUATED -// Unofficial macro indicating P0426R1 support in C++17 -# define __cpp_lib_constexpr_char_traits 201611L -#endif - // 21.1 /** * @brief Basis for explicit traits specializations. diff --git a/libstdc++-v3/include/bits/chrono.h b/libstdc++-v3/include/bits/chrono.h index e9490767c562..50aca84f142f 100644 --- a/libstdc++-v3/include/bits/chrono.h +++ b/libstdc++-v3/include/bits/chrono.h @@ -32,6 +32,10 @@ #pragma GCC system_header +#define __glibcxx_want_chrono +#define __glibcxx_want_chrono_udls +#include + #if __cplusplus >= 201103L #include @@ -276,8 +280,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION if constexpr (is_same_v<_ToDur, duration<_Rep, _Period>>) return __d; else + { #endif - { using __to_period = typename _ToDur::period; using __to_rep = typename _ToDur::rep; using __cf = ratio_divide<_Period, __to_period>; @@ -285,7 +289,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION using __dc = __duration_cast_impl<_ToDur, __cf, __cr, __cf::num == 1, __cf::den == 1>; return __dc::__cast(__d); - } +#if __cpp_inline_variables && __cpp_if_constexpr + } +#endif } /** Trait indicating whether to treat a type as a floating-point type. @@ -368,9 +374,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { }; #endif // C++20 -#if __cplusplus >= 201703L -# define __cpp_lib_chrono 201611L - +#ifdef __cpp_lib_chrono // C++ >= 17 && HOSTED /** Convert a `duration` to type `ToDur` and round down. * * If the duration cannot be represented exactly in the result type, @@ -464,7 +468,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION // Make chrono::ceil also usable as chrono::__detail::ceil. namespace __detail { using chrono::ceil; } -#else // ! C++17 +#else // ! __cpp_lib_chrono // We want to use ceil even when compiling for earlier standards versions. // C++11 only allows a single statement in a constexpr function, so we @@ -486,7 +490,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION return __detail::__ceil_impl(chrono::duration_cast<_ToDur>(__d), __d); } } -#endif // C++17 +#endif // __cpp_lib_chrono /// duration_values template @@ -1310,9 +1314,7 @@ _GLIBCXX_END_INLINE_ABI_NAMESPACE(_V2) #endif // C++20 } // namespace chrono -#if __cplusplus >= 201402L -#define __cpp_lib_chrono_udls 201304L - +#ifdef __cpp_lib_chrono_udls // C++ >= 14 && HOSTED inline namespace literals { /** ISO C++ 2014 namespace for suffixes for duration literals. @@ -1433,7 +1435,7 @@ _GLIBCXX_END_INLINE_ABI_NAMESPACE(_V2) { using namespace literals::chrono_literals; } // namespace chrono -#endif // C++14 +#endif // __cpp_lib_chrono_udls #if __cplusplus >= 201703L namespace filesystem diff --git a/libstdc++-v3/include/bits/chrono_io.h b/libstdc++-v3/include/bits/chrono_io.h index c95301361d87..7352df095ff4 100644 --- a/libstdc++-v3/include/bits/chrono_io.h +++ b/libstdc++-v3/include/bits/chrono_io.h @@ -38,7 +38,7 @@ #include // setw, setfill #include -#include +#include namespace std _GLIBCXX_VISIBILITY(default) { @@ -69,34 +69,9 @@ namespace __detail #define _GLIBCXX_WIDEN_(C, S) ::std::chrono::__detail::_Widen(S, L##S) #define _GLIBCXX_WIDEN(S) _GLIBCXX_WIDEN_(_CharT, S) - - // Write an arbitrary duration suffix into the buffer. - template - constexpr const char* - __units_suffix_misc(char* __buf, size_t /* TODO check length? */) noexcept - { - namespace __tc = std::__detail; - char* __p = __buf; - __p[0] = '['; - unsigned __nlen = __tc::__to_chars_len((uintmax_t)_Period::num); - __tc::__to_chars_10_impl(__p + 1, __nlen, (uintmax_t)_Period::num); - __p += 1 + __nlen; - if constexpr (_Period::den != 1) - { - __p[0] = '/'; - unsigned __dlen = __tc::__to_chars_len((uintmax_t)_Period::den); - __tc::__to_chars_10_impl(__p + 1, __dlen, (uintmax_t)_Period::den); - __p += 1 + __dlen; - } - __p[0] = ']'; - __p[1] = 's'; - __p[2] = '\0'; - return __buf; - } - template - constexpr auto - __units_suffix(char* __buf, size_t __n) noexcept + constexpr basic_string_view<_CharT> + __units_suffix() noexcept { // The standard say these are all narrow strings, which would need to // be widened at run-time when inserted into a wide stream. We use @@ -134,7 +109,22 @@ namespace __detail _GLIBCXX_UNITS_SUFFIX(ratio<3600>, "h") _GLIBCXX_UNITS_SUFFIX(ratio<86400>, "d") #undef _GLIBCXX_UNITS_SUFFIX - return __detail::__units_suffix_misc<_Period>(__buf, __n); + return {}; + } + + template + inline _Out + __fmt_units_suffix(_Out __out) noexcept + { + if (auto __s = __detail::__units_suffix<_Period, _CharT>(); __s.size()) + return __format::__write(std::move(__out), __s); + else if constexpr (_Period::den == 1) + return std::format_to(std::move(__out), _GLIBCXX_WIDEN("[{}]s"), + (uintmax_t)_Period::num); + else + return std::format_to(std::move(__out), _GLIBCXX_WIDEN("[{}/{}]s"), + (uintmax_t)_Period::num, + (uintmax_t)_Period::den); } } // namespace __detail /// @endcond @@ -149,14 +139,14 @@ namespace __detail operator<<(std::basic_ostream<_CharT, _Traits>& __os, const duration<_Rep, _Period>& __d) { + using _Out = ostreambuf_iterator<_CharT, _Traits>; using period = typename _Period::type; - char __buf[sizeof("[/]s") + 2 * numeric_limits::digits10]; std::basic_ostringstream<_CharT, _Traits> __s; __s.flags(__os.flags()); __s.imbue(__os.getloc()); __s.precision(__os.precision()); __s << __d.count(); - __s << __detail::__units_suffix(__buf, sizeof(__buf)); + __detail::__fmt_units_suffix(_Out(__s)); __os << std::move(__s).str(); return __os; } @@ -235,9 +225,13 @@ namespace __format }; constexpr _ChronoParts - operator|(_ChronoParts __x, _ChronoParts __y) + operator|(_ChronoParts __x, _ChronoParts __y) noexcept { return static_cast<_ChronoParts>((int)__x | (int)__y); } + constexpr _ChronoParts& + operator|=(_ChronoParts& __x, _ChronoParts __y) noexcept + { return __x = __x | __y; } + // TODO rename this to chrono::__formatter? or chrono::__detail::__formatter? template struct __formatter_chrono @@ -1052,32 +1046,16 @@ namespace __format template typename _FormatContext::iterator _M_q(const _Tp&, typename _FormatContext::iterator __out, - _FormatContext& __ctx) const + _FormatContext&) const { // %q The duration's unit suffix if constexpr (!chrono::__is_duration_v<_Tp>) __throw_format_error("format error: argument is not a duration"); else { + namespace __d = chrono::__detail; using period = typename _Tp::period; - char __buf[sizeof("[/]s") + 2 * numeric_limits::digits10]; - constexpr size_t __n = sizeof(__buf); - auto __s = chrono::__detail::__units_suffix(__buf, - __n); - if constexpr (is_same_v) - return std::format_to(std::move(__out), _S_empty_spec, __s); - else - { - // Suffix was written to __buf as narrow string. - _CharT __wbuf[__n]; - size_t __len = __builtin_strlen(__buf); - locale __loc = _M_locale(__ctx); - auto& __ct = use_facet>(__loc); - __ct.widen(__buf, __len, __wbuf); - __wbuf[__len] = 0; - return std::format_to(std::move(__out), _S_empty_spec, - __wbuf); - } + return __d::__fmt_units_suffix(std::move(__out)); } } @@ -1368,18 +1346,18 @@ namespace __format { if (__t._M_abbrev) { - __string_view __wsv; + string_view __sv = *__t._M_abbrev; if constexpr (is_same_v<_CharT, char>) - __wsv = *__t._M_abbrev; + return __format::__write(std::move(__out), __sv); else { - string_view __sv = *__t._M_abbrev; + // TODO use resize_and_overwrite basic_string<_CharT> __ws(__sv.size(), _CharT()); auto& __ct = use_facet>(_M_locale(__ctx)); __ct.widen(__sv.begin(), __sv.end(), __ws.data()); - __wsv = __ws; + __string_view __wsv = __ws; + return __format::__write(std::move(__out), __wsv); } - return __format::__write(std::move(__out), __wsv); } } else if constexpr (__is_specialization_of<_Tp, __utc_leap_second>) @@ -2136,25 +2114,156 @@ namespace chrono /// @addtogroup chrono /// @{ - // TODO: from_stream for duration -#if 0 +/// @cond undocumented +namespace __detail +{ + template + struct _Parser + { + static_assert(is_same_v, _Duration>); + + explicit + _Parser(__format::_ChronoParts __need) : _M_need(__need) { } + + _Parser(_Parser&&) = delete; + void operator=(_Parser&&) = delete; + + _Duration _M_time{}; // since midnight + sys_days _M_sys_days{}; + year_month_day _M_ymd{}; + weekday _M_wd{}; + __format::_ChronoParts _M_need; + + template + basic_istream<_CharT, _Traits>& + operator()(basic_istream<_CharT, _Traits>& __is, const _CharT* __fmt, + basic_string<_CharT, _Traits, _Alloc>* __abbrev = nullptr, + minutes* __offset = nullptr); + + private: + // Read an unsigned integer from the stream and return it. + // Extract no more than __n digits. Set failbit if an integer isn't read. + template + static int_least32_t + _S_read_unsigned(basic_istream<_CharT, _Traits>& __is, + ios_base::iostate& __err, int __n) + { + int_least32_t __val = _S_try_read_digit(__is, __err); + if (__val == -1) [[unlikely]] + __err |= ios_base::failbit; + else + { + int __n1 = (std::min)(__n, 9); + // Cannot overflow __val unless we read more than 9 digits + for (int __i = 1; __i < __n1; ++__i) + if (auto __dig = _S_try_read_digit(__is, __err); __dig != -1) + { + __val *= 10; + __val += __dig; + } + + while (__n1++ < __n) [[unlikely]] + if (auto __dig = _S_try_read_digit(__is, __err); __dig != -1) + { + if (__builtin_mul_overflow(__val, 10, &__val) + || __builtin_add_overflow(__val, __dig, &__val)) + { + __err |= ios_base::failbit; + return -1; + } + } + } + return __val; + } + + // Read an unsigned integer from the stream and return it. + // Extract no more than __n digits. Set failbit if an integer isn't read. + template + static int_least32_t + _S_read_signed(basic_istream<_CharT, _Traits>& __is, + ios_base::iostate& __err, int __n) + { + auto __sign = __is.peek(); + if (__sign == '-' || __sign == '+') + (void) __is.get(); + int_least32_t __val = _S_read_unsigned(__is, __err, __n); + if (__err & ios_base::failbit) + { + if (__sign == '-') [[unlikely]] + __val *= -1; + } + return __val; + } + + // Read a digit from the stream and return it, or return -1. + // If no digit is read eofbit will be set (but not failbit). + template + static int_least32_t + _S_try_read_digit(basic_istream<_CharT, _Traits>& __is, + ios_base::iostate& __err) + { + int_least32_t __val = -1; + auto __i = __is.peek(); + if (!_Traits::eq_int_type(__i, _Traits::eof())) [[likely]] + { + _CharT __c = _Traits::to_char_type(__i); + if (_CharT('0') <= __c && __c <= _CharT('9')) [[likely]] + { + (void) __is.get(); + __val = __c - _CharT('0'); + } + } + else + __err |= ios_base::eofbit; + return __val; + } + + // Read the specified character and return true. + // If the character is not found, set failbit and return false. + template + static bool + _S_read_chr(basic_istream<_CharT, _Traits>& __is, + ios_base::iostate& __err, _CharT __c) + { + auto __i = __is.peek(); + if (_Traits::eq_int_type(__i, _Traits::eof())) + __err |= ios_base::eofbit; + else if (_Traits::to_char_type(__i) == __c) [[likely]] + { + (void) __is.get(); + return true; + } + __err |= ios_base::failbit; + return false; + } + }; + + template + using _Parser_t = _Parser>; + +} // namespace __detail +/// ~endcond + template> - basic_istream<_CharT, _Traits>& + inline basic_istream<_CharT, _Traits>& from_stream(basic_istream<_CharT, _Traits>& __is, const _CharT* __fmt, duration<_Rep, _Period>& __d, basic_string<_CharT, _Traits, _Alloc>* __abbrev = nullptr, minutes* __offset = nullptr) { + auto __need = __format::_ChronoParts::_TimeOfDay; + __detail::_Parser_t> __p(__need); + if (__p(__is, __fmt, __abbrev, __offset)) + __d = chrono::duration_cast>(__p._M_time); + return __is; } -#endif template inline basic_ostream<_CharT, _Traits>& operator<<(basic_ostream<_CharT, _Traits>& __os, const day& __d) { - using _Ctx = __conditional_t, - format_context, wformat_context>; + using _Ctx = __format::__format_context<_CharT>; using _Str = basic_string_view<_CharT>; _Str __s = _GLIBCXX_WIDEN("{:02d} is not a valid day"); if (__d.ok()) @@ -2163,14 +2272,25 @@ namespace chrono return __os; } - // TODO from_stream for day + template> + inline basic_istream<_CharT, _Traits>& + from_stream(basic_istream<_CharT, _Traits>& __is, const _CharT* __fmt, + day& __d, + basic_string<_CharT, _Traits, _Alloc>* __abbrev = nullptr, + minutes* __offset = nullptr) + { + __detail::_Parser<> __p(__format::_ChronoParts::_Day); + if (__p(__is, __fmt, __abbrev, __offset)) + __d = __p._M_ymd.day(); + return __is; + } template inline basic_ostream<_CharT, _Traits>& operator<<(basic_ostream<_CharT, _Traits>& __os, const month& __m) { - using _Ctx = __conditional_t, - format_context, wformat_context>; + using _Ctx = __format::__format_context<_CharT>; using _Str = basic_string_view<_CharT>; _Str __s = _GLIBCXX_WIDEN("{:L%b}{} is not a valid month"); if (__m.ok()) @@ -2182,14 +2302,25 @@ namespace chrono return __os; } - // TODO from_stream for month + template> + inline basic_istream<_CharT, _Traits>& + from_stream(basic_istream<_CharT, _Traits>& __is, const _CharT* __fmt, + month& __m, + basic_string<_CharT, _Traits, _Alloc>* __abbrev = nullptr, + minutes* __offset = nullptr) + { + __detail::_Parser<> __p(__format::_ChronoParts::_Month); + if (__p(__is, __fmt, __abbrev, __offset)) + __m = __p._M_ymd.month(); + return __is; + } template inline basic_ostream<_CharT, _Traits>& operator<<(basic_ostream<_CharT, _Traits>& __os, const year& __y) { - using _Ctx = __conditional_t, - format_context, wformat_context>; + using _Ctx = __format::__format_context<_CharT>; using _Str = basic_string_view<_CharT>; _Str __s = _GLIBCXX_WIDEN("-{:04d} is not a valid year"); if (__y.ok()) @@ -2203,14 +2334,25 @@ namespace chrono return __os; } - // TODO from_stream for year + template> + inline basic_istream<_CharT, _Traits>& + from_stream(basic_istream<_CharT, _Traits>& __is, const _CharT* __fmt, + year& __y, + basic_string<_CharT, _Traits, _Alloc>* __abbrev = nullptr, + minutes* __offset = nullptr) + { + __detail::_Parser<> __p(__format::_ChronoParts::_Year); + if (__p(__is, __fmt, __abbrev, __offset)) + __y = __p._M_ymd.year(); + return __is; + } template inline basic_ostream<_CharT, _Traits>& operator<<(basic_ostream<_CharT, _Traits>& __os, const weekday& __wd) { - using _Ctx = __conditional_t, - format_context, wformat_context>; + using _Ctx = __format::__format_context<_CharT>; using _Str = basic_string_view<_CharT>; _Str __s = _GLIBCXX_WIDEN("{:L%a}{} is not a valid weekday"); if (__wd.ok()) @@ -2222,7 +2364,19 @@ namespace chrono return __os; } - // TODO from_stream for weekday + template> + inline basic_istream<_CharT, _Traits>& + from_stream(basic_istream<_CharT, _Traits>& __is, const _CharT* __fmt, + weekday& __wd, + basic_string<_CharT, _Traits, _Alloc>* __abbrev = nullptr, + minutes* __offset = nullptr) + { + __detail::_Parser<> __p(__format::_ChronoParts::_Weekday); + if (__p(__is, __fmt, __abbrev, __offset)) + __wd = __p._M_wd; + return __is; + } template inline basic_ostream<_CharT, _Traits>& @@ -2236,15 +2390,14 @@ namespace chrono __os2.imbue(__os.getloc()); __os2 << __wdi.weekday(); const auto __i = __wdi.index(); - if constexpr (is_same_v<_CharT, char>) - __os2 << std::format("[{}", __i); - else - __os2 << std::format(L"[{}", __i); - basic_string_view<_CharT> __s = _GLIBCXX_WIDEN(" is not a valid index]"); + basic_string_view<_CharT> __s + = _GLIBCXX_WIDEN("[ is not a valid index]"); + __os2 << __s[0]; + __os2 << std::format(_GLIBCXX_WIDEN("{}"), __i); if (__i >= 1 && __i <= 5) __os2 << __s.back(); else - __os2 << __s; + __os2 << __s.substr(1); __os << __os2.view(); return __os; } @@ -2279,7 +2432,21 @@ namespace chrono return __os; } - // TODO from_stream for month_day + template> + inline basic_istream<_CharT, _Traits>& + from_stream(basic_istream<_CharT, _Traits>& __is, const _CharT* __fmt, + month_day& __md, + basic_string<_CharT, _Traits, _Alloc>* __abbrev = nullptr, + minutes* __offset = nullptr) + { + using __format::_ChronoParts; + auto __need = _ChronoParts::_Month | _ChronoParts::_Day; + __detail::_Parser<> __p(__need); + if (__p(__is, __fmt, __abbrev, __offset)) + __md = month_day(__p._M_ymd.month(), __p._M_ymd.day()); + return __is; + } template inline basic_ostream<_CharT, _Traits>& @@ -2289,11 +2456,7 @@ namespace chrono // As above, just write straight to a stringstream, as if by "{:L}/last" basic_stringstream<_CharT> __os2; __os2.imbue(__os.getloc()); - __os2 << __mdl.month(); - if constexpr (is_same_v<_CharT, char>) - __os2 << "/last"; - else - __os2 << L"/last"; + __os2 << __mdl.month() << _GLIBCXX_WIDEN("/last"); __os << __os2.view(); return __os; } @@ -2351,15 +2514,28 @@ namespace chrono return __os; } - // TODO from_stream for year_month + template> + inline basic_istream<_CharT, _Traits>& + from_stream(basic_istream<_CharT, _Traits>& __is, const _CharT* __fmt, + year_month& __ym, + basic_string<_CharT, _Traits, _Alloc>* __abbrev = nullptr, + minutes* __offset = nullptr) + { + using __format::_ChronoParts; + auto __need = _ChronoParts::_Year | _ChronoParts::_Month; + __detail::_Parser<> __p(__need); + if (__p(__is, __fmt, __abbrev, __offset)) + __ym = year_month(__p._M_ymd.year(), __p._M_ymd.month()); + return __is; + } template inline basic_ostream<_CharT, _Traits>& operator<<(basic_ostream<_CharT, _Traits>& __os, const year_month_day& __ymd) { - using _Ctx = __conditional_t, - format_context, wformat_context>; + using _Ctx = __format::__format_context<_CharT>; using _Str = basic_string_view<_CharT>; _Str __s = _GLIBCXX_WIDEN("{:%F} is not a valid date"); __os << std::vformat(__ymd.ok() ? __s.substr(0, 5) : __s, @@ -2367,7 +2543,22 @@ namespace chrono return __os; } - // TODO from_stream for year_month_day + template> + inline basic_istream<_CharT, _Traits>& + from_stream(basic_istream<_CharT, _Traits>& __is, const _CharT* __fmt, + year_month_day& __ymd, + basic_string<_CharT, _Traits, _Alloc>* __abbrev = nullptr, + minutes* __offset = nullptr) + { + using __format::_ChronoParts; + auto __need = _ChronoParts::_Year | _ChronoParts::_Month + | _ChronoParts::_Day; + __detail::_Parser<> __p(__need); + if (__p(__is, __fmt, __abbrev, __offset)) + __ymd = __p._M_ymd; + return __is; + } template inline basic_ostream<_CharT, _Traits>& @@ -2498,7 +2689,28 @@ namespace chrono return __os; } - // TODO: from_stream for sys_time + template> + basic_istream<_CharT, _Traits>& + from_stream(basic_istream<_CharT, _Traits>& __is, const _CharT* __fmt, + sys_time<_Duration>& __tp, + basic_string<_CharT, _Traits, _Alloc>* __abbrev = nullptr, + minutes* __offset = nullptr) + { + minutes __off{}; + if (!__offset) + __offset = &__off; + using __format::_ChronoParts; + auto __need = _ChronoParts::_Year | _ChronoParts::_Month + | _ChronoParts::_Day | _ChronoParts::_TimeOfDay; + __detail::_Parser_t<_Duration> __p(__need); + if (__p(__is, __fmt, __abbrev, __offset)) + { + auto __st = __p._M_sys_days + __p._M_time - *__offset; + __tp = chrono::time_point_cast<_Duration>(__st); + } + return __is; + } template inline basic_ostream<_CharT, _Traits>& @@ -2509,7 +2721,19 @@ namespace chrono return __os; } - // TODO: from_stream for utc_time + template> + inline basic_istream<_CharT, _Traits>& + from_stream(basic_istream<_CharT, _Traits>& __is, const _CharT* __fmt, + utc_time<_Duration>& __tp, + basic_string<_CharT, _Traits, _Alloc>* __abbrev = nullptr, + minutes* __offset = nullptr) + { + sys_time<_Duration> __st; + if (chrono::from_stream(__is, __fmt, __st, __abbrev, __offset)) + __tp = utc_clock::from_sys(__st); + return __is; + } template inline basic_ostream<_CharT, _Traits>& @@ -2520,7 +2744,19 @@ namespace chrono return __os; } - // TODO: from_stream for tai_time + template> + inline basic_istream<_CharT, _Traits>& + from_stream(basic_istream<_CharT, _Traits>& __is, const _CharT* __fmt, + tai_time<_Duration>& __tp, + basic_string<_CharT, _Traits, _Alloc>* __abbrev = nullptr, + minutes* __offset = nullptr) + { + utc_time<_Duration> __ut; + if (chrono::from_stream(__is, __fmt, __ut, __abbrev, __offset)) + __tp = tai_clock::from_utc(__ut); + return __is; + } template inline basic_ostream<_CharT, _Traits>& @@ -2531,8 +2767,19 @@ namespace chrono return __os; } - // TODO: from_stream for gps_time - + template> + inline basic_istream<_CharT, _Traits>& + from_stream(basic_istream<_CharT, _Traits>& __is, const _CharT* __fmt, + gps_time<_Duration>& __tp, + basic_string<_CharT, _Traits, _Alloc>* __abbrev = nullptr, + minutes* __offset = nullptr) + { + utc_time<_Duration> __ut; + if (chrono::from_stream(__is, __fmt, __ut, __abbrev, __offset)) + __tp = gps_clock::from_utc(__ut); + return __is; + } template inline basic_ostream<_CharT, _Traits>& @@ -2543,7 +2790,19 @@ namespace chrono return __os; } - // TODO: from_stream for file_time + template> + inline basic_istream<_CharT, _Traits>& + from_stream(basic_istream<_CharT, _Traits>& __is, const _CharT* __fmt, + file_time<_Duration>& __tp, + basic_string<_CharT, _Traits, _Alloc>* __abbrev = nullptr, + minutes* __offset = nullptr) + { + sys_time<_Duration> __st; + if (chrono::from_stream(__is, __fmt, __st, __abbrev, __offset)) + __tp = file_clock::from_sys(__st); + return __is; + } template inline basic_ostream<_CharT, _Traits>& @@ -2554,7 +2813,1377 @@ namespace chrono return __os; } - // TODO: from_stream for local_time + template> + basic_istream<_CharT, _Traits>& + from_stream(basic_istream<_CharT, _Traits>& __is, const _CharT* __fmt, + local_time<_Duration>& __tp, + basic_string<_CharT, _Traits, _Alloc>* __abbrev = nullptr, + minutes* __offset = nullptr) + { + using __format::_ChronoParts; + auto __need = _ChronoParts::_Year | _ChronoParts::_Month + | _ChronoParts::_Day | _ChronoParts::_TimeOfDay; + __detail::_Parser_t<_Duration> __p(__need); + if (__p(__is, __fmt, __abbrev, __offset)) + { + days __d = __p._M_sys_days.time_since_epoch(); + auto __t = local_days(__d) + __p._M_time; // ignore offset + __tp = chrono::time_point_cast<_Duration>(__t); + } + return __is; + } + + // [time.parse] parsing + +namespace __detail +{ + template, + typename... _OptArgs> + concept __parsable = requires (basic_istream<_CharT, _Traits>& __is, + const _CharT* __fmt, _Parsable& __tp, + _OptArgs*... __args) + { from_stream(__is, __fmt, __tp, __args...); }; + + template, + typename _Alloc = allocator<_CharT>> + struct _Parse + { + private: + using __string_type = basic_string<_CharT, _Traits, _Alloc>; + + public: + _Parse(const _CharT* __fmt, _Parsable& __tp, + basic_string<_CharT, _Traits, _Alloc>* __abbrev = nullptr, + minutes* __offset = nullptr) + : _M_fmt(__fmt), _M_tp(std::__addressof(__tp)), + _M_abbrev(__abbrev), _M_offset(__offset) + { } + + _Parse(_Parse&&) = delete; + _Parse& operator=(_Parse&&) = delete; + + private: + using __stream_type = basic_istream<_CharT, _Traits>; + + const _CharT* const _M_fmt; + _Parsable* const _M_tp; + __string_type* const _M_abbrev; + minutes* const _M_offset; + + friend __stream_type& + operator>>(__stream_type& __is, _Parse&& __p) + { + if (__p._M_offset) + from_stream(__is, __p._M_fmt, *__p._M_tp, __p._M_abbrev, + __p._M_offset); + else if (__p._M_abbrev) + from_stream(__is, __p._M_fmt, *__p._M_tp, __p._M_abbrev); + else + from_stream(__is, __p._M_fmt, *__p._M_tp); + return __is; + } + + friend void operator>>(__stream_type&, _Parse&) = delete; + friend void operator>>(__stream_type&, const _Parse&) = delete; + }; +} // namespace __detail + + template _Parsable> + [[nodiscard, __gnu__::__access__(__read_only__, 1)]] + inline auto + parse(const _CharT* __fmt, _Parsable& __tp) + { return __detail::_Parse<_Parsable, _CharT>(__fmt, __tp); } + + template _Parsable> + [[nodiscard]] + inline auto + parse(const basic_string<_CharT, _Traits, _Alloc>& __fmt, _Parsable& __tp) + { + return __detail::_Parse<_Parsable, _CharT, _Traits>(__fmt.c_str(), __tp); + } + + template, + __detail::__parsable<_CharT, _Traits, _StrT> _Parsable> + [[nodiscard, __gnu__::__access__(__read_only__, 1)]] + inline auto + parse(const _CharT* __fmt, _Parsable& __tp, + basic_string<_CharT, _Traits, _Alloc>& __abbrev) + { + auto __pa = std::__addressof(__abbrev); + return __detail::_Parse<_Parsable, _CharT, _Traits, _Alloc>(__fmt, __tp, + __pa); + } + + template, + __detail::__parsable<_CharT, _Traits, _StrT> _Parsable> + [[nodiscard]] + inline auto + parse(const basic_string<_CharT, _Traits, _Alloc>& __fmt, _Parsable& __tp, + basic_string<_CharT, _Traits, _Alloc>& __abbrev) + { + auto __pa = std::__addressof(__abbrev); + return __detail::_Parse<_Parsable, _CharT, _Traits, _Alloc>(__fmt.c_str(), + __tp, __pa); + } + + template, + typename _StrT = basic_string<_CharT, _Traits>, + __detail::__parsable<_CharT, _Traits, _StrT, minutes> _Parsable> + [[nodiscard, __gnu__::__access__(__read_only__, 1)]] + inline auto + parse(const _CharT* __fmt, _Parsable& __tp, minutes& __offset) + { + return __detail::_Parse<_Parsable, _CharT>(__fmt, __tp, nullptr, + &__offset); + } + + template, + __detail::__parsable<_CharT, _Traits, _StrT, minutes> _Parsable> + [[nodiscard]] + inline auto + parse(const basic_string<_CharT, _Traits, _Alloc>& __fmt, _Parsable& __tp, + minutes& __offset) + { + return __detail::_Parse<_Parsable, _CharT, _Traits, _Alloc>(__fmt.c_str(), + __tp, nullptr, + &__offset); + } + + template, + __detail::__parsable<_CharT, _Traits, _StrT, minutes> _Parsable> + [[nodiscard, __gnu__::__access__(__read_only__, 1)]] + inline auto + parse(const _CharT* __fmt, _Parsable& __tp, + basic_string<_CharT, _Traits, _Alloc>& __abbrev, minutes& __offset) + { + auto __pa = std::__addressof(__abbrev); + return __detail::_Parse<_Parsable, _CharT, _Traits, _Alloc>(__fmt, __tp, + __pa, + &__offset); + } + + template, + __detail::__parsable<_CharT, _Traits, _StrT, minutes> _Parsable> + [[nodiscard]] + inline auto + parse(const basic_string<_CharT, _Traits, _Alloc>& __fmt, _Parsable& __tp, + basic_string<_CharT, _Traits, _Alloc>& __abbrev, minutes& __offset) + { + auto __pa = std::__addressof(__abbrev); + return __detail::_Parse<_Parsable, _CharT, _Traits, _Alloc>(__fmt.c_str(), + __tp, __pa, + &__offset); + } + + /// @cond undocumented + template + template + basic_istream<_CharT, _Traits>& + __detail::_Parser<_Duration>:: + operator()(basic_istream<_CharT, _Traits>& __is, const _CharT* __fmt, + basic_string<_CharT, _Traits, _Alloc>* __abbrev, + minutes* __offset) + { + using sentry = typename basic_istream<_CharT, _Traits>::sentry; + ios_base::iostate __err = ios_base::goodbit; + if (sentry __cerb(__is, true); __cerb) + { + locale __loc = __is.getloc(); + auto& __tmget = std::use_facet>(__loc); + auto& __tmpunct = std::use_facet>(__loc); + + // RAII type to save and restore stream state. + struct _Stream_state + { + explicit + _Stream_state(basic_istream<_CharT, _Traits>& __i) + : _M_is(__i), + _M_flags(__i.flags(ios_base::skipws | ios_base::dec)), + _M_w(__i.width(0)) + { } + + ~_Stream_state() + { + _M_is.flags(_M_flags); + _M_is.width(_M_w); + } + + _Stream_state(_Stream_state&&) = delete; + + basic_istream<_CharT, _Traits>& _M_is; + ios_base::fmtflags _M_flags; + streamsize _M_w; + }; + + auto __is_failed = [](ios_base::iostate __e) { + return static_cast(__e & ios_base::failbit); + }; + + // Read an unsigned integer from the stream and return it. + // Extract no more than __n digits. Set __err on error. + auto __read_unsigned = [&] (int __n) { + return _S_read_unsigned(__is, __err, __n); + }; + + // Read a signed integer from the stream and return it. + // Extract no more than __n digits. Set __err on error. + auto __read_signed = [&] (int __n) { + return _S_read_signed(__is, __err, __n); + }; + + // Read an expected character from the stream. + auto __read_chr = [&__is, &__err] (_CharT __c) { + return _S_read_chr(__is, __err, __c); + }; + + using __format::_ChronoParts; + _ChronoParts __parts{}; + + const year __bad_y = --year::min(); // SHRT_MIN + const month __bad_mon(255); + const day __bad_day(255); + const weekday __bad_wday(255); + const hours __bad_h(-1); + const minutes __bad_min(-9999); + const seconds __bad_sec(-1); + + year __y = __bad_y, __yy = __bad_y; // %Y, %yy + year __iso_y = __bad_y, __iso_yy = __bad_y; // %G, %g + month __m = __bad_mon; // %m + day __d = __bad_day; // %d + weekday __wday = __bad_wday; // %a %A %u %w + hours __h = __bad_h, __h12 = __bad_h; // %H, %I + minutes __min = __bad_min; // %M + _Duration __s = __bad_sec; // %S + int __ampm = 0; // %p + int __iso_wk = -1, __sunday_wk = -1, __monday_wk = -1; // %V, %U, %W + int __century = -1; // %C + int __dayofyear = -1; // %j (for non-duration) + + minutes __tz_offset = __bad_min; + basic_string<_CharT, _Traits> __tz_abbr; + + // bool __is_neg = false; // TODO: how is this handled for parsing? + + _CharT __mod{}; // One of 'E' or 'O' or nul. + unsigned __num = 0; // Non-zero for N modifier. + bool __is_flag = false; // True if we're processing a % flag. + + // If an out-of-range value is extracted (e.g. 61min for %M), + // do not set failbit immediately because we might not need it + // (e.g. parsing chrono::year doesn't care about invalid %M values). + // Instead set the variable back to its initial 'bad' state, + // and also set related variables corresponding to the same field + // (e.g. a bad %M value for __min should also reset __h and __s). + // If a valid value is needed later the bad value will cause failure. + + // For some fields we don't know the correct range when parsing and + // we have to be liberal in what we accept, e.g. we allow 366 for + // day-of-year because that's valid in leap years, and we allow 31 + // for day-of-month. If those values are needed to determine the + // result then we can do a correct range check at the end when we + // know the how many days the relevant year or month actually has. + + while (*__fmt) + { + _CharT __c = *__fmt++; + if (!__is_flag) + { + if (__c == '%') + __is_flag = true; // This is the start of a flag. + else if (std::isspace(__c, __loc)) + std::ws(__is); // Match zero or more whitespace characters. + else if (!__read_chr(__c)) [[unlikely]] + break; // Failed to match the expected character. + + continue; // Process next character in the format string. + } + + // Now processing a flag. + switch (__c) + { + case 'a': // Locale's weekday name + case 'A': // (full or abbreviated, matched case-insensitively). + if (__mod || __num) [[unlikely]] + __err = ios_base::failbit; + else + { + struct tm __tm{}; + __tmget.get(__is, {}, __is, __err, &__tm, + __fmt - 2, __fmt); + if (!__is_failed(__err)) + __wday = weekday(__tm.tm_wday); + } + __parts |= _ChronoParts::_Weekday; + break; + + case 'b': // Locale's month name + case 'h': // (full or abbreviated, matched case-insensitively). + case 'B': + if (__mod || __num) [[unlikely]] + __err = ios_base::failbit; + else + { + // strptime behaves differently for %b and %B, + // but chrono::parse says they're equivalent. + // Luckily libstdc++ std::time_get works as needed. + struct tm __tm{}; + __tmget.get(__is, {}, __is, __err, &__tm, + __fmt - 2, __fmt); + if (!__is_failed(__err)) + __m = month(__tm.tm_mon + 1); + } + __parts |= _ChronoParts::_Month; + break; + + case 'c': // Locale's date and time representation. + if (__mod == 'O' || __num) [[unlikely]] + __err |= ios_base::failbit; + else + { + struct tm __tm{}; + __tmget.get(__is, {}, __is, __err, &__tm, + __fmt - 2 - (__mod == 'E'), __fmt); + if (!__is_failed(__err)) + { + __y = year(__tm.tm_year + 1900); + __m = month(__tm.tm_mon + 1); + __d = day(__tm.tm_mday); + __h = hours(__tm.tm_hour); + __min = minutes(__tm.tm_min); + __s = duration_cast<_Duration>(seconds(__tm.tm_sec)); + } + } + __parts |= _ChronoParts::_DateTime; + break; + + case 'C': // Century + if (!__mod) [[likely]] + { + auto __v = __read_signed(__num ? __num : 2); + if (!__is_failed(__err)) + { + int __cmin = (int)year::min() / 100; + int __cmax = (int)year::max() / 100; + if (__cmin <= __v && __v <= __cmax) + __century = __v * 100; + else + __century = -2; // This prevents guessing century. + } + } + else if (__mod == 'E') + { + struct tm __tm{}; + __tmget.get(__is, {}, __is, __err, &__tm, + __fmt - 3, __fmt); + if (!__is_failed(__err)) + __century = __tm.tm_year; + } + else [[unlikely]] + __err |= ios_base::failbit; + // N.B. don't set this here: __parts |= _ChronoParts::_Year; + break; + + case 'd': // Day of month (1-31) + case 'e': + if (!__mod) [[likely]] + { + auto __v = __read_unsigned(__num ? __num : 2); + if (!__is_failed(__err)) + __d = day(__v); + } + else if (__mod == 'O') + { + struct tm __tm{}; + __tmget.get(__is, {}, __is, __err, &__tm, + __fmt - 3, __fmt); + if (!__is_failed(__err)) + __d = day(__tm.tm_mday); + } + else [[unlikely]] + __err |= ios_base::failbit; + __parts |= _ChronoParts::_Day; + break; + + case 'D': // %m/%d/%y + if (__mod || __num) [[unlikely]] + __err |= ios_base::failbit; + else + { + auto __month = __read_unsigned(2); // %m + __read_chr('/'); + auto __day = __read_unsigned(2); // %d + __read_chr('/'); + auto __year = __read_unsigned(2); // %y + if (__is_failed(__err)) + break; + __y = year(__year + 1900 + 100 * int(__year < 69)); + __m = month(__month); + __d = day(__day); + if (!year_month_day(__y, __m, __d).ok()) + { + __y = __yy = __iso_y = __iso_yy = __bad_y; + __m = __bad_mon; + __d = __bad_day; + break; + } + } + __parts |= _ChronoParts::_Date; + break; + + case 'F': // %Y-%m-%d - any N modifier only applies to %Y. + if (__mod) [[unlikely]] + __err |= ios_base::failbit; + else + { + auto __year = __read_signed(__num ? __num : 4); // %Y + __read_chr('-'); + auto __month = __read_unsigned(2); // %m + __read_chr('-'); + auto __day = __read_unsigned(2); // %d + if (__is_failed(__err)) + break; + __y = year(__year); + __m = month(__month); + __d = day(__day); + if (!year_month_day(__y, __m, __d).ok()) + { + __y = __yy = __iso_y = __iso_yy = __bad_y; + __m = __bad_mon; + __d = __bad_day; + break; + } + } + __parts |= _ChronoParts::_Date; + break; + + case 'g': // Last two digits of ISO week-based year. + if (__mod) [[unlikely]] + __err |= ios_base::failbit; + else + { + auto __val = __read_unsigned(__num ? __num : 2); + if (__val >= 0 && __val <= 99) + { + __iso_yy = year(__val); + if (__century == -1) // No %C has been parsed yet. + __century = 2000; + } + else + __iso_yy = __iso_y = __y = __yy = __bad_y; + } + __parts |= _ChronoParts::_Year; + break; + + case 'G': // ISO week-based year. + if (__mod) [[unlikely]] + __err |= ios_base::failbit; + else + __iso_y = year(__read_unsigned(__num ? __num : 4)); + __parts |= _ChronoParts::_Year; + break; + + case 'H': // 24-hour (00-23) + case 'I': // 12-hour (1-12) + if (__mod == 'E') [[unlikely]] + __err |= ios_base::failbit; + else if (__mod == 'O') + { +#if 0 + struct tm __tm{}; + __tm.tm_ampm = 1; + __tmget.get(__is, {}, __is, __err, &__tm, + __fmt - 3, __fmt); + if (!__is_failed(__err)) + { + if (__c == 'I') + { + __h12 = hours(__tm.tm_hour); + __h = __bad_h; + } + else + __h = hours(__tm.tm_hour); + } +#else + // XXX %OI seems to be unimplementable. + __err |= ios_base::failbit; +#endif + } + else + { + auto __val = __read_unsigned(__num ? __num : 2); + if (__c == 'I' && __val >= 1 && __val <= 12) + { + __h12 = hours(__val); + __h = __bad_h; + } + else if (__c == 'H' && __val >= 0 && __val <= 23) + { + __h = hours(__val); + __h12 = __bad_h; + } + else + { + if (_M_need & _ChronoParts::_TimeOfDay) + __err |= ios_base::failbit; + break; + } + } + __parts |= _ChronoParts::_TimeOfDay; + break; + + case 'j': // For duration, count of days, otherwise day of year + if (__mod) [[unlikely]] + __err |= ios_base::failbit; + else if (_M_need == _ChronoParts::_TimeOfDay) // duration + { + auto __val = __read_signed(__num ? __num : 3); + if (!__is_failed(__err)) + { + __h = days(__val); // __h will get added to _M_time + __parts |= _ChronoParts::_TimeOfDay; + } + } + else + { + __dayofyear = __read_unsigned(__num ? __num : 3); + // N.B. do not alter __parts here, done after loop. + // No need for range checking here either. + } + break; + + case 'm': // Month (1-12) + if (__mod == 'E') [[unlikely]] + __err |= ios_base::failbit; + else if (__mod == 'O') + { + struct tm __tm{}; + __tmget.get(__is, {}, __is, __err, &__tm, + __fmt - 2, __fmt); + if (!__is_failed(__err)) + __m = month(__tm.tm_mon + 1); + } + else + { + auto __val = __read_unsigned(__num ? __num : 2); + if (__val >= 1 && __val <= 12) + __m = month(__val); + else + __m = __bad_mon; + } + __parts |= _ChronoParts::_Month; + break; + + case 'M': // Minutes + if (__mod == 'E') [[unlikely]] + __err |= ios_base::failbit; + else if (__mod == 'O') + { + struct tm __tm{}; + __tmget.get(__is, {}, __is, __err, &__tm, + __fmt - 2, __fmt); + if (!__is_failed(__err)) + __min = minutes(__tm.tm_min); + } + else + { + auto __val = __read_unsigned(__num ? __num : 2); + if (0 <= __val && __val < 60) + __min = minutes(__val); + else + { + if (_M_need & _ChronoParts::_TimeOfDay) + __err |= ios_base::failbit; + break; + } + } + __parts |= _ChronoParts::_TimeOfDay; + break; + + case 'p': // Locale's AM/PM designation for 12-hour clock. + if (__mod || __num) + __err |= ios_base::failbit; + else + { + // Can't use std::time_get here as it can't parse %p + // in isolation without %I. This might be faster anyway. + const _CharT* __ampms[2]; + __tmpunct._M_am_pm(__ampms); + int __n = 0, __which = 3; + while (__which != 0) + { + auto __i = __is.peek(); + if (_Traits::eq_int_type(__i, _Traits::eof())) + { + __err |= ios_base::eofbit | ios_base::failbit; + break; + } + __i = std::toupper(_Traits::to_char_type(__i), __loc); + if (__which & 1) + { + if (__i != std::toupper(__ampms[0][__n], __loc)) + __which ^= 1; + else if (__ampms[0][__n + 1] == _CharT()) + { + __which = 1; + (void) __is.get(); + break; + } + } + if (__which & 2) + { + if (__i != std::toupper(__ampms[1][__n], __loc)) + __which ^= 2; + else if (__ampms[1][__n + 1] == _CharT()) + { + __which = 2; + (void) __is.get(); + break; + } + } + if (__which) + (void) __is.get(); + ++__n; + } + if (__which == 0 || __which == 3) + __err |= ios_base::failbit; + else + __ampm = __which; + } + break; + + case 'r': // Locale's 12-hour time. + if (__mod || __num) + __err |= ios_base::failbit; + else + { + struct tm __tm{}; + __tmget.get(__is, {}, __is, __err, &__tm, + __fmt - 2, __fmt); + if (!__is_failed(__err)) + { + __h = hours(__tm.tm_hour); + __min = minutes(__tm.tm_min); + __s = seconds(__tm.tm_sec); + } + } + __parts |= _ChronoParts::_TimeOfDay; + break; + + case 'R': // %H:%M + case 'T': // %H:%M:%S + if (__mod || __num) [[unlikely]] + { + __err |= ios_base::failbit; + break; + } + else + { + auto __val = __read_unsigned(2); + if (__val == -1 || __val > 23) [[unlikely]] + { + if (_M_need & _ChronoParts::_TimeOfDay) + __err |= ios_base::failbit; + break; + } + if (!__read_chr(':')) [[unlikely]] + break; + __h = hours(__val); + + __val = __read_unsigned(2); + if (__val == -1 || __val > 60) [[unlikely]] + { + if (_M_need & _ChronoParts::_TimeOfDay) + __err |= ios_base::failbit; + break; + } + __min = minutes(__val); + + if (__c == 'R') + { + __parts |= _ChronoParts::_TimeOfDay; + break; + } + else if (!__read_chr(':')) [[unlikely]] + break; + } + [[fallthrough]]; + + case 'S': // Seconds + if (__mod == 'E') [[unlikely]] + __err |= ios_base::failbit; + else if (__mod == 'O') + { + struct tm __tm{}; + __tmget.get(__is, {}, __is, __err, &__tm, + __fmt - 3, __fmt); + if (!__is_failed(__err)) + __s = seconds(__tm.tm_sec); + } + else if constexpr (ratio_equal_v>) + { + auto __val = __read_unsigned(__num ? __num : 2); + if (0 <= __val && __val <= 59) [[likely]] + __s = seconds(__val); + else + { + if (_M_need & _ChronoParts::_TimeOfDay) + __err |= ios_base::failbit; + break; + } + } + else + { + basic_stringstream<_CharT> __buf; + auto __digit = _S_try_read_digit(__is, __err); + if (__digit != -1) + { + __buf.put(_CharT('0') + __digit); + __digit = _S_try_read_digit(__is, __err); + if (__digit != -1) + __buf.put(_CharT('0') + __digit); + } + + auto __i = __is.peek(); + if (_Traits::eq_int_type(__i, _Traits::eof())) + __err |= ios_base::eofbit; + else + { + auto& __np = use_facet>(__loc); + auto __dp = __np.decimal_point(); + _CharT __c = _Traits::to_char_type(__i); + if (__c == __dp) + { + (void) __is.get(); + __buf.put(__c); + int __prec + = hh_mm_ss<_Duration>::fractional_width; + do + { + __digit = _S_try_read_digit(__is, __err); + if (__digit != -1) + __buf.put(_CharT('0') + __digit); + else + break; + } + while (--__prec); + } + } + + if (!__is_failed(__err)) + { + auto& __ng = use_facet>(__loc); + long double __val; + ios_base::iostate __err2{}; + __ng.get(__buf, {}, __buf, __err2, __val); + if (__is_failed(__err2)) [[unlikely]] + __err |= __err2; + else + { + duration __fs(__val); + __s = duration_cast<_Duration>(__fs); + } + } + } + __parts |= _ChronoParts::_TimeOfDay; + break; + + case 'u': // ISO weekday (1-7) + case 'w': // Weekday (0-6) + if (__mod == 'E') [[unlikely]] + __err |= ios_base::failbit; + else if (__mod == 'O') + { + if (__c == 'w') + { + struct tm __tm{}; + __tmget.get(__is, {}, __is, __err, &__tm, + __fmt - 3, __fmt); + if (!__is_failed(__err)) + __wday = weekday(__tm.tm_wday); + } + else + __err |= ios_base::failbit; + } + else + { + const int __lo = __c == 'u' ? 1 : 0; + const int __hi = __lo + 6; + auto __val = __read_unsigned(__num ? __num : 1); + if (__lo <= __val && __val <= __hi) + __wday = weekday(__val); + else + { + __wday = __bad_wday; + break; + } + } + __parts |= _ChronoParts::_Weekday; + break; + + case 'U': // Week number of the year (from first Sunday). + case 'V': // ISO week-based week number. + case 'W': // Week number of the year (from first Monday). + if (__mod == 'E') [[unlikely]] + __err |= ios_base::failbit; + else if (__mod == 'O') + { + if (__c == 'V') [[unlikely]] + __err |= ios_base::failbit; + else + { + // TODO nl_langinfo_l(ALT_DIGITS) ? + // Not implementable using std::time_get. + } + } + else + { + const int __lo = __c == 'V' ? 1 : 0; + const int __hi = 53; + auto __val = __read_unsigned(__num ? __num : 2); + if (__lo <= __val && __val <= __hi) + { + switch (__c) + { + case 'U': + __sunday_wk = __val; + break; + case 'V': + __iso_wk = __val; + break; + case 'W': + __monday_wk = __val; + break; + } + } + else + __iso_wk = __sunday_wk = __monday_wk = -1; + } + // N.B. do not alter __parts here, done after loop. + break; + + case 'x': // Locale's date representation. + if (__mod == 'O' || __num) [[unlikely]] + __err |= ios_base::failbit; + else + { + struct tm __tm{}; + __tmget.get(__is, {}, __is, __err, &__tm, + __fmt - 2 - (__mod == 'E'), __fmt); + if (!__is_failed(__err)) + { + __y = year(__tm.tm_year + 1900); + __m = month(__tm.tm_mon + 1); + __d = day(__tm.tm_mday); + } + } + __parts |= _ChronoParts::_Date; + break; + + case 'X': // Locale's time representation. + if (__mod == 'O' || __num) [[unlikely]] + __err |= ios_base::failbit; + else + { + struct tm __tm{}; + __tmget.get(__is, {}, __is, __err, &__tm, + __fmt - 2 - (__mod == 'E'), __fmt); + if (!__is_failed(__err)) + { + __h = hours(__tm.tm_hour); + __min = minutes(__tm.tm_min); + __s = duration_cast<_Duration>(seconds(__tm.tm_sec)); + } + } + __parts |= _ChronoParts::_TimeOfDay; + break; + + case 'y': // Last two digits of year. + if (__mod) [[unlikely]] + { + struct tm __tm{}; + __tmget.get(__is, {}, __is, __err, &__tm, + __fmt - 3, __fmt); + if (!__is_failed(__err)) + { + int __cent = __tm.tm_year < 2000 ? 1900 : 2000; + __yy = year(__tm.tm_year - __cent); + if (__century == -1) // No %C has been parsed yet. + __century = __cent; + } + } + else + { + auto __val = __read_unsigned(__num ? __num : 2); + if (__val >= 0 && __val <= 99) + { + __yy = year(__val); + if (__century == -1) // No %C has been parsed yet. + __century = __val < 69 ? 2000 : 1900; + } + else + __y = __yy = __iso_yy = __iso_y = __bad_y; + } + __parts |= _ChronoParts::_Year; + break; + + case 'Y': // Year + if (__mod == 'O') [[unlikely]] + __err |= ios_base::failbit; + else if (__mod == 'E') + { + struct tm __tm{}; + __tmget.get(__is, {}, __is, __err, &__tm, + __fmt - 3, __fmt); + if (!__is_failed(__err)) + __y = year(__tm.tm_year); + } + else + { + auto __val = __read_unsigned(__num ? __num : 4); + if (!__is_failed(__err)) + __y = year(__val); + } + __parts |= _ChronoParts::_Year; + break; + + case 'z': + if (__num) [[unlikely]] + __err |= ios_base::failbit; + else + { + // For %Ez and %Oz read [+|-][h]h[:mm]. + // For %z read [+|-]hh[mm]. + + auto __i = __is.peek(); + if (_Traits::eq_int_type(__i, _Traits::eof())) + { + __err |= ios_base::eofbit | ios_base::failbit; + break; + } + _CharT __ic = _Traits::to_char_type(__i); + const bool __neg = __ic == _CharT('-'); + if (__ic == _CharT('-') || __ic == _CharT('+')) + (void) __is.get(); + + int_least32_t __hh; + if (__mod) + { + // Read h[h] + __hh = __read_unsigned(2); + } + else + { + // Read hh + __hh = 10 * _S_try_read_digit(__is, __err); + __hh += _S_try_read_digit(__is, __err); + } + + if (__is_failed(__err)) + break; + + __i = __is.peek(); + if (_Traits::eq_int_type(__i, _Traits::eof())) + { + __err |= ios_base::eofbit; + __tz_offset = minutes(__hh * (__neg ? -60 : 60)); + break; + } + __ic = _Traits::to_char_type(__i); + + bool __read_mm = false; + if (__mod) + { + if (__ic == _GLIBCXX_WIDEN(":")[0]) + { + // Read [:mm] part. + (void) __is.get(); + __read_mm = true; + } + } + else if (_CharT('0') <= __ic && __ic <= _CharT('9')) + { + // Read [mm] part. + __read_mm = true; + } + + int_least32_t __mm = 0; + if (__read_mm) + { + __mm = 10 * _S_try_read_digit(__is, __err); + __mm += _S_try_read_digit(__is, __err); + } + + if (!__is_failed(__err)) + { + auto __z = __hh * 60 + __mm; + __tz_offset = minutes(__neg ? -__z : __z); + } + } + break; + + case 'Z': + if (__mod || __num) [[unlikely]] + __err |= ios_base::failbit; + else + { + basic_string_view<_CharT> __x = _GLIBCXX_WIDEN("_/-+"); + __tz_abbr.clear(); + while (true) + { + auto __i = __is.peek(); + if (!_Traits::eq_int_type(__i, _Traits::eof())) + { + _CharT __a = _Traits::to_char_type(__i); + if (std::isalnum(__a, __loc) + || __x.find(__a) != __x.npos) + { + __tz_abbr.push_back(__a); + (void) __is.get(); + continue; + } + } + else + __err |= ios_base::eofbit; + break; + } + if (__tz_abbr.empty()) + __err |= ios_base::failbit; + } + break; + + case 'n': // Exactly one whitespace character. + if (__mod || __num) [[unlikely]] + __err |= ios_base::failbit; + else + { + _CharT __i = __is.peek(); + if (_Traits::eq_int_type(__i, _Traits::eof())) + __err |= ios_base::eofbit | ios_base::failbit; + else if (std::isspace(_Traits::to_char_type(__i), __loc)) + (void) __is.get(); + else + __err |= ios_base::failbit; + } + break; + + case 't': // Zero or one whitespace characters. + if (__mod || __num) [[unlikely]] + __err |= ios_base::failbit; + else + { + _CharT __i = __is.peek(); + if (_Traits::eq_int_type(__i, _Traits::eof())) + __err |= ios_base::eofbit; + else if (std::isspace(_Traits::to_char_type(__i), __loc)) + (void) __is.get(); + } + break; + + case '%': // A % character. + if (__mod || __num) [[unlikely]] + __err |= ios_base::failbit; + else + __read_chr('%'); + break; + + case 'O': // Modifiers + case 'E': + if (__mod || __num) [[unlikely]] + { + __err |= ios_base::failbit; + break; + } + __mod = __c; + continue; + + default: + if (_CharT('1') <= __c && __c <= _CharT('9')) + { + if (!__mod) [[likely]] + { + // %Nx - extract positive decimal integer N + auto __end = __fmt + _Traits::length(__fmt); + auto [__v, __ptr] + = __format::__parse_integer(__fmt - 1, __end); + if (__ptr) [[likely]] + { + __num = __v; + __fmt = __ptr; + continue; + } + } + } + __err |= ios_base::failbit; + } + + if (__is_failed(__err)) [[unlikely]] + break; + + __is_flag = false; + __num = 0; + __mod = _CharT(); + } + + if (__century >= 0) + { + if (__yy != __bad_y && __y == __bad_y) + __y = years(__century) + __yy; // Use %y instead of %Y + if (__iso_yy != __bad_y && __iso_y == __bad_y) + __iso_y = years(__century) + __iso_yy; // Use %g instead of %G + } + + bool __can_use_doy = false; + bool __can_use_iso_wk = false; + bool __can_use_sun_wk = false; + bool __can_use_mon_wk = false; + + // A year + day-of-year can be converted to a full date. + if (__y != __bad_y && __dayofyear >= 0) + { + __can_use_doy = true; + __parts |= _ChronoParts::_Date; + } + else if (__y != __bad_y && __wday != __bad_wday && __sunday_wk >= 0) + { + __can_use_sun_wk = true; + __parts |= _ChronoParts::_Date; + } + else if (__y != __bad_y && __wday != __bad_wday && __monday_wk >= 0) + { + __can_use_mon_wk = true; + __parts |= _ChronoParts::_Date; + } + else if (__iso_y != __bad_y && __wday != __bad_wday && __iso_wk > 0) + { + // An ISO week date can be converted to a full date. + __can_use_iso_wk = true; + __parts |= _ChronoParts::_Date; + } + + if (__is_failed(__err)) [[unlikely]] + ; // Don't bother doing any more work. + else if (__is_flag) [[unlikely]] // incomplete format flag + __err |= ios_base::failbit; + else if ((_M_need & __parts) == _M_need) [[likely]] + { + // We try to avoid calculating _M_sys_days and _M_ymd unless + // necessary, because converting sys_days to year_month_day + // (or vice versa) requires non-trivial calculations. + // If we have y/m/d values then use them to populate _M_ymd + // and only convert it to _M_sys_days if the caller needs that. + // But if we don't have y/m/d and need to calculate the date + // from the day-of-year or a week+weekday then we set _M_sys_days + // and only convert it to _M_ymd if the caller needs that. + + // We do more error checking here, but only for the fields that + // we actually need to use. For example, we will not diagnose + // an invalid dayofyear==366 for non-leap years unless actually + // using __dayofyear. This should mean we never produce invalid + // results, but it means not all invalid inputs are diagnosed, + // e.g. "2023-01-01 366" >> "%F %j" ignores the invalid 366. + // We also do not diagnose inconsistent values for the same + // field, e.g. "2021 2022 2023" >> "%C%y %Y %Y" just uses 2023. + + // Whether the caller wants _M_wd. + // The _Weekday bit is only set for chrono::weekday. + const bool __need_wday = _M_need & _ChronoParts::_Weekday; + + // Whether the caller wants _M_sys_days and _M_time. + // Only true for time_points. + const bool __need_time = _M_need & _ChronoParts::_TimeOfDay; + + if (__need_wday && __wday != __bad_wday) + _M_wd = __wday; // Caller only wants a weekday and we have one. + else if (_M_need & _ChronoParts::_Date) // subsumes __need_wday + { + // Whether the caller wants _M_ymd. + // True for chrono::year etc., false for time_points. + const bool __need_ymd = !__need_wday && !__need_time; + + if ((_M_need & _ChronoParts::_Year && __y == __bad_y) + || (_M_need & _ChronoParts::_Month && __m == __bad_mon) + || (_M_need & _ChronoParts::_Day && __d == __bad_day)) + { + // Missing at least one of y/m/d so calculate sys_days + // from the other data we have available. + + if (__can_use_doy) + { + if ((0 < __dayofyear && __dayofyear <= 365) + || (__dayofyear == 366 && __y.is_leap())) + [[likely]] + { + _M_sys_days = sys_days(__y/January/1) + + days(__dayofyear - 1); + if (__need_ymd) + _M_ymd = year_month_day(_M_sys_days); + } + else + __err |= ios_base::failbit; + } + else if (__can_use_iso_wk) + { + // Calculate y/m/d from ISO week date. + + if (__iso_wk == 53) + { + // A year has 53 weeks iff Jan 1st is a Thursday + // or Jan 1 is a Wednesday and it's a leap year. + const sys_days __jan4(__iso_y/January/4); + weekday __wd1(__jan4 - days(3)); + if (__wd1 != Thursday) + if (__wd1 != Wednesday || !__iso_y.is_leap()) + __err |= ios_base::failbit; + } + + if (!__is_failed(__err)) [[likely]] + { + // First Thursday is always in week one: + sys_days __w(Thursday[1]/January/__iso_y); + // First day of week-based year: + __w -= Thursday - Monday; + __w += days(weeks(__iso_wk - 1)); + __w += __wday - Monday; + _M_sys_days = __w; + + if (__need_ymd) + _M_ymd = year_month_day(_M_sys_days); + } + } + else if (__can_use_sun_wk) + { + // Calculate y/m/d from week number + weekday. + sys_days __wk1(__y/January/Sunday[1]); + _M_sys_days = __wk1 + weeks(__sunday_wk - 1) + + days(__wday.c_encoding()); + _M_ymd = year_month_day(_M_sys_days); + if (_M_ymd.year() != __y) [[unlikely]] + __err |= ios_base::failbit; + } + else if (__can_use_mon_wk) + { + // Calculate y/m/d from week number + weekday. + sys_days __wk1(__y/January/Monday[1]); + _M_sys_days = __wk1 + weeks(__monday_wk - 1) + + days(__wday.c_encoding() - 1); + _M_ymd = year_month_day(_M_sys_days); + if (_M_ymd.year() != __y) [[unlikely]] + __err |= ios_base::failbit; + } + else // Should not be able to get here. + __err |= ios_base::failbit; + } + else + { + // We know that all fields the caller needs are present, + // but check that their values are in range. + // Make unwanted fields valid so that _M_ymd.ok() is true. + + if (_M_need & _ChronoParts::_Year) + { + if (!__y.ok()) [[unlikely]] + __err |= ios_base::failbit; + } + else if (__y == __bad_y) + __y = 1972y; // Leap year so that Feb 29 is valid. + + if (_M_need & _ChronoParts::_Month) + { + if (!__m.ok()) [[unlikely]] + __err |= ios_base::failbit; + } + else if (__m == __bad_mon) + __m = January; + + if (_M_need & _ChronoParts::_Day) + { + if (__d < day(1) || __d > (__y/__m/last).day()) + __err |= ios_base::failbit; + } + else if (__d == __bad_day) + __d = 1d; + + if (year_month_day __ymd(__y, __m, __d); __ymd.ok()) + { + _M_ymd = __ymd; + if (__need_wday || __need_time) + _M_sys_days = sys_days(_M_ymd); + } + else [[unlikely]] + __err |= ios_base::failbit; + } + + if (__need_wday) + _M_wd = weekday(_M_sys_days); + } + + // Need to set _M_time for both durations and time_points. + if (__need_time) + { + if (__h == __bad_h && __h12 != __bad_h) + { + if (__ampm == 1) + __h = __h12 == hours(12) ? hours(0) : __h12; + else if (__ampm == 2) + __h = __h12 == hours(12) ? __h12 : __h12 + hours(12); + else [[unlikely]] + __err |= ios_base::failbit; + } + + auto __t = _M_time.zero(); + bool __ok = false; + + if (__h != __bad_h) + { + __ok = true; + __t += __h; + } + + if (__min != __bad_min) + { + __ok = true; + __t += __min; + } + + if (__s != __bad_sec) + { + __ok = true; + __t += __s; + } + + if (__ok) + _M_time = __t; + else + __err |= ios_base::failbit; + } + + if (!__is_failed(__err)) [[likely]] + { + if (__offset && __tz_offset != __bad_min) + *__offset = __tz_offset; + if (__abbrev && !__tz_abbr.empty()) + *__abbrev = std::move(__tz_abbr); + } + } + else + __err |= ios_base::failbit; + } + if (__err) + __is.setstate(__err); + return __is; + } + /// @endcond #undef _GLIBCXX_WIDEN /// @} group chrono diff --git a/libstdc++-v3/include/bits/cow_string.h b/libstdc++-v3/include/bits/cow_string.h index e5f094fd13eb..5411dfe32a9f 100644 --- a/libstdc++-v3/include/bits/cow_string.h +++ b/libstdc++-v3/include/bits/cow_string.h @@ -36,13 +36,8 @@ #include // _Atomic_word, __is_single_threaded -#ifdef __cpp_lib_is_constant_evaluated -// Support P1032R1 in C++20 (but not P0980R1 for COW strings). -# define __cpp_lib_constexpr_string 201811L -#elif __cplusplus >= 201703L && _GLIBCXX_HAVE_IS_CONSTANT_EVALUATED -// Support P0426R1 changes to char_traits in C++17. -# define __cpp_lib_constexpr_string 201611L -#endif +#define __glibcxx_want_constexpr_string +#include namespace std _GLIBCXX_VISIBILITY(default) { @@ -970,6 +965,48 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION #pragma GCC diagnostic pop #endif +#ifdef __cpp_lib_string_resize_and_overwrite // C++ >= 23 + /** Resize the string and call a function to fill it. + * + * @param __n The maximum size requested. + * @param __op A callable object that writes characters to the string. + * + * This is a low-level function that is easy to misuse, be careful. + * + * Calling `str.resize_and_overwrite(n, op)` will reserve at least `n` + * characters in `str`, evaluate `n2 = std::move(op)(str.data(), n)`, + * and finally set the string length to `n2` (adding a null terminator + * at the end). The function object `op` is allowed to write to the + * extra capacity added by the initial reserve operation, which is not + * allowed if you just call `str.reserve(n)` yourself. + * + * This can be used to efficiently fill a `string` buffer without the + * overhead of zero-initializing characters that will be overwritten + * anyway. + * + * The callable `op` must not access the string directly (only through + * the pointer passed as its first argument), must not write more than + * `n` characters to the string, must return a value no greater than `n`, + * and must ensure that all characters up to the returned length are + * valid after it returns (i.e. there must be no uninitialized values + * left in the string after the call, because accessing them would + * have undefined behaviour). If `op` exits by throwing an exception + * the behaviour is undefined. + * + * @since C++23 + */ + template + void + resize_and_overwrite(size_type __n, _Operation __op); +#endif // __cpp_lib_string_resize_and_overwrite + +#if __cplusplus >= 201103L + /// Non-standard version of resize_and_overwrite for C++11 and above. + template + void + __resize_and_overwrite(size_type __n, _Operation __op); +#endif + /** * Returns the total number of characters that the %string can hold * before needing to allocate more memory. @@ -3716,6 +3753,54 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION // 21.3.5.7 par 3: do not append null. (good.) return __n; } + +#ifdef __cpp_lib_string_resize_and_overwrite // C++ >= 23 + template + template + [[__gnu__::__always_inline__]] + void + basic_string<_CharT, _Traits, _Alloc>:: + __resize_and_overwrite(const size_type __n, _Operation __op) + { resize_and_overwrite<_Operation&>(__n, __op); } +#endif + +#if __cplusplus >= 201103L + template + template + void + basic_string<_CharT, _Traits, _Alloc>:: +#ifdef __cpp_lib_string_resize_and_overwrite // C++ >= 23 + resize_and_overwrite(const size_type __n, _Operation __op) +#else + __resize_and_overwrite(const size_type __n, _Operation __op) +#endif + { + const size_type __capacity = capacity(); + _CharT* __p; + if (__n > __capacity || _M_rep()->_M_is_shared()) + this->reserve(__n); + __p = _M_data(); + struct _Terminator { + ~_Terminator() { _M_this->_M_rep()->_M_set_length_and_sharable(_M_r); } + basic_string* _M_this; + size_type _M_r; + }; + _Terminator __term{this, 0}; + auto __r = std::move(__op)(__p + 0, __n + 0); +#ifdef __cpp_lib_concepts + static_assert(ranges::__detail::__is_integer_like); +#else + static_assert(__gnu_cxx::__is_integer_nonstrict::__value, + "resize_and_overwrite operation must return an integer"); +#endif + _GLIBCXX_DEBUG_ASSERT(__r >= 0 && __r <= __n); + __term._M_r = size_type(__r); + if (__term._M_r > __n) + __builtin_unreachable(); + } +#endif // C++11 + + _GLIBCXX_END_NAMESPACE_VERSION } // namespace std #endif // ! _GLIBCXX_USE_CXX11_ABI diff --git a/libstdc++-v3/include/bits/erase_if.h b/libstdc++-v3/include/bits/erase_if.h index bb1b53dd4f60..4ff81e0f98f3 100644 --- a/libstdc++-v3/include/bits/erase_if.h +++ b/libstdc++-v3/include/bits/erase_if.h @@ -32,18 +32,16 @@ #pragma GCC system_header -#if __cplusplus >= 201402L - #include +#define __glibcxx_want_erase_if +#include + +#if __cplusplus >= 201402L namespace std { _GLIBCXX_BEGIN_NAMESPACE_VERSION -#if __cplusplus > 201703L -# define __cpp_lib_erase_if 202002L -#endif - namespace __detail { template #include +#define __glibcxx_want_list_remove_return_type +#include + namespace std _GLIBCXX_VISIBILITY(default) { _GLIBCXX_BEGIN_NAMESPACE_VERSION @@ -1180,8 +1183,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER /// @} private: -#if __cplusplus > 201703L -# define __cpp_lib_list_remove_return_type 201806L +#ifdef __cpp_lib_list_remove_return_type // C++20 && HOSTED using __remove_return_type = size_type; # define _GLIBCXX_FWDLIST_REMOVE_RETURN_TYPE_TAG \ __attribute__((__abi_tag__("__cxx20"))) diff --git a/libstdc++-v3/include/bits/hashtable.h b/libstdc++-v3/include/bits/hashtable.h index 954a1c7a58da..4c12dc895b2a 100644 --- a/libstdc++-v3/include/bits/hashtable.h +++ b/libstdc++-v3/include/bits/hashtable.h @@ -39,6 +39,9 @@ # include #endif +#define __glibcxx_want_generic_unordered_lookup +#include + namespace std _GLIBCXX_VISIBILITY(default) { _GLIBCXX_BEGIN_NAMESPACE_VERSION @@ -756,9 +759,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION std::pair equal_range(const key_type& __k) const; -#if __cplusplus >= 202002L -#define __cpp_lib_generic_unordered_lookup 201811L - +#ifdef __cpp_lib_generic_unordered_lookup // C++ >= 20 && HOSTED template, typename = __has_is_transparent_t<_Equal, _Kt>> @@ -788,7 +789,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION typename = __has_is_transparent_t<_Equal, _Kt>> pair _M_equal_range_tr(const _Kt& __k) const; -#endif // C++20 +#endif // __cpp_lib_generic_unordered_lookup private: // Bucket index computation helpers. diff --git a/libstdc++-v3/include/bits/ios_base.h b/libstdc++-v3/include/bits/ios_base.h index addfd054e769..3253eaaa2335 100644 --- a/libstdc++-v3/include/bits/ios_base.h +++ b/libstdc++-v3/include/bits/ios_base.h @@ -46,6 +46,9 @@ # include #endif +#define __glibcxx_want_ios_noreplace +#include + namespace std _GLIBCXX_VISIBILITY(default) { _GLIBCXX_BEGIN_NAMESPACE_VERSION @@ -473,8 +476,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION static const openmode __noreplace = _S_noreplace; -#if __cplusplus >= 202100L -#define __cpp_lib_ios_noreplace 202207L +#ifdef __cpp_lib_ios_noreplace // C++ >= 23 && HOSTED /// Open a file in exclusive mode. static const openmode noreplace = _S_noreplace; #endif diff --git a/libstdc++-v3/include/bits/list.tcc b/libstdc++-v3/include/bits/list.tcc index 3e5b1f7b972c..344386aa4d0e 100644 --- a/libstdc++-v3/include/bits/list.tcc +++ b/libstdc++-v3/include/bits/list.tcc @@ -654,7 +654,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER { // Move all nodes back into *this. __carry._M_put_all(end()._M_node); - for (int __i = 0; __i < sizeof(__tmp)/sizeof(__tmp[0]); ++__i) + for (size_t __i = 0; __i < sizeof(__tmp)/sizeof(__tmp[0]); ++__i) __tmp[__i]._M_put_all(end()._M_node); __throw_exception_again; } diff --git a/libstdc++-v3/include/bits/move.h b/libstdc++-v3/include/bits/move.h index 4a8fceff96ac..00997d6f1fb6 100644 --- a/libstdc++-v3/include/bits/move.h +++ b/libstdc++-v3/include/bits/move.h @@ -37,6 +37,9 @@ # include // Brings in std::declval too. #endif +#define __glibcxx_want_addressof_constexpr +#include + namespace std _GLIBCXX_VISIBILITY(default) { _GLIBCXX_BEGIN_NAMESPACE_VERSION @@ -120,11 +123,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION // declval, from type_traits. -#if __cplusplus > 201402L - // _GLIBCXX_RESOLVE_LIB_DEFECTS - // 2296. std::addressof should be constexpr -# define __cpp_lib_addressof_constexpr 201603L -#endif /** * @brief Returns the actual address of the object or function * referenced by r, even in the presence of an overloaded diff --git a/libstdc++-v3/include/bits/move_only_function.h b/libstdc++-v3/include/bits/move_only_function.h index 71d520749788..0aa5980324a7 100644 --- a/libstdc++-v3/include/bits/move_only_function.h +++ b/libstdc++-v3/include/bits/move_only_function.h @@ -32,7 +32,10 @@ #pragma GCC system_header -#if __cplusplus > 202002L +#define __glibcxx_want_move_only_function +#include + +#ifdef __cpp_lib_move_only_function // C++ >= 23 && HOSTED #include #include @@ -41,8 +44,6 @@ namespace std _GLIBCXX_VISIBILITY(default) { _GLIBCXX_BEGIN_NAMESPACE_VERSION -#define __cpp_lib_move_only_function 202110L - template class move_only_function; // not defined @@ -212,5 +213,5 @@ _GLIBCXX_END_NAMESPACE_VERSION #define _GLIBCXX_MOF_REF && #include "mofunc_impl.h" -#endif // C++23 +#endif // __cpp_lib_move_only_function #endif // _GLIBCXX_MOVE_ONLY_FUNCTION_H diff --git a/libstdc++-v3/include/bits/new_allocator.h b/libstdc++-v3/include/bits/new_allocator.h index 0a0b12eb5041..357700292edc 100644 --- a/libstdc++-v3/include/bits/new_allocator.h +++ b/libstdc++-v3/include/bits/new_allocator.h @@ -96,6 +96,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _GLIBCXX20_CONSTEXPR __new_allocator(const __new_allocator<_Tp1>&) _GLIBCXX_USE_NOEXCEPT { } +#if __cplusplus >= 201103L + __new_allocator& operator=(const __new_allocator&) = default; +#endif + #if __cplusplus <= 201703L ~__new_allocator() _GLIBCXX_USE_NOEXCEPT { } diff --git a/libstdc++-v3/include/bits/node_handle.h b/libstdc++-v3/include/bits/node_handle.h index 8904a5ac4963..16471355c19b 100644 --- a/libstdc++-v3/include/bits/node_handle.h +++ b/libstdc++-v3/include/bits/node_handle.h @@ -33,8 +33,10 @@ #pragma GCC system_header -#if __cplusplus >= 201703L -# define __cpp_lib_node_extract 201606L +#define __glibcxx_want_node_extract +#include + +#ifdef __cpp_lib_node_extract // C++ >= 17 && HOSTED #include #include @@ -390,5 +392,5 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _GLIBCXX_END_NAMESPACE_VERSION } // namespace std -#endif // C++17 +#endif // __cpp_lib_node_extract #endif diff --git a/libstdc++-v3/include/bits/ptr_traits.h b/libstdc++-v3/include/bits/ptr_traits.h index 8a919ec10909..9e2f4f3f2163 100644 --- a/libstdc++-v3/include/bits/ptr_traits.h +++ b/libstdc++-v3/include/bits/ptr_traits.h @@ -34,12 +34,9 @@ #include -/* Duplicate definition with unique_ptr.h. */ -#if __cplusplus > 202002L && defined(__cpp_constexpr_dynamic_alloc) -# define __cpp_lib_constexpr_memory 202202L -#elif __cplusplus > 201703L -# define __cpp_lib_constexpr_memory 201811L -#endif +#define __glibcxx_want_constexpr_memory +#define __glibcxx_want_to_address +#include #if __cplusplus > 201703L #include @@ -215,7 +212,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION return __ptr; } -#if __cplusplus <= 201703L +#ifndef __cpp_lib_to_address // C++ < 20 template constexpr typename std::pointer_traits<_Ptr>::element_type* __to_address(const _Ptr& __ptr) @@ -237,8 +234,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION return std::__to_address(__ptr.operator->()); } -#define __cpp_lib_to_address 201711L - /** * @brief Obtain address referenced by a pointer to an object * @param __ptr A pointer to an object @@ -261,7 +256,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION constexpr auto to_address(const _Ptr& __ptr) noexcept { return std::__to_address(__ptr); } -#endif // C++2a +#endif // __cpp_lib_to_address _GLIBCXX_END_NAMESPACE_VERSION } // namespace std diff --git a/libstdc++-v3/include/bits/range_access.h b/libstdc++-v3/include/bits/range_access.h index b7169c616f9a..9751b8e88d57 100644 --- a/libstdc++-v3/include/bits/range_access.h +++ b/libstdc++-v3/include/bits/range_access.h @@ -32,6 +32,10 @@ #pragma GCC system_header +#define __glibcxx_want_nonmember_container_access +#define __glibcxx_want_ssize +#include + #if __cplusplus >= 201103L #include #include // common_type_t, make_signed_t @@ -251,9 +255,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION #endif // C++14 -#if __cplusplus >= 201703L -#define __cpp_lib_nonmember_container_access 201411L - +#ifdef __cpp_lib_nonmember_container_access // C++ >= 17 /** * @brief Return the size of a container. * @param __cont Container. @@ -345,9 +347,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION constexpr const _Tp* data(initializer_list<_Tp> __il) noexcept { return __il.begin(); } +#endif // __cpp_lib_nonmember_container_access -#if __cplusplus > 201703L -#define __cpp_lib_ssize 201902L +#ifdef __cpp_lib_ssize // C++ >= 20 template [[nodiscard, __gnu__::__always_inline__]] constexpr auto @@ -364,9 +366,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION constexpr ptrdiff_t ssize(const _Tp (&)[_Num]) noexcept { return _Num; } -#endif // C++20 - -#endif // C++17 +#endif // __cpp_lib_ssize _GLIBCXX_END_NAMESPACE_VERSION } // namespace diff --git a/libstdc++-v3/include/bits/ranges_algo.h b/libstdc++-v3/include/bits/ranges_algo.h index da66ff8045d9..a06794c02c9d 100644 --- a/libstdc++-v3/include/bits/ranges_algo.h +++ b/libstdc++-v3/include/bits/ranges_algo.h @@ -39,6 +39,13 @@ #include #include // concept uniform_random_bit_generator +#define __glibcxx_want_ranges_contains +#define __glibcxx_want_ranges_find_last +#define __glibcxx_want_ranges_fold +#define __glibcxx_want_ranges_iota +#define __glibcxx_want_shift +#include + #if __cpp_lib_concepts namespace std _GLIBCXX_VISIBILITY(default) { @@ -3465,10 +3472,7 @@ namespace ranges inline constexpr __prev_permutation_fn prev_permutation{}; -#if __cplusplus > 202002L - -#define __cpp_lib_ranges_contains 202207L - +#if __cpp_lib_ranges_contains >= 202207L // C++ >= 23 struct __contains_fn { template _Sent, @@ -3522,7 +3526,9 @@ namespace ranges inline constexpr __contains_subrange_fn contains_subrange{}; -#define __cpp_lib_ranges_iota 202202L +#endif // __cpp_lib_ranges_contains + +#if __cpp_lib_ranges_iota >= 202202L // C++ >= 23 template struct out_value_result @@ -3572,7 +3578,9 @@ namespace ranges inline constexpr __iota_fn iota{}; -#define __cpp_lib_ranges_find_last 202207L +#endif // __cpp_lib_ranges_iota + +#if __cpp_lib_ranges_find_last >= 202207L // C++ >= 23 struct __find_last_fn { @@ -3700,7 +3708,9 @@ namespace ranges inline constexpr __find_last_if_not_fn find_last_if_not{}; -#define __cpp_lib_ranges_fold 202207L +#endif // __cpp_lib_ranges_find_last + +#if __cpp_lib_ranges_fold >= 202207L // C++ >= 23 template struct in_value_result @@ -3947,10 +3957,9 @@ namespace ranges }; inline constexpr __fold_right_last_fn fold_right_last{}; -#endif // C++23 +#endif // __cpp_lib_ranges_fold } // namespace ranges -#define __cpp_lib_shift 201806L template constexpr _ForwardIterator shift_left(_ForwardIterator __first, _ForwardIterator __last, diff --git a/libstdc++-v3/include/bits/ranges_cmp.h b/libstdc++-v3/include/bits/ranges_cmp.h index 6710d829a379..96fa79667e6f 100644 --- a/libstdc++-v3/include/bits/ranges_cmp.h +++ b/libstdc++-v3/include/bits/ranges_cmp.h @@ -30,6 +30,9 @@ #ifndef _RANGES_CMP_H #define _RANGES_CMP_H 1 +#define __glibcxx_want_ranges +#include + #if __cplusplus > 201703L # include # include @@ -55,14 +58,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION using is_transparent = __is_transparent; }; -#ifdef __cpp_lib_concepts -// Define this here, included by all the headers that need to define it. -#if __cplusplus > 202002L -#define __cpp_lib_ranges 202202L -#else -#define __cpp_lib_ranges 202110L -#endif - +#ifdef __cpp_lib_ranges // C++ >= 20 namespace ranges { namespace __detail @@ -179,7 +175,7 @@ namespace ranges }; } // namespace ranges -#endif // library concepts +#endif // __cpp_lib_ranges _GLIBCXX_END_NAMESPACE_VERSION } // namespace std #endif // C++20 diff --git a/libstdc++-v3/include/bits/regex.h b/libstdc++-v3/include/bits/regex.h index 26ac6a21c31d..2d3068687213 100644 --- a/libstdc++-v3/include/bits/regex.h +++ b/libstdc++-v3/include/bits/regex.h @@ -2740,6 +2740,9 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 typedef const value_type* pointer; typedef const value_type& reference; typedef std::forward_iterator_tag iterator_category; +#if __cplusplus > 201703L + typedef std::input_iterator_tag iterator_concept; +#endif /** * @brief Provides a singular iterator, useful for indicating @@ -2869,6 +2872,9 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 typedef const value_type* pointer; typedef const value_type& reference; typedef std::forward_iterator_tag iterator_category; +#if __cplusplus > 201703L + typedef std::input_iterator_tag iterator_concept; +#endif public: /** diff --git a/libstdc++-v3/include/bits/regex_executor.tcc b/libstdc++-v3/include/bits/regex_executor.tcc index 38fbe3dc854d..9643a3575d7c 100644 --- a/libstdc++-v3/include/bits/regex_executor.tcc +++ b/libstdc++-v3/include/bits/regex_executor.tcc @@ -339,7 +339,7 @@ namespace __detail template struct _Backref_matcher { - _Backref_matcher(bool __icase, const _TraitsT& __traits) + _Backref_matcher(bool /* __icase */, const _TraitsT& __traits) : _M_traits(__traits) { } bool diff --git a/libstdc++-v3/include/bits/shared_ptr.h b/libstdc++-v3/include/bits/shared_ptr.h index 2c24eada9507..9b5ee571c3e0 100644 --- a/libstdc++-v3/include/bits/shared_ptr.h +++ b/libstdc++-v3/include/bits/shared_ptr.h @@ -52,6 +52,10 @@ #include // std::basic_ostream #include +#define __glibcxx_want_shared_ptr_weak_type +#define __glibcxx_want_enable_shared_from_this +#include + namespace std _GLIBCXX_VISIBILITY(default) { _GLIBCXX_BEGIN_NAMESPACE_VERSION @@ -189,8 +193,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION /// The type pointed to by the stored pointer, remove_extent_t<_Tp> using element_type = typename __shared_ptr<_Tp>::element_type; -#if __cplusplus >= 201703L -# define __cpp_lib_shared_ptr_weak_type 201606L +#ifdef __cpp_lib_shared_ptr_weak_type // C++ >= 17 && HOSTED /// The corresponding weak_ptr type for this shared_ptr /// @since C++17 using weak_type = weak_ptr<_Tp>; @@ -938,8 +941,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION shared_from_this() const { return shared_ptr(this->_M_weak_this); } -#if __cplusplus > 201402L || !defined(__STRICT_ANSI__) // c++1z or gnu++11 -#define __cpp_lib_enable_shared_from_this 201603L +#ifdef __cpp_lib_enable_shared_from_this // C++ >= 17 && HOSTED /** @{ * Get a `weak_ptr` referring to the object that has `*this` as its base. * @since C++17 diff --git a/libstdc++-v3/include/bits/shared_ptr_atomic.h b/libstdc++-v3/include/bits/shared_ptr_atomic.h index 2295b48e7326..ae2d1b7a094c 100644 --- a/libstdc++-v3/include/bits/shared_ptr_atomic.h +++ b/libstdc++-v3/include/bits/shared_ptr_atomic.h @@ -32,6 +32,9 @@ #include +#define __glibcxx_want_atomic_shared_ptr +#include + // Annotations for the custom locking in atomic>. #if defined _GLIBCXX_TSAN && __has_include() #include @@ -99,7 +102,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION */ template inline bool - atomic_is_lock_free(const __shared_ptr<_Tp, _Lp>* __p) + atomic_is_lock_free(const __shared_ptr<_Tp, _Lp>*) { #ifdef __GTHREADS return __gthread_active_p() == 0; @@ -355,10 +358,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION /// @} group pointer_abstractions -#if __cplusplus >= 202002L -# define __cpp_lib_atomic_shared_ptr 201711L +#ifdef __cpp_lib_atomic_shared_ptr // C++ >= 20 && HOSTED template - class atomic; + struct atomic; /** * @addtogroup pointer_abstractions @@ -376,7 +378,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { using value_type = _Tp; - friend class atomic<_Tp>; + friend struct atomic<_Tp>; // An atomic version of __shared_count<> and __weak_count<>. // Stores a _Sp_counted_base<>* but uses the LSB as a lock. @@ -610,7 +612,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION }; template - class atomic> + struct atomic> { public: using value_type = shared_ptr<_Tp>; @@ -733,7 +735,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION }; template - class atomic> + struct atomic> { public: using value_type = weak_ptr<_Tp>; diff --git a/libstdc++-v3/include/bits/shared_ptr_base.h b/libstdc++-v3/include/bits/shared_ptr_base.h index 2c948d5b8384..33282e596b20 100644 --- a/libstdc++-v3/include/bits/shared_ptr_base.h +++ b/libstdc++-v3/include/bits/shared_ptr_base.h @@ -67,6 +67,10 @@ # include #endif +#define __glibcxx_want_smart_ptr_for_overwrite +#define __glibcxx_want_shared_ptr_arrays +#include + namespace std _GLIBCXX_VISIBILITY(default) { _GLIBCXX_BEGIN_NAMESPACE_VERSION @@ -652,8 +656,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _Impl _M_impl; }; -#if __cplusplus >= 202002L -# define __cpp_lib_smart_ptr_for_overwrite 202002L +#ifdef __cpp_lib_smart_ptr_for_overwrite // C++ >= 20 && HOSTED struct _Sp_overwrite_tag { }; // Partial specialization used for make_shared_for_overwrite(). @@ -712,13 +715,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _M_get_deleter(const std::type_info&) noexcept override { return nullptr; } }; -#endif // C++20 - -#if __cplusplus <= 201703L -# define __cpp_lib_shared_ptr_arrays 201611L -#else -# define __cpp_lib_shared_ptr_arrays 201707L +#endif // __cpp_lib_smart_ptr_for_overwrite +#if __cpp_lib_shared_ptr_arrays >= 201707L // C++ >= 20 && HOSTED struct _Sp_overwrite_tag; // For make_shared, make_shared, allocate_shared etc. @@ -880,7 +879,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _M_get_deleter(const std::type_info&) noexcept override { return nullptr; } }; -#endif // C++20 +#endif // __cpp_lib_shared_ptr_arrays >= 201707L // The default deleter for shared_ptr and shared_ptr. struct __sp_array_delete @@ -899,7 +898,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template struct __not_alloc_shared_tag<_Sp_alloc_shared_tag<_Tp>> { }; -#if __cpp_lib_shared_ptr_arrays >= 201707L +#if __cpp_lib_shared_ptr_arrays >= 201707L // C++ >= 20 && HOSTED template struct __not_alloc_shared_tag<_Sp_counted_array_base<_Alloc>> { }; #endif @@ -975,7 +974,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION __p = __pi->_M_ptr(); } -#if __cpp_lib_shared_ptr_arrays >= 201707L +#if __cpp_lib_shared_ptr_arrays >= 201707L // C++ >= 20 && HOSTED template __shared_count(_Tp*& __p, const _Sp_counted_array_base<_Alloc>& __a, _Init __init) @@ -1717,7 +1716,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION friend __shared_ptr<_Tp1, _Lp1> __allocate_shared(const _Alloc& __a, _Args&&... __args); -#if __cpp_lib_shared_ptr_arrays >= 201707L +#if __cpp_lib_shared_ptr_arrays >= 201707L // C++ >= 20 && HOSTED // This constructor is non-standard, it is used by allocate_shared. template*> __shared_ptr(const _Sp_counted_array_base<_Alloc>& __a, diff --git a/libstdc++-v3/include/bits/specfun.h b/libstdc++-v3/include/bits/specfun.h index afb13857036f..fdaaaf4576b6 100644 --- a/libstdc++-v3/include/bits/specfun.h +++ b/libstdc++-v3/include/bits/specfun.h @@ -32,9 +32,9 @@ #include -#define __STDCPP_MATH_SPEC_FUNCS__ 201003L - -#define __cpp_lib_math_special_functions 201603L +#define __glibcxx_want_math_spec_funcs +#define __glibcxx_want_math_special_functions +#include #if __cplusplus <= 201403L && __STDCPP_WANT_MATH_SPEC_FUNCS__ == 0 # error include and define __STDCPP_WANT_MATH_SPEC_FUNCS__ diff --git a/libstdc++-v3/include/bits/stl_algo.h b/libstdc++-v3/include/bits/stl_algo.h index 3abf0f69d468..637d53d6b951 100644 --- a/libstdc++-v3/include/bits/stl_algo.h +++ b/libstdc++-v3/include/bits/stl_algo.h @@ -72,6 +72,10 @@ # endif #endif +#define __glibcxx_want_clamp +#define __glibcxx_want_sample +#include + // See concept_check.h for the __glibcxx_*_requires macros. namespace std _GLIBCXX_VISIBILITY(default) @@ -3598,11 +3602,9 @@ _GLIBCXX_END_INLINE_ABI_NAMESPACE(_V2) return std::__is_permutation(__first1, __last1, __first2, __last2, __gnu_cxx::__ops::__iter_comp_iter(__pred)); } +#endif // C++14 -#if __cplusplus >= 201703L - -#define __cpp_lib_clamp 201603L - +#ifdef __cpp_lib_clamp // C++ >= 17 /** * @brief Returns the value clamped between lo and hi. * @ingroup sorting_algorithms @@ -3641,8 +3643,7 @@ _GLIBCXX_END_INLINE_ABI_NAMESPACE(_V2) __glibcxx_assert(!__comp(__hi, __lo)); return std::min(std::max(__val, __lo, __comp), __hi, __comp); } -#endif // C++17 -#endif // C++14 +#endif // __cpp_lib_clamp /** * @brief Generate two uniformly distributed integers using a @@ -5812,9 +5813,9 @@ _GLIBCXX_BEGIN_NAMESPACE_ALGO } return __out; } +#endif // C++14 -#if __cplusplus > 201402L -#define __cpp_lib_sample 201603L +#ifdef __cpp_lib_sample // C++ >= 17 /// Take a random sample from a population. template @@ -5842,8 +5843,7 @@ _GLIBCXX_BEGIN_NAMESPACE_ALGO __sample(__first, __last, __pop_cat{}, __out, __samp_cat{}, __d, std::forward<_UniformRandomBitGenerator>(__g)); } -#endif // C++17 -#endif // C++14 +#endif // __cpp_lib_sample _GLIBCXX_END_NAMESPACE_ALGO _GLIBCXX_END_NAMESPACE_VERSION diff --git a/libstdc++-v3/include/bits/stl_algobase.h b/libstdc++-v3/include/bits/stl_algobase.h index dd95e94f7e92..2f5a4bd4fd4b 100644 --- a/libstdc++-v3/include/bits/stl_algobase.h +++ b/libstdc++-v3/include/bits/stl_algobase.h @@ -79,6 +79,9 @@ # include #endif +#define __glibcxx_want_robust_nonmodifying_seq_ops +#include + namespace std _GLIBCXX_VISIBILITY(default) { _GLIBCXX_BEGIN_NAMESPACE_VERSION @@ -1518,15 +1521,12 @@ _GLIBCXX_END_NAMESPACE_CONTAINER return std::__bit_width(make_unsigned_t<_Tp>(__n)) - 1; #else // Use +__n so it promotes to at least int. - const int __sz = sizeof(+__n); - int __w = __sz * __CHAR_BIT__ - 1; - if (__sz == sizeof(long long)) - __w -= __builtin_clzll(+__n); - else if (__sz == sizeof(long)) - __w -= __builtin_clzl(+__n); - else if (__sz == sizeof(int)) - __w -= __builtin_clz(+__n); - return __w; + return (sizeof(+__n) * __CHAR_BIT__ - 1) + - (sizeof(+__n) == sizeof(long long) + ? __builtin_clzll(+__n) + : (sizeof(+__n) == sizeof(long) + ? __builtin_clzl(+__n) + : __builtin_clz(+__n))); #endif } @@ -1648,10 +1648,7 @@ _GLIBCXX_BEGIN_NAMESPACE_ALGO } #endif // C++11 -#if __cplusplus > 201103L - -#define __cpp_lib_robust_nonmodifying_seq_ops 201304L - +#ifdef __cpp_lib_robust_nonmodifying_seq_ops // C++ >= 14 /** * @brief Tests a range for element-wise equality. * @ingroup non_mutating_algorithms @@ -1713,7 +1710,7 @@ _GLIBCXX_BEGIN_NAMESPACE_ALGO return _GLIBCXX_STD_A::__equal4(__first1, __last1, __first2, __last2, __binary_pred); } -#endif // C++14 +#endif // __cpp_lib_robust_nonmodifying_seq_ops /** * @brief Performs @b dictionary comparison on ranges. @@ -1955,8 +1952,7 @@ _GLIBCXX_BEGIN_NAMESPACE_ALGO __gnu_cxx::__ops::__iter_comp_iter(__binary_pred)); } -#if __cplusplus > 201103L - +#if __cpp_lib_robust_nonmodifying_seq_ops // C++ >= 14 template _GLIBCXX20_CONSTEXPR diff --git a/libstdc++-v3/include/bits/stl_function.h b/libstdc++-v3/include/bits/stl_function.h index fa03f32b1b82..608d4e96fb2c 100644 --- a/libstdc++-v3/include/bits/stl_function.h +++ b/libstdc++-v3/include/bits/stl_function.h @@ -60,6 +60,9 @@ #include #endif +#define __glibcxx_want_transparent_operators +#include + namespace std _GLIBCXX_VISIBILITY(default) { _GLIBCXX_BEGIN_NAMESPACE_VERSION @@ -153,7 +156,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION * @{ */ -#if __cplusplus > 201103L +#if __cpp_lib_transparent_operators // C++ >= 14 struct __is_transparent; // undefined template @@ -241,10 +244,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION }; #pragma GCC diagnostic pop -#if __cplusplus > 201103L - -#define __cpp_lib_transparent_operators 201510L - +#ifdef __cpp_lib_transparent_operators // C++ >= 14 template<> struct plus { @@ -345,7 +345,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION * * @{ */ -#if __cplusplus > 201103L +#if __cpp_lib_transparent_operators // C++ >= 14 template struct equal_to; @@ -489,7 +489,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION }; #pragma GCC diagnostic pop -#if __cplusplus >= 201402L +#ifdef __cpp_lib_transparent_operators // C++ >= 14 /// One of the @link comparison_functors comparison functors@endlink. template<> struct equal_to @@ -765,7 +765,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION is_convertible<_Tp, const volatile void*>, is_convertible<_Up, const volatile void*>>; }; -#endif // C++14 +#endif // __cpp_lib_transparent_operators /** @} */ // 20.3.4 logical operations @@ -777,7 +777,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION * * @{ */ -#if __cplusplus > 201103L +#ifdef __cpp_lib_transparent_operators // C++ >= 14 template struct logical_and; @@ -822,7 +822,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION }; #pragma GCC diagnostic pop -#if __cplusplus > 201103L +#ifdef __cpp_lib_transparent_operators // C++ >= 14 /// One of the @link logical_functors Boolean operations functors@endlink. template<> struct logical_and @@ -867,10 +867,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION typedef __is_transparent is_transparent; }; -#endif +#endif // __cpp_lib_transparent_operators /** @} */ -#if __cplusplus > 201103L +#ifdef __cpp_lib_transparent_operators // C++ >= 14 template struct bit_and; @@ -926,7 +926,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION }; #pragma GCC diagnostic pop -#if __cplusplus > 201103L +#ifdef __cpp_lib_transparent_operators // C++ >= 14 template <> struct bit_and { @@ -1416,7 +1416,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION /** @} */ -#if __cplusplus >= 201402L +#ifdef __cpp_lib_transparent_operators // C++ >= 14 template> struct __has_is_transparent { }; diff --git a/libstdc++-v3/include/bits/stl_iterator.h b/libstdc++-v3/include/bits/stl_iterator.h index b22d9a4fdb3a..b75f87e056de 100644 --- a/libstdc++-v3/include/bits/stl_iterator.h +++ b/libstdc++-v3/include/bits/stl_iterator.h @@ -70,12 +70,11 @@ # include #endif -#if __cplusplus > 201703L -# define __cpp_lib_array_constexpr 201811L -# define __cpp_lib_constexpr_iterator 201811L -#elif __cplusplus == 201703L -# define __cpp_lib_array_constexpr 201803L -#endif +#define __glibcxx_want_constexpr_iterator +#define __glibcxx_want_array_constexpr +#define __glibcxx_want_make_reverse_iterator +#define __glibcxx_want_move_iterator_concept +#include #if __cplusplus >= 202002L # include @@ -642,9 +641,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION __make_reverse_iterator(_Iterator __i) { return reverse_iterator<_Iterator>(__i); } -# if __cplusplus >= 201402L -# define __cpp_lib_make_reverse_iterator 201402L - +# ifdef __cpp_lib_make_reverse_iterator // C++ >= 14 // _GLIBCXX_RESOLVE_LIB_DEFECTS // DR 2285. make_reverse_iterator /// Generator function for reverse_iterator. @@ -661,7 +658,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION disable_sized_sentinel_for, reverse_iterator<_Iterator2>> = true; # endif // C++20 -# endif // C++14 +# endif // __cpp_lib_make_reverse_iterator template _GLIBCXX20_CONSTEXPR @@ -1426,11 +1423,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { }; template - requires requires { typename iterator_traits<_Iterator>::iterator_category; } + requires requires { typename __iter_category_t<_Iterator>; } struct __move_iter_cat<_Iterator> { using iterator_category - = __clamp_iter_cat::iterator_category, + = __clamp_iter_cat<__iter_category_t<_Iterator>, random_access_iterator_tag>; }; #endif @@ -1461,7 +1458,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template friend class move_iterator; -#if __cpp_lib_concepts +#if __cpp_lib_concepts // C++20 && concepts // _GLIBCXX_RESOLVE_LIB_DEFECTS // 3435. three_way_comparable_with, [...]> template @@ -1487,9 +1484,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION public: using iterator_type = _Iterator; -#if __cplusplus > 201703L && __cpp_lib_concepts - // This is P2520R0, a C++23 change, but we treat it as a DR against C++20. -# define __cpp_lib_move_iterator_concept 202207L +#ifdef __cpp_lib_move_iterator_concept // C++ >= 20 && lib_concepts using iterator_concept = decltype(_S_iter_concept()); // iterator_category defined in __move_iter_cat @@ -2288,8 +2283,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION static auto _S_iter_cat() { - using _Traits = iterator_traits<_It>; - if constexpr (requires { requires derived_from, forward_iterator_tag>; }) return forward_iterator_tag{}; else @@ -2615,7 +2609,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template struct __basic_const_iterator_iter_cat<_It> - { using iterator_category = iterator_traits<_It>::iterator_category; }; + { using iterator_category = __iter_category_t<_It>; }; } // namespace detail template diff --git a/libstdc++-v3/include/bits/stl_iterator_base_types.h b/libstdc++-v3/include/bits/stl_iterator_base_types.h index 5d2c8b325d9f..841b5eca3ad1 100644 --- a/libstdc++-v3/include/bits/stl_iterator_base_types.h +++ b/libstdc++-v3/include/bits/stl_iterator_base_types.h @@ -243,16 +243,16 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION #if __cplusplus >= 201103L template - using __iterator_category_t + using __iter_category_t = typename iterator_traits<_Iter>::iterator_category; template using _RequireInputIter = - __enable_if_t, + __enable_if_t, input_iterator_tag>::value>; template> + typename _Cat = __iter_category_t<_It>> struct __is_random_access_iter : is_base_of { diff --git a/libstdc++-v3/include/bits/stl_list.h b/libstdc++-v3/include/bits/stl_list.h index bf1f1b37ab44..82256b7f1c5c 100644 --- a/libstdc++-v3/include/bits/stl_list.h +++ b/libstdc++-v3/include/bits/stl_list.h @@ -65,6 +65,9 @@ #include #endif +#define __glibcxx_want_list_remove_return_type +#include + namespace std _GLIBCXX_VISIBILITY(default) { _GLIBCXX_BEGIN_NAMESPACE_VERSION @@ -1761,8 +1764,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 #endif private: -#if __cplusplus > 201703L -# define __cpp_lib_list_remove_return_type 201806L +#ifdef __cpp_lib_list_remove_return_type // C++ >= 20 && HOSTED typedef size_type __remove_return_type; # define _GLIBCXX_LIST_REMOVE_RETURN_TYPE_TAG \ __attribute__((__abi_tag__("__cxx20"))) diff --git a/libstdc++-v3/include/bits/stl_map.h b/libstdc++-v3/include/bits/stl_map.h index 059916d0a7f1..02cce9b37d8c 100644 --- a/libstdc++-v3/include/bits/stl_map.h +++ b/libstdc++-v3/include/bits/stl_map.h @@ -63,6 +63,9 @@ #include #endif +#define __glibcxx_want_map_try_emplace +#include + namespace std _GLIBCXX_VISIBILITY(default) { _GLIBCXX_BEGIN_NAMESPACE_VERSION @@ -696,8 +699,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER { merge(__source); } #endif // C++17 -#if __cplusplus > 201402L -#define __cpp_lib_map_try_emplace 201411L +#ifdef __cpp_lib_map_try_emplace // C++ >= 17 && HOSTED /** * @brief Attempts to build and insert a std::pair into the %map. * diff --git a/libstdc++-v3/include/bits/stl_pair.h b/libstdc++-v3/include/bits/stl_pair.h index 3f1624f40b4e..197a90987e61 100644 --- a/libstdc++-v3/include/bits/stl_pair.h +++ b/libstdc++-v3/include/bits/stl_pair.h @@ -63,9 +63,12 @@ #endif #if __cplusplus >= 202002L # include -# define __cpp_lib_constexpr_utility 201811L #endif +#define __glibcxx_want_constexpr_utility +#define __glibcxx_want_tuples_by_type +#include + namespace std _GLIBCXX_VISIBILITY(default) { _GLIBCXX_BEGIN_NAMESPACE_VERSION @@ -1050,10 +1053,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION get(const pair<_Tp1, _Tp2>&& __in) noexcept { return __pair_get<_Int>::__const_move_get(std::move(__in)); } -#if __cplusplus >= 201402L - -#define __cpp_lib_tuples_by_type 201304L +#ifdef __cpp_lib_tuples_by_type // C++ >= 14 template constexpr _Tp& get(pair<_Tp, _Up>& __p) noexcept @@ -1093,6 +1094,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION constexpr const _Tp&& get(const pair<_Up, _Tp>&& __p) noexcept { return std::move(__p.second); } +#endif // __cpp_lib_tuples_by_type + #if __cplusplus > 202002L template, common_type_t<_T2, _U2>>; }; #endif // C++23 -#endif // C++14 /// @} #endif // C++11 diff --git a/libstdc++-v3/include/bits/stl_queue.h b/libstdc++-v3/include/bits/stl_queue.h index 8a8dc95f8896..1d22578eb1e6 100644 --- a/libstdc++-v3/include/bits/stl_queue.h +++ b/libstdc++-v3/include/bits/stl_queue.h @@ -62,6 +62,9 @@ # include #endif +#define __glibcxx_want_adaptor_iterator_pair_constructor +#include + namespace std _GLIBCXX_VISIBILITY(default) { _GLIBCXX_BEGIN_NAMESPACE_VERSION @@ -194,10 +197,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template> queue(queue&& __q, const _Alloc& __a) : c(std::move(__q.c), __a) { } +#endif -#if __cplusplus > 202002L -#define __cpp_lib_adaptor_iterator_pair_constructor 202106L - +#ifdef __cpp_lib_adaptor_iterator_pair_constructor // C++ >= 23 && HOSTED template> queue(_InputIterator __first, _InputIterator __last) @@ -208,7 +210,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION typename = _Uses<_Alloc>> queue(_InputIterator __first, _InputIterator __last, const _Alloc& __a) : c(__first, __last, __a) { } -#endif #endif /** diff --git a/libstdc++-v3/include/bits/stl_stack.h b/libstdc++-v3/include/bits/stl_stack.h index 006b18c9683f..2d09098ca867 100644 --- a/libstdc++-v3/include/bits/stl_stack.h +++ b/libstdc++-v3/include/bits/stl_stack.h @@ -62,6 +62,9 @@ # include #endif +#define __glibcxx_want_adaptor_iterator_pair_constructor +#include + namespace std _GLIBCXX_VISIBILITY(default) { _GLIBCXX_BEGIN_NAMESPACE_VERSION @@ -170,9 +173,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION stack(_Sequence&& __c) : c(std::move(__c)) { } -#if __cplusplus > 202002L -#define __cpp_lib_adaptor_iterator_pair_constructor 202106L - +#ifdef __cpp_lib_adaptor_iterator_pair_constructor // C++ >= 23 && HOSTED template> stack(_InputIterator __first, _InputIterator __last) diff --git a/libstdc++-v3/include/bits/stl_tree.h b/libstdc++-v3/include/bits/stl_tree.h index 3c331fbc952a..1cf887b028ec 100644 --- a/libstdc++-v3/include/bits/stl_tree.h +++ b/libstdc++-v3/include/bits/stl_tree.h @@ -72,14 +72,13 @@ # include #endif +#define __glibcxx_want_generic_associative_lookup +#include + namespace std _GLIBCXX_VISIBILITY(default) { _GLIBCXX_BEGIN_NAMESPACE_VERSION -#if __cplusplus > 201103L -# define __cpp_lib_generic_associative_lookup 201304L -#endif - // Red-black tree class, designed for use in implementing STL // associative containers (set, multiset, map, and multimap). The // insertion and deletion algorithms are based on those in Cormen, @@ -1554,7 +1553,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION = _Rb_tree<_Key, _Val, _KeyOfValue, _Compare2, _Alloc>; template - friend class _Rb_tree_merge_helper; + friend struct _Rb_tree_merge_helper; /// Merge from a compatible container into one with unique keys. template diff --git a/libstdc++-v3/include/bits/stl_uninitialized.h b/libstdc++-v3/include/bits/stl_uninitialized.h index be7b4afdd05f..5174cfbcbe2c 100644 --- a/libstdc++-v3/include/bits/stl_uninitialized.h +++ b/libstdc++-v3/include/bits/stl_uninitialized.h @@ -67,6 +67,9 @@ #include #endif +#define __glibcxx_want_raw_memory_algorithms +#include + namespace std _GLIBCXX_VISIBILITY(default) { _GLIBCXX_BEGIN_NAMESPACE_VERSION @@ -806,8 +809,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { template static void - __uninit_default_novalue(_ForwardIterator __first, - _ForwardIterator __last) + __uninit_default_novalue(_ForwardIterator, _ForwardIterator) { } }; @@ -964,9 +966,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION /// @endcond #endif -#if __cplusplus >= 201703L -# define __cpp_lib_raw_memory_algorithms 201606L - +#ifdef __cpp_lib_raw_memory_algorithms // C++ >= 17 /** * @brief Default-initializes objects in the range [first,last). * @param __first A forward iterator. @@ -1059,7 +1059,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION __count, __result); return {__res.first.base(), __res.second}; } -#endif // C++17 +#endif // __cpp_lib_raw_memory_algorithms #if __cplusplus >= 201103L /// @cond undocumented diff --git a/libstdc++-v3/include/bits/stl_vector.h b/libstdc++-v3/include/bits/stl_vector.h index 70ced3d101fb..1a353397e073 100644 --- a/libstdc++-v3/include/bits/stl_vector.h +++ b/libstdc++-v3/include/bits/stl_vector.h @@ -64,9 +64,11 @@ #endif #if __cplusplus >= 202002L # include -#define __cpp_lib_constexpr_vector 201907L #endif +#define __glibcxx_want_constexpr_vector +#include + #include #if _GLIBCXX_SANITIZE_STD_ALLOCATOR && _GLIBCXX_SANITIZE_VECTOR diff --git a/libstdc++-v3/include/bits/streambuf_iterator.h b/libstdc++-v3/include/bits/streambuf_iterator.h index 32285a668fc4..14a95ad42c2c 100644 --- a/libstdc++-v3/include/bits/streambuf_iterator.h +++ b/libstdc++-v3/include/bits/streambuf_iterator.h @@ -223,7 +223,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION #if __cplusplus > 201703L && __cpp_lib_concepts [[nodiscard]] friend bool - operator==(const istreambuf_iterator& __i, default_sentinel_t __s) + operator==(const istreambuf_iterator& __i, default_sentinel_t) { return __i._M_at_eof(); } #endif }; diff --git a/libstdc++-v3/include/bits/unique_ptr.h b/libstdc++-v3/include/bits/unique_ptr.h index f0c6d2383b47..d92fe79e2f2e 100644 --- a/libstdc++-v3/include/bits/unique_ptr.h +++ b/libstdc++-v3/include/bits/unique_ptr.h @@ -1,3 +1,4 @@ + // unique_ptr implementation -*- C++ -*- // Copyright (C) 2008-2023 Free Software Foundation, Inc. @@ -43,12 +44,9 @@ # endif #endif -/* Duplicate definition with ptr_traits.h. */ -#if __cplusplus > 202002L && defined(__cpp_constexpr_dynamic_alloc) -# define __cpp_lib_constexpr_memory 202202L -#elif __cplusplus > 201703L -# define __cpp_lib_constexpr_memory 201811L -#endif +#define __glibcxx_want_constexpr_memory +#define __glibcxx_want_make_unique +#include namespace std _GLIBCXX_VISIBILITY(default) { @@ -1029,9 +1027,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION public __uniq_ptr_hash> { }; -#if __cplusplus >= 201402L && _GLIBCXX_HOSTED -#define __cpp_lib_make_unique 201304L - +#ifdef __cpp_lib_make_unique // C++ >= 14 && HOSTED /// @cond undocumented namespace __detail { diff --git a/libstdc++-v3/include/bits/unordered_map.h b/libstdc++-v3/include/bits/unordered_map.h index 2f63bc5f1fad..4c9a6bae2fd7 100644 --- a/libstdc++-v3/include/bits/unordered_map.h +++ b/libstdc++-v3/include/bits/unordered_map.h @@ -35,6 +35,9 @@ #include // hash #include // equal_to +#define __glibcxx_want_unordered_map_try_emplace +#include + namespace std _GLIBCXX_VISIBILITY(default) { _GLIBCXX_BEGIN_NAMESPACE_VERSION @@ -449,8 +452,9 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER iterator insert(const_iterator, node_type&& __nh) { return _M_h._M_reinsert_node(std::move(__nh)).position; } +#endif // C++17 -#define __cpp_lib_unordered_map_try_emplace 201411L +#ifdef __cpp_lib_unordered_map_try_emplace // C++ >= 17 && HOSTED /** * @brief Attempts to build and insert a std::pair into the * %unordered_map. @@ -534,7 +538,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER return _M_h.try_emplace(__hint, std::move(__k), std::forward<_Args>(__args)...).first; } -#endif // C++17 +#endif // __cpp_lib_unordered_map_try_emplace ///@{ /** diff --git a/libstdc++-v3/include/bits/uses_allocator.h b/libstdc++-v3/include/bits/uses_allocator.h index d3b26c7d9745..ebd26d291b3c 100644 --- a/libstdc++-v3/include/bits/uses_allocator.h +++ b/libstdc++-v3/include/bits/uses_allocator.h @@ -168,7 +168,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION #endif // C++14 template - void __uses_allocator_construct_impl(__uses_alloc0 __a, _Tp* __ptr, + void __uses_allocator_construct_impl(__uses_alloc0, _Tp* __ptr, _Args&&... __args) { ::new ((void*)__ptr) _Tp(std::forward<_Args>(__args)...); } diff --git a/libstdc++-v3/include/bits/uses_allocator_args.h b/libstdc++-v3/include/bits/uses_allocator_args.h index bc038f034584..a4eae74d5e96 100644 --- a/libstdc++-v3/include/bits/uses_allocator_args.h +++ b/libstdc++-v3/include/bits/uses_allocator_args.h @@ -32,8 +32,10 @@ #pragma GCC system_header -#if __cplusplus > 201703L && __cpp_concepts +#define __glibcxx_want_make_obj_using_allocator +#include +#ifdef __cpp_lib_make_obj_using_allocator // C++ >= 20 && concepts #include // for placement operator new #include // for tuple, make_tuple, make_from_tuple #include // construct_at @@ -49,10 +51,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION /** @addtogroup allocators * @{ */ - -// Not specified by C++20, used internally -#define __cpp_lib_make_obj_using_allocator 201811L - template constexpr auto uses_allocator_construction_args(const _Alloc& __a, @@ -247,5 +245,5 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION /// @} _GLIBCXX_END_NAMESPACE_VERSION } // namespace std -#endif // C++20 +#endif // __cpp_lib_make_obj_using_allocator #endif // _USES_ALLOCATOR_ARGS diff --git a/libstdc++-v3/include/bits/utility.h b/libstdc++-v3/include/bits/utility.h index 4692aa0c9b01..bed945256425 100644 --- a/libstdc++-v3/include/bits/utility.h +++ b/libstdc++-v3/include/bits/utility.h @@ -35,6 +35,11 @@ #pragma GCC system_header +#define __glibcxx_want_tuple_element_t +#define __glibcxx_want_integer_sequence +#define __glibcxx_want_ranges_zip +#include + #if __cplusplus >= 201103L #include @@ -123,17 +128,17 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } return __n; } +#endif // C++14 // The standard says this macro and alias template should be in but we // define them here, to be available in , and too. // _GLIBCXX_RESOLVE_LIB_DEFECTS // 3378. tuple_size_v/tuple_element_t should be available when // tuple_size/tuple_element are -#define __cpp_lib_tuple_element_t 201402L - +#ifdef __cpp_lib_tuple_element_t // C++ >= 14 template using tuple_element_t = typename tuple_element<__i, _Tp>::type; -#endif // C++14 +#endif // Stores a tuple of indices. Used by tuple and pair, and by bind() to // extract the elements in a tuple. @@ -155,9 +160,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION #endif }; -#if __cplusplus >= 201402L - -#define __cpp_lib_integer_sequence 201304L +#ifdef __cpp_lib_integer_sequence // C++ >= 14 /// Class template integer_sequence template @@ -187,6 +190,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION /// Alias template index_sequence_for template using index_sequence_for = make_index_sequence; +#endif // __cpp_lib_integer_sequence #if __cplusplus >= 201703L @@ -222,7 +226,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION using __is_in_place_type = bool_constant<__is_in_place_type_v<_Tp>>; #endif // C++17 -#endif // C++14 #if __has_builtin(__type_pack_element) template @@ -269,10 +272,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION #endif #endif -#if __cplusplus > 202002L -#define __cpp_lib_ranges_zip 202110L // for and -#endif - _GLIBCXX_END_NAMESPACE_VERSION } // namespace diff --git a/libstdc++-v3/include/bits/vector.tcc b/libstdc++-v3/include/bits/vector.tcc index ada396c9b30a..80631d1e2a19 100644 --- a/libstdc++-v3/include/bits/vector.tcc +++ b/libstdc++-v3/include/bits/vector.tcc @@ -488,78 +488,83 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER private: _Guard(const _Guard&); }; - _Guard __guard(__new_start, __len, _M_impl); - // The order of the three operations is dictated by the C++11 - // case, where the moves could alter a new element belonging - // to the existing vector. This is an issue only for callers - // taking the element by lvalue ref (see last bullet of C++11 - // [res.on.arguments]). + { + _Guard __guard(__new_start, __len, _M_impl); - // If this throws, the existing elements are unchanged. + // The order of the three operations is dictated by the C++11 + // case, where the moves could alter a new element belonging + // to the existing vector. This is an issue only for callers + // taking the element by lvalue ref (see last bullet of C++11 + // [res.on.arguments]). + + // If this throws, the existing elements are unchanged. #if __cplusplus >= 201103L - _Alloc_traits::construct(this->_M_impl, - std::__to_address(__new_start + __elems_before), - std::forward<_Args>(__args)...); + _Alloc_traits::construct(this->_M_impl, + std::__to_address(__new_start + __elems_before), + std::forward<_Args>(__args)...); #else - _Alloc_traits::construct(this->_M_impl, - __new_start + __elems_before, - __x); + _Alloc_traits::construct(this->_M_impl, + __new_start + __elems_before, + __x); #endif #if __cplusplus >= 201103L - if _GLIBCXX17_CONSTEXPR (_S_use_relocate()) - { - // Relocation cannot throw. - __new_finish = _S_relocate(__old_start, __position.base(), - __new_start, _M_get_Tp_allocator()); - ++__new_finish; - __new_finish = _S_relocate(__position.base(), __old_finish, - __new_finish, _M_get_Tp_allocator()); - } - else -#endif - { - // RAII type to destroy initialized elements. - struct _Guard_elts + if _GLIBCXX17_CONSTEXPR (_S_use_relocate()) { - pointer _M_first, _M_last; // Elements to destroy - _Tp_alloc_type& _M_alloc; + // Relocation cannot throw. + __new_finish = _S_relocate(__old_start, __position.base(), + __new_start, _M_get_Tp_allocator()); + ++__new_finish; + __new_finish = _S_relocate(__position.base(), __old_finish, + __new_finish, _M_get_Tp_allocator()); + } + else +#endif + { + // RAII type to destroy initialized elements. + struct _Guard_elts + { + pointer _M_first, _M_last; // Elements to destroy + _Tp_alloc_type& _M_alloc; - _GLIBCXX20_CONSTEXPR - _Guard_elts(pointer __elt, _Tp_alloc_type& __a) - : _M_first(__elt), _M_last(__elt + 1), _M_alloc(__a) - { } + _GLIBCXX20_CONSTEXPR + _Guard_elts(pointer __elt, _Tp_alloc_type& __a) + : _M_first(__elt), _M_last(__elt + 1), _M_alloc(__a) + { } - _GLIBCXX20_CONSTEXPR - ~_Guard_elts() - { std::_Destroy(_M_first, _M_last, _M_alloc); } + _GLIBCXX20_CONSTEXPR + ~_Guard_elts() + { std::_Destroy(_M_first, _M_last, _M_alloc); } - private: - _Guard_elts(const _Guard_elts&); - }; + private: + _Guard_elts(const _Guard_elts&); + }; - // Guard the new element so it will be destroyed if anything throws. - _Guard_elts __guard_elts(__new_start + __elems_before, _M_impl); + // Guard the new element so it will be destroyed if anything throws. + _Guard_elts __guard_elts(__new_start + __elems_before, _M_impl); - __new_finish = std::__uninitialized_move_if_noexcept_a( - __old_start, __position.base(), - __new_start, _M_get_Tp_allocator()); + __new_finish = std::__uninitialized_move_if_noexcept_a( + __old_start, __position.base(), + __new_start, _M_get_Tp_allocator()); - ++__new_finish; - // Guard everything before the new element too. - __guard_elts._M_first = __new_start; + ++__new_finish; + // Guard everything before the new element too. + __guard_elts._M_first = __new_start; - __new_finish = std::__uninitialized_move_if_noexcept_a( - __position.base(), __old_finish, - __new_finish, _M_get_Tp_allocator()); + __new_finish = std::__uninitialized_move_if_noexcept_a( + __position.base(), __old_finish, + __new_finish, _M_get_Tp_allocator()); - // New storage has been fully initialized, destroy the old elements. - __guard_elts._M_first = __old_start; - __guard_elts._M_last = __old_finish; - } - __guard._M_storage = __old_start; - __guard._M_len = this->_M_impl._M_end_of_storage - __old_start; + // New storage has been fully initialized, destroy the old elements. + __guard_elts._M_first = __old_start; + __guard_elts._M_last = __old_finish; + } + __guard._M_storage = __old_start; + __guard._M_len = this->_M_impl._M_end_of_storage - __old_start; + } + // deallocate should be called before assignments to _M_impl, + // to avoid call-clobbering this->_M_impl._M_start = __new_start; this->_M_impl._M_finish = __new_finish; @@ -728,49 +733,54 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER private: _Guard(const _Guard&); }; - _Guard __guard(__new_start, __len, _M_impl); - std::__uninitialized_default_n_a(__new_start + __size, __n, - _M_get_Tp_allocator()); + { + _Guard __guard(__new_start, __len, _M_impl); - if _GLIBCXX17_CONSTEXPR (_S_use_relocate()) - { - _S_relocate(__old_start, __old_finish, - __new_start, _M_get_Tp_allocator()); - } - else - { - // RAII type to destroy initialized elements. - struct _Guard_elts + std::__uninitialized_default_n_a(__new_start + __size, __n, + _M_get_Tp_allocator()); + + if _GLIBCXX17_CONSTEXPR (_S_use_relocate()) { - pointer _M_first, _M_last; // Elements to destroy - _Tp_alloc_type& _M_alloc; + _S_relocate(__old_start, __old_finish, + __new_start, _M_get_Tp_allocator()); + } + else + { + // RAII type to destroy initialized elements. + struct _Guard_elts + { + pointer _M_first, _M_last; // Elements to destroy + _Tp_alloc_type& _M_alloc; - _GLIBCXX20_CONSTEXPR - _Guard_elts(pointer __first, size_type __n, - _Tp_alloc_type& __a) - : _M_first(__first), _M_last(__first + __n), _M_alloc(__a) - { } + _GLIBCXX20_CONSTEXPR + _Guard_elts(pointer __first, size_type __n, + _Tp_alloc_type& __a) + : _M_first(__first), _M_last(__first + __n), _M_alloc(__a) + { } - _GLIBCXX20_CONSTEXPR - ~_Guard_elts() - { std::_Destroy(_M_first, _M_last, _M_alloc); } + _GLIBCXX20_CONSTEXPR + ~_Guard_elts() + { std::_Destroy(_M_first, _M_last, _M_alloc); } - private: - _Guard_elts(const _Guard_elts&); - }; - _Guard_elts __guard_elts(__new_start + __size, __n, _M_impl); + private: + _Guard_elts(const _Guard_elts&); + }; + _Guard_elts __guard_elts(__new_start + __size, __n, _M_impl); - std::__uninitialized_move_if_noexcept_a( - __old_start, __old_finish, __new_start, - _M_get_Tp_allocator()); + std::__uninitialized_move_if_noexcept_a( + __old_start, __old_finish, __new_start, + _M_get_Tp_allocator()); - __guard_elts._M_first = __old_start; - __guard_elts._M_last = __old_finish; - } - _GLIBCXX_ASAN_ANNOTATE_REINIT; - __guard._M_storage = __old_start; - __guard._M_len = this->_M_impl._M_end_of_storage - __old_start; + __guard_elts._M_first = __old_start; + __guard_elts._M_last = __old_finish; + } + _GLIBCXX_ASAN_ANNOTATE_REINIT; + __guard._M_storage = __old_start; + __guard._M_len = this->_M_impl._M_end_of_storage - __old_start; + } + // deallocate should be called before assignments to _M_impl, + // to avoid call-clobbering this->_M_impl._M_start = __new_start; this->_M_impl._M_finish = __new_start + __size + __n; diff --git a/libstdc++-v3/include/bits/version.def b/libstdc++-v3/include/bits/version.def new file mode 100644 index 000000000000..80c13d4a447e --- /dev/null +++ b/libstdc++-v3/include/bits/version.def @@ -0,0 +1,1615 @@ +// Feature test macro definitions -*- C++ -*- +// Copyright (C) 2023 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 +// . + +AutoGen Definitions version.tpl; + +// The top level variable ftms is an array of feature test macros. Each entry +// consists of a structure like following: + +// Schema: +// ftms = { +// name = FTM NAME; +// [stdname = FTM STANDARD MACRO NAME;] +// values = { +// v = VALUE FOR FTM IF MATCHING; +// [extra_cond = STRING;] +// [cxxmin = NUMBER;] +// [gnuxxmin = NUMBER;] +// [gthread = yes|no;] +// [hosted = yes|no;] +// [cxx11abi = yes|no;] +// }; ... +// }; + +// The elements in square brackets are optional. These are formulated into a +// logical expression like: +// ((strict && c++ >= cxxmin) || (!strict && c++ >= gnuxxmin)) +// && (gthr <=> gthread) +// && (host <=> hosted) +// && (cxx11 <=> cxx11abi) +// && (extra_cond) +// Where gthr, cxx11 and host are _GLIBCXX_HAS_GTHREADS, _GLIBCXX_USE_CXX11_ABI +// and _GLIBCXX_HOSTED respectively. If any of these are omitted, their +// sub-expressions are equivalent to the identity. Specially, if gnuxxmin is +// omitted, it is taken to be the value of cxxmin, and so, only if both are +// omitted, the clause is omitted. + +// stdname configures the name of the *standard* macro emitted, i.e. it +// replaces only the __cpp_lib_ macro in the emitted definition. Defaults to +// __cpp_lib_${name} + +// N.B This list needs to be in topological sort order, as later entries in +// this list can and do use the earlier entries. + +ftms = { + name = incomplete_container_elements; + values = { + v = 201505; + hosted = yes; + }; +}; + +ftms = { + name = uncaught_exceptions; + values = { + v = 201411; + cxxmin = 17; + gnuxxmin = 03; + }; +}; + +ftms = { + name = allocator_traits_is_always_equal; + values = { + v = 201411; + cxxmin = 11; + }; +}; + +ftms = { + name = is_null_pointer; + values = { + v = 201309; + cxxmin = 11; + }; +}; + +ftms = { + name = result_of_sfinae; + values = { + v = 201210; + cxxmin = 11; + }; +}; + +ftms = { + name = shared_ptr_arrays; + values = { + v = 201707; + cxxmin = 20; + hosted = yes; + }; + values = { + v = 201611; + cxxmin = 11; + hosted = yes; + }; +}; + +ftms = { + name = is_swappable; + values = { + v = 201603; + cxxmin = 17; + gnuxxmin = 11; + }; +}; + +ftms = { + name = void_t; + values = { + v = 201411; + cxxmin = 17; + gnuxxmin = 11; + }; +}; + +ftms = { + name = enable_shared_from_this; + values = { + v = 201603; + cxxmin = 17; + gnuxxmin = 11; + hosted = yes; + }; +}; + +ftms = { + name = math_spec_funcs; + stdname = "__STDCPP_MATH_SPEC_FUNCS__"; + values = { + v = 201003; + cxxmin = 11; + }; +}; + +ftms = { + name = coroutine; + values = { + v = 201902; + // It is very likely that earlier versions would work, but they are + // untested. + cxxmin = 14; + extra_cond = "__cpp_impl_coroutine"; + }; +}; + +ftms = { + name = exchange_function; + values = { + v = 201304; + cxxmin = 14; + }; +}; + +ftms = { + name = integer_sequence; + values = { + v = 201304; + cxxmin = 14; + }; +}; + +ftms = { + name = integral_constant_callable; + values = { + v = 201304; + cxxmin = 14; + }; +}; + +ftms = { + name = is_final; + values = { + v = 201402; + cxxmin = 14; + }; +}; + +ftms = { + name = make_reverse_iterator; + values = { + v = 201402; + cxxmin = 14; + }; +}; + +ftms = { + name = null_iterators; + values = { + v = 201304; + cxxmin = 14; + extra_cond = "!defined(_GLIBCXX_DEBUG)"; + }; +}; + +ftms = { + name = transformation_trait_aliases; + values = { + v = 201304; + cxxmin = 14; + }; +}; + +ftms = { + name = transparent_operators; + values = { + v = 201510; + cxxmin = 14; + }; +}; + +ftms = { + name = tuple_element_t; + values = { + v = 201402; + cxxmin = 14; + }; +}; + +ftms = { + name = tuples_by_type; + values = { + v = 201304; + cxxmin = 14; + }; +}; + +ftms = { + name = robust_nonmodifying_seq_ops; + values = { + v = 201304; + cxxmin = 14; + }; +}; + +ftms = { + name = to_chars; + values = { + v = 201611; + cxxmin = 14; + extra_cond = "_GLIBCXX_FLOAT_IS_IEEE_BINARY32 " + "&& _GLIBCXX_DOUBLE_IS_IEEE_BINARY64 " + "&& __SIZE_WIDTH__ >= 32"; + }; +}; + +ftms = { + name = chrono_udls; + values = { + v = 201304; + cxxmin = 14; + hosted = yes; + }; +}; + +ftms = { + name = complex_udls; + values = { + v = 201309; + cxxmin = 14; + hosted = yes; + }; +}; + +ftms = { + name = generic_associative_lookup; + values = { + v = 201304; + cxxmin = 14; + hosted = yes; + }; +}; + +ftms = { + name = make_unique; + values = { + v = 201304; + cxxmin = 14; + hosted = yes; + }; +}; + +ftms = { + name = quoted_string_io; + values = { + v = 201304; + cxxmin = 14; + hosted = yes; + }; +}; + +ftms = { + name = shared_timed_mutex; + values = { + v = 201402; + cxxmin = 14; + hosted = yes; + gthread = yes; + }; +}; + +ftms = { + name = string_udls; + values = { + v = 201304; + cxxmin = 14; + hosted = yes; + }; +}; + +ftms = { + name = addressof_constexpr; + values = { + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 2296. std::addressof should be constexpr + v = 201603; + cxxmin = 17; + }; +}; + +ftms = { + name = any; + values = { + v = 201606; + cxxmin = 17; + }; +}; + +ftms = { + name = apply; + values = { + v = 201603; + cxxmin = 17; + }; +}; + +ftms = { + name = as_const; + values = { + v = 201510; + cxxmin = 17; + }; +}; + +ftms = { + name = atomic_is_always_lock_free; + values = { + v = 201603; + cxxmin = 17; + }; +}; + +ftms = { + name = bool_constant; + values = { + v = 201505; + cxxmin = 17; + }; +}; + +ftms = { + name = byte; + values = { + v = 201603; + cxxmin = 17; + }; +}; + +ftms = { + name = has_unique_object_representations; + values = { + v = 201606; + cxxmin = 17; + extra_cond = "defined(_GLIBCXX_HAVE_BUILTIN_HAS_UNIQ_OBJ_REP)"; + }; +}; + +ftms = { + name = hardware_interference_size; + values = { + v = 201703; + cxxmin = 17; + extra_cond = "defined(__GCC_DESTRUCTIVE_SIZE)"; + }; +}; + +ftms = { + name = invoke; + values = { + v = 201411; + cxxmin = 17; + }; +}; + +ftms = { + name = is_aggregate; + values = { + v = 201703; + cxxmin = 17; + extra_cond = "defined(_GLIBCXX_HAVE_BUILTIN_IS_AGGREGATE)"; + }; +}; + +ftms = { + name = is_invocable; + values = { + v = 201703; + cxxmin = 17; + }; +}; + +ftms = { + name = launder; + values = { + v = 201606; + cxxmin = 17; + extra_cond = "defined(_GLIBCXX_HAVE_BUILTIN_LAUNDER)"; + }; +}; + +ftms = { + name = logical_traits; + values = { + v = 201510; + cxxmin = 17; + }; +}; + +ftms = { + name = make_from_tuple; + values = { + v = 201606; + cxxmin = 17; + }; +}; + +ftms = { + name = not_fn; + values = { + v = 201603; + cxxmin = 17; + }; +}; + +ftms = { + name = type_trait_variable_templates; + values = { + v = 201510; + cxxmin = 17; + }; +}; + +ftms = { + name = variant; + values = { + v = 202106; + cxxmin = 20; + extra_cond = "__cpp_concepts >= 202002L && __cpp_constexpr >= 201811L"; + }; + values = { + v = 202102; + cxxmin = 17; + }; +}; + +ftms = { + // Used in earlier draft of SD6. + name = lcm; + values = { + v = 201606; + cxxmin = 17; + }; +}; + +ftms = { + // Used in earlier draft of SD6. + name = gcd; + values = { + v = 201606; + cxxmin = 17; + }; +}; + +ftms = { + name = gcd_lcm; + values = { + v = 201606; + cxxmin = 17; + }; +}; + +ftms = { + name = raw_memory_algorithms; + values = { + v = 201606; + cxxmin = 17; + }; +}; + +ftms = { + name = array_constexpr; + values = { + v = 201811; + cxxmin = 20; + }; + values = { + v = 201803; + cxxmin = 17; + }; +}; + +ftms = { + name = nonmember_container_access; + values = { + v = 201411; + cxxmin = 17; + }; +}; + +ftms = { + name = clamp; + values = { + v = 201603; + cxxmin = 17; + }; +}; + +ftms = { + name = sample; + values = { + v = 201603; + cxxmin = 17; + }; +}; + +ftms = { + name = boyer_moore_searcher; + values = { + v = 201603; + cxxmin = 17; + hosted = yes; + }; +}; + +ftms = { + name = chrono; + values = { + v = 201907; + cxxmin = 20; + hosted = yes; + }; + values = { + v = 201611; + cxxmin = 17; + hosted = yes; + }; +}; + +ftms = { + name = execution; + values = { + v = 201902; // FIXME: should be 201603L + cxxmin = 17; + hosted = yes; + }; +}; + +ftms = { + name = filesystem; + values = { + v = 201703; + cxxmin = 17; + hosted = yes; + }; +}; + +ftms = { + name = hypot; + values = { + v = 201603; + cxxmin = 17; + hosted = yes; + }; +}; + +ftms = { + name = map_try_emplace; + values = { + v = 201411; + cxxmin = 17; + hosted = yes; + }; +}; + +ftms = { + name = math_special_functions; + values = { + v = 201603; + cxxmin = 17; + hosted = yes; + }; +}; + +ftms = { + name = memory_resource; + values = { + v = 201603; + cxxmin = 17; + hosted = yes; + gthread = yes; + }; + values = { + v = 1; + /* For when there's no gthread. */ + cxxmin = 17; + hosted = yes; + gthread = no; + }; +}; + +ftms = { + name = node_extract; + values = { + v = 201606; + cxxmin = 17; + hosted = yes; + }; +}; + +ftms = { + name = parallel_algorithm; + values = { + v = 201603; + cxxmin = 17; + hosted = yes; + }; +}; + +ftms = { + name = scoped_lock; + values = { + v = 201703; + cxxmin = 17; + hosted = yes; + gthread = yes; + }; +}; + +ftms = { + name = shared_mutex; + values = { + v = 201505; + cxxmin = 17; + hosted = yes; + gthread = yes; + }; +}; + +ftms = { + name = shared_ptr_weak_type; + values = { + v = 201606; + cxxmin = 17; + hosted = yes; + }; +}; + +ftms = { + name = string_view; + values = { + v = 201803; + cxxmin = 17; + hosted = yes; + }; +}; + +ftms = { + name = unordered_map_try_emplace; + values = { + v = 201411; + cxxmin = 17; + hosted = yes; + }; +}; + +ftms = { + name = assume_aligned; + values = { + v = 201811; + cxxmin = 20; + }; +}; + +ftms = { + name = atomic_flag_test; + values = { + v = 201907; + cxxmin = 20; + }; +}; + +ftms = { + name = atomic_float; + values = { + v = 201711; + cxxmin = 20; + }; +}; + +ftms = { + name = atomic_lock_free_type_aliases; + values = { + v = 201907; + cxxmin = 20; + }; +}; + +ftms = { + name = atomic_ref; + values = { + v = 201806; + cxxmin = 20; + }; +}; + +ftms = { + name = atomic_value_initialization; + values = { + v = 201911; + cxxmin = 20; + }; +}; + +ftms = { + name = bind_front; + values = { + v = 201907; + cxxmin = 20; + }; +}; + +ftms = { + name = starts_ends_with; + values = { + v = 201711; + cxxmin = 20; + }; +}; + +ftms = { + name = bit_cast; + values = { + v = 201806; + cxxmin = 20; + extra_cond = "__has_builtin(__builtin_bit_cast)"; + }; +}; + +ftms = { + name = bitops; + values = { + v = 201907; + cxxmin = 20; + }; +}; + +ftms = { + name = bounded_array_traits; + values = { + v = 201902; + cxxmin = 20; + }; +}; + +ftms = { + name = concepts; + values = { + v = 202002; + cxxmin = 20; + extra_cond = "__cpp_concepts >= 201907L"; + }; +}; + +// Moved down here (after concepts) by topological sort. +ftms = { + name = optional; + values = { + v = 202110; + cxxmin = 23; + extra_cond = "__glibcxx_concepts"; + }; + values = { + v = 202106; + cxxmin = 20; + }; + values = { + v = 201606; + cxxmin = 17; + }; +}; + +ftms = { + name = destroying_delete; + values = { + v = 201806; + cxxmin = 20; + extra_cond = "__cpp_impl_destroying_delete"; + }; +}; + +ftms = { + name = constexpr_string_view; + values = { + v = 201811; + cxxmin = 20; + }; +}; + +ftms = { + name = endian; + values = { + v = 201907; + cxxmin = 20; + }; +}; + +ftms = { + name = int_pow2; + values = { + v = 202002; + cxxmin = 20; + }; +}; + +ftms = { + name = integer_comparison_functions; + values = { + v = 202002; + cxxmin = 20; + }; +}; + +ftms = { + name = is_constant_evaluated; + values = { + v = 201811; + cxxmin = 20; + extra_cond = "defined(_GLIBCXX_HAVE_IS_CONSTANT_EVALUATED)"; + }; +}; + +// Moved down here (after is_constant_evaluated) by topological sort. +ftms = { + name = constexpr_char_traits; + values = { + // Unofficial macro indicating P1032R1 support in C++20 + v = 201811; + cxxmin = 20; + extra_cond = "defined(__glibcxx_is_constant_evaluated)"; + }; + values = { + // Unofficial macro indicating P0426R1 support in C++17 + v = 201611; + cxxmin = 17; + extra_cond = "_GLIBCXX_HAVE_IS_CONSTANT_EVALUATED"; + }; +}; + +ftms = { + name = is_layout_compatible; + values = { + v = 201907; + cxxmin = 20; + extra_cond = "__has_builtin(__is_layout_compatible) " + "&& __has_builtin(__builtin_is_corresponding_member)"; + }; +}; + +ftms = { + name = is_nothrow_convertible; + values = { + v = 201806; + cxxmin = 20; + }; +}; + +ftms = { + name = is_pointer_interconvertible; + values = { + v = 201907; + cxxmin = 20; + extra_cond = + "__has_builtin(__is_pointer_interconvertible_base_of) " + "&& __has_builtin(__builtin_is_pointer_interconvertible_with_class)"; + }; +}; + +ftms = { + name = math_constants; + values = { + v = 201907; + cxxmin = 20; + }; +}; + +ftms = { + name = make_obj_using_allocator; + values = { + // Not specified by C++20, used internally + v = 201811; + cxxmin = 20; + extra_cond = "__cpp_concepts"; + }; +}; + +ftms = { + name = remove_cvref; + values = { + v = 201711; + cxxmin = 20; + }; +}; + +ftms = { + name = source_location; + values = { + v = 201907; + cxxmin = 20; + extra_cond = "__has_builtin(__builtin_source_location)"; + }; +}; + +ftms = { + name = span; + values = { + v = 202002; + cxxmin = 20; + extra_cond = "__glibcxx_concepts"; + }; +}; + +ftms = { + name = ssize; + values = { + v = 201902; + cxxmin = 20; + }; +}; + +ftms = { + name = three_way_comparison; + values = { + v = 201907; + cxxmin = 20; + extra_cond = "__cpp_impl_three_way_comparison >= 201907L " + "&& __glibcxx_concepts"; + }; +}; + +ftms = { + name = to_address; + values = { + v = 201711; + cxxmin = 20; + }; +}; + +ftms = { + name = to_array; + values = { + v = 201907; + cxxmin = 20; + extra_cond = "__cpp_generic_lambdas >= 201707L"; + }; +}; + +ftms = { + name = type_identity; + values = { + v = 201806; + cxxmin = 20; + }; +}; + +ftms = { + name = unwrap_ref; + values = { + v = 201811; + cxxmin = 20; + }; +}; + +ftms = { + name = constexpr_iterator; + values = { + v = 201811; + cxxmin = 20; + }; +}; + +ftms = { + name = interpolate; + values = { + v = 201902; + cxxmin = 20; + }; +}; + +ftms = { + name = constexpr_utility; + values = { + v = 201811; + cxxmin = 20; + }; +}; + +ftms = { + name = shift; + values = { + v = 201806; + cxxmin = 20; + }; +}; + +ftms = { + name = ranges; + values = { + v = 202202; + cxxmin = 23; + extra_cond = "__glibcxx_concepts"; + }; + values = { + v = 202110; + cxxmin = 20; + extra_cond = "__glibcxx_concepts"; + }; +}; + +ftms = { + name = constexpr_numeric; + values = { + v = 201911; + cxxmin = 20; + }; +}; + +ftms = { + name = constexpr_functional; + values = { + v = 201907; + cxxmin = 20; + }; +}; + +ftms = { + name = constexpr_algorithms; + values = { + v = 201806; + cxxmin = 20; + }; +}; + +ftms = { + name = constexpr_tuple; + values = { + v = 201811; + cxxmin = 20; + }; +}; + +ftms = { + name = constexpr_memory; + values = { + v = 202202; + cxxmin = 23; + extra_cond = "__cpp_constexpr_dynamic_alloc"; + }; + values = { + v = 201811; + cxxmin = 20; + }; +}; + +ftms = { + name = atomic_shared_ptr; + values = { + v = 201711; + cxxmin = 20; + hosted = yes; + }; +}; + +ftms = { + name = atomic_wait; + // atomic_wait is available if either futexes or gthread are. + values = { + v = 201907; + cxxmin = 20; + hosted = yes; + gthread = yes; + }; + values = { + v = 201907; + cxxmin = 20; + hosted = yes; + gthread = no; + extra_cond = "defined(_GLIBCXX_HAVE_LINUX_FUTEX)"; + }; +}; + +ftms = { + name = barrier; + values = { + v = 201907; + cxxmin = 20; + // This condition carries in the hosted&&(futex||gthread) logic from above. + extra_cond = "__cpp_aligned_new && __glibcxx_atomic_wait"; + }; +}; + +ftms = { + // 201907 Text Formatting, Integration of chrono, printf corner cases. + // 202106 std::format improvements. + // 202110 Fixing locale handling in chrono formatters, generator-like types. + // 202207 Encodings in localized formatting of chrono, basic-format-string. + // 202207 P2286R8 Formatting Ranges + // 202207 P2585R1 Improving default container formatting + // TODO: #define __cpp_lib_format_ranges 202207L + name = format; + values = { + v = 202106; + cxxmin = 20; + hosted = yes; + }; +}; + +// #undef __glibcxx_chrono +// #define __glibcxx_chrono 201907L +// FIXME: #define __glibcxx_execution 201902L + +ftms = { + name = constexpr_complex; + values = { + v = 201711; + cxxmin = 20; + hosted = yes; + }; +}; + +ftms = { + name = constexpr_dynamic_alloc; + values = { + v = 201907; + cxxmin = 20; + hosted = yes; + }; +}; + +ftms = { + name = constexpr_string; + values = { + v = 201907; + cxxmin = 20; + hosted = yes; + cxx11abi = yes; + extra_cond = "defined(__glibcxx_is_constant_evaluated)"; + }; + values = { + v = 201811; + cxxmin = 20; + hosted = yes; + cxx11abi = no; + extra_cond = "defined(__glibcxx_is_constant_evaluated)"; + }; + values = { + v = 201611; + cxxmin = 17; + hosted = yes; + extra_cond = "_GLIBCXX_HAVE_IS_CONSTANT_EVALUATED"; + }; +}; + +ftms = { + name = constexpr_vector; + values = { + v = 201907; + cxxmin = 20; + hosted = yes; + }; +}; + +ftms = { + name = erase_if; + values = { + v = 202002; + cxxmin = 20; + hosted = yes; + }; +}; + +ftms = { + name = generic_unordered_lookup; + values = { + v = 201811; + cxxmin = 20; + hosted = yes; + }; +}; + +ftms = { + name = jthread; + values = { + v = 201911; + gthread = yes; + hosted = yes; + cxxmin = 20; + }; +}; + +ftms = { + name = latch; + values = { + v = 201907; + cxxmin = 20; + extra_cond = "__glibcxx_atomic_wait"; + }; +}; + +ftms = { + name = list_remove_return_type; + values = { + v = 201806; + cxxmin = 20; + hosted = yes; + }; +}; + +ftms = { + name = polymorphic_allocator; + values = { + v = 201902; + cxxmin = 20; + hosted = yes; + }; +}; + +ftms = { + name = move_iterator_concept; + values = { + v = 202207; + // This is P2520R0, a C++23 change, but we treat it as a DR against C++20. + cxxmin = 20; + extra_cond = "__glibcxx_concepts"; + }; +}; + +ftms = { + name = semaphore; + values = { + v = 201907; + cxxmin = 20; + hosted = yes; + extra_cond = "__glibcxx_atomic_wait || _GLIBCXX_HAVE_POSIX_SEMAPHORE"; + }; +}; + +ftms = { + name = smart_ptr_for_overwrite; + values = { + v = 202002; + cxxmin = 20; + hosted = yes; + }; +}; + +ftms = { + name = syncbuf; + values = { + v = 201803; + cxxmin = 20; + hosted = yes; + cxx11abi = yes; + }; +}; + +ftms = { + name = byteswap; + values = { + v = 202110; + cxxmin = 23; + }; +}; + +ftms = { + name = constexpr_charconv; + values = { + v = 202207; + cxxmin = 23; + }; +}; + +ftms = { + name = constexpr_typeinfo; + values = { + v = 202106; + cxxmin = 23; + }; +}; + +ftms = { + name = expected; + values = { + v = 202211; + cxxmin = 23; + extra_cond = "__cpp_concepts >= 202002L"; + }; +}; + +ftms = { + name = invoke_r; + values = { + v = 202106; + cxxmin = 23; + }; +}; + +ftms = { + name = is_scoped_enum; + values = { + v = 202011; + cxxmin = 23; + }; +}; + +ftms = { + name = reference_from_temporary; + values = { + v = 202202; + extra_cond = + "__has_builtin(__reference_constructs_from_temporary) " + "&& __has_builtin(__reference_converts_from_temporary)"; + cxxmin = 23; + }; +}; + +ftms = { + name = to_underlying; + values = { + v = 202102; + cxxmin = 23; + }; +}; + +ftms = { + name = unreachable; + values = { + v = 202202; + cxxmin = 23; + }; +}; + +ftms = { + name = ranges_zip; + values = { + v = 202110; + cxxmin = 23; + }; +}; + +ftms = { + name = ranges_chunk; + values = { + v = 202202; + cxxmin = 23; + }; +}; + +ftms = { + name = ranges_slide; + values = { + v = 202202; + cxxmin = 23; + }; +}; + +ftms = { + name = ranges_chunk_by; + values = { + v = 202202; + cxxmin = 23; + }; +}; + +ftms = { + name = ranges_join_with; + values = { + v = 202202; + cxxmin = 23; + }; +}; + +ftms = { + name = ranges_repeat; + values = { + v = 202207; + cxxmin = 23; + }; +}; + +ftms = { + name = ranges_stride; + values = { + v = 202207; + cxxmin = 23; + }; +}; + +ftms = { + name = ranges_cartesian_product; + values = { + v = 202207; + cxxmin = 23; + }; +}; + +ftms = { + name = ranges_as_rvalue; + values = { + v = 202207; + cxxmin = 23; + }; +}; + +ftms = { + name = ranges_as_const; + values = { + v = 202207; + cxxmin = 23; + }; +}; + +ftms = { + name = ranges_enumerate; + values = { + v = 202302; + cxxmin = 23; + }; +}; + +ftms = { + name = ranges_fold; + values = { + v = 202207; + cxxmin = 23; + }; +}; + +ftms = { + name = ranges_contains; + values = { + v = 202207; + cxxmin = 23; + }; +}; + +ftms = { + name = ranges_iota; + values = { + v = 202202; + cxxmin = 23; + }; +}; + +ftms = { + name = ranges_find_last; + values = { + v = 202207; + cxxmin = 23; + }; +}; + +ftms = { + name = constexpr_bitset; + values = { + v = 202202; + cxxmin = 23; + hosted = yes; + extra_cond = "__cpp_constexpr_dynamic_alloc"; + }; +}; + +ftms = { + name = stdatomic_h; + values = { + v = 202011; + cxxmin = 23; + }; +}; + +ftms = { + name = adaptor_iterator_pair_constructor; + values = { + v = 202106; + cxxmin = 23; + hosted = yes; + }; +}; + +ftms = { + name = ios_noreplace; + values = { + v = 202207; + cxxmin = 23; + hosted = yes; + }; +}; + +ftms = { + name = move_only_function; + values = { + v = 202110; + cxxmin = 23; + hosted = yes; + }; +}; + +ftms = { + name = spanstream; + values = { + v = 202106; + cxxmin = 23; + hosted = yes; + extra_cond = "__glibcxx_span"; + }; +}; + +ftms = { + name = stacktrace; + values = { + v = 202011; + cxxmin = 23; + hosted = yes; + extra_cond = "_GLIBCXX_HAVE_STACKTRACE"; + }; +}; + +ftms = { + name = string_contains; + values = { + v = 202011; + cxxmin = 23; + hosted = yes; + }; +}; + +ftms = { + name = string_resize_and_overwrite; + values = { + v = 202110; + cxxmin = 23; + hosted = yes; + }; +}; + +ftms = { + name = ratio; + values = { + v = 202306; + cxxmin = 26; + }; +}; + +ftms = { + name = to_string; + values = { + v = 202306; + cxxmin = 26; + hosted = yes; + extra_cond = "__glibcxx_to_chars"; + }; +}; + +// Standard test specifications. +stds[97] = ">= 199711L"; +stds[03] = ">= 199711L"; +stds[11] = ">= 201103L"; +stds[14] = ">= 201402L"; +stds[17] = ">= 201703L"; +stds[20] = ">= 202002L"; +stds[23] = ">= 202302L"; +stds[26] = "> 202302L"; // TODO: update when finalized + +// Local Variables: +// compile-command: "autogen version.def" +// End: diff --git a/libstdc++-v3/include/bits/version.h b/libstdc++-v3/include/bits/version.h new file mode 100644 index 000000000000..5bddb4b8adc6 --- /dev/null +++ b/libstdc++-v3/include/bits/version.h @@ -0,0 +1,1964 @@ +// Copyright (C) 2023 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 +// . + +// DO NOT EDIT THIS FILE (version.h) +// +// It has been AutoGen-ed +// From the definitions version.def +// and the template file version.tpl + +/** @file bits/version.h + * This is an internal header file, included by other library headers. + * Do not attempt to use it directly. @headername{version} + */ + +// Usage guide: +// +// In your usual header, do something like: +// +// #define __glibcxx_want_ranges +// #define __glibcxx_want_concepts +// #include +// +// This will generate the FTMs you named, and let you use them in your code as +// if it was user code. All macros are also exposed under __glibcxx_NAME even +// if unwanted, to permit bits and other FTMs to depend on them for condtional +// computation without exposing extra FTMs to user code. + +#pragma GCC system_header + +#include + +// from version.def line 65 +#if !defined(__cpp_lib_incomplete_container_elements) +# if _GLIBCXX_HOSTED +# define __glibcxx_incomplete_container_elements 201505L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_incomplete_container_elements) +# define __cpp_lib_incomplete_container_elements 201505L +# endif +# endif +#endif /* !defined(__cpp_lib_incomplete_container_elements) && defined(__glibcxx_want_incomplete_container_elements) */ +#undef __glibcxx_want_incomplete_container_elements + +// from version.def line 73 +#if !defined(__cpp_lib_uncaught_exceptions) +# if ((defined(__STRICT_ANSI__) && __cplusplus >= 201703L) || (!defined(__STRICT_ANSI__) && __cplusplus >= 199711L)) +# define __glibcxx_uncaught_exceptions 201411L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_uncaught_exceptions) +# define __cpp_lib_uncaught_exceptions 201411L +# endif +# endif +#endif /* !defined(__cpp_lib_uncaught_exceptions) && defined(__glibcxx_want_uncaught_exceptions) */ +#undef __glibcxx_want_uncaught_exceptions + +// from version.def line 82 +#if !defined(__cpp_lib_allocator_traits_is_always_equal) +# if (__cplusplus >= 201103L) +# define __glibcxx_allocator_traits_is_always_equal 201411L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_allocator_traits_is_always_equal) +# define __cpp_lib_allocator_traits_is_always_equal 201411L +# endif +# endif +#endif /* !defined(__cpp_lib_allocator_traits_is_always_equal) && defined(__glibcxx_want_allocator_traits_is_always_equal) */ +#undef __glibcxx_want_allocator_traits_is_always_equal + +// from version.def line 90 +#if !defined(__cpp_lib_is_null_pointer) +# if (__cplusplus >= 201103L) +# define __glibcxx_is_null_pointer 201309L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_is_null_pointer) +# define __cpp_lib_is_null_pointer 201309L +# endif +# endif +#endif /* !defined(__cpp_lib_is_null_pointer) && defined(__glibcxx_want_is_null_pointer) */ +#undef __glibcxx_want_is_null_pointer + +// from version.def line 98 +#if !defined(__cpp_lib_result_of_sfinae) +# if (__cplusplus >= 201103L) +# define __glibcxx_result_of_sfinae 201210L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_result_of_sfinae) +# define __cpp_lib_result_of_sfinae 201210L +# endif +# endif +#endif /* !defined(__cpp_lib_result_of_sfinae) && defined(__glibcxx_want_result_of_sfinae) */ +#undef __glibcxx_want_result_of_sfinae + +// from version.def line 106 +#if !defined(__cpp_lib_shared_ptr_arrays) +# if (__cplusplus >= 202002L) && _GLIBCXX_HOSTED +# define __glibcxx_shared_ptr_arrays 201707L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_shared_ptr_arrays) +# define __cpp_lib_shared_ptr_arrays 201707L +# endif +# elif (__cplusplus >= 201103L) && _GLIBCXX_HOSTED +# define __glibcxx_shared_ptr_arrays 201611L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_shared_ptr_arrays) +# define __cpp_lib_shared_ptr_arrays 201611L +# endif +# endif +#endif /* !defined(__cpp_lib_shared_ptr_arrays) && defined(__glibcxx_want_shared_ptr_arrays) */ +#undef __glibcxx_want_shared_ptr_arrays + +// from version.def line 120 +#if !defined(__cpp_lib_is_swappable) +# if ((defined(__STRICT_ANSI__) && __cplusplus >= 201703L) || (!defined(__STRICT_ANSI__) && __cplusplus >= 201103L)) +# define __glibcxx_is_swappable 201603L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_is_swappable) +# define __cpp_lib_is_swappable 201603L +# endif +# endif +#endif /* !defined(__cpp_lib_is_swappable) && defined(__glibcxx_want_is_swappable) */ +#undef __glibcxx_want_is_swappable + +// from version.def line 129 +#if !defined(__cpp_lib_void_t) +# if ((defined(__STRICT_ANSI__) && __cplusplus >= 201703L) || (!defined(__STRICT_ANSI__) && __cplusplus >= 201103L)) +# define __glibcxx_void_t 201411L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_void_t) +# define __cpp_lib_void_t 201411L +# endif +# endif +#endif /* !defined(__cpp_lib_void_t) && defined(__glibcxx_want_void_t) */ +#undef __glibcxx_want_void_t + +// from version.def line 138 +#if !defined(__cpp_lib_enable_shared_from_this) +# if ((defined(__STRICT_ANSI__) && __cplusplus >= 201703L) || (!defined(__STRICT_ANSI__) && __cplusplus >= 201103L)) && _GLIBCXX_HOSTED +# define __glibcxx_enable_shared_from_this 201603L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_enable_shared_from_this) +# define __cpp_lib_enable_shared_from_this 201603L +# endif +# endif +#endif /* !defined(__cpp_lib_enable_shared_from_this) && defined(__glibcxx_want_enable_shared_from_this) */ +#undef __glibcxx_want_enable_shared_from_this + +// from version.def line 148 +#if !defined(__cpp_lib_math_spec_funcs) +# if (__cplusplus >= 201103L) +# define __glibcxx_math_spec_funcs 201003L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_math_spec_funcs) +# define __STDCPP_MATH_SPEC_FUNCS__ 201003L +# endif +# endif +#endif /* !defined(__cpp_lib_math_spec_funcs) && defined(__glibcxx_want_math_spec_funcs) */ +#undef __glibcxx_want_math_spec_funcs + +// from version.def line 157 +#if !defined(__cpp_lib_coroutine) +# if (__cplusplus >= 201402L) && (__cpp_impl_coroutine) +# define __glibcxx_coroutine 201902L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_coroutine) +# define __cpp_lib_coroutine 201902L +# endif +# endif +#endif /* !defined(__cpp_lib_coroutine) && defined(__glibcxx_want_coroutine) */ +#undef __glibcxx_want_coroutine + +// from version.def line 168 +#if !defined(__cpp_lib_exchange_function) +# if (__cplusplus >= 201402L) +# define __glibcxx_exchange_function 201304L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_exchange_function) +# define __cpp_lib_exchange_function 201304L +# endif +# endif +#endif /* !defined(__cpp_lib_exchange_function) && defined(__glibcxx_want_exchange_function) */ +#undef __glibcxx_want_exchange_function + +// from version.def line 176 +#if !defined(__cpp_lib_integer_sequence) +# if (__cplusplus >= 201402L) +# define __glibcxx_integer_sequence 201304L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_integer_sequence) +# define __cpp_lib_integer_sequence 201304L +# endif +# endif +#endif /* !defined(__cpp_lib_integer_sequence) && defined(__glibcxx_want_integer_sequence) */ +#undef __glibcxx_want_integer_sequence + +// from version.def line 184 +#if !defined(__cpp_lib_integral_constant_callable) +# if (__cplusplus >= 201402L) +# define __glibcxx_integral_constant_callable 201304L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_integral_constant_callable) +# define __cpp_lib_integral_constant_callable 201304L +# endif +# endif +#endif /* !defined(__cpp_lib_integral_constant_callable) && defined(__glibcxx_want_integral_constant_callable) */ +#undef __glibcxx_want_integral_constant_callable + +// from version.def line 192 +#if !defined(__cpp_lib_is_final) +# if (__cplusplus >= 201402L) +# define __glibcxx_is_final 201402L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_is_final) +# define __cpp_lib_is_final 201402L +# endif +# endif +#endif /* !defined(__cpp_lib_is_final) && defined(__glibcxx_want_is_final) */ +#undef __glibcxx_want_is_final + +// from version.def line 200 +#if !defined(__cpp_lib_make_reverse_iterator) +# if (__cplusplus >= 201402L) +# define __glibcxx_make_reverse_iterator 201402L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_make_reverse_iterator) +# define __cpp_lib_make_reverse_iterator 201402L +# endif +# endif +#endif /* !defined(__cpp_lib_make_reverse_iterator) && defined(__glibcxx_want_make_reverse_iterator) */ +#undef __glibcxx_want_make_reverse_iterator + +// from version.def line 208 +#if !defined(__cpp_lib_null_iterators) +# if (__cplusplus >= 201402L) && (!defined(_GLIBCXX_DEBUG)) +# define __glibcxx_null_iterators 201304L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_null_iterators) +# define __cpp_lib_null_iterators 201304L +# endif +# endif +#endif /* !defined(__cpp_lib_null_iterators) && defined(__glibcxx_want_null_iterators) */ +#undef __glibcxx_want_null_iterators + +// from version.def line 217 +#if !defined(__cpp_lib_transformation_trait_aliases) +# if (__cplusplus >= 201402L) +# define __glibcxx_transformation_trait_aliases 201304L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_transformation_trait_aliases) +# define __cpp_lib_transformation_trait_aliases 201304L +# endif +# endif +#endif /* !defined(__cpp_lib_transformation_trait_aliases) && defined(__glibcxx_want_transformation_trait_aliases) */ +#undef __glibcxx_want_transformation_trait_aliases + +// from version.def line 225 +#if !defined(__cpp_lib_transparent_operators) +# if (__cplusplus >= 201402L) +# define __glibcxx_transparent_operators 201510L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_transparent_operators) +# define __cpp_lib_transparent_operators 201510L +# endif +# endif +#endif /* !defined(__cpp_lib_transparent_operators) && defined(__glibcxx_want_transparent_operators) */ +#undef __glibcxx_want_transparent_operators + +// from version.def line 233 +#if !defined(__cpp_lib_tuple_element_t) +# if (__cplusplus >= 201402L) +# define __glibcxx_tuple_element_t 201402L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_tuple_element_t) +# define __cpp_lib_tuple_element_t 201402L +# endif +# endif +#endif /* !defined(__cpp_lib_tuple_element_t) && defined(__glibcxx_want_tuple_element_t) */ +#undef __glibcxx_want_tuple_element_t + +// from version.def line 241 +#if !defined(__cpp_lib_tuples_by_type) +# if (__cplusplus >= 201402L) +# define __glibcxx_tuples_by_type 201304L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_tuples_by_type) +# define __cpp_lib_tuples_by_type 201304L +# endif +# endif +#endif /* !defined(__cpp_lib_tuples_by_type) && defined(__glibcxx_want_tuples_by_type) */ +#undef __glibcxx_want_tuples_by_type + +// from version.def line 249 +#if !defined(__cpp_lib_robust_nonmodifying_seq_ops) +# if (__cplusplus >= 201402L) +# define __glibcxx_robust_nonmodifying_seq_ops 201304L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_robust_nonmodifying_seq_ops) +# define __cpp_lib_robust_nonmodifying_seq_ops 201304L +# endif +# endif +#endif /* !defined(__cpp_lib_robust_nonmodifying_seq_ops) && defined(__glibcxx_want_robust_nonmodifying_seq_ops) */ +#undef __glibcxx_want_robust_nonmodifying_seq_ops + +// from version.def line 257 +#if !defined(__cpp_lib_to_chars) +# if (__cplusplus >= 201402L) && (_GLIBCXX_FLOAT_IS_IEEE_BINARY32 && _GLIBCXX_DOUBLE_IS_IEEE_BINARY64 && __SIZE_WIDTH__ >= 32) +# define __glibcxx_to_chars 201611L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_to_chars) +# define __cpp_lib_to_chars 201611L +# endif +# endif +#endif /* !defined(__cpp_lib_to_chars) && defined(__glibcxx_want_to_chars) */ +#undef __glibcxx_want_to_chars + +// from version.def line 268 +#if !defined(__cpp_lib_chrono_udls) +# if (__cplusplus >= 201402L) && _GLIBCXX_HOSTED +# define __glibcxx_chrono_udls 201304L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_chrono_udls) +# define __cpp_lib_chrono_udls 201304L +# endif +# endif +#endif /* !defined(__cpp_lib_chrono_udls) && defined(__glibcxx_want_chrono_udls) */ +#undef __glibcxx_want_chrono_udls + +// from version.def line 277 +#if !defined(__cpp_lib_complex_udls) +# if (__cplusplus >= 201402L) && _GLIBCXX_HOSTED +# define __glibcxx_complex_udls 201309L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_complex_udls) +# define __cpp_lib_complex_udls 201309L +# endif +# endif +#endif /* !defined(__cpp_lib_complex_udls) && defined(__glibcxx_want_complex_udls) */ +#undef __glibcxx_want_complex_udls + +// from version.def line 286 +#if !defined(__cpp_lib_generic_associative_lookup) +# if (__cplusplus >= 201402L) && _GLIBCXX_HOSTED +# define __glibcxx_generic_associative_lookup 201304L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_generic_associative_lookup) +# define __cpp_lib_generic_associative_lookup 201304L +# endif +# endif +#endif /* !defined(__cpp_lib_generic_associative_lookup) && defined(__glibcxx_want_generic_associative_lookup) */ +#undef __glibcxx_want_generic_associative_lookup + +// from version.def line 295 +#if !defined(__cpp_lib_make_unique) +# if (__cplusplus >= 201402L) && _GLIBCXX_HOSTED +# define __glibcxx_make_unique 201304L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_make_unique) +# define __cpp_lib_make_unique 201304L +# endif +# endif +#endif /* !defined(__cpp_lib_make_unique) && defined(__glibcxx_want_make_unique) */ +#undef __glibcxx_want_make_unique + +// from version.def line 304 +#if !defined(__cpp_lib_quoted_string_io) +# if (__cplusplus >= 201402L) && _GLIBCXX_HOSTED +# define __glibcxx_quoted_string_io 201304L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_quoted_string_io) +# define __cpp_lib_quoted_string_io 201304L +# endif +# endif +#endif /* !defined(__cpp_lib_quoted_string_io) && defined(__glibcxx_want_quoted_string_io) */ +#undef __glibcxx_want_quoted_string_io + +// from version.def line 313 +#if !defined(__cpp_lib_shared_timed_mutex) +# if (__cplusplus >= 201402L) && defined(_GLIBCXX_HAS_GTHREADS) && _GLIBCXX_HOSTED +# define __glibcxx_shared_timed_mutex 201402L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_shared_timed_mutex) +# define __cpp_lib_shared_timed_mutex 201402L +# endif +# endif +#endif /* !defined(__cpp_lib_shared_timed_mutex) && defined(__glibcxx_want_shared_timed_mutex) */ +#undef __glibcxx_want_shared_timed_mutex + +// from version.def line 323 +#if !defined(__cpp_lib_string_udls) +# if (__cplusplus >= 201402L) && _GLIBCXX_HOSTED +# define __glibcxx_string_udls 201304L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_string_udls) +# define __cpp_lib_string_udls 201304L +# endif +# endif +#endif /* !defined(__cpp_lib_string_udls) && defined(__glibcxx_want_string_udls) */ +#undef __glibcxx_want_string_udls + +// from version.def line 332 +#if !defined(__cpp_lib_addressof_constexpr) +# if (__cplusplus >= 201703L) +# define __glibcxx_addressof_constexpr 201603L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_addressof_constexpr) +# define __cpp_lib_addressof_constexpr 201603L +# endif +# endif +#endif /* !defined(__cpp_lib_addressof_constexpr) && defined(__glibcxx_want_addressof_constexpr) */ +#undef __glibcxx_want_addressof_constexpr + +// from version.def line 342 +#if !defined(__cpp_lib_any) +# if (__cplusplus >= 201703L) +# define __glibcxx_any 201606L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_any) +# define __cpp_lib_any 201606L +# endif +# endif +#endif /* !defined(__cpp_lib_any) && defined(__glibcxx_want_any) */ +#undef __glibcxx_want_any + +// from version.def line 350 +#if !defined(__cpp_lib_apply) +# if (__cplusplus >= 201703L) +# define __glibcxx_apply 201603L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_apply) +# define __cpp_lib_apply 201603L +# endif +# endif +#endif /* !defined(__cpp_lib_apply) && defined(__glibcxx_want_apply) */ +#undef __glibcxx_want_apply + +// from version.def line 358 +#if !defined(__cpp_lib_as_const) +# if (__cplusplus >= 201703L) +# define __glibcxx_as_const 201510L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_as_const) +# define __cpp_lib_as_const 201510L +# endif +# endif +#endif /* !defined(__cpp_lib_as_const) && defined(__glibcxx_want_as_const) */ +#undef __glibcxx_want_as_const + +// from version.def line 366 +#if !defined(__cpp_lib_atomic_is_always_lock_free) +# if (__cplusplus >= 201703L) +# define __glibcxx_atomic_is_always_lock_free 201603L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_atomic_is_always_lock_free) +# define __cpp_lib_atomic_is_always_lock_free 201603L +# endif +# endif +#endif /* !defined(__cpp_lib_atomic_is_always_lock_free) && defined(__glibcxx_want_atomic_is_always_lock_free) */ +#undef __glibcxx_want_atomic_is_always_lock_free + +// from version.def line 374 +#if !defined(__cpp_lib_bool_constant) +# if (__cplusplus >= 201703L) +# define __glibcxx_bool_constant 201505L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_bool_constant) +# define __cpp_lib_bool_constant 201505L +# endif +# endif +#endif /* !defined(__cpp_lib_bool_constant) && defined(__glibcxx_want_bool_constant) */ +#undef __glibcxx_want_bool_constant + +// from version.def line 382 +#if !defined(__cpp_lib_byte) +# if (__cplusplus >= 201703L) +# define __glibcxx_byte 201603L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_byte) +# define __cpp_lib_byte 201603L +# endif +# endif +#endif /* !defined(__cpp_lib_byte) && defined(__glibcxx_want_byte) */ +#undef __glibcxx_want_byte + +// from version.def line 390 +#if !defined(__cpp_lib_has_unique_object_representations) +# if (__cplusplus >= 201703L) && (defined(_GLIBCXX_HAVE_BUILTIN_HAS_UNIQ_OBJ_REP)) +# define __glibcxx_has_unique_object_representations 201606L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_has_unique_object_representations) +# define __cpp_lib_has_unique_object_representations 201606L +# endif +# endif +#endif /* !defined(__cpp_lib_has_unique_object_representations) && defined(__glibcxx_want_has_unique_object_representations) */ +#undef __glibcxx_want_has_unique_object_representations + +// from version.def line 399 +#if !defined(__cpp_lib_hardware_interference_size) +# if (__cplusplus >= 201703L) && (defined(__GCC_DESTRUCTIVE_SIZE)) +# define __glibcxx_hardware_interference_size 201703L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_hardware_interference_size) +# define __cpp_lib_hardware_interference_size 201703L +# endif +# endif +#endif /* !defined(__cpp_lib_hardware_interference_size) && defined(__glibcxx_want_hardware_interference_size) */ +#undef __glibcxx_want_hardware_interference_size + +// from version.def line 408 +#if !defined(__cpp_lib_invoke) +# if (__cplusplus >= 201703L) +# define __glibcxx_invoke 201411L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_invoke) +# define __cpp_lib_invoke 201411L +# endif +# endif +#endif /* !defined(__cpp_lib_invoke) && defined(__glibcxx_want_invoke) */ +#undef __glibcxx_want_invoke + +// from version.def line 416 +#if !defined(__cpp_lib_is_aggregate) +# if (__cplusplus >= 201703L) && (defined(_GLIBCXX_HAVE_BUILTIN_IS_AGGREGATE)) +# define __glibcxx_is_aggregate 201703L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_is_aggregate) +# define __cpp_lib_is_aggregate 201703L +# endif +# endif +#endif /* !defined(__cpp_lib_is_aggregate) && defined(__glibcxx_want_is_aggregate) */ +#undef __glibcxx_want_is_aggregate + +// from version.def line 425 +#if !defined(__cpp_lib_is_invocable) +# if (__cplusplus >= 201703L) +# define __glibcxx_is_invocable 201703L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_is_invocable) +# define __cpp_lib_is_invocable 201703L +# endif +# endif +#endif /* !defined(__cpp_lib_is_invocable) && defined(__glibcxx_want_is_invocable) */ +#undef __glibcxx_want_is_invocable + +// from version.def line 433 +#if !defined(__cpp_lib_launder) +# if (__cplusplus >= 201703L) && (defined(_GLIBCXX_HAVE_BUILTIN_LAUNDER)) +# define __glibcxx_launder 201606L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_launder) +# define __cpp_lib_launder 201606L +# endif +# endif +#endif /* !defined(__cpp_lib_launder) && defined(__glibcxx_want_launder) */ +#undef __glibcxx_want_launder + +// from version.def line 442 +#if !defined(__cpp_lib_logical_traits) +# if (__cplusplus >= 201703L) +# define __glibcxx_logical_traits 201510L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_logical_traits) +# define __cpp_lib_logical_traits 201510L +# endif +# endif +#endif /* !defined(__cpp_lib_logical_traits) && defined(__glibcxx_want_logical_traits) */ +#undef __glibcxx_want_logical_traits + +// from version.def line 450 +#if !defined(__cpp_lib_make_from_tuple) +# if (__cplusplus >= 201703L) +# define __glibcxx_make_from_tuple 201606L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_make_from_tuple) +# define __cpp_lib_make_from_tuple 201606L +# endif +# endif +#endif /* !defined(__cpp_lib_make_from_tuple) && defined(__glibcxx_want_make_from_tuple) */ +#undef __glibcxx_want_make_from_tuple + +// from version.def line 458 +#if !defined(__cpp_lib_not_fn) +# if (__cplusplus >= 201703L) +# define __glibcxx_not_fn 201603L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_not_fn) +# define __cpp_lib_not_fn 201603L +# endif +# endif +#endif /* !defined(__cpp_lib_not_fn) && defined(__glibcxx_want_not_fn) */ +#undef __glibcxx_want_not_fn + +// from version.def line 466 +#if !defined(__cpp_lib_type_trait_variable_templates) +# if (__cplusplus >= 201703L) +# define __glibcxx_type_trait_variable_templates 201510L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_type_trait_variable_templates) +# define __cpp_lib_type_trait_variable_templates 201510L +# endif +# endif +#endif /* !defined(__cpp_lib_type_trait_variable_templates) && defined(__glibcxx_want_type_trait_variable_templates) */ +#undef __glibcxx_want_type_trait_variable_templates + +// from version.def line 474 +#if !defined(__cpp_lib_variant) +# if (__cplusplus >= 202002L) && (__cpp_concepts >= 202002L && __cpp_constexpr >= 201811L) +# define __glibcxx_variant 202106L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_variant) +# define __cpp_lib_variant 202106L +# endif +# elif (__cplusplus >= 201703L) +# define __glibcxx_variant 202102L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_variant) +# define __cpp_lib_variant 202102L +# endif +# endif +#endif /* !defined(__cpp_lib_variant) && defined(__glibcxx_want_variant) */ +#undef __glibcxx_want_variant + +// from version.def line 488 +#if !defined(__cpp_lib_lcm) +# if (__cplusplus >= 201703L) +# define __glibcxx_lcm 201606L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_lcm) +# define __cpp_lib_lcm 201606L +# endif +# endif +#endif /* !defined(__cpp_lib_lcm) && defined(__glibcxx_want_lcm) */ +#undef __glibcxx_want_lcm + +// from version.def line 497 +#if !defined(__cpp_lib_gcd) +# if (__cplusplus >= 201703L) +# define __glibcxx_gcd 201606L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_gcd) +# define __cpp_lib_gcd 201606L +# endif +# endif +#endif /* !defined(__cpp_lib_gcd) && defined(__glibcxx_want_gcd) */ +#undef __glibcxx_want_gcd + +// from version.def line 505 +#if !defined(__cpp_lib_gcd_lcm) +# if (__cplusplus >= 201703L) +# define __glibcxx_gcd_lcm 201606L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_gcd_lcm) +# define __cpp_lib_gcd_lcm 201606L +# endif +# endif +#endif /* !defined(__cpp_lib_gcd_lcm) && defined(__glibcxx_want_gcd_lcm) */ +#undef __glibcxx_want_gcd_lcm + +// from version.def line 513 +#if !defined(__cpp_lib_raw_memory_algorithms) +# if (__cplusplus >= 201703L) +# define __glibcxx_raw_memory_algorithms 201606L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_raw_memory_algorithms) +# define __cpp_lib_raw_memory_algorithms 201606L +# endif +# endif +#endif /* !defined(__cpp_lib_raw_memory_algorithms) && defined(__glibcxx_want_raw_memory_algorithms) */ +#undef __glibcxx_want_raw_memory_algorithms + +// from version.def line 521 +#if !defined(__cpp_lib_array_constexpr) +# if (__cplusplus >= 202002L) +# define __glibcxx_array_constexpr 201811L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_array_constexpr) +# define __cpp_lib_array_constexpr 201811L +# endif +# elif (__cplusplus >= 201703L) +# define __glibcxx_array_constexpr 201803L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_array_constexpr) +# define __cpp_lib_array_constexpr 201803L +# endif +# endif +#endif /* !defined(__cpp_lib_array_constexpr) && defined(__glibcxx_want_array_constexpr) */ +#undef __glibcxx_want_array_constexpr + +// from version.def line 533 +#if !defined(__cpp_lib_nonmember_container_access) +# if (__cplusplus >= 201703L) +# define __glibcxx_nonmember_container_access 201411L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_nonmember_container_access) +# define __cpp_lib_nonmember_container_access 201411L +# endif +# endif +#endif /* !defined(__cpp_lib_nonmember_container_access) && defined(__glibcxx_want_nonmember_container_access) */ +#undef __glibcxx_want_nonmember_container_access + +// from version.def line 541 +#if !defined(__cpp_lib_clamp) +# if (__cplusplus >= 201703L) +# define __glibcxx_clamp 201603L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_clamp) +# define __cpp_lib_clamp 201603L +# endif +# endif +#endif /* !defined(__cpp_lib_clamp) && defined(__glibcxx_want_clamp) */ +#undef __glibcxx_want_clamp + +// from version.def line 549 +#if !defined(__cpp_lib_sample) +# if (__cplusplus >= 201703L) +# define __glibcxx_sample 201603L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_sample) +# define __cpp_lib_sample 201603L +# endif +# endif +#endif /* !defined(__cpp_lib_sample) && defined(__glibcxx_want_sample) */ +#undef __glibcxx_want_sample + +// from version.def line 557 +#if !defined(__cpp_lib_boyer_moore_searcher) +# if (__cplusplus >= 201703L) && _GLIBCXX_HOSTED +# define __glibcxx_boyer_moore_searcher 201603L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_boyer_moore_searcher) +# define __cpp_lib_boyer_moore_searcher 201603L +# endif +# endif +#endif /* !defined(__cpp_lib_boyer_moore_searcher) && defined(__glibcxx_want_boyer_moore_searcher) */ +#undef __glibcxx_want_boyer_moore_searcher + +// from version.def line 566 +#if !defined(__cpp_lib_chrono) +# if (__cplusplus >= 202002L) && _GLIBCXX_HOSTED +# define __glibcxx_chrono 201907L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_chrono) +# define __cpp_lib_chrono 201907L +# endif +# elif (__cplusplus >= 201703L) && _GLIBCXX_HOSTED +# define __glibcxx_chrono 201611L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_chrono) +# define __cpp_lib_chrono 201611L +# endif +# endif +#endif /* !defined(__cpp_lib_chrono) && defined(__glibcxx_want_chrono) */ +#undef __glibcxx_want_chrono + +// from version.def line 580 +#if !defined(__cpp_lib_execution) +# if (__cplusplus >= 201703L) && _GLIBCXX_HOSTED +# define __glibcxx_execution 201902L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_execution) +# define __cpp_lib_execution 201902L +# endif +# endif +#endif /* !defined(__cpp_lib_execution) && defined(__glibcxx_want_execution) */ +#undef __glibcxx_want_execution + +// from version.def line 589 +#if !defined(__cpp_lib_filesystem) +# if (__cplusplus >= 201703L) && _GLIBCXX_HOSTED +# define __glibcxx_filesystem 201703L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_filesystem) +# define __cpp_lib_filesystem 201703L +# endif +# endif +#endif /* !defined(__cpp_lib_filesystem) && defined(__glibcxx_want_filesystem) */ +#undef __glibcxx_want_filesystem + +// from version.def line 598 +#if !defined(__cpp_lib_hypot) +# if (__cplusplus >= 201703L) && _GLIBCXX_HOSTED +# define __glibcxx_hypot 201603L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_hypot) +# define __cpp_lib_hypot 201603L +# endif +# endif +#endif /* !defined(__cpp_lib_hypot) && defined(__glibcxx_want_hypot) */ +#undef __glibcxx_want_hypot + +// from version.def line 607 +#if !defined(__cpp_lib_map_try_emplace) +# if (__cplusplus >= 201703L) && _GLIBCXX_HOSTED +# define __glibcxx_map_try_emplace 201411L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_map_try_emplace) +# define __cpp_lib_map_try_emplace 201411L +# endif +# endif +#endif /* !defined(__cpp_lib_map_try_emplace) && defined(__glibcxx_want_map_try_emplace) */ +#undef __glibcxx_want_map_try_emplace + +// from version.def line 616 +#if !defined(__cpp_lib_math_special_functions) +# if (__cplusplus >= 201703L) && _GLIBCXX_HOSTED +# define __glibcxx_math_special_functions 201603L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_math_special_functions) +# define __cpp_lib_math_special_functions 201603L +# endif +# endif +#endif /* !defined(__cpp_lib_math_special_functions) && defined(__glibcxx_want_math_special_functions) */ +#undef __glibcxx_want_math_special_functions + +// from version.def line 625 +#if !defined(__cpp_lib_memory_resource) +# if (__cplusplus >= 201703L) && defined(_GLIBCXX_HAS_GTHREADS) && _GLIBCXX_HOSTED +# define __glibcxx_memory_resource 201603L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_memory_resource) +# define __cpp_lib_memory_resource 201603L +# endif +# elif (__cplusplus >= 201703L) && !defined(_GLIBCXX_HAS_GTHREADS) && _GLIBCXX_HOSTED +# define __glibcxx_memory_resource 1L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_memory_resource) +# define __cpp_lib_memory_resource 1L +# endif +# endif +#endif /* !defined(__cpp_lib_memory_resource) && defined(__glibcxx_want_memory_resource) */ +#undef __glibcxx_want_memory_resource + +// from version.def line 642 +#if !defined(__cpp_lib_node_extract) +# if (__cplusplus >= 201703L) && _GLIBCXX_HOSTED +# define __glibcxx_node_extract 201606L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_node_extract) +# define __cpp_lib_node_extract 201606L +# endif +# endif +#endif /* !defined(__cpp_lib_node_extract) && defined(__glibcxx_want_node_extract) */ +#undef __glibcxx_want_node_extract + +// from version.def line 651 +#if !defined(__cpp_lib_parallel_algorithm) +# if (__cplusplus >= 201703L) && _GLIBCXX_HOSTED +# define __glibcxx_parallel_algorithm 201603L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_parallel_algorithm) +# define __cpp_lib_parallel_algorithm 201603L +# endif +# endif +#endif /* !defined(__cpp_lib_parallel_algorithm) && defined(__glibcxx_want_parallel_algorithm) */ +#undef __glibcxx_want_parallel_algorithm + +// from version.def line 660 +#if !defined(__cpp_lib_scoped_lock) +# if (__cplusplus >= 201703L) && defined(_GLIBCXX_HAS_GTHREADS) && _GLIBCXX_HOSTED +# define __glibcxx_scoped_lock 201703L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_scoped_lock) +# define __cpp_lib_scoped_lock 201703L +# endif +# endif +#endif /* !defined(__cpp_lib_scoped_lock) && defined(__glibcxx_want_scoped_lock) */ +#undef __glibcxx_want_scoped_lock + +// from version.def line 670 +#if !defined(__cpp_lib_shared_mutex) +# if (__cplusplus >= 201703L) && defined(_GLIBCXX_HAS_GTHREADS) && _GLIBCXX_HOSTED +# define __glibcxx_shared_mutex 201505L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_shared_mutex) +# define __cpp_lib_shared_mutex 201505L +# endif +# endif +#endif /* !defined(__cpp_lib_shared_mutex) && defined(__glibcxx_want_shared_mutex) */ +#undef __glibcxx_want_shared_mutex + +// from version.def line 680 +#if !defined(__cpp_lib_shared_ptr_weak_type) +# if (__cplusplus >= 201703L) && _GLIBCXX_HOSTED +# define __glibcxx_shared_ptr_weak_type 201606L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_shared_ptr_weak_type) +# define __cpp_lib_shared_ptr_weak_type 201606L +# endif +# endif +#endif /* !defined(__cpp_lib_shared_ptr_weak_type) && defined(__glibcxx_want_shared_ptr_weak_type) */ +#undef __glibcxx_want_shared_ptr_weak_type + +// from version.def line 689 +#if !defined(__cpp_lib_string_view) +# if (__cplusplus >= 201703L) && _GLIBCXX_HOSTED +# define __glibcxx_string_view 201803L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_string_view) +# define __cpp_lib_string_view 201803L +# endif +# endif +#endif /* !defined(__cpp_lib_string_view) && defined(__glibcxx_want_string_view) */ +#undef __glibcxx_want_string_view + +// from version.def line 698 +#if !defined(__cpp_lib_unordered_map_try_emplace) +# if (__cplusplus >= 201703L) && _GLIBCXX_HOSTED +# define __glibcxx_unordered_map_try_emplace 201411L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_unordered_map_try_emplace) +# define __cpp_lib_unordered_map_try_emplace 201411L +# endif +# endif +#endif /* !defined(__cpp_lib_unordered_map_try_emplace) && defined(__glibcxx_want_unordered_map_try_emplace) */ +#undef __glibcxx_want_unordered_map_try_emplace + +// from version.def line 707 +#if !defined(__cpp_lib_assume_aligned) +# if (__cplusplus >= 202002L) +# define __glibcxx_assume_aligned 201811L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_assume_aligned) +# define __cpp_lib_assume_aligned 201811L +# endif +# endif +#endif /* !defined(__cpp_lib_assume_aligned) && defined(__glibcxx_want_assume_aligned) */ +#undef __glibcxx_want_assume_aligned + +// from version.def line 715 +#if !defined(__cpp_lib_atomic_flag_test) +# if (__cplusplus >= 202002L) +# define __glibcxx_atomic_flag_test 201907L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_atomic_flag_test) +# define __cpp_lib_atomic_flag_test 201907L +# endif +# endif +#endif /* !defined(__cpp_lib_atomic_flag_test) && defined(__glibcxx_want_atomic_flag_test) */ +#undef __glibcxx_want_atomic_flag_test + +// from version.def line 723 +#if !defined(__cpp_lib_atomic_float) +# if (__cplusplus >= 202002L) +# define __glibcxx_atomic_float 201711L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_atomic_float) +# define __cpp_lib_atomic_float 201711L +# endif +# endif +#endif /* !defined(__cpp_lib_atomic_float) && defined(__glibcxx_want_atomic_float) */ +#undef __glibcxx_want_atomic_float + +// from version.def line 731 +#if !defined(__cpp_lib_atomic_lock_free_type_aliases) +# if (__cplusplus >= 202002L) +# define __glibcxx_atomic_lock_free_type_aliases 201907L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_atomic_lock_free_type_aliases) +# define __cpp_lib_atomic_lock_free_type_aliases 201907L +# endif +# endif +#endif /* !defined(__cpp_lib_atomic_lock_free_type_aliases) && defined(__glibcxx_want_atomic_lock_free_type_aliases) */ +#undef __glibcxx_want_atomic_lock_free_type_aliases + +// from version.def line 739 +#if !defined(__cpp_lib_atomic_ref) +# if (__cplusplus >= 202002L) +# define __glibcxx_atomic_ref 201806L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_atomic_ref) +# define __cpp_lib_atomic_ref 201806L +# endif +# endif +#endif /* !defined(__cpp_lib_atomic_ref) && defined(__glibcxx_want_atomic_ref) */ +#undef __glibcxx_want_atomic_ref + +// from version.def line 747 +#if !defined(__cpp_lib_atomic_value_initialization) +# if (__cplusplus >= 202002L) +# define __glibcxx_atomic_value_initialization 201911L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_atomic_value_initialization) +# define __cpp_lib_atomic_value_initialization 201911L +# endif +# endif +#endif /* !defined(__cpp_lib_atomic_value_initialization) && defined(__glibcxx_want_atomic_value_initialization) */ +#undef __glibcxx_want_atomic_value_initialization + +// from version.def line 755 +#if !defined(__cpp_lib_bind_front) +# if (__cplusplus >= 202002L) +# define __glibcxx_bind_front 201907L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_bind_front) +# define __cpp_lib_bind_front 201907L +# endif +# endif +#endif /* !defined(__cpp_lib_bind_front) && defined(__glibcxx_want_bind_front) */ +#undef __glibcxx_want_bind_front + +// from version.def line 763 +#if !defined(__cpp_lib_starts_ends_with) +# if (__cplusplus >= 202002L) +# define __glibcxx_starts_ends_with 201711L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_starts_ends_with) +# define __cpp_lib_starts_ends_with 201711L +# endif +# endif +#endif /* !defined(__cpp_lib_starts_ends_with) && defined(__glibcxx_want_starts_ends_with) */ +#undef __glibcxx_want_starts_ends_with + +// from version.def line 771 +#if !defined(__cpp_lib_bit_cast) +# if (__cplusplus >= 202002L) && (__has_builtin(__builtin_bit_cast)) +# define __glibcxx_bit_cast 201806L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_bit_cast) +# define __cpp_lib_bit_cast 201806L +# endif +# endif +#endif /* !defined(__cpp_lib_bit_cast) && defined(__glibcxx_want_bit_cast) */ +#undef __glibcxx_want_bit_cast + +// from version.def line 780 +#if !defined(__cpp_lib_bitops) +# if (__cplusplus >= 202002L) +# define __glibcxx_bitops 201907L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_bitops) +# define __cpp_lib_bitops 201907L +# endif +# endif +#endif /* !defined(__cpp_lib_bitops) && defined(__glibcxx_want_bitops) */ +#undef __glibcxx_want_bitops + +// from version.def line 788 +#if !defined(__cpp_lib_bounded_array_traits) +# if (__cplusplus >= 202002L) +# define __glibcxx_bounded_array_traits 201902L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_bounded_array_traits) +# define __cpp_lib_bounded_array_traits 201902L +# endif +# endif +#endif /* !defined(__cpp_lib_bounded_array_traits) && defined(__glibcxx_want_bounded_array_traits) */ +#undef __glibcxx_want_bounded_array_traits + +// from version.def line 796 +#if !defined(__cpp_lib_concepts) +# if (__cplusplus >= 202002L) && (__cpp_concepts >= 201907L) +# define __glibcxx_concepts 202002L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_concepts) +# define __cpp_lib_concepts 202002L +# endif +# endif +#endif /* !defined(__cpp_lib_concepts) && defined(__glibcxx_want_concepts) */ +#undef __glibcxx_want_concepts + +// from version.def line 806 +#if !defined(__cpp_lib_optional) +# if (__cplusplus >= 202302L) && (__glibcxx_concepts) +# define __glibcxx_optional 202110L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_optional) +# define __cpp_lib_optional 202110L +# endif +# elif (__cplusplus >= 202002L) +# define __glibcxx_optional 202106L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_optional) +# define __cpp_lib_optional 202106L +# endif +# elif (__cplusplus >= 201703L) +# define __glibcxx_optional 201606L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_optional) +# define __cpp_lib_optional 201606L +# endif +# endif +#endif /* !defined(__cpp_lib_optional) && defined(__glibcxx_want_optional) */ +#undef __glibcxx_want_optional + +// from version.def line 823 +#if !defined(__cpp_lib_destroying_delete) +# if (__cplusplus >= 202002L) && (__cpp_impl_destroying_delete) +# define __glibcxx_destroying_delete 201806L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_destroying_delete) +# define __cpp_lib_destroying_delete 201806L +# endif +# endif +#endif /* !defined(__cpp_lib_destroying_delete) && defined(__glibcxx_want_destroying_delete) */ +#undef __glibcxx_want_destroying_delete + +// from version.def line 832 +#if !defined(__cpp_lib_constexpr_string_view) +# if (__cplusplus >= 202002L) +# define __glibcxx_constexpr_string_view 201811L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_constexpr_string_view) +# define __cpp_lib_constexpr_string_view 201811L +# endif +# endif +#endif /* !defined(__cpp_lib_constexpr_string_view) && defined(__glibcxx_want_constexpr_string_view) */ +#undef __glibcxx_want_constexpr_string_view + +// from version.def line 840 +#if !defined(__cpp_lib_endian) +# if (__cplusplus >= 202002L) +# define __glibcxx_endian 201907L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_endian) +# define __cpp_lib_endian 201907L +# endif +# endif +#endif /* !defined(__cpp_lib_endian) && defined(__glibcxx_want_endian) */ +#undef __glibcxx_want_endian + +// from version.def line 848 +#if !defined(__cpp_lib_int_pow2) +# if (__cplusplus >= 202002L) +# define __glibcxx_int_pow2 202002L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_int_pow2) +# define __cpp_lib_int_pow2 202002L +# endif +# endif +#endif /* !defined(__cpp_lib_int_pow2) && defined(__glibcxx_want_int_pow2) */ +#undef __glibcxx_want_int_pow2 + +// from version.def line 856 +#if !defined(__cpp_lib_integer_comparison_functions) +# if (__cplusplus >= 202002L) +# define __glibcxx_integer_comparison_functions 202002L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_integer_comparison_functions) +# define __cpp_lib_integer_comparison_functions 202002L +# endif +# endif +#endif /* !defined(__cpp_lib_integer_comparison_functions) && defined(__glibcxx_want_integer_comparison_functions) */ +#undef __glibcxx_want_integer_comparison_functions + +// from version.def line 864 +#if !defined(__cpp_lib_is_constant_evaluated) +# if (__cplusplus >= 202002L) && (defined(_GLIBCXX_HAVE_IS_CONSTANT_EVALUATED)) +# define __glibcxx_is_constant_evaluated 201811L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_is_constant_evaluated) +# define __cpp_lib_is_constant_evaluated 201811L +# endif +# endif +#endif /* !defined(__cpp_lib_is_constant_evaluated) && defined(__glibcxx_want_is_constant_evaluated) */ +#undef __glibcxx_want_is_constant_evaluated + +// from version.def line 874 +#if !defined(__cpp_lib_constexpr_char_traits) +# if (__cplusplus >= 202002L) && (defined(__glibcxx_is_constant_evaluated)) +# define __glibcxx_constexpr_char_traits 201811L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_constexpr_char_traits) +# define __cpp_lib_constexpr_char_traits 201811L +# endif +# elif (__cplusplus >= 201703L) && (_GLIBCXX_HAVE_IS_CONSTANT_EVALUATED) +# define __glibcxx_constexpr_char_traits 201611L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_constexpr_char_traits) +# define __cpp_lib_constexpr_char_traits 201611L +# endif +# endif +#endif /* !defined(__cpp_lib_constexpr_char_traits) && defined(__glibcxx_want_constexpr_char_traits) */ +#undef __glibcxx_want_constexpr_char_traits + +// from version.def line 890 +#if !defined(__cpp_lib_is_layout_compatible) +# if (__cplusplus >= 202002L) && (__has_builtin(__is_layout_compatible) && __has_builtin(__builtin_is_corresponding_member)) +# define __glibcxx_is_layout_compatible 201907L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_is_layout_compatible) +# define __cpp_lib_is_layout_compatible 201907L +# endif +# endif +#endif /* !defined(__cpp_lib_is_layout_compatible) && defined(__glibcxx_want_is_layout_compatible) */ +#undef __glibcxx_want_is_layout_compatible + +// from version.def line 900 +#if !defined(__cpp_lib_is_nothrow_convertible) +# if (__cplusplus >= 202002L) +# define __glibcxx_is_nothrow_convertible 201806L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_is_nothrow_convertible) +# define __cpp_lib_is_nothrow_convertible 201806L +# endif +# endif +#endif /* !defined(__cpp_lib_is_nothrow_convertible) && defined(__glibcxx_want_is_nothrow_convertible) */ +#undef __glibcxx_want_is_nothrow_convertible + +// from version.def line 908 +#if !defined(__cpp_lib_is_pointer_interconvertible) +# if (__cplusplus >= 202002L) && (__has_builtin(__is_pointer_interconvertible_base_of) && __has_builtin(__builtin_is_pointer_interconvertible_with_class)) +# define __glibcxx_is_pointer_interconvertible 201907L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_is_pointer_interconvertible) +# define __cpp_lib_is_pointer_interconvertible 201907L +# endif +# endif +#endif /* !defined(__cpp_lib_is_pointer_interconvertible) && defined(__glibcxx_want_is_pointer_interconvertible) */ +#undef __glibcxx_want_is_pointer_interconvertible + +// from version.def line 919 +#if !defined(__cpp_lib_math_constants) +# if (__cplusplus >= 202002L) +# define __glibcxx_math_constants 201907L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_math_constants) +# define __cpp_lib_math_constants 201907L +# endif +# endif +#endif /* !defined(__cpp_lib_math_constants) && defined(__glibcxx_want_math_constants) */ +#undef __glibcxx_want_math_constants + +// from version.def line 927 +#if !defined(__cpp_lib_make_obj_using_allocator) +# if (__cplusplus >= 202002L) && (__cpp_concepts) +# define __glibcxx_make_obj_using_allocator 201811L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_make_obj_using_allocator) +# define __cpp_lib_make_obj_using_allocator 201811L +# endif +# endif +#endif /* !defined(__cpp_lib_make_obj_using_allocator) && defined(__glibcxx_want_make_obj_using_allocator) */ +#undef __glibcxx_want_make_obj_using_allocator + +// from version.def line 937 +#if !defined(__cpp_lib_remove_cvref) +# if (__cplusplus >= 202002L) +# define __glibcxx_remove_cvref 201711L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_remove_cvref) +# define __cpp_lib_remove_cvref 201711L +# endif +# endif +#endif /* !defined(__cpp_lib_remove_cvref) && defined(__glibcxx_want_remove_cvref) */ +#undef __glibcxx_want_remove_cvref + +// from version.def line 945 +#if !defined(__cpp_lib_source_location) +# if (__cplusplus >= 202002L) && (__has_builtin(__builtin_source_location)) +# define __glibcxx_source_location 201907L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_source_location) +# define __cpp_lib_source_location 201907L +# endif +# endif +#endif /* !defined(__cpp_lib_source_location) && defined(__glibcxx_want_source_location) */ +#undef __glibcxx_want_source_location + +// from version.def line 954 +#if !defined(__cpp_lib_span) +# if (__cplusplus >= 202002L) && (__glibcxx_concepts) +# define __glibcxx_span 202002L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_span) +# define __cpp_lib_span 202002L +# endif +# endif +#endif /* !defined(__cpp_lib_span) && defined(__glibcxx_want_span) */ +#undef __glibcxx_want_span + +// from version.def line 963 +#if !defined(__cpp_lib_ssize) +# if (__cplusplus >= 202002L) +# define __glibcxx_ssize 201902L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_ssize) +# define __cpp_lib_ssize 201902L +# endif +# endif +#endif /* !defined(__cpp_lib_ssize) && defined(__glibcxx_want_ssize) */ +#undef __glibcxx_want_ssize + +// from version.def line 971 +#if !defined(__cpp_lib_three_way_comparison) +# if (__cplusplus >= 202002L) && (__cpp_impl_three_way_comparison >= 201907L && __glibcxx_concepts) +# define __glibcxx_three_way_comparison 201907L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_three_way_comparison) +# define __cpp_lib_three_way_comparison 201907L +# endif +# endif +#endif /* !defined(__cpp_lib_three_way_comparison) && defined(__glibcxx_want_three_way_comparison) */ +#undef __glibcxx_want_three_way_comparison + +// from version.def line 981 +#if !defined(__cpp_lib_to_address) +# if (__cplusplus >= 202002L) +# define __glibcxx_to_address 201711L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_to_address) +# define __cpp_lib_to_address 201711L +# endif +# endif +#endif /* !defined(__cpp_lib_to_address) && defined(__glibcxx_want_to_address) */ +#undef __glibcxx_want_to_address + +// from version.def line 989 +#if !defined(__cpp_lib_to_array) +# if (__cplusplus >= 202002L) && (__cpp_generic_lambdas >= 201707L) +# define __glibcxx_to_array 201907L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_to_array) +# define __cpp_lib_to_array 201907L +# endif +# endif +#endif /* !defined(__cpp_lib_to_array) && defined(__glibcxx_want_to_array) */ +#undef __glibcxx_want_to_array + +// from version.def line 998 +#if !defined(__cpp_lib_type_identity) +# if (__cplusplus >= 202002L) +# define __glibcxx_type_identity 201806L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_type_identity) +# define __cpp_lib_type_identity 201806L +# endif +# endif +#endif /* !defined(__cpp_lib_type_identity) && defined(__glibcxx_want_type_identity) */ +#undef __glibcxx_want_type_identity + +// from version.def line 1006 +#if !defined(__cpp_lib_unwrap_ref) +# if (__cplusplus >= 202002L) +# define __glibcxx_unwrap_ref 201811L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_unwrap_ref) +# define __cpp_lib_unwrap_ref 201811L +# endif +# endif +#endif /* !defined(__cpp_lib_unwrap_ref) && defined(__glibcxx_want_unwrap_ref) */ +#undef __glibcxx_want_unwrap_ref + +// from version.def line 1014 +#if !defined(__cpp_lib_constexpr_iterator) +# if (__cplusplus >= 202002L) +# define __glibcxx_constexpr_iterator 201811L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_constexpr_iterator) +# define __cpp_lib_constexpr_iterator 201811L +# endif +# endif +#endif /* !defined(__cpp_lib_constexpr_iterator) && defined(__glibcxx_want_constexpr_iterator) */ +#undef __glibcxx_want_constexpr_iterator + +// from version.def line 1022 +#if !defined(__cpp_lib_interpolate) +# if (__cplusplus >= 202002L) +# define __glibcxx_interpolate 201902L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_interpolate) +# define __cpp_lib_interpolate 201902L +# endif +# endif +#endif /* !defined(__cpp_lib_interpolate) && defined(__glibcxx_want_interpolate) */ +#undef __glibcxx_want_interpolate + +// from version.def line 1030 +#if !defined(__cpp_lib_constexpr_utility) +# if (__cplusplus >= 202002L) +# define __glibcxx_constexpr_utility 201811L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_constexpr_utility) +# define __cpp_lib_constexpr_utility 201811L +# endif +# endif +#endif /* !defined(__cpp_lib_constexpr_utility) && defined(__glibcxx_want_constexpr_utility) */ +#undef __glibcxx_want_constexpr_utility + +// from version.def line 1038 +#if !defined(__cpp_lib_shift) +# if (__cplusplus >= 202002L) +# define __glibcxx_shift 201806L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_shift) +# define __cpp_lib_shift 201806L +# endif +# endif +#endif /* !defined(__cpp_lib_shift) && defined(__glibcxx_want_shift) */ +#undef __glibcxx_want_shift + +// from version.def line 1046 +#if !defined(__cpp_lib_ranges) +# if (__cplusplus >= 202302L) && (__glibcxx_concepts) +# define __glibcxx_ranges 202202L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_ranges) +# define __cpp_lib_ranges 202202L +# endif +# elif (__cplusplus >= 202002L) && (__glibcxx_concepts) +# define __glibcxx_ranges 202110L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_ranges) +# define __cpp_lib_ranges 202110L +# endif +# endif +#endif /* !defined(__cpp_lib_ranges) && defined(__glibcxx_want_ranges) */ +#undef __glibcxx_want_ranges + +// from version.def line 1060 +#if !defined(__cpp_lib_constexpr_numeric) +# if (__cplusplus >= 202002L) +# define __glibcxx_constexpr_numeric 201911L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_constexpr_numeric) +# define __cpp_lib_constexpr_numeric 201911L +# endif +# endif +#endif /* !defined(__cpp_lib_constexpr_numeric) && defined(__glibcxx_want_constexpr_numeric) */ +#undef __glibcxx_want_constexpr_numeric + +// from version.def line 1068 +#if !defined(__cpp_lib_constexpr_functional) +# if (__cplusplus >= 202002L) +# define __glibcxx_constexpr_functional 201907L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_constexpr_functional) +# define __cpp_lib_constexpr_functional 201907L +# endif +# endif +#endif /* !defined(__cpp_lib_constexpr_functional) && defined(__glibcxx_want_constexpr_functional) */ +#undef __glibcxx_want_constexpr_functional + +// from version.def line 1076 +#if !defined(__cpp_lib_constexpr_algorithms) +# if (__cplusplus >= 202002L) +# define __glibcxx_constexpr_algorithms 201806L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_constexpr_algorithms) +# define __cpp_lib_constexpr_algorithms 201806L +# endif +# endif +#endif /* !defined(__cpp_lib_constexpr_algorithms) && defined(__glibcxx_want_constexpr_algorithms) */ +#undef __glibcxx_want_constexpr_algorithms + +// from version.def line 1084 +#if !defined(__cpp_lib_constexpr_tuple) +# if (__cplusplus >= 202002L) +# define __glibcxx_constexpr_tuple 201811L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_constexpr_tuple) +# define __cpp_lib_constexpr_tuple 201811L +# endif +# endif +#endif /* !defined(__cpp_lib_constexpr_tuple) && defined(__glibcxx_want_constexpr_tuple) */ +#undef __glibcxx_want_constexpr_tuple + +// from version.def line 1092 +#if !defined(__cpp_lib_constexpr_memory) +# if (__cplusplus >= 202302L) && (__cpp_constexpr_dynamic_alloc) +# define __glibcxx_constexpr_memory 202202L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_constexpr_memory) +# define __cpp_lib_constexpr_memory 202202L +# endif +# elif (__cplusplus >= 202002L) +# define __glibcxx_constexpr_memory 201811L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_constexpr_memory) +# define __cpp_lib_constexpr_memory 201811L +# endif +# endif +#endif /* !defined(__cpp_lib_constexpr_memory) && defined(__glibcxx_want_constexpr_memory) */ +#undef __glibcxx_want_constexpr_memory + +// from version.def line 1105 +#if !defined(__cpp_lib_atomic_shared_ptr) +# if (__cplusplus >= 202002L) && _GLIBCXX_HOSTED +# define __glibcxx_atomic_shared_ptr 201711L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_atomic_shared_ptr) +# define __cpp_lib_atomic_shared_ptr 201711L +# endif +# endif +#endif /* !defined(__cpp_lib_atomic_shared_ptr) && defined(__glibcxx_want_atomic_shared_ptr) */ +#undef __glibcxx_want_atomic_shared_ptr + +// from version.def line 1114 +#if !defined(__cpp_lib_atomic_wait) +# if (__cplusplus >= 202002L) && defined(_GLIBCXX_HAS_GTHREADS) && _GLIBCXX_HOSTED +# define __glibcxx_atomic_wait 201907L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_atomic_wait) +# define __cpp_lib_atomic_wait 201907L +# endif +# elif (__cplusplus >= 202002L) && !defined(_GLIBCXX_HAS_GTHREADS) && _GLIBCXX_HOSTED && (defined(_GLIBCXX_HAVE_LINUX_FUTEX)) +# define __glibcxx_atomic_wait 201907L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_atomic_wait) +# define __cpp_lib_atomic_wait 201907L +# endif +# endif +#endif /* !defined(__cpp_lib_atomic_wait) && defined(__glibcxx_want_atomic_wait) */ +#undef __glibcxx_want_atomic_wait + +// from version.def line 1132 +#if !defined(__cpp_lib_barrier) +# if (__cplusplus >= 202002L) && (__cpp_aligned_new && __glibcxx_atomic_wait) +# define __glibcxx_barrier 201907L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_barrier) +# define __cpp_lib_barrier 201907L +# endif +# endif +#endif /* !defined(__cpp_lib_barrier) && defined(__glibcxx_want_barrier) */ +#undef __glibcxx_want_barrier + +// from version.def line 1149 +#if !defined(__cpp_lib_format) +# if (__cplusplus >= 202002L) && _GLIBCXX_HOSTED +# define __glibcxx_format 202106L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_format) +# define __cpp_lib_format 202106L +# endif +# endif +#endif /* !defined(__cpp_lib_format) && defined(__glibcxx_want_format) */ +#undef __glibcxx_want_format + +// from version.def line 1162 +#if !defined(__cpp_lib_constexpr_complex) +# if (__cplusplus >= 202002L) && _GLIBCXX_HOSTED +# define __glibcxx_constexpr_complex 201711L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_constexpr_complex) +# define __cpp_lib_constexpr_complex 201711L +# endif +# endif +#endif /* !defined(__cpp_lib_constexpr_complex) && defined(__glibcxx_want_constexpr_complex) */ +#undef __glibcxx_want_constexpr_complex + +// from version.def line 1171 +#if !defined(__cpp_lib_constexpr_dynamic_alloc) +# if (__cplusplus >= 202002L) && _GLIBCXX_HOSTED +# define __glibcxx_constexpr_dynamic_alloc 201907L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_constexpr_dynamic_alloc) +# define __cpp_lib_constexpr_dynamic_alloc 201907L +# endif +# endif +#endif /* !defined(__cpp_lib_constexpr_dynamic_alloc) && defined(__glibcxx_want_constexpr_dynamic_alloc) */ +#undef __glibcxx_want_constexpr_dynamic_alloc + +// from version.def line 1180 +#if !defined(__cpp_lib_constexpr_string) +# if (__cplusplus >= 202002L) && _GLIBCXX_USE_CXX11_ABI && _GLIBCXX_HOSTED && (defined(__glibcxx_is_constant_evaluated)) +# define __glibcxx_constexpr_string 201907L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_constexpr_string) +# define __cpp_lib_constexpr_string 201907L +# endif +# elif (__cplusplus >= 202002L) && !_GLIBCXX_USE_CXX11_ABI && _GLIBCXX_HOSTED && (defined(__glibcxx_is_constant_evaluated)) +# define __glibcxx_constexpr_string 201811L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_constexpr_string) +# define __cpp_lib_constexpr_string 201811L +# endif +# elif (__cplusplus >= 201703L) && _GLIBCXX_HOSTED && (_GLIBCXX_HAVE_IS_CONSTANT_EVALUATED) +# define __glibcxx_constexpr_string 201611L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_constexpr_string) +# define __cpp_lib_constexpr_string 201611L +# endif +# endif +#endif /* !defined(__cpp_lib_constexpr_string) && defined(__glibcxx_want_constexpr_string) */ +#undef __glibcxx_want_constexpr_string + +// from version.def line 1204 +#if !defined(__cpp_lib_constexpr_vector) +# if (__cplusplus >= 202002L) && _GLIBCXX_HOSTED +# define __glibcxx_constexpr_vector 201907L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_constexpr_vector) +# define __cpp_lib_constexpr_vector 201907L +# endif +# endif +#endif /* !defined(__cpp_lib_constexpr_vector) && defined(__glibcxx_want_constexpr_vector) */ +#undef __glibcxx_want_constexpr_vector + +// from version.def line 1213 +#if !defined(__cpp_lib_erase_if) +# if (__cplusplus >= 202002L) && _GLIBCXX_HOSTED +# define __glibcxx_erase_if 202002L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_erase_if) +# define __cpp_lib_erase_if 202002L +# endif +# endif +#endif /* !defined(__cpp_lib_erase_if) && defined(__glibcxx_want_erase_if) */ +#undef __glibcxx_want_erase_if + +// from version.def line 1222 +#if !defined(__cpp_lib_generic_unordered_lookup) +# if (__cplusplus >= 202002L) && _GLIBCXX_HOSTED +# define __glibcxx_generic_unordered_lookup 201811L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_generic_unordered_lookup) +# define __cpp_lib_generic_unordered_lookup 201811L +# endif +# endif +#endif /* !defined(__cpp_lib_generic_unordered_lookup) && defined(__glibcxx_want_generic_unordered_lookup) */ +#undef __glibcxx_want_generic_unordered_lookup + +// from version.def line 1231 +#if !defined(__cpp_lib_jthread) +# if (__cplusplus >= 202002L) && defined(_GLIBCXX_HAS_GTHREADS) && _GLIBCXX_HOSTED +# define __glibcxx_jthread 201911L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_jthread) +# define __cpp_lib_jthread 201911L +# endif +# endif +#endif /* !defined(__cpp_lib_jthread) && defined(__glibcxx_want_jthread) */ +#undef __glibcxx_want_jthread + +// from version.def line 1241 +#if !defined(__cpp_lib_latch) +# if (__cplusplus >= 202002L) && (__glibcxx_atomic_wait) +# define __glibcxx_latch 201907L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_latch) +# define __cpp_lib_latch 201907L +# endif +# endif +#endif /* !defined(__cpp_lib_latch) && defined(__glibcxx_want_latch) */ +#undef __glibcxx_want_latch + +// from version.def line 1250 +#if !defined(__cpp_lib_list_remove_return_type) +# if (__cplusplus >= 202002L) && _GLIBCXX_HOSTED +# define __glibcxx_list_remove_return_type 201806L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_list_remove_return_type) +# define __cpp_lib_list_remove_return_type 201806L +# endif +# endif +#endif /* !defined(__cpp_lib_list_remove_return_type) && defined(__glibcxx_want_list_remove_return_type) */ +#undef __glibcxx_want_list_remove_return_type + +// from version.def line 1259 +#if !defined(__cpp_lib_polymorphic_allocator) +# if (__cplusplus >= 202002L) && _GLIBCXX_HOSTED +# define __glibcxx_polymorphic_allocator 201902L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_polymorphic_allocator) +# define __cpp_lib_polymorphic_allocator 201902L +# endif +# endif +#endif /* !defined(__cpp_lib_polymorphic_allocator) && defined(__glibcxx_want_polymorphic_allocator) */ +#undef __glibcxx_want_polymorphic_allocator + +// from version.def line 1268 +#if !defined(__cpp_lib_move_iterator_concept) +# if (__cplusplus >= 202002L) && (__glibcxx_concepts) +# define __glibcxx_move_iterator_concept 202207L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_move_iterator_concept) +# define __cpp_lib_move_iterator_concept 202207L +# endif +# endif +#endif /* !defined(__cpp_lib_move_iterator_concept) && defined(__glibcxx_want_move_iterator_concept) */ +#undef __glibcxx_want_move_iterator_concept + +// from version.def line 1278 +#if !defined(__cpp_lib_semaphore) +# if (__cplusplus >= 202002L) && _GLIBCXX_HOSTED && (__glibcxx_atomic_wait || _GLIBCXX_HAVE_POSIX_SEMAPHORE) +# define __glibcxx_semaphore 201907L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_semaphore) +# define __cpp_lib_semaphore 201907L +# endif +# endif +#endif /* !defined(__cpp_lib_semaphore) && defined(__glibcxx_want_semaphore) */ +#undef __glibcxx_want_semaphore + +// from version.def line 1288 +#if !defined(__cpp_lib_smart_ptr_for_overwrite) +# if (__cplusplus >= 202002L) && _GLIBCXX_HOSTED +# define __glibcxx_smart_ptr_for_overwrite 202002L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_smart_ptr_for_overwrite) +# define __cpp_lib_smart_ptr_for_overwrite 202002L +# endif +# endif +#endif /* !defined(__cpp_lib_smart_ptr_for_overwrite) && defined(__glibcxx_want_smart_ptr_for_overwrite) */ +#undef __glibcxx_want_smart_ptr_for_overwrite + +// from version.def line 1297 +#if !defined(__cpp_lib_syncbuf) +# if (__cplusplus >= 202002L) && _GLIBCXX_USE_CXX11_ABI && _GLIBCXX_HOSTED +# define __glibcxx_syncbuf 201803L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_syncbuf) +# define __cpp_lib_syncbuf 201803L +# endif +# endif +#endif /* !defined(__cpp_lib_syncbuf) && defined(__glibcxx_want_syncbuf) */ +#undef __glibcxx_want_syncbuf + +// from version.def line 1307 +#if !defined(__cpp_lib_byteswap) +# if (__cplusplus >= 202302L) +# define __glibcxx_byteswap 202110L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_byteswap) +# define __cpp_lib_byteswap 202110L +# endif +# endif +#endif /* !defined(__cpp_lib_byteswap) && defined(__glibcxx_want_byteswap) */ +#undef __glibcxx_want_byteswap + +// from version.def line 1315 +#if !defined(__cpp_lib_constexpr_charconv) +# if (__cplusplus >= 202302L) +# define __glibcxx_constexpr_charconv 202207L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_constexpr_charconv) +# define __cpp_lib_constexpr_charconv 202207L +# endif +# endif +#endif /* !defined(__cpp_lib_constexpr_charconv) && defined(__glibcxx_want_constexpr_charconv) */ +#undef __glibcxx_want_constexpr_charconv + +// from version.def line 1323 +#if !defined(__cpp_lib_constexpr_typeinfo) +# if (__cplusplus >= 202302L) +# define __glibcxx_constexpr_typeinfo 202106L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_constexpr_typeinfo) +# define __cpp_lib_constexpr_typeinfo 202106L +# endif +# endif +#endif /* !defined(__cpp_lib_constexpr_typeinfo) && defined(__glibcxx_want_constexpr_typeinfo) */ +#undef __glibcxx_want_constexpr_typeinfo + +// from version.def line 1331 +#if !defined(__cpp_lib_expected) +# if (__cplusplus >= 202302L) && (__cpp_concepts >= 202002L) +# define __glibcxx_expected 202211L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_expected) +# define __cpp_lib_expected 202211L +# endif +# endif +#endif /* !defined(__cpp_lib_expected) && defined(__glibcxx_want_expected) */ +#undef __glibcxx_want_expected + +// from version.def line 1340 +#if !defined(__cpp_lib_invoke_r) +# if (__cplusplus >= 202302L) +# define __glibcxx_invoke_r 202106L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_invoke_r) +# define __cpp_lib_invoke_r 202106L +# endif +# endif +#endif /* !defined(__cpp_lib_invoke_r) && defined(__glibcxx_want_invoke_r) */ +#undef __glibcxx_want_invoke_r + +// from version.def line 1348 +#if !defined(__cpp_lib_is_scoped_enum) +# if (__cplusplus >= 202302L) +# define __glibcxx_is_scoped_enum 202011L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_is_scoped_enum) +# define __cpp_lib_is_scoped_enum 202011L +# endif +# endif +#endif /* !defined(__cpp_lib_is_scoped_enum) && defined(__glibcxx_want_is_scoped_enum) */ +#undef __glibcxx_want_is_scoped_enum + +// from version.def line 1356 +#if !defined(__cpp_lib_reference_from_temporary) +# if (__cplusplus >= 202302L) && (__has_builtin(__reference_constructs_from_temporary) && __has_builtin(__reference_converts_from_temporary)) +# define __glibcxx_reference_from_temporary 202202L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_reference_from_temporary) +# define __cpp_lib_reference_from_temporary 202202L +# endif +# endif +#endif /* !defined(__cpp_lib_reference_from_temporary) && defined(__glibcxx_want_reference_from_temporary) */ +#undef __glibcxx_want_reference_from_temporary + +// from version.def line 1367 +#if !defined(__cpp_lib_to_underlying) +# if (__cplusplus >= 202302L) +# define __glibcxx_to_underlying 202102L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_to_underlying) +# define __cpp_lib_to_underlying 202102L +# endif +# endif +#endif /* !defined(__cpp_lib_to_underlying) && defined(__glibcxx_want_to_underlying) */ +#undef __glibcxx_want_to_underlying + +// from version.def line 1375 +#if !defined(__cpp_lib_unreachable) +# if (__cplusplus >= 202302L) +# define __glibcxx_unreachable 202202L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_unreachable) +# define __cpp_lib_unreachable 202202L +# endif +# endif +#endif /* !defined(__cpp_lib_unreachable) && defined(__glibcxx_want_unreachable) */ +#undef __glibcxx_want_unreachable + +// from version.def line 1383 +#if !defined(__cpp_lib_ranges_zip) +# if (__cplusplus >= 202302L) +# define __glibcxx_ranges_zip 202110L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_ranges_zip) +# define __cpp_lib_ranges_zip 202110L +# endif +# endif +#endif /* !defined(__cpp_lib_ranges_zip) && defined(__glibcxx_want_ranges_zip) */ +#undef __glibcxx_want_ranges_zip + +// from version.def line 1391 +#if !defined(__cpp_lib_ranges_chunk) +# if (__cplusplus >= 202302L) +# define __glibcxx_ranges_chunk 202202L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_ranges_chunk) +# define __cpp_lib_ranges_chunk 202202L +# endif +# endif +#endif /* !defined(__cpp_lib_ranges_chunk) && defined(__glibcxx_want_ranges_chunk) */ +#undef __glibcxx_want_ranges_chunk + +// from version.def line 1399 +#if !defined(__cpp_lib_ranges_slide) +# if (__cplusplus >= 202302L) +# define __glibcxx_ranges_slide 202202L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_ranges_slide) +# define __cpp_lib_ranges_slide 202202L +# endif +# endif +#endif /* !defined(__cpp_lib_ranges_slide) && defined(__glibcxx_want_ranges_slide) */ +#undef __glibcxx_want_ranges_slide + +// from version.def line 1407 +#if !defined(__cpp_lib_ranges_chunk_by) +# if (__cplusplus >= 202302L) +# define __glibcxx_ranges_chunk_by 202202L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_ranges_chunk_by) +# define __cpp_lib_ranges_chunk_by 202202L +# endif +# endif +#endif /* !defined(__cpp_lib_ranges_chunk_by) && defined(__glibcxx_want_ranges_chunk_by) */ +#undef __glibcxx_want_ranges_chunk_by + +// from version.def line 1415 +#if !defined(__cpp_lib_ranges_join_with) +# if (__cplusplus >= 202302L) +# define __glibcxx_ranges_join_with 202202L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_ranges_join_with) +# define __cpp_lib_ranges_join_with 202202L +# endif +# endif +#endif /* !defined(__cpp_lib_ranges_join_with) && defined(__glibcxx_want_ranges_join_with) */ +#undef __glibcxx_want_ranges_join_with + +// from version.def line 1423 +#if !defined(__cpp_lib_ranges_repeat) +# if (__cplusplus >= 202302L) +# define __glibcxx_ranges_repeat 202207L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_ranges_repeat) +# define __cpp_lib_ranges_repeat 202207L +# endif +# endif +#endif /* !defined(__cpp_lib_ranges_repeat) && defined(__glibcxx_want_ranges_repeat) */ +#undef __glibcxx_want_ranges_repeat + +// from version.def line 1431 +#if !defined(__cpp_lib_ranges_stride) +# if (__cplusplus >= 202302L) +# define __glibcxx_ranges_stride 202207L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_ranges_stride) +# define __cpp_lib_ranges_stride 202207L +# endif +# endif +#endif /* !defined(__cpp_lib_ranges_stride) && defined(__glibcxx_want_ranges_stride) */ +#undef __glibcxx_want_ranges_stride + +// from version.def line 1439 +#if !defined(__cpp_lib_ranges_cartesian_product) +# if (__cplusplus >= 202302L) +# define __glibcxx_ranges_cartesian_product 202207L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_ranges_cartesian_product) +# define __cpp_lib_ranges_cartesian_product 202207L +# endif +# endif +#endif /* !defined(__cpp_lib_ranges_cartesian_product) && defined(__glibcxx_want_ranges_cartesian_product) */ +#undef __glibcxx_want_ranges_cartesian_product + +// from version.def line 1447 +#if !defined(__cpp_lib_ranges_as_rvalue) +# if (__cplusplus >= 202302L) +# define __glibcxx_ranges_as_rvalue 202207L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_ranges_as_rvalue) +# define __cpp_lib_ranges_as_rvalue 202207L +# endif +# endif +#endif /* !defined(__cpp_lib_ranges_as_rvalue) && defined(__glibcxx_want_ranges_as_rvalue) */ +#undef __glibcxx_want_ranges_as_rvalue + +// from version.def line 1455 +#if !defined(__cpp_lib_ranges_as_const) +# if (__cplusplus >= 202302L) +# define __glibcxx_ranges_as_const 202207L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_ranges_as_const) +# define __cpp_lib_ranges_as_const 202207L +# endif +# endif +#endif /* !defined(__cpp_lib_ranges_as_const) && defined(__glibcxx_want_ranges_as_const) */ +#undef __glibcxx_want_ranges_as_const + +// from version.def line 1463 +#if !defined(__cpp_lib_ranges_enumerate) +# if (__cplusplus >= 202302L) +# define __glibcxx_ranges_enumerate 202302L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_ranges_enumerate) +# define __cpp_lib_ranges_enumerate 202302L +# endif +# endif +#endif /* !defined(__cpp_lib_ranges_enumerate) && defined(__glibcxx_want_ranges_enumerate) */ +#undef __glibcxx_want_ranges_enumerate + +// from version.def line 1471 +#if !defined(__cpp_lib_ranges_fold) +# if (__cplusplus >= 202302L) +# define __glibcxx_ranges_fold 202207L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_ranges_fold) +# define __cpp_lib_ranges_fold 202207L +# endif +# endif +#endif /* !defined(__cpp_lib_ranges_fold) && defined(__glibcxx_want_ranges_fold) */ +#undef __glibcxx_want_ranges_fold + +// from version.def line 1479 +#if !defined(__cpp_lib_ranges_contains) +# if (__cplusplus >= 202302L) +# define __glibcxx_ranges_contains 202207L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_ranges_contains) +# define __cpp_lib_ranges_contains 202207L +# endif +# endif +#endif /* !defined(__cpp_lib_ranges_contains) && defined(__glibcxx_want_ranges_contains) */ +#undef __glibcxx_want_ranges_contains + +// from version.def line 1487 +#if !defined(__cpp_lib_ranges_iota) +# if (__cplusplus >= 202302L) +# define __glibcxx_ranges_iota 202202L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_ranges_iota) +# define __cpp_lib_ranges_iota 202202L +# endif +# endif +#endif /* !defined(__cpp_lib_ranges_iota) && defined(__glibcxx_want_ranges_iota) */ +#undef __glibcxx_want_ranges_iota + +// from version.def line 1495 +#if !defined(__cpp_lib_ranges_find_last) +# if (__cplusplus >= 202302L) +# define __glibcxx_ranges_find_last 202207L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_ranges_find_last) +# define __cpp_lib_ranges_find_last 202207L +# endif +# endif +#endif /* !defined(__cpp_lib_ranges_find_last) && defined(__glibcxx_want_ranges_find_last) */ +#undef __glibcxx_want_ranges_find_last + +// from version.def line 1503 +#if !defined(__cpp_lib_constexpr_bitset) +# if (__cplusplus >= 202302L) && _GLIBCXX_HOSTED && (__cpp_constexpr_dynamic_alloc) +# define __glibcxx_constexpr_bitset 202202L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_constexpr_bitset) +# define __cpp_lib_constexpr_bitset 202202L +# endif +# endif +#endif /* !defined(__cpp_lib_constexpr_bitset) && defined(__glibcxx_want_constexpr_bitset) */ +#undef __glibcxx_want_constexpr_bitset + +// from version.def line 1513 +#if !defined(__cpp_lib_stdatomic_h) +# if (__cplusplus >= 202302L) +# define __glibcxx_stdatomic_h 202011L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_stdatomic_h) +# define __cpp_lib_stdatomic_h 202011L +# endif +# endif +#endif /* !defined(__cpp_lib_stdatomic_h) && defined(__glibcxx_want_stdatomic_h) */ +#undef __glibcxx_want_stdatomic_h + +// from version.def line 1521 +#if !defined(__cpp_lib_adaptor_iterator_pair_constructor) +# if (__cplusplus >= 202302L) && _GLIBCXX_HOSTED +# define __glibcxx_adaptor_iterator_pair_constructor 202106L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_adaptor_iterator_pair_constructor) +# define __cpp_lib_adaptor_iterator_pair_constructor 202106L +# endif +# endif +#endif /* !defined(__cpp_lib_adaptor_iterator_pair_constructor) && defined(__glibcxx_want_adaptor_iterator_pair_constructor) */ +#undef __glibcxx_want_adaptor_iterator_pair_constructor + +// from version.def line 1530 +#if !defined(__cpp_lib_ios_noreplace) +# if (__cplusplus >= 202302L) && _GLIBCXX_HOSTED +# define __glibcxx_ios_noreplace 202207L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_ios_noreplace) +# define __cpp_lib_ios_noreplace 202207L +# endif +# endif +#endif /* !defined(__cpp_lib_ios_noreplace) && defined(__glibcxx_want_ios_noreplace) */ +#undef __glibcxx_want_ios_noreplace + +// from version.def line 1539 +#if !defined(__cpp_lib_move_only_function) +# if (__cplusplus >= 202302L) && _GLIBCXX_HOSTED +# define __glibcxx_move_only_function 202110L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_move_only_function) +# define __cpp_lib_move_only_function 202110L +# endif +# endif +#endif /* !defined(__cpp_lib_move_only_function) && defined(__glibcxx_want_move_only_function) */ +#undef __glibcxx_want_move_only_function + +// from version.def line 1548 +#if !defined(__cpp_lib_spanstream) +# if (__cplusplus >= 202302L) && _GLIBCXX_HOSTED && (__glibcxx_span) +# define __glibcxx_spanstream 202106L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_spanstream) +# define __cpp_lib_spanstream 202106L +# endif +# endif +#endif /* !defined(__cpp_lib_spanstream) && defined(__glibcxx_want_spanstream) */ +#undef __glibcxx_want_spanstream + +// from version.def line 1558 +#if !defined(__cpp_lib_stacktrace) +# if (__cplusplus >= 202302L) && _GLIBCXX_HOSTED && (_GLIBCXX_HAVE_STACKTRACE) +# define __glibcxx_stacktrace 202011L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_stacktrace) +# define __cpp_lib_stacktrace 202011L +# endif +# endif +#endif /* !defined(__cpp_lib_stacktrace) && defined(__glibcxx_want_stacktrace) */ +#undef __glibcxx_want_stacktrace + +// from version.def line 1568 +#if !defined(__cpp_lib_string_contains) +# if (__cplusplus >= 202302L) && _GLIBCXX_HOSTED +# define __glibcxx_string_contains 202011L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_string_contains) +# define __cpp_lib_string_contains 202011L +# endif +# endif +#endif /* !defined(__cpp_lib_string_contains) && defined(__glibcxx_want_string_contains) */ +#undef __glibcxx_want_string_contains + +// from version.def line 1577 +#if !defined(__cpp_lib_string_resize_and_overwrite) +# if (__cplusplus >= 202302L) && _GLIBCXX_HOSTED +# define __glibcxx_string_resize_and_overwrite 202110L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_string_resize_and_overwrite) +# define __cpp_lib_string_resize_and_overwrite 202110L +# endif +# endif +#endif /* !defined(__cpp_lib_string_resize_and_overwrite) && defined(__glibcxx_want_string_resize_and_overwrite) */ +#undef __glibcxx_want_string_resize_and_overwrite + +// from version.def line 1586 +#if !defined(__cpp_lib_ratio) +# if (__cplusplus > 202302L) +# define __glibcxx_ratio 202306L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_ratio) +# define __cpp_lib_ratio 202306L +# endif +# endif +#endif /* !defined(__cpp_lib_ratio) && defined(__glibcxx_want_ratio) */ +#undef __glibcxx_want_ratio + +// from version.def line 1594 +#if !defined(__cpp_lib_to_string) +# if (__cplusplus > 202302L) && _GLIBCXX_HOSTED && (__glibcxx_to_chars) +# define __glibcxx_to_string 202306L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_to_string) +# define __cpp_lib_to_string 202306L +# endif +# endif +#endif /* !defined(__cpp_lib_to_string) && defined(__glibcxx_want_to_string) */ +#undef __glibcxx_want_to_string + +#undef __glibcxx_want_all diff --git a/libstdc++-v3/include/bits/version.tpl b/libstdc++-v3/include/bits/version.tpl new file mode 100644 index 000000000000..0b15eed35c3b --- /dev/null +++ b/libstdc++-v3/include/bits/version.tpl @@ -0,0 +1,210 @@ +/*{ AutoGen5 template -*- C++ -*- +h +(use-modules (srfi srfi-1)) +}*/ +// Copyright (C) 2023 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 +// . + +/*{ (dne "// ") }*/ + +/** @file bits/version.h + * This is an internal header file, included by other library headers. + * Do not attempt to use it directly. @headername{version} + */ + +// Usage guide: +// +// In your usual header, do something like: +// +// #define __glibcxx_want_ranges +// #define __glibcxx_want_concepts +// #include +// +// This will generate the FTMs you named, and let you use them in your code as +// if it was user code. All macros are also exposed under __glibcxx_NAME even +// if unwanted, to permit bits and other FTMs to depend on them for condtional +// computation without exposing extra FTMs to user code. + +#pragma GCC system_header + +#include +/*{ + +;; Helper for dealing with autogens redefined (error) +(define (ferror msg . args) + (error (apply format (cons* #f msg args)))) + + ;; Helper function that, in the context of a single FTM value, generates the +;; condition expression that fulfills the specification of this value. See the +;; comment block in version.def for an explanation of the format this +;; function parses. +(define (generate-cond) + (define c++min #f) + (define gnu++min #f) + (define gthread #f) + (define hosted #f) + (define c++11-abi #f) + (define extra-cond (get "extra_cond")) + + (define conds '()) + (define (prepend x) + (if x (set! conds (cons x conds)))) + + (if (string-null? extra-cond) + (set! extra-cond #f)) + + (let ((cxxmin (get "cxxmin")) + (gnuxxmin (get "gnuxxmin")) + (getstdcond + (lambda (var) + (let ((ver (get var))) + (if (not (string-null? ver)) + (let ((std-cond (get (format #f "stds[~a]" ver)))) + (if (string-null? std-cond) + (ferror "Standard ~s invalid." ver)) + std-cond) + #f))))) + (set! c++min (getstdcond "cxxmin")) + (set! gnu++min (getstdcond "gnuxxmin"))) + + (let ((process-tristate + (lambda (name) + (let ((val (get name))) + (cond + ((equal? val "") #f) ; Don't test + ((equal? val "yes") "") ; Test directly + ((equal? val "no") "!") ; Invert + (else (ferror "Bad ~a value ~a." name val))))))) + (set! gthread (process-tristate "gthread")) + (set! c++11-abi (process-tristate "cxx11abi")) + (set! hosted (process-tristate "hosted"))) + + (prepend (if extra-cond (format #f "(~a)" extra-cond) #f)) + (prepend (if hosted (format #f "~a~a" hosted "_GLIBCXX_HOSTED") #f)) + (prepend (if gthread (format #f "~a~a" gthread "defined(_GLIBCXX_HAS_GTHREADS)") #f)) + (prepend (if c++11-abi (format #f "~a~a" c++11-abi "_GLIBCXX_USE_CXX11_ABI") #f)) + + (prepend + (let ((strict "defined(__STRICT_ANSI__)") + (c++ "__cplusplus")) + (cond + ((or (and (equal? c++min gnu++min) c++min) + (and (not gnu++min) c++min)) + ;; If we have both values, and they are equal, or we only have gnu++min, + ;; we want to output a simple check. + (format #f "(~a ~a)" c++ c++min)) + ((and gnu++min c++min) + ;; We have differing cases for strict and non-strict modes. + (format #f "((~a && ~a ~a) || (!~a && ~a ~a))" + strict c++ c++min + strict c++ gnu++min)) + ((and gnu++min (not c++min)) + (format #f "(!~a && (~a ~a))" strict c++ gnu++min)) + (else #f)))) + (string-join conds " && " 'strict-infix)) + + + }*/ +/*{ FOR ftms + }*/// /*{ (def-file-line "name") }*/ +#if !defined(__cpp_lib_/*{name}*/) +/*{ FOR values }*//*{ # + + This macro block defines two versions of each FTM: + + 1. __glibcxx_NAME, which is defined unconditionally, and + 2. __cpp_lib_NAME, which is defined only if marked as wanted. + + This allows FTMs to depend on eachother in their definitions without messing + with the exported values. + + This can also be used by bits that do not want to expose FTMs that they can't + implement. + +}*/# /*{(unless (first-for?) "el")}*/if /*{(generate-cond)}*/ +# define __glibcxx_/*{name}*/ /*{v}*/L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_/*{name}*/) +# define /*{ +;; Compute the name for this FTM based on stdname/name. +(if (exist? "stdname") + (get "stdname") + (format #f "__cpp_lib_~a" (get "name"))) +}*/ /*{v}*/L +# endif +/*{ ENDFOR values + }*/# endif +#endif /* !defined(__cpp_lib_/*{name}*/) && defined(__glibcxx_want_/*{name}*/) */ +#undef __glibcxx_want_/*{name +}*//*{ (unless (last-for?) "\n\n" "\n")}*/ +/*{ ENDFOR ftms }*//*{ + +;; Helper that generates [LO, HI]. +(define (closed-int-set lo hi) + (iota (+ (- hi lo) 1) lo)) + +;; Sanity checking for duplicates and for value order. +(let ((ht (make-hash-table (count "ftms")))) + (for-each + (lambda (idx) + (let ((name (get (format #f "ftms[~a].name" idx)))) + (if (string-null? name) (ferror "No name for FTM ~a" idx)) + (let ((cur (cdr (or (hash-get-handle ht name) '(1 . 0))))) + (hash-set! ht name (+ cur 1))))) + (closed-int-set (low-lim "ftms") (high-lim "ftms"))) + (if (hash-fold + (lambda (name count prior) + (if (= 1 count) + prior + (begin + (printf "FTM %s appears %d times.\n" name count) + #t))) + #f ht) + (error "Duplicates found."))) + +(define (check-value-order ftm key order) + (let ((valmin 999999)) ; TODO(arsen): bump before year 10000 + (for-each + (lambda (vidx) + (let* ((sval (get (format #f "values[~a].~a" vidx key))) + (val (string->number sval))) + (unless (string-null? sval) + (unless val (ferror "Bad value in FTM ~a" ftm)) + (if (order val valmin) + (ferror "Found inverted ~s value in FTM ~a: ~a" key ftm sval)) + (set! valmin val)))) + (closed-int-set (low-lim "values") (high-lim "values"))))) + +}*//*{ FOR ftms }*//*{# + Check for values that are in ascending order. Because it is generally the + case that FTMs increase as the values of tests they probe for do, we check + them to prevent simple, silly errors. + + We're iterating in a separate FOR block rather than in pure Guile since, for + some reason, high-lim and low-lim do not work with complex names that include + periods and indices (whereas exist? and others do). +}*//*{ +(let ((ftm (get "name"))) + (check-value-order (get "name") "v" >) + (check-value-order (get "name") "cxxmin" >) + (check-value-order (get "name") "gnuxxmin" >)) +}*//*{ ENDFOR ftms }*/ +#undef __glibcxx_want_all diff --git a/libstdc++-v3/include/c_compatibility/stdatomic.h b/libstdc++-v3/include/c_compatibility/stdatomic.h index 0b633262d08f..52daa16c9b1e 100644 --- a/libstdc++-v3/include/c_compatibility/stdatomic.h +++ b/libstdc++-v3/include/c_compatibility/stdatomic.h @@ -29,10 +29,11 @@ #ifndef _GLIBCXX_STDATOMIC_H #define _GLIBCXX_STDATOMIC_H -#if __cplusplus > 202002L -#include +#define __glibcxx_want_stdatomic_h +#include -#define __cpp_lib_stdatomic_h 202011L +#ifdef __cpp_lib_stdatomic_h // C++ >= 23 +#include #define _Atomic(_Tp) std::atomic<_Tp> @@ -126,5 +127,5 @@ using std::atomic_signal_fence; #elif defined __clang__ # include_next -#endif // C++23 +#endif // __cpp_lib_stdatomic_h #endif // _GLIBCXX_STDATOMIC_H diff --git a/libstdc++-v3/include/c_global/cmath b/libstdc++-v3/include/c_global/cmath index b0ba395eb5cd..6461c92ebfe6 100644 --- a/libstdc++-v3/include/c_global/cmath +++ b/libstdc++-v3/include/c_global/cmath @@ -51,6 +51,10 @@ #ifndef _GLIBCXX_CMATH #define _GLIBCXX_CMATH 1 +#define __glibcxx_want_hypot +#define __glibcxx_want_interpolate +#include + // Get rid of those macros defined in in lieu of real functions. #undef div #undef acos @@ -1135,7 +1139,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template constexpr typename __gnu_cxx::__enable_if<__is_integer<_Tp>::__value, bool>::__type - isfinite(_Tp __x) + isfinite(_Tp) { return true; } #endif @@ -1162,7 +1166,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template constexpr typename __gnu_cxx::__enable_if<__is_integer<_Tp>::__value, bool>::__type - isinf(_Tp __x) + isinf(_Tp) { return false; } #endif @@ -1189,7 +1193,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template constexpr typename __gnu_cxx::__enable_if<__is_integer<_Tp>::__value, bool>::__type - isnan(_Tp __x) + isnan(_Tp) { return false; } #endif @@ -3544,11 +3548,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION #endif // _GLIBCXX_USE_C99_MATH_FUNCS #endif // C++11 -#if __cplusplus >= 201703L - +#ifdef __cpp_lib_hypot // C++ >= 17 && HOSTED // [c.math.hypot3], three-dimensional hypotenuse -#define __cpp_lib_hypot 201603L - template inline _Tp __hypot3(_Tp __x, _Tp __y, _Tp __z) @@ -3616,12 +3617,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { return std::__hypot3<__gnu_cxx::__bfloat16_t>(__x, __y, __z); } #endif -#endif // C++17 +#endif // __cpp_lib_hypot -#if __cplusplus >= 202002L +#ifdef __cpp_lib_interpolate // C++ >= 20 // linear interpolation -# define __cpp_lib_interpolate 201902L - template constexpr _Fp __lerp(_Fp __a, _Fp __b, _Fp __t) noexcept @@ -3691,8 +3690,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION lerp(__gnu_cxx::__bfloat16_t __x, __gnu_cxx::__bfloat16_t __y, __gnu_cxx::__bfloat16_t __z) noexcept { return std::__lerp<__gnu_cxx::__bfloat16_t>(__x, __y, __z); } #endif - -#endif // C++20 +#endif // __cpp_lib_interpolate _GLIBCXX_END_NAMESPACE_VERSION } // namespace diff --git a/libstdc++-v3/include/c_global/cstddef b/libstdc++-v3/include/c_global/cstddef index 728ac796542c..3cdd551d3aee 100644 --- a/libstdc++-v3/include/c_global/cstddef +++ b/libstdc++-v3/include/c_global/cstddef @@ -49,6 +49,9 @@ #include #include +#define __glibcxx_want_byte +#include + extern "C++" { #if __cplusplus >= 201103L @@ -59,12 +62,10 @@ namespace std } #endif // C++11 -#if __cplusplus >= 201703L +#ifdef __cpp_lib_byte // C++ >= 17 namespace std { _GLIBCXX_BEGIN_NAMESPACE_VERSION -#define __cpp_lib_byte 201603L - /// std::byte enum class byte : unsigned char {}; @@ -185,7 +186,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _GLIBCXX_END_NAMESPACE_VERSION } // namespace std -#endif // C++17 +#endif // __cpp_lib_byte } // extern "C++" #endif // _GLIBCXX_CSTDDEF diff --git a/libstdc++-v3/include/experimental/bits/fs_path.h b/libstdc++-v3/include/experimental/bits/fs_path.h index e0e47188bb98..bf07754fd848 100644 --- a/libstdc++-v3/include/experimental/bits/fs_path.h +++ b/libstdc++-v3/include/experimental/bits/fs_path.h @@ -1042,7 +1042,7 @@ namespace __detail inline std::basic_string<_CharT, _Traits, _Allocator> path::string(const _Allocator& __a) const { - if _GLIBCXX_CONSTEXPR (is_same<_CharT, value_type>::value) + if _GLIBCXX17_CONSTEXPR (is_same<_CharT, value_type>::value) return { _M_pathname.begin(), _M_pathname.end(), __a }; using _WString = basic_string<_CharT, _Traits, _Allocator>; diff --git a/libstdc++-v3/include/experimental/internet b/libstdc++-v3/include/experimental/internet index bd9a05f12aa9..173913a8cec5 100644 --- a/libstdc++-v3/include/experimental/internet +++ b/libstdc++-v3/include/experimental/internet @@ -252,7 +252,7 @@ namespace ip __string_with<_Allocator> to_string(const _Allocator& __a = _Allocator()) const { - auto __write = [__addr = to_uint()](char* __p, size_t __n) { + auto __write = [__addr = to_uint()](char* __p, size_t) { auto __to_chars = [](char* __p, uint8_t __v) { unsigned __n = __v >= 100u ? 3 : __v >= 10u ? 2 : 1; std::__detail::__to_chars_10_impl(__p, __n, __v); diff --git a/libstdc++-v3/include/std/algorithm b/libstdc++-v3/include/std/algorithm index fc393eeacf75..c6ebb86e6a94 100644 --- a/libstdc++-v3/include/std/algorithm +++ b/libstdc++-v3/include/std/algorithm @@ -63,7 +63,10 @@ # include #endif -#if __cplusplus > 201402L && _GLIBCXX_HOSTED +#define __glibcxx_want_parallel_algorithm +#include + +#if __cpp_lib_parallel_algorithm // C++ >= 17 && HOSTED // Parallel STL algorithms # if _PSTL_EXECUTION_POLICIES_DEFINED // If has already been included, pull in implementations @@ -73,10 +76,7 @@ # include # define _PSTL_ALGORITHM_FORWARD_DECLARED 1 # endif - -// Feature test macro for parallel algorithms -# define __cpp_lib_parallel_algorithm 201603L -#endif // C++17 && HOSTED +#endif #ifdef _GLIBCXX_PARALLEL # include diff --git a/libstdc++-v3/include/std/any b/libstdc++-v3/include/std/any index a221445df275..288eb9155691 100644 --- a/libstdc++-v3/include/std/any +++ b/libstdc++-v3/include/std/any @@ -31,7 +31,10 @@ #pragma GCC system_header -#if __cplusplus >= 201703L +#define __glibcxx_want_any +#include + +#ifdef __cpp_lib_any // C++ >= 17 #include #include @@ -67,8 +70,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION #endif } -#define __cpp_lib_any 201606L - /** * @brief A type-safe container of any type. * @@ -652,5 +653,5 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _GLIBCXX_END_NAMESPACE_VERSION } // namespace std -#endif // C++17 +#endif // __cpp_lib_any #endif // _GLIBCXX_ANY diff --git a/libstdc++-v3/include/std/array b/libstdc++-v3/include/std/array index ad36cdad6d21..0e32d7b52d01 100644 --- a/libstdc++-v3/include/std/array +++ b/libstdc++-v3/include/std/array @@ -45,6 +45,9 @@ #include // std::index_sequence, std::tuple_size #include +#define __glibcxx_want_to_array +#include + namespace std _GLIBCXX_VISIBILITY(default) { _GLIBCXX_BEGIN_NAMESPACE_VERSION @@ -297,7 +300,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION operator==(const array<_Tp, _Nm>& __one, const array<_Tp, _Nm>& __two) { return std::equal(__one.begin(), __one.end(), __two.begin()); } -#if __cpp_lib_three_way_comparison && __cpp_lib_concepts +#if __cpp_lib_three_way_comparison // C++ >= 20 && lib_concepts template [[nodiscard]] constexpr __detail::__synth3way_t<_Tp> @@ -414,8 +417,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION return std::move(std::get<_Int>(__arr)); } -#if __cplusplus >= 202002L && __cpp_generic_lambdas >= 201707L -#define __cpp_lib_to_array 201907L +#ifdef __cpp_lib_to_array // C++ >= 20 && __cpp_generic_lambdas >= 201707L template [[nodiscard]] constexpr array, _Nm> @@ -473,7 +475,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION else __builtin_unreachable(); // FIXME: see PR c++/91388 } -#endif // C++20 +#endif // __cpp_lib_to_array // Tuple interface to class template array. diff --git a/libstdc++-v3/include/std/atomic b/libstdc++-v3/include/std/atomic index 111df2a978b5..713ee2cc5397 100644 --- a/libstdc++-v3/include/std/atomic +++ b/libstdc++-v3/include/std/atomic @@ -38,6 +38,12 @@ # include #else +#define __glibcxx_want_atomic_is_always_lock_free +#define __glibcxx_want_atomic_float +#define __glibcxx_want_atomic_ref +#define __glibcxx_want_atomic_lock_free_type_aliases +#include + #include namespace std _GLIBCXX_VISIBILITY(default) @@ -49,10 +55,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION * @{ */ -#if __cplusplus >= 201703L -# define __cpp_lib_atomic_is_always_lock_free 201603L -#endif - template struct atomic; @@ -95,7 +97,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION bool is_lock_free() const volatile noexcept { return _M_base.is_lock_free(); } -#if __cplusplus >= 201703L +#ifdef __cpp_lib_atomic_is_always_lock_free // C++ >= 17 static constexpr bool is_always_lock_free = ATOMIC_BOOL_LOCK_FREE == 2; #endif @@ -268,7 +270,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION reinterpret_cast(-_S_alignment)); } -#if __cplusplus >= 201703L +#ifdef __cpp_lib_atomic_is_always_lock_free // C++ >= 17 static constexpr bool is_always_lock_free = __atomic_always_lock_free(sizeof(_M_i), 0); #endif @@ -386,23 +388,23 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { return compare_exchange_strong(__e, __i, __m, __cmpexch_failure_order(__m)); } -#if __cpp_lib_atomic_wait - void - wait(_Tp __old, memory_order __m = memory_order_seq_cst) const noexcept - { - std::__atomic_wait_address_v(&_M_i, __old, - [__m, this] { return this->load(__m); }); - } +#if __cpp_lib_atomic_wait // C++ >= 20 + void + wait(_Tp __old, memory_order __m = memory_order_seq_cst) const noexcept + { + std::__atomic_wait_address_v(&_M_i, __old, + [__m, this] { return this->load(__m); }); + } - // TODO add const volatile overload + // TODO add const volatile overload - void - notify_one() noexcept - { std::__atomic_notify_address(&_M_i, false); } + void + notify_one() noexcept + { std::__atomic_notify_address(&_M_i, false); } - void - notify_all() noexcept - { std::__atomic_notify_address(&_M_i, true); } + void + notify_all() noexcept + { std::__atomic_notify_address(&_M_i, true); } #endif // __cpp_lib_atomic_wait }; @@ -557,7 +559,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION is_lock_free() const volatile noexcept { return _M_b.is_lock_free(); } -#if __cplusplus >= 201703L +#ifdef __cpp_lib_atomic_is_always_lock_free // C++ >= 17 static constexpr bool is_always_lock_free = ATOMIC_POINTER_LOCK_FREE == 2; #endif @@ -720,7 +722,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION using __base_type::operator __integral_type; using __base_type::operator=; -#if __cplusplus >= 201703L +#ifdef __cpp_lib_atomic_is_always_lock_free // C++ >= 17 static constexpr bool is_always_lock_free = ATOMIC_CHAR_LOCK_FREE == 2; #endif }; @@ -743,7 +745,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION using __base_type::operator __integral_type; using __base_type::operator=; -#if __cplusplus >= 201703L +#ifdef __cpp_lib_atomic_is_always_lock_free // C++ >= 17 static constexpr bool is_always_lock_free = ATOMIC_CHAR_LOCK_FREE == 2; #endif }; @@ -766,7 +768,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION using __base_type::operator __integral_type; using __base_type::operator=; -#if __cplusplus >= 201703L +#ifdef __cpp_lib_atomic_is_always_lock_free // C++ >= 17 static constexpr bool is_always_lock_free = ATOMIC_CHAR_LOCK_FREE == 2; #endif }; @@ -789,7 +791,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION using __base_type::operator __integral_type; using __base_type::operator=; -#if __cplusplus >= 201703L +#ifdef __cpp_lib_atomic_is_always_lock_free // C++ >= 17 static constexpr bool is_always_lock_free = ATOMIC_SHORT_LOCK_FREE == 2; #endif }; @@ -812,7 +814,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION using __base_type::operator __integral_type; using __base_type::operator=; -#if __cplusplus >= 201703L +#ifdef __cpp_lib_atomic_is_always_lock_free // C++ >= 17 static constexpr bool is_always_lock_free = ATOMIC_SHORT_LOCK_FREE == 2; #endif }; @@ -835,7 +837,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION using __base_type::operator __integral_type; using __base_type::operator=; -#if __cplusplus >= 201703L +#ifdef __cpp_lib_atomic_is_always_lock_free // C++ >= 17 static constexpr bool is_always_lock_free = ATOMIC_INT_LOCK_FREE == 2; #endif }; @@ -858,7 +860,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION using __base_type::operator __integral_type; using __base_type::operator=; -#if __cplusplus >= 201703L +#ifdef __cpp_lib_atomic_is_always_lock_free // C++ >= 17 static constexpr bool is_always_lock_free = ATOMIC_INT_LOCK_FREE == 2; #endif }; @@ -881,7 +883,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION using __base_type::operator __integral_type; using __base_type::operator=; -#if __cplusplus >= 201703L +#ifdef __cpp_lib_atomic_is_always_lock_free // C++ >= 17 static constexpr bool is_always_lock_free = ATOMIC_LONG_LOCK_FREE == 2; #endif }; @@ -904,7 +906,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION using __base_type::operator __integral_type; using __base_type::operator=; -#if __cplusplus >= 201703L +#ifdef __cpp_lib_atomic_is_always_lock_free // C++ >= 17 static constexpr bool is_always_lock_free = ATOMIC_LONG_LOCK_FREE == 2; #endif }; @@ -927,7 +929,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION using __base_type::operator __integral_type; using __base_type::operator=; -#if __cplusplus >= 201703L +#ifdef __cpp_lib_atomic_is_always_lock_free // C++ >= 17 static constexpr bool is_always_lock_free = ATOMIC_LLONG_LOCK_FREE == 2; #endif }; @@ -950,7 +952,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION using __base_type::operator __integral_type; using __base_type::operator=; -#if __cplusplus >= 201703L +#ifdef __cpp_lib_atomic_is_always_lock_free // C++ >= 17 static constexpr bool is_always_lock_free = ATOMIC_LLONG_LOCK_FREE == 2; #endif }; @@ -973,7 +975,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION using __base_type::operator __integral_type; using __base_type::operator=; -#if __cplusplus >= 201703L +#ifdef __cpp_lib_atomic_is_always_lock_free // C++ >= 17 static constexpr bool is_always_lock_free = ATOMIC_WCHAR_T_LOCK_FREE == 2; #endif }; @@ -997,7 +999,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION using __base_type::operator __integral_type; using __base_type::operator=; -#if __cplusplus > 201402L +#ifdef __cpp_lib_atomic_is_always_lock_free // C++ >= 17 static constexpr bool is_always_lock_free = ATOMIC_CHAR8_T_LOCK_FREE == 2; #endif @@ -1022,7 +1024,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION using __base_type::operator __integral_type; using __base_type::operator=; -#if __cplusplus >= 201703L +#ifdef __cpp_lib_atomic_is_always_lock_free // C++ >= 17 static constexpr bool is_always_lock_free = ATOMIC_CHAR16_T_LOCK_FREE == 2; #endif @@ -1046,7 +1048,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION using __base_type::operator __integral_type; using __base_type::operator=; -#if __cplusplus >= 201703L +#ifdef __cpp_lib_atomic_is_always_lock_free // C++ >= 17 static constexpr bool is_always_lock_free = ATOMIC_CHAR32_T_LOCK_FREE == 2; #endif @@ -1614,8 +1616,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION __atomic_val_t<_ITp> __i) noexcept { return atomic_fetch_xor_explicit(__a, __i, memory_order_seq_cst); } -#if __cplusplus > 201703L -#define __cpp_lib_atomic_float 201711L +#ifdef __cpp_lib_atomic_float template<> struct atomic : __atomic_float { @@ -1745,9 +1746,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION using __atomic_float<__gnu_cxx::__bfloat16_t>::operator=; }; #endif +#endif // __cpp_lib_atomic_float -#define __cpp_lib_atomic_ref 201806L - +#ifdef __cpp_lib_atomic_ref /// Class template to provide atomic operations on a non-atomic variable. template struct atomic_ref : __atomic_ref<_Tp> @@ -1762,26 +1763,28 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION using __atomic_ref<_Tp>::operator=; }; +#endif // __cpp_lib_atomic_ref -#define __cpp_lib_atomic_lock_free_type_aliases 201907L -#ifdef _GLIBCXX_HAVE_PLATFORM_WAIT +#ifdef __cpp_lib_atomic_lock_free_type_aliases +# ifdef _GLIBCXX_HAVE_PLATFORM_WAIT using atomic_signed_lock_free = atomic>; using atomic_unsigned_lock_free = atomic>; -#elif ATOMIC_INT_LOCK_FREE || !(ATOMIC_LONG_LOCK_FREE || ATOMIC_CHAR_LOCK_FREE) +# elif ATOMIC_INT_LOCK_FREE || !(ATOMIC_LONG_LOCK_FREE || ATOMIC_CHAR_LOCK_FREE) using atomic_signed_lock_free = atomic; using atomic_unsigned_lock_free = atomic; -#elif ATOMIC_LONG_LOCK_FREE +# elif ATOMIC_LONG_LOCK_FREE using atomic_signed_lock_free = atomic; using atomic_unsigned_lock_free = atomic; -#elif ATOMIC_CHAR_LOCK_FREE +# elif ATOMIC_CHAR_LOCK_FREE using atomic_signed_lock_free = atomic; using atomic_unsigned_lock_free = atomic; +# else +# error "libstdc++ bug: no lock-free atomics but they were emitted in " +# endif #endif -#endif // C++2a - /// @} group atomics _GLIBCXX_END_NAMESPACE_VERSION diff --git a/libstdc++-v3/include/std/barrier b/libstdc++-v3/include/std/barrier index 6070ad5cd274..8e03a5820c6e 100644 --- a/libstdc++-v3/include/std/barrier +++ b/libstdc++-v3/include/std/barrier @@ -42,16 +42,16 @@ #include // threading primitive -#if __cplusplus > 201703L +#define __glibcxx_want_barrier +#include + +#ifdef __cpp_lib_barrier // C++ >= 20 && __cpp_aligned_new && lib_atomic_wait #include -#if __cpp_lib_atomic_wait && __cpp_aligned_new #include #include #include -#define __cpp_lib_barrier 201907L - namespace std _GLIBCXX_VISIBILITY(default) { _GLIBCXX_BEGIN_NAMESPACE_VERSION @@ -261,6 +261,5 @@ It looks different from literature pseudocode for two main reasons: _GLIBCXX_END_NAMESPACE_VERSION } // namespace -#endif // __cpp_lib_atomic_wait && __cpp_aligned_new -#endif // __cplusplus > 201703L +#endif // __cpp_lib_barrier #endif // _GLIBCXX_BARRIER diff --git a/libstdc++-v3/include/std/bit b/libstdc++-v3/include/std/bit index 5eb40218be9d..987b6cdbb355 100644 --- a/libstdc++-v3/include/std/bit +++ b/libstdc++-v3/include/std/bit @@ -52,6 +52,13 @@ namespace __gnu_cxx /// @endcond #endif +#define __glibcxx_want_bit_cast +#define __glibcxx_want_byteswap +#define __glibcxx_want_bitops +#define __glibcxx_want_int_pow2 +#define __glibcxx_want_endian +#include + namespace std _GLIBCXX_VISIBILITY(default) { _GLIBCXX_BEGIN_NAMESPACE_VERSION @@ -65,8 +72,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION * @{ */ -#if __cplusplus > 201703l && __has_builtin(__builtin_bit_cast) -#define __cpp_lib_bit_cast 201806L +#ifdef __cpp_lib_bit_cast // C++ >= 20 /// Create a value of type `To` from the bits of `from`. /** @@ -86,10 +92,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { return __builtin_bit_cast(_To, __from); } -#endif +#endif // __cpp_lib_bit_cast -#if __cplusplus > 202002L -#define __cpp_lib_byteswap 202110L +#ifdef __cpp_lib_byteswap // C++ >= 23 /// Reverse order of bytes in the object representation of `value`. /** @@ -142,7 +147,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } return __val; } -#endif +#endif // __cpp_lib_byteswap /// @cond undocumented @@ -370,9 +375,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION /// @endcond -#if __cplusplus > 201703L - -#define __cpp_lib_bitops 201907L +#ifdef __cpp_lib_bitops // C++ >= 20 /// @cond undocumented template @@ -425,11 +428,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION constexpr _If_is_unsigned_integer<_Tp, int> popcount(_Tp __x) noexcept { return std::__popcount(__x); } +#endif // __cpp_lib_bitops +#ifdef __cpp_lib_int_pow2 // C++ >= 20 // [bit.pow.two], integral powers of 2 -#define __cpp_lib_int_pow2 202002L - /// True if `x` is a power of two, false otherwise. template constexpr _If_is_unsigned_integer<_Tp, bool> @@ -455,8 +458,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION constexpr _If_is_unsigned_integer<_Tp, int> bit_width(_Tp __x) noexcept { return std::__bit_width(__x); } +#endif // defined (__cpp_lib_int_pow2) -#define __cpp_lib_endian 201907L +#ifdef __cpp_lib_endian // C++ >= 20 /// Byte order constants /** @@ -471,7 +475,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION big = __ORDER_BIG_ENDIAN__, native = __BYTE_ORDER__ }; -#endif // C++2a +#endif // __cpp_lib_endian /// @} diff --git a/libstdc++-v3/include/std/bitset b/libstdc++-v3/include/std/bitset index acd5768d6f6a..a0379ed101a1 100644 --- a/libstdc++-v3/include/std/bitset +++ b/libstdc++-v3/include/std/bitset @@ -58,6 +58,9 @@ # include #endif +#define __glibcxx_want_constexpr_bitset +#include + #define _GLIBCXX_BITSET_BITS_PER_WORD (__CHAR_BIT__ * __SIZEOF_LONG__) #define _GLIBCXX_BITSET_WORDS(__n) \ ((__n) / _GLIBCXX_BITSET_BITS_PER_WORD + \ @@ -69,10 +72,6 @@ namespace std _GLIBCXX_VISIBILITY(default) { _GLIBCXX_BEGIN_NAMESPACE_CONTAINER -#if __cplusplus > 202002L && _GLIBCXX_HOSTED -# define __cpp_lib_constexpr_bitset 202202L -#endif - /** * Base class, general case. It is a class invariant that _Nw will be * nonnegative. diff --git a/libstdc++-v3/include/std/charconv b/libstdc++-v3/include/std/charconv index b34d672f5bd0..01711d38576a 100644 --- a/libstdc++-v3/include/std/charconv +++ b/libstdc++-v3/include/std/charconv @@ -45,14 +45,9 @@ #include // for std::errc #include -#if _GLIBCXX_FLOAT_IS_IEEE_BINARY32 && _GLIBCXX_DOUBLE_IS_IEEE_BINARY64 \ - && __SIZE_WIDTH__ >= 32 && _GLIBCXX_HOSTED -# define __cpp_lib_to_chars 201611L -#endif - -#if __cplusplus > 202002L -# define __cpp_lib_constexpr_charconv 202207L -#endif +#define __glibcxx_want_to_chars +#define __glibcxx_want_constexpr_charconv +#include namespace std _GLIBCXX_VISIBILITY(default) { @@ -242,7 +237,7 @@ namespace __detail static_assert(__integer_to_chars_is_unsigned<_Tp>, "implementation bug"); to_chars_result __res; - unsigned __len; + unsigned __len = 0; if _GLIBCXX17_CONSTEXPR (__gnu_cxx::__int_traits<_Tp>::__digits <= 16) { diff --git a/libstdc++-v3/include/std/chrono b/libstdc++-v3/include/std/chrono index 660e8d2b7460..10e868e5a036 100644 --- a/libstdc++-v3/include/std/chrono +++ b/libstdc++-v3/include/std/chrono @@ -50,12 +50,6 @@ # include #endif -#if __cplusplus >= 202002L -// TODO formatting and parsing -// # undef __cpp_lib_chrono -// # define __cpp_lib_chrono 201907L -#endif - namespace std _GLIBCXX_VISIBILITY(default) { _GLIBCXX_BEGIN_NAMESPACE_VERSION @@ -2792,7 +2786,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION private: friend const tzdb& reload_tzdb(); - friend class tzdb_list::_Node; + friend struct tzdb_list::_Node; explicit time_zone_link(nullptr_t) { } @@ -2896,7 +2890,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION private: explicit leap_second(seconds::rep __s) : _M_s(__s) { } - friend class tzdb_list::_Node; + friend struct tzdb_list::_Node; friend const tzdb& reload_tzdb(); @@ -2937,7 +2931,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION private: friend const tzdb& reload_tzdb(); friend class time_zone; - friend class tzdb_list::_Node; + friend struct tzdb_list::_Node; }; tzdb_list& get_tzdb_list(); @@ -3039,7 +3033,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template zoned_time(_TimeZonePtr __z, const zoned_time<_Duration2, _TimeZonePtr2>& __zt, - choose __c) + choose) requires is_convertible_v, sys_time<_Duration>> : _M_zone(__z), _M_tp(__zt._M_tp) { } @@ -3057,7 +3051,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template zoned_time(string_view __name, const zoned_time<_Duration2, _TimeZonePtr2>& __zt, - choose __c) + choose) requires is_convertible_v, sys_time<_Duration>> && requires { { _Traits::locate_zone(__name) } -> convertible_to<_TimeZonePtr>; diff --git a/libstdc++-v3/include/std/complex b/libstdc++-v3/include/std/complex index f01a3af43718..b70fd6ea6a7a 100644 --- a/libstdc++-v3/include/std/complex +++ b/libstdc++-v3/include/std/complex @@ -47,10 +47,15 @@ // Get rid of a macro possibly defined in #undef complex -#if __cplusplus > 201703L -# define __cpp_lib_constexpr_complex 201711L +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wc99-extensions" #endif +#define __glibcxx_want_constexpr_complex +#define __glibcxx_want_complex_udls +#include + namespace std _GLIBCXX_VISIBILITY(default) { _GLIBCXX_BEGIN_NAMESPACE_VERSION @@ -1359,6 +1364,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } #endif +#if __cplusplus >= 201103L + _GLIBCXX14_CONSTEXPR complex(const complex&) = default; +#endif + #if __cplusplus > 202002L template explicit(!requires(_Up __u) { value_type{__u}; }) @@ -1512,6 +1521,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } #endif +#if __cplusplus >= 201103L + _GLIBCXX14_CONSTEXPR complex(const complex&) = default; +#endif + #if __cplusplus > 202002L template explicit(!requires(_Up __u) { value_type{__u}; }) @@ -1666,6 +1679,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } #endif +#if __cplusplus >= 201103L + _GLIBCXX14_CONSTEXPR complex(const complex&) = default; +#endif + #if __cplusplus > 202002L template explicit(!requires(_Up __u) { value_type{__u}; }) @@ -1901,6 +1918,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION // Let the compiler synthesize the copy and assignment // operator. It always does a pretty good job. + constexpr complex(const complex&) = default; constexpr complex& operator=(const complex&) = default; template @@ -2586,13 +2604,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION return std::complex<__type>(__x, -__type()); } -#if __cplusplus > 201103L +#ifdef __cpp_lib_complex_udls // C++ >= 14 inline namespace literals { inline namespace complex_literals { #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wliteral-suffix" -#define __cpp_lib_complex_udls 201309L constexpr std::complex operator""if(long double __num) @@ -2622,11 +2639,15 @@ inline namespace complex_literals { } // inline namespace complex_literals } // inline namespace literals -#endif // C++14 +#endif // __cpp_lib_complex_udls _GLIBCXX_END_NAMESPACE_VERSION } // namespace #endif // C++11 +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + #endif /* _GLIBCXX_COMPLEX */ diff --git a/libstdc++-v3/include/std/concepts b/libstdc++-v3/include/std/concepts index d77f7e5647ac..d8a05ffab33b 100644 --- a/libstdc++-v3/include/std/concepts +++ b/libstdc++-v3/include/std/concepts @@ -30,10 +30,12 @@ #ifndef _GLIBCXX_CONCEPTS #define _GLIBCXX_CONCEPTS 1 -#if __cplusplus > 201703L && __cpp_concepts >= 201907L - #pragma GCC system_header +#define __glibcxx_want_concepts +#include + +#ifdef __cpp_lib_concepts // C++ >= 20 && concepts /** * @defgroup concepts Concepts * @ingroup utilities @@ -47,8 +49,6 @@ namespace std _GLIBCXX_VISIBILITY(default) { _GLIBCXX_BEGIN_NAMESPACE_VERSION -#define __cpp_lib_concepts 202002L - // [concepts.lang], language-related concepts namespace __detail @@ -376,6 +376,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _GLIBCXX_END_NAMESPACE_VERSION } // namespace -#endif // C++2a +#endif // __cpp_lib_concepts #endif /* _GLIBCXX_CONCEPTS */ diff --git a/libstdc++-v3/include/std/coroutine b/libstdc++-v3/include/std/coroutine index b0ca18949dbe..14d0ea28b915 100644 --- a/libstdc++-v3/include/std/coroutine +++ b/libstdc++-v3/include/std/coroutine @@ -31,8 +31,14 @@ #pragma GCC system_header -// It is very likely that earlier versions would work, but they are untested. -#if __cplusplus >= 201402L +#define __glibcxx_want_coroutine +#include + +#if !__cpp_impl_coroutine +# error "the header requires -fcoroutines" +#endif + +#ifdef __cpp_lib_coroutine // C++ >= 14 && impl_coroutine #include #if __cplusplus > 201703L @@ -55,10 +61,6 @@ namespace std _GLIBCXX_VISIBILITY (default) { _GLIBCXX_BEGIN_NAMESPACE_VERSION -#if __cpp_impl_coroutine - -#define __cpp_lib_coroutine 201902L - inline namespace __n4861 { // C++20 17.12.2 coroutine traits @@ -351,13 +353,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } }; -#else -#error "the header requires -fcoroutines" -#endif - _GLIBCXX_END_NAMESPACE_VERSION } // namespace std -#endif // C++14 (we are allowing use from at least this) +#endif // __cpp_lib_coroutine #endif // _GLIBCXX_COROUTINE diff --git a/libstdc++-v3/include/std/deque b/libstdc++-v3/include/std/deque index e3d50d2cf8b1..c0b05ddfc647 100644 --- a/libstdc++-v3/include/std/deque +++ b/libstdc++-v3/include/std/deque @@ -68,6 +68,9 @@ #include #include +#define __glibcxx_want_erase_if +#include + #ifdef _GLIBCXX_DEBUG # include #endif @@ -86,13 +89,11 @@ _GLIBCXX_END_NAMESPACE_VERSION } // namespace std #endif // C++17 -#if __cplusplus > 201703L +#ifdef __cpp_lib_erase_if // C++ >= 20 && erase_if namespace std _GLIBCXX_VISIBILITY(default) { _GLIBCXX_BEGIN_NAMESPACE_VERSION -#define __cpp_lib_erase_if 202002L - template inline typename deque<_Tp, _Alloc>::size_type erase_if(deque<_Tp, _Alloc>& __cont, _Predicate __pred) @@ -134,6 +135,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } _GLIBCXX_END_NAMESPACE_VERSION } // namespace std -#endif // C++20 +#endif // __cpp_lib_erase_if #endif /* _GLIBCXX_DEQUE */ diff --git a/libstdc++-v3/include/std/execution b/libstdc++-v3/include/std/execution index 14c8bbeef4f7..4349e2b9dd5a 100644 --- a/libstdc++-v3/include/std/execution +++ b/libstdc++-v3/include/std/execution @@ -29,7 +29,12 @@ #include // execution policies are hosted only -#if __cplusplus >= 201703L +#define __glibcxx_want_parallel_algorithm +#define __glibcxx_want_execution +#include + +// C++ >= 17 && HOSTED +#if defined(__cpp_lib_parallel_algorithm) || defined(__cpp_lib_execution) # include # include @@ -50,10 +55,6 @@ # include # endif -// Feature test macro for parallel algorithms -# define __cpp_lib_parallel_algorithm 201603L -# define __cpp_lib_execution 201902L - #endif // C++17 #endif /* _GLIBCXX_EXECUTION */ diff --git a/libstdc++-v3/include/std/expected b/libstdc++-v3/include/std/expected index a63557448f76..a796f0b6f27e 100644 --- a/libstdc++-v3/include/std/expected +++ b/libstdc++-v3/include/std/expected @@ -31,8 +31,10 @@ #pragma GCC system_header -#if __cplusplus > 202002L && __cpp_concepts >= 202002L +#define __glibcxx_want_expected +#include +#ifdef __cpp_lib_expected // C++ >= 23 && __cpp_concepts >= 202002L #include #include // exception #include // __invoke @@ -50,8 +52,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION * @{ */ -#define __cpp_lib_expected 202211L - /// Discriminated union that holds an expected value or an error value. /** * @since C++23 @@ -1815,5 +1815,5 @@ namespace __expected _GLIBCXX_END_NAMESPACE_VERSION } // namespace std -#endif // C++23 +#endif // __cpp_lib_expected #endif // _GLIBCXX_EXPECTED diff --git a/libstdc++-v3/include/std/filesystem b/libstdc++-v3/include/std/filesystem index d46e842826d0..69b5a9cae285 100644 --- a/libstdc++-v3/include/std/filesystem +++ b/libstdc++-v3/include/std/filesystem @@ -34,7 +34,10 @@ #include -#if __cplusplus >= 201703L +#define __glibcxx_want_filesystem +#include + +#ifdef __cpp_lib_filesystem // C++ >= 17 && HOSTED /** * @defgroup filesystem File System @@ -50,8 +53,6 @@ #include #include -#define __cpp_lib_filesystem 201703L - -#endif // C++17 +#endif // __cpp_lib_filesystem #endif // _GLIBCXX_FILESYSTEM diff --git a/libstdc++-v3/include/std/format b/libstdc++-v3/include/std/format index 1e0ef612ddd8..128a5b79282e 100644 --- a/libstdc++-v3/include/std/format +++ b/libstdc++-v3/include/std/format @@ -33,7 +33,10 @@ #include // for std::string -#if __cplusplus >= 202002L +#define __glibcxx_want_format +#include + +#ifdef __cpp_lib_format // C++ >= 20 && HOSTED #include #include @@ -60,18 +63,6 @@ namespace std _GLIBCXX_VISIBILITY(default) { _GLIBCXX_BEGIN_NAMESPACE_VERSION -// 201907 Text Formatting, Integration of chrono, printf corner cases. -// 202106 std::format improvements. -// 202110 Fixing locale handling in chrono formatters, generator-like types. -// 202207 Encodings in localized formatting of chrono, basic-format-string. -#define __cpp_lib_format 202106L - -#if __cplusplus > 202002L -// 202207 P2286R8 Formatting Ranges -// 202207 P2585R1 Improving default container formatting -// TODO: #define __cpp_lib_format_ranges 202207L -#endif - // [format.context], class template basic_format_context template class basic_format_context; @@ -79,22 +70,27 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION namespace __format { // Type-erased character sink. - template struct _Sink; + template class _Sink; // Output iterator that writes to a type-erase character sink. template class _Sink_iter; + + template + using __format_context = basic_format_context<_Sink_iter<_CharT>, _CharT>; } // namespace __format /// @endcond - using format_context - = basic_format_context<__format::_Sink_iter, char>; - using wformat_context - = basic_format_context<__format::_Sink_iter, wchar_t>; + using format_context = __format::__format_context; +#ifdef _GLIBCXX_USE_WCHAR_T + using wformat_context = __format::__format_context; +#endif // [format.args], class template basic_format_args template class basic_format_args; using format_args = basic_format_args; +#ifdef _GLIBCXX_USE_WCHAR_T using wformat_args = basic_format_args; +#endif // [format.arguments], arguments // [format.arg], class template basic_format_arg @@ -127,9 +123,11 @@ namespace __format template using format_string = basic_format_string...>; +#ifdef _GLIBCXX_USE_WCHAR_T template using wformat_string = basic_format_string...>; +#endif // [format.formatter], formatter @@ -190,7 +188,9 @@ namespace __format // [format.parse.ctx], class template basic_format_parse_context template class basic_format_parse_context; using format_parse_context = basic_format_parse_context; +#ifdef _GLIBCXX_USE_WCHAR_T using wformat_parse_context = basic_format_parse_context; +#endif template class basic_format_parse_context @@ -280,13 +280,13 @@ namespace __format } else { - unsigned short __val = 0; constexpr int __n = 32; char __buf[__n]{}; for (int __i = 0; __i < __n && (__first + __i) != __last; ++__i) __buf[__i] = __first[__i]; auto [__v, __ptr] = __format::__parse_integer(__buf, __buf + __n); - return {__v, __first + (__ptr - __buf)}; + if (__ptr) [[likely]] + return {__v, __first + (__ptr - __buf)}; } return {0, nullptr}; } @@ -319,7 +319,7 @@ namespace __format // Presentation types for integral types (including bool and charT). _Pres_d = 1, _Pres_b, _Pres_B, _Pres_o, _Pres_x, _Pres_X, _Pres_c, // Presentation types for floating-point types. - _Pres_a = 1, _Pres_A, _Pres_e, _Pres_E, _Pres_f, _Pres_g, _Pres_G, + _Pres_a = 1, _Pres_A, _Pres_e, _Pres_E, _Pres_f, _Pres_F, _Pres_g, _Pres_G, _Pres_p = 0, _Pres_P, // For pointers. _Pres_s = 0, // For strings and bool. _Pres_esc = 0xf, // For strings and charT. @@ -521,10 +521,11 @@ namespace __format if (__first[0] != '.') return __first; - ++__first; + iterator __next = ++__first; bool __arg_id = false; - auto __next = _S_parse_width_or_precision(__first, __last, _M_prec, - __arg_id, __pc); + if (__next != __last) + __next = _S_parse_width_or_precision(__first, __last, _M_prec, + __arg_id, __pc); if (__next == __first) __throw_format_error("format error: missing precision after '.' in " "format string"); @@ -754,8 +755,13 @@ namespace __format bool _M_hasval = false; }; +#ifdef _GLIBCXX_USE_WCHAR_T template concept __char = same_as<_CharT, char> || same_as<_CharT, wchar_t>; +#else + template + concept __char = same_as<_CharT, char>; +#endif template<__char _CharT> struct __formatter_str @@ -1134,26 +1140,22 @@ namespace __format { size_t __width = _M_spec._M_get_width(__fc); - _Optional_locale __loc; - basic_string_view<_CharT> __str; if constexpr (is_same_v) __str = __narrow_str; +#ifdef _GLIBCXX_USE_WCHAR_T else { - __loc = __fc.locale(); - auto& __ct = use_facet>(__loc.value()); size_t __n = __narrow_str.size(); auto __p = (_CharT*)__builtin_alloca(__n * sizeof(_CharT)); - __ct.widen(__narrow_str.data(), __narrow_str.data() + __n, __p); + std::__to_wstring_numeric(__narrow_str.data(), __n, __p); __str = {__p, __n}; } +#endif if (_M_spec._M_localized) { - if constexpr (is_same_v) - __loc = __fc.locale(); - const auto& __l = __loc.value(); + const auto& __l = __fc.locale(); if (__l.name() != "C") { auto& __np = use_facet>(__l); @@ -1391,10 +1393,13 @@ namespace __format ++__first; break; case 'f': - case 'F': __spec._M_type = _Pres_f; ++__first; break; + case 'F': + __spec._M_type = _Pres_F; + ++__first; + break; case 'g': __spec._M_type = _Pres_g; ++__first; @@ -1451,6 +1456,9 @@ namespace __format __use_prec = true; __fmt = chars_format::scientific; break; + case _Pres_F: + __upper = true; + [[fallthrough]]; case _Pres_f: __use_prec = true; __fmt = chars_format::fixed; @@ -1468,6 +1476,8 @@ namespace __format if (__use_prec) __fmt = chars_format::general; break; + default: + __builtin_unreachable(); } // Write value into buffer using std::to_chars. @@ -1487,9 +1497,29 @@ namespace __format { // If the buffer is too small it's probably because of a large // precision, or a very large value in fixed format. - size_t __guess = __prec + sizeof(__buf); - if (__fmt == chars_format::fixed) - __guess += max((int)__builtin_log10(__builtin_abs(__v)) / 2, 1); + size_t __guess = 8 + __prec; + if (__fmt == chars_format::fixed) // +ddd.prec + { + if constexpr (is_same_v<_Fp, float> || is_same_v<_Fp, double> + || is_same_v<_Fp, long double>) + { + // The number of digits to the left of the decimal point + // is floor(log10(max(abs(__v),1)))+1 + int __exp{}; + if constexpr (is_same_v<_Fp, float>) + __builtin_frexpf(__v, &__exp); + else if constexpr (is_same_v<_Fp, double>) + __builtin_frexp(__v, &__exp); + else if constexpr (is_same_v<_Fp, long double>) + __builtin_frexpl(__v, &__exp); + if (__exp > 0) + __guess += 1U + __exp * 4004U / 13301U; // log10(2) approx. + } + else + __guess += numeric_limits<_Fp>::max_exponent10; + } + if (__guess <= sizeof(__buf)) [[unlikely]] + __guess = sizeof(__buf) * 2; __dynbuf.reserve(__guess); do @@ -1500,8 +1530,8 @@ namespace __format return __res.ec == errc{} ? __res.ptr - __p : 0; }; - _S_resize_and_overwrite(__dynbuf, __dynbuf.capacity() * 2, - __overwrite); + __dynbuf.__resize_and_overwrite(__dynbuf.capacity() * 2, + __overwrite); __start = __dynbuf.data() + 1; // reserve space for sign __end = __dynbuf.data() + __dynbuf.size(); } @@ -1593,36 +1623,23 @@ namespace __format } } - // TODO move everything below to a new member function that - // doesn't depend on _Fp type. - - - _Optional_locale __loc; - basic_string_view<_CharT> __str; basic_string<_CharT> __wstr; + basic_string_view<_CharT> __str; if constexpr (is_same_v<_CharT, char>) __str = __narrow_str; +#ifdef _GLIBCXX_USE_WCHAR_T else { - __loc = __fc.locale(); - auto& __ct = use_facet>(__loc.value()); - const char* __data = __narrow_str.data(); - auto __overwrite = [&__data, &__ct](_CharT* __p, size_t __n) - { - __ct.widen(__data, __data + __n, __p); - return __n; - }; - _S_resize_and_overwrite(__wstr, __narrow_str.size(), __overwrite); + __wstr = std::__to_wstring_numeric(__narrow_str); __str = __wstr; } +#endif if (_M_spec._M_localized) { - if constexpr (is_same_v) - __wstr = _M_localize(__str, __expc, __fc.locale()); - else - __wstr = _M_localize(__str, __expc, __loc.value()); - __str = __wstr; + __wstr = _M_localize(__str, __expc, __fc.locale()); + if (!__wstr.empty()) + __str = __wstr; } size_t __width = _M_spec._M_get_width(__fc); @@ -1677,9 +1694,24 @@ namespace __format } else { - const auto& __ct = use_facet>(__loc); - __dot = __ct.widen('.'); - __exp = __ct.widen(__expc); + __dot = L'.'; + switch (__expc) + { + case 'e': + __exp = L'e'; + break; + case 'E': + __exp = L'E'; + break; + case 'p': + __exp = L'p'; + break; + case 'P': + __exp = L'P'; + break; + default: + __builtin_unreachable(); + } } if (__grp.empty() && __point == __dot) @@ -1707,29 +1739,17 @@ namespace __format } return (__end - __p); }; - _S_resize_and_overwrite(__lstr, __e * 2 + __r, __overwrite); + __lstr.__resize_and_overwrite(__e * 2 + __r, __overwrite); return __lstr; } - template - static void - _S_resize_and_overwrite(basic_string<_Ch>& __str, size_t __n, _Func __f) - { -#if __cpp_lib_string_resize_and_overwrite - __str.resize_and_overwrite(__n, __f); -#else - __str.resize(__n); - __str.resize(__f(__str.data(), __n)); -#endif - } - _Spec<_CharT> _M_spec{}; }; } // namespace __format /// @endcond - // Format a character. + /// Format a character. template<__format::__char _CharT> struct formatter<_CharT, _CharT> { @@ -1766,7 +1786,8 @@ namespace __format __format::__formatter_int<_CharT> _M_f; }; - // Format a char value for wide character output. +#ifdef _GLIBCXX_USE_WCHAR_T + /// Format a char value for wide character output. template<> struct formatter { @@ -1800,6 +1821,7 @@ namespace __format private: __format::__formatter_int _M_f; }; +#endif // USE_WCHAR_T /** Format a string. * @{ @@ -1895,6 +1917,7 @@ namespace __format __format::__formatter_str _M_f; }; +#ifdef _GLIBCXX_USE_WCHAR_T template struct formatter, wchar_t> { @@ -1918,6 +1941,7 @@ namespace __format private: __format::__formatter_str _M_f; }; +#endif // USE_WCHAR_T template struct formatter, char> @@ -1943,6 +1967,7 @@ namespace __format __format::__formatter_str _M_f; }; +#ifdef _GLIBCXX_USE_WCHAR_T template struct formatter, wchar_t> { @@ -1966,6 +1991,7 @@ namespace __format private: __format::__formatter_str _M_f; }; +#endif // USE_WCHAR_T /// @} /// Format an integer. @@ -2015,6 +2041,7 @@ namespace __format }; #endif +#if defined __cpp_lib_to_chars /// Format a floating-point value. template<__format::__formattable_float _Tp, __format::__char _CharT> struct formatter<_Tp, _CharT> @@ -2035,6 +2062,140 @@ namespace __format __format::__formatter_fp<_CharT> _M_f; }; +#if __LDBL_MANT_DIG__ == __DBL_MANT_DIG__ + // Reuse __formatter_fp::format for long double. + template<__format::__char _CharT> + struct formatter + { + formatter() = default; + + [[__gnu__::__always_inline__]] + constexpr typename basic_format_parse_context<_CharT>::iterator + parse(basic_format_parse_context<_CharT>& __pc) + { return _M_f.parse(__pc); } + + template + typename basic_format_context<_Out, _CharT>::iterator + format(long double __u, basic_format_context<_Out, _CharT>& __fc) const + { return _M_f.format((double)__u, __fc); } + + private: + __format::__formatter_fp<_CharT> _M_f; + }; +#endif + +#ifdef __STDCPP_FLOAT16_T__ + // Reuse __formatter_fp::format for _Float16. + template<__format::__char _CharT> + struct formatter<_Float16, _CharT> + { + formatter() = default; + + [[__gnu__::__always_inline__]] + constexpr typename basic_format_parse_context<_CharT>::iterator + parse(basic_format_parse_context<_CharT>& __pc) + { return _M_f.parse(__pc); } + + template + typename basic_format_context<_Out, _CharT>::iterator + format(_Float16 __u, basic_format_context<_Out, _CharT>& __fc) const + { return _M_f.format((float)__u, __fc); } + + private: + __format::__formatter_fp<_CharT> _M_f; + }; +#endif + +#if defined(__FLT32_DIG__) + // Reuse __formatter_fp::format for _Float32. + template<__format::__char _CharT> + struct formatter<_Float32, _CharT> + { + formatter() = default; + + [[__gnu__::__always_inline__]] + constexpr typename basic_format_parse_context<_CharT>::iterator + parse(basic_format_parse_context<_CharT>& __pc) + { return _M_f.parse(__pc); } + + template + typename basic_format_context<_Out, _CharT>::iterator + format(_Float32 __u, basic_format_context<_Out, _CharT>& __fc) const + { return _M_f.format((float)__u, __fc); } + + private: + __format::__formatter_fp<_CharT> _M_f; + }; +#endif + +#if defined(__FLT64_DIG__) + // Reuse __formatter_fp::format for _Float64. + template<__format::__char _CharT> + struct formatter<_Float64, _CharT> + { + formatter() = default; + + [[__gnu__::__always_inline__]] + constexpr typename basic_format_parse_context<_CharT>::iterator + parse(basic_format_parse_context<_CharT>& __pc) + { return _M_f.parse(__pc); } + + template + typename basic_format_context<_Out, _CharT>::iterator + format(_Float64 __u, basic_format_context<_Out, _CharT>& __fc) const + { return _M_f.format((double)__u, __fc); } + + private: + __format::__formatter_fp<_CharT> _M_f; + }; +#endif + +#if defined(__FLT128_DIG__) && _GLIBCXX_FORMAT_F128 == 1 + // Reuse __formatter_fp::format<__float128_t, Out> for _Float128. + template<__format::__char _CharT> + struct formatter<_Float128, _CharT> + { + formatter() = default; + + [[__gnu__::__always_inline__]] + constexpr typename basic_format_parse_context<_CharT>::iterator + parse(basic_format_parse_context<_CharT>& __pc) + { return _M_f.parse(__pc); } + + template + typename basic_format_context<_Out, _CharT>::iterator + format(_Float128 __u, basic_format_context<_Out, _CharT>& __fc) const + { return _M_f.format((__format::__float128_t)__u, __fc); } + + private: + __format::__formatter_fp<_CharT> _M_f; + }; +#endif + +#ifdef __STDCPP_BFLOAT16_T__ + // Reuse __formatter_fp::format for bfloat16_t. + template<__format::__char _CharT> + struct formatter<__gnu_cxx::__bfloat16_t, _CharT> + { + formatter() = default; + + [[__gnu__::__always_inline__]] + constexpr typename basic_format_parse_context<_CharT>::iterator + parse(basic_format_parse_context<_CharT>& __pc) + { return _M_f.parse(__pc); } + + template + typename basic_format_context<_Out, _CharT>::iterator + format(__gnu_cxx::__bfloat16_t __u, + basic_format_context<_Out, _CharT>& __fc) const + { return _M_f.format((float)__u, __fc); } + + private: + __format::__formatter_fp<_CharT> _M_f; + }; +#endif +#endif // __cpp_lib_to_chars + /** Format a pointer. * @{ */ @@ -2072,7 +2233,11 @@ namespace __format // _GLIBCXX_RESOLVE_LIB_DEFECTS // P2510R3 Formatting pointers -#define _GLIBCXX_P2518R3 (__cplusplus > 202302L || ! defined __STRICT_ANSI__) +#if __cplusplus > 202302L || ! defined __STRICT_ANSI__ +#define _GLIBCXX_P2518R3 1 +#else +#define _GLIBCXX_P2518R3 0 +#endif #if _GLIBCXX_P2518R3 __first = __spec._M_parse_zero_fill(__first, __last); @@ -2130,14 +2295,14 @@ namespace __format basic_string_view<_CharT> __str; if constexpr (is_same_v<_CharT, char>) __str = string_view(__buf, __n); +#ifdef _GLIBCXX_USE_WCHAR_T else { - const std::locale& __loc = __fc.locale(); - auto& __ct = use_facet>(__loc); auto __p = (_CharT*)__builtin_alloca(__n * sizeof(_CharT)); - __ct.widen(__buf, __buf + __n, __p); + std::__to_wstring_numeric(__buf, __n, __p); __str = wstring_view(__p, __n); } +#endif #if _GLIBCXX_P2518R3 if (_M_spec._M_zero_fill) @@ -2372,11 +2537,10 @@ namespace __format // Replace the current output range. void - _M_reset(span<_CharT> __s, - typename span<_CharT>::iterator __next) noexcept + _M_reset(span<_CharT> __s, size_t __pos = 0) noexcept { _M_span = __s; - _M_next = __next; + _M_next = __s.begin() + __pos; } // Called by the iterator for *it++ = c @@ -2434,7 +2598,7 @@ namespace __format // A sink that fills a sequence (e.g. std::string, std::vector, std::deque). // Writes to a buffer then appends that to the sequence when it fills up. template - class _Seq_sink : public _Buf_sink + class _Seq_sink final : public _Buf_sink { using _CharT = typename _Seq::value_type; @@ -2445,6 +2609,8 @@ namespace __format _M_overflow() override { auto __s = this->_M_used(); + if (__s.empty()) + return; if constexpr (__is_specialization_of<_Seq, basic_string>) _M_seq.append(__s.data(), __s.size()); else @@ -2453,6 +2619,9 @@ namespace __format } public: + // TODO: for SSO string, use SSO buffer as initial span, then switch + // to _M_buf if it overflows? Or even do that for all unused capacity? + [[__gnu__::__always_inline__]] _Seq_sink() noexcept(is_nothrow_default_constructible_v<_Seq>) { } @@ -2466,7 +2635,8 @@ namespace __format _Seq get() && { - _Seq_sink::_M_overflow(); + if (this->_M_used().size() != 0) + _Seq_sink::_M_overflow(); return std::move(_M_seq); } }; @@ -2522,7 +2692,8 @@ namespace __format format_to_n_result<_OutIter> _M_finish() && { - _Iter_sink::_M_overflow(); + if (this->_M_used().size() != 0) + _Iter_sink::_M_overflow(); iter_difference_t<_OutIter> __count(_M_count); return { std::move(_M_out), __count }; } @@ -2536,6 +2707,7 @@ namespace __format // not introduce any invalid pointer arithmetic or overflows that would not // have happened anyway. template + requires same_as, _CharT> class _Iter_sink<_CharT, _OutIter> : public _Sink<_CharT> { using uint64_t = __UINTPTR_TYPE__; @@ -2548,24 +2720,26 @@ namespace __format protected: void - _M_overflow() + _M_overflow() override { + if (this->_M_unused().size() != 0) + return; // No need to switch to internal buffer yet. + auto __s = this->_M_used(); - _M_count += __s.size(); if (_M_max >= 0) { + _M_count += __s.size(); // Span was already sized for the maximum character count, // if it overflows then any further output must go to the // internal buffer, to be discarded. - span<_CharT> __buf{_M_buf}; - this->_M_reset(__buf, __buf.begin()); + this->_M_reset(this->_M_buf); } else { // No maximum character count. Just extend the span to allow // writing more characters to it. - this->_M_reset({__s.data(), __s.size() + 1024}, __s.end()); + this->_M_reset({__s.data(), __s.size() + 1024}, __s.size()); } } @@ -2613,15 +2787,18 @@ namespace __format format_to_n_result<_OutIter> _M_finish() && { - _Iter_sink::_M_overflow(); - iter_difference_t<_OutIter> __count(_M_count); auto __s = this->_M_used(); - auto __last = _M_first; - if (__s.data() == _M_buf) // Wrote at least _M_max characters. - __last += _M_max; - else - __last += iter_difference_t<_OutIter>(__s.size()); - return { __last, __count }; + if (__s.data() == _M_buf) + { + // Switched to internal buffer, so must have written _M_max. + iter_difference_t<_OutIter> __count(_M_count + __s.size()); + return { _M_first + _M_max, __count }; + } + else // Not using internal buffer yet + { + iter_difference_t<_OutIter> __count(__s.size()); + return { _M_first + __count, __count }; + } } }; @@ -2629,7 +2806,7 @@ namespace __format _Arg_none, _Arg_bool, _Arg_c, _Arg_i, _Arg_u, _Arg_ll, _Arg_ull, _Arg_flt, _Arg_dbl, _Arg_ldbl, _Arg_str, _Arg_sv, _Arg_ptr, _Arg_handle, _Arg_i128, _Arg_u128, - _Arg_bf16, _Arg_f16, _Arg_f32, _Arg_f64, + _Arg_bf16, _Arg_f16, _Arg_f32, _Arg_f64, // These are unused. #ifdef _GLIBCXX_LONG_DOUBLE_ALT128_COMPAT _Arg_next_value_, _Arg_f128 = _Arg_ldbl, @@ -2673,7 +2850,6 @@ namespace __format __int128 _M_i128; unsigned __int128 _M_u128; #endif - // TODO _Float16 etc. #ifdef _GLIBCXX_LONG_DOUBLE_ALT128_COMPAT __ieee128 _M_f128; __ibm128 _M_ibm128; @@ -2902,7 +3078,15 @@ namespace __format return type_identity<__ieee128>(); #endif - // TODO bfloat16 and float16 +#if defined(__FLT16_DIG__) && defined(_GLIBCXX_FLOAT_IS_IEEE_BINARY32) + else if constexpr (is_same_v<_Td, _Float16>) + return type_identity(); +#endif + +#if defined(__BFLT16_DIG__) && defined(_GLIBCXX_FLOAT_IS_IEEE_BINARY32) + else if constexpr (is_same_v<_Td, decltype(0.0bf16)>) + return type_identity(); +#endif #ifdef __FLT32_DIG__ else if constexpr (is_same_v<_Td, _Float32>) @@ -3094,14 +3278,16 @@ namespace __format case _Arg_u128: return std::forward<_Visitor>(__vis)(_M_val._M_u128); #endif - // TODO _Arg_f16 etc. #if _GLIBCXX_FORMAT_F128 == 2 case _Arg_f128: return std::forward<_Visitor>(__vis)(_M_val._M_f128); #endif + + default: + // _Arg_f16 etc. + __builtin_unreachable(); } - __builtin_unreachable(); } }; @@ -3290,6 +3476,7 @@ namespace __format template template + inline basic_format_args<_Context>:: basic_format_args(const _Store<_Args...>& __store) noexcept { @@ -3332,12 +3519,14 @@ namespace __format return _Store(__fmt_args...); } +#ifdef _GLIBCXX_USE_WCHAR_T /// Capture formatting arguments for use by `std::vformat` (for wide output). template [[nodiscard,__gnu__::__always_inline__]] inline auto make_wformat_args(_Args&&... __args) noexcept { return std::make_format_args(__args...); } +#endif /// @cond undocumented namespace __format @@ -3410,15 +3599,6 @@ namespace __format /// @cond undocumented namespace __format { - template - [[__gnu__::__always_inline__]] - inline void - __write(_Ctx& __ctx, basic_string_view<_CharT> __str) - requires requires { { __ctx.out() } -> output_iterator; } - { - __ctx.advance_to(__format::__write(__ctx.out())); - } - // Abstract base class defining an interface for scanning format strings. // Scan the characters in a format string, dividing it up into strings of // ordinary characters, escape sequences, and replacement fields. @@ -3534,7 +3714,9 @@ namespace __format _M_pc.advance_to(__ptr); } _M_format_arg(__id); - _M_pc.advance_to(_M_pc.begin() + 1); // Move past '}' + if (begin() == end() || *begin() != '}') + __format::__unmatched_left_brace_in_format_string(); + _M_pc.advance_to(begin() + 1); // Move past '}' } constexpr virtual void _M_format_arg(size_t __id) = 0; @@ -3682,25 +3864,33 @@ namespace __format vformat_to(_Out __out, string_view __fmt, format_args __args) { return __format::__do_vformat_to(std::move(__out), __fmt, __args); } +#ifdef _GLIBCXX_USE_WCHAR_T template requires output_iterator<_Out, const wchar_t&> [[__gnu__::__always_inline__]] inline _Out vformat_to(_Out __out, wstring_view __fmt, wformat_args __args) { return __format::__do_vformat_to(std::move(__out), __fmt, __args); } +#endif template requires output_iterator<_Out, const char&> [[__gnu__::__always_inline__]] inline _Out vformat_to(_Out __out, const locale& __loc, string_view __fmt, format_args __args) - { return __format::__do_vformat_to(std::move(__out), __fmt, __args, &__loc); } + { + return __format::__do_vformat_to(std::move(__out), __fmt, __args, &__loc); + } +#ifdef _GLIBCXX_USE_WCHAR_T template requires output_iterator<_Out, const wchar_t&> [[__gnu__::__always_inline__]] inline _Out vformat_to(_Out __out, const locale& __loc, wstring_view __fmt, wformat_args __args) - { return __format::__do_vformat_to(std::move(__out), __fmt, __args, &__loc); } + { + return __format::__do_vformat_to(std::move(__out), __fmt, __args, &__loc); + } +#endif [[nodiscard]] inline string @@ -3711,6 +3901,7 @@ namespace __format return std::move(__buf).get(); } +#ifdef _GLIBCXX_USE_WCHAR_T [[nodiscard]] inline wstring vformat(wstring_view __fmt, wformat_args __args) @@ -3719,6 +3910,7 @@ namespace __format std::vformat_to(__buf.out(), __fmt, __args); return std::move(__buf).get(); } +#endif [[nodiscard]] inline string @@ -3729,6 +3921,7 @@ namespace __format return std::move(__buf).get(); } +#ifdef _GLIBCXX_USE_WCHAR_T [[nodiscard]] inline wstring vformat(const locale& __loc, wstring_view __fmt, wformat_args __args) @@ -3737,6 +3930,7 @@ namespace __format std::vformat_to(__buf.out(), __loc, __fmt, __args); return std::move(__buf).get(); } +#endif template [[nodiscard]] @@ -3744,11 +3938,13 @@ namespace __format format(format_string<_Args...> __fmt, _Args&&... __args) { return std::vformat(__fmt.get(), std::make_format_args(__args...)); } +#ifdef _GLIBCXX_USE_WCHAR_T template [[nodiscard]] inline wstring format(wformat_string<_Args...> __fmt, _Args&&... __args) { return std::vformat(__fmt.get(), std::make_wformat_args(__args...)); } +#endif template [[nodiscard]] @@ -3760,6 +3956,7 @@ namespace __format std::make_format_args(__args...)); } +#ifdef _GLIBCXX_USE_WCHAR_T template [[nodiscard]] inline wstring @@ -3769,6 +3966,7 @@ namespace __format return std::vformat(__loc, __fmt.get(), std::make_wformat_args(__args...)); } +#endif template requires output_iterator<_Out, const char&> @@ -3779,6 +3977,7 @@ namespace __format std::make_format_args(std::forward<_Args>(__args)...)); } +#ifdef _GLIBCXX_USE_WCHAR_T template requires output_iterator<_Out, const wchar_t&> inline _Out @@ -3787,6 +3986,7 @@ namespace __format return std::vformat_to(std::move(__out), __fmt.get(), std::make_wformat_args(std::forward<_Args>(__args)...)); } +#endif template requires output_iterator<_Out, const char&> @@ -3798,6 +3998,7 @@ namespace __format std::make_format_args(std::forward<_Args>(__args)...)); } +#ifdef _GLIBCXX_USE_WCHAR_T template requires output_iterator<_Out, const wchar_t&> inline _Out @@ -3807,6 +4008,7 @@ namespace __format return std::vformat_to(std::move(__out), __loc, __fmt.get(), std::make_wformat_args(std::forward<_Args>(__args)...)); } +#endif template requires output_iterator<_Out, const char&> @@ -3820,6 +4022,7 @@ namespace __format return std::move(__sink)._M_finish(); } +#ifdef _GLIBCXX_USE_WCHAR_T template requires output_iterator<_Out, const wchar_t&> inline format_to_n_result<_Out> @@ -3831,6 +4034,7 @@ namespace __format std::make_wformat_args(__args...)); return std::move(__sink)._M_finish(); } +#endif template requires output_iterator<_Out, const char&> @@ -3844,6 +4048,7 @@ namespace __format return std::move(__sink)._M_finish(); } +#ifdef _GLIBCXX_USE_WCHAR_T template requires output_iterator<_Out, const wchar_t&> inline format_to_n_result<_Out> @@ -3855,24 +4060,22 @@ namespace __format std::make_wformat_args(__args...)); return std::move(__sink)._M_finish(); } +#endif /// @cond undocumented namespace __format { #if 1 template - class _Counting_sink : public _Iter_sink<_CharT, _CharT*> + class _Counting_sink final : public _Iter_sink<_CharT, _CharT*> { public: _Counting_sink() : _Iter_sink<_CharT, _CharT*>(nullptr, 0) { } [[__gnu__::__always_inline__]] size_t - count() - { - _Counting_sink::_M_overflow(); - return this->_M_count; - } + count() const + { return this->_M_count + this->_M_used().size(); } }; #else template @@ -3914,6 +4117,7 @@ namespace __format return __buf.count(); } +#ifdef _GLIBCXX_USE_WCHAR_T template [[nodiscard]] inline size_t @@ -3924,6 +4128,7 @@ namespace __format std::make_wformat_args(std::forward<_Args>(__args)...)); return __buf.count(); } +#endif template [[nodiscard]] @@ -3937,6 +4142,7 @@ namespace __format return __buf.count(); } +#ifdef _GLIBCXX_USE_WCHAR_T template [[nodiscard]] inline size_t @@ -3948,6 +4154,7 @@ namespace __format std::make_wformat_args(std::forward<_Args>(__args)...)); return __buf.count(); } +#endif #if __cpp_lib_format_ranges // [format.range], formatting of ranges @@ -4020,5 +4227,5 @@ namespace __format _GLIBCXX_END_NAMESPACE_VERSION } // namespace std -#endif // C++20 +#endif // __cpp_lib_format #endif // _GLIBCXX_FORMAT diff --git a/libstdc++-v3/include/std/forward_list b/libstdc++-v3/include/std/forward_list index 1c110df971b7..bd642a16e421 100644 --- a/libstdc++-v3/include/std/forward_list +++ b/libstdc++-v3/include/std/forward_list @@ -45,6 +45,9 @@ # include #endif +#define __glibcxx_want_erase_if +#include + #if __cplusplus >= 201703L #include namespace std _GLIBCXX_VISIBILITY(default) @@ -59,13 +62,10 @@ _GLIBCXX_END_NAMESPACE_VERSION } // namespace std #endif // C++17 -#if __cplusplus > 201703L +#ifdef __cpp_lib_erase_if // C++ >= 20 && HOSTED namespace std _GLIBCXX_VISIBILITY(default) { _GLIBCXX_BEGIN_NAMESPACE_VERSION - -#define __cpp_lib_erase_if 202002L - template inline typename forward_list<_Tp, _Alloc>::size_type erase_if(forward_list<_Tp, _Alloc>& __cont, _Predicate __pred) @@ -82,7 +82,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } _GLIBCXX_END_NAMESPACE_VERSION } // namespace std -#endif // C++20 +#endif // __cpp_lib_erase_if #endif // C++11 diff --git a/libstdc++-v3/include/std/functional b/libstdc++-v3/include/std/functional index 4a4b8b2b2e61..60d4d1f3dd22 100644 --- a/libstdc++-v3/include/std/functional +++ b/libstdc++-v3/include/std/functional @@ -48,6 +48,14 @@ #include #include // std::equal_to, std::unary_function etc. +#define __glibcxx_want_invoke +#define __glibcxx_want_constexpr_functional +#define __glibcxx_want_invoke_r +#define __glibcxx_want_bind_front +#define __glibcxx_want_not_fn +#define __glibcxx_want_boyer_moore_searcher +#include + #if __cplusplus >= 201103L #include @@ -86,13 +94,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION */ template struct _Placeholder { }; -#if __cplusplus >= 201103L - -#if __cplusplus >= 201703L -# define __cpp_lib_invoke 201411L -# if __cplusplus > 201703L -# define __cpp_lib_constexpr_functional 201907L -# endif +#ifdef __cpp_lib_invoke // C++ >= 17 /** Invoke a callable object. * @@ -113,9 +115,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION return std::__invoke(std::forward<_Callable>(__fn), std::forward<_Args>(__args)...); } +#endif -#if __cplusplus > 202002L -# define __cpp_lib_invoke_r 202106L +#ifdef __cpp_lib_invoke_r // C++ >= 23 /** Invoke a callable object and convert the result to `_Res`. * @@ -133,11 +135,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION return std::__invoke_r<_Res>(std::forward<_Callable>(__fn), std::forward<_Args>(__args)...); } -#endif // C++23 -#endif // C++17 +#endif // __cpp_lib_invoke_r /// @cond undocumented +#if __cplusplus >= 201103L template::value> class _Mem_fn_base @@ -910,8 +912,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION std::forward<_BoundArgs>(__args)...); } -#if __cplusplus > 201703L -#define __cpp_lib_bind_front 201907L +#ifdef __cpp_lib_bind_front // C++ >= 20 template struct _Bind_front @@ -1077,7 +1078,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION return _Bind_front_t<_Fn, _Args...>(0, std::forward<_Fn>(__fn), std::forward<_Args>(__args)...); } -#endif // C++20 +#endif // __cpp_lib_bind_front #if __cplusplus >= 201402L /// Generalized negator. @@ -1147,9 +1148,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template<> struct __is_byte_like> : true_type { }; +#endif // [func.not_fn] Function template not_fn -#define __cpp_lib_not_fn 201603L +#ifdef __cpp_lib_not_fn // C++ >= 17 /** Wrap a function object to create one that negates its result. * * The function template `std::not_fn` creates a "forwarding call wrapper", @@ -1170,7 +1172,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { return _Not_fn>{std::forward<_Fn>(__fn), 0}; } +#endif +#if __cplusplus >= 201703L // Searchers template> @@ -1203,8 +1207,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION tuple<_ForwardIterator1, _ForwardIterator1, _BinaryPredicate> _M_m; }; -#if _GLIBCXX_HOSTED -#define __cpp_lib_boyer_moore_searcher 201603L +#ifdef __cpp_lib_boyer_moore_searcher // C++ >= 17 && HOSTED template struct __boyer_moore_map_base @@ -1448,7 +1451,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } return std::make_pair(__last, __last); } -#endif // HOSTED +#endif // __cpp_lib_boyer_moore_searcher #endif // C++17 #endif // C++14 diff --git a/libstdc++-v3/include/std/future b/libstdc++-v3/include/std/future index 95b413a2e51a..c46ead742c30 100644 --- a/libstdc++-v3/include/std/future +++ b/libstdc++-v3/include/std/future @@ -314,7 +314,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION // Keep it simple for std::allocator. template static _Ptr<_Result<_Res>> - _S_allocate_result(const std::allocator<_Tp>& __a) + _S_allocate_result(const std::allocator<_Tp>&) { return _Ptr<_Result<_Res>>(new _Result<_Res>); } @@ -625,10 +625,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION class _Async_state_impl; template - class _Task_state_base; + struct _Task_state_base; template - class _Task_state; + struct _Task_state; template @@ -1574,7 +1574,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION // _GLIBCXX_RESOLVE_LIB_DEFECTS // 2095. missing constructors needed for uses-allocator construction template - packaged_task(allocator_arg_t, const _Allocator& __a) noexcept + packaged_task(allocator_arg_t, const _Allocator&) noexcept { } template diff --git a/libstdc++-v3/include/std/iomanip b/libstdc++-v3/include/std/iomanip index eb82fc584b6c..5861c9c001f8 100644 --- a/libstdc++-v3/include/std/iomanip +++ b/libstdc++-v3/include/std/iomanip @@ -41,6 +41,9 @@ #include #include +#define __glibcxx_want_quoted_string_io +#include + #if __cplusplus >= 201103L #include #if __cplusplus > 201103L @@ -450,9 +453,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION return __is; } -#if __cplusplus >= 201402L - -#define __cpp_lib_quoted_string_io 201304L +#ifdef __cpp_lib_quoted_string_io // C++ >= 14 && HOSTED /** * @brief Manipulator for quoted strings. @@ -502,7 +503,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION basic_string_view<_CharT, _Traits>, _CharT>(__sv, __delim, __escape); } #endif // C++17 -#endif // C++14 +#endif // __cpp_lib_quoted_string_io #endif // __cplusplus >= 201103L diff --git a/libstdc++-v3/include/std/iterator b/libstdc++-v3/include/std/iterator index 695e18e2c472..8c8670fbdf08 100644 --- a/libstdc++-v3/include/std/iterator +++ b/libstdc++-v3/include/std/iterator @@ -67,9 +67,8 @@ #endif #include -#if __cplusplus >= 201402L && ! defined _GLIBCXX_DEBUG // PR libstdc++/70303 -# define __cpp_lib_null_iterators 201304L -#endif +#define __glibcxx_want_null_iterators +#include #if __cplusplus >= 202002L #include // ranges::distance, ranges::next, ranges::prev diff --git a/libstdc++-v3/include/std/latch b/libstdc++-v3/include/std/latch index a5a92fad9193..27cd80d71005 100644 --- a/libstdc++-v3/include/std/latch +++ b/libstdc++-v3/include/std/latch @@ -33,18 +33,17 @@ #include // concurrency -#if __cplusplus > 201703L +#define __glibcxx_want_latch +#include +#ifdef __cpp_lib_latch // C++ >= 20 && atomic_wait #include #include -#if __cpp_lib_atomic_wait namespace std _GLIBCXX_VISIBILITY(default) { _GLIBCXX_BEGIN_NAMESPACE_VERSION -#define __cpp_lib_latch 201907L - class latch { public: @@ -91,6 +90,5 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION }; _GLIBCXX_END_NAMESPACE_VERSION } // namespace -#endif // __cpp_lib_atomic_wait -#endif // __cplusplus > 201703L +#endif // __cpp_lib_latch #endif // _GLIBCXX_LATCH diff --git a/libstdc++-v3/include/std/limits b/libstdc++-v3/include/std/limits index 52b19ef8264a..ec0b7a1ca7bf 100644 --- a/libstdc++-v3/include/std/limits +++ b/libstdc++-v3/include/std/limits @@ -1890,188 +1890,196 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION #undef __glibcxx_long_double_traps #undef __glibcxx_long_double_tinyness_before -#if __cplusplus > 202002L - #define __glibcxx_concat3_(P,M,S) P ## M ## S #define __glibcxx_concat3(P,M,S) __glibcxx_concat3_ (P,M,S) +#if __cplusplus >= 201103L +# define __max_digits10 max_digits10 +#endif + #define __glibcxx_float_n(BITSIZE) \ __extension__ \ template<> \ struct numeric_limits<_Float##BITSIZE> \ { \ - static constexpr bool is_specialized = true; \ + static _GLIBCXX_USE_CONSTEXPR bool is_specialized = true; \ \ - static constexpr _Float##BITSIZE \ - min() noexcept \ + static _GLIBCXX_CONSTEXPR _Float##BITSIZE \ + min() _GLIBCXX_USE_NOEXCEPT \ { return __glibcxx_concat3 (__FLT, BITSIZE, _MIN__); } \ \ - static constexpr _Float##BITSIZE \ - max() noexcept \ + static _GLIBCXX_CONSTEXPR _Float##BITSIZE \ + max() _GLIBCXX_USE_NOEXCEPT \ { return __glibcxx_concat3 (__FLT, BITSIZE, _MAX__); } \ \ - static constexpr _Float##BITSIZE \ - lowest() noexcept \ + static _GLIBCXX_CONSTEXPR _Float##BITSIZE \ + lowest() _GLIBCXX_USE_NOEXCEPT \ { return -__glibcxx_concat3 (__FLT, BITSIZE, _MAX__); } \ \ - static constexpr int digits \ + static _GLIBCXX_USE_CONSTEXPR int digits \ = __glibcxx_concat3 (__FLT, BITSIZE, _MANT_DIG__); \ - static constexpr int digits10 \ + static _GLIBCXX_USE_CONSTEXPR int digits10 \ = __glibcxx_concat3 (__FLT, BITSIZE, _DIG__); \ - static constexpr int max_digits10 \ + static _GLIBCXX_USE_CONSTEXPR int __max_digits10 \ = __glibcxx_max_digits10 (__glibcxx_concat3 (__FLT, BITSIZE, \ _MANT_DIG__)); \ - static constexpr bool is_signed = true; \ - static constexpr bool is_integer = false; \ - static constexpr bool is_exact = false; \ - static constexpr int radix = __FLT_RADIX__; \ + static _GLIBCXX_USE_CONSTEXPR bool is_signed = true; \ + static _GLIBCXX_USE_CONSTEXPR bool is_integer = false; \ + static _GLIBCXX_USE_CONSTEXPR bool is_exact = false; \ + static _GLIBCXX_USE_CONSTEXPR int radix = __FLT_RADIX__; \ \ - static constexpr _Float##BITSIZE \ - epsilon() noexcept \ + static _GLIBCXX_CONSTEXPR _Float##BITSIZE \ + epsilon() _GLIBCXX_USE_NOEXCEPT \ { return __glibcxx_concat3 (__FLT, BITSIZE, _EPSILON__); } \ \ - static constexpr _Float##BITSIZE \ - round_error() noexcept { return 0.5F##BITSIZE; } \ + static _GLIBCXX_CONSTEXPR _Float##BITSIZE \ + round_error() _GLIBCXX_USE_NOEXCEPT { return 0.5F##BITSIZE; } \ \ - static constexpr int min_exponent \ + static _GLIBCXX_USE_CONSTEXPR int min_exponent \ = __glibcxx_concat3 (__FLT, BITSIZE, _MIN_EXP__); \ - static constexpr int min_exponent10 \ + static _GLIBCXX_USE_CONSTEXPR int min_exponent10 \ = __glibcxx_concat3 (__FLT, BITSIZE, _MIN_10_EXP__); \ - static constexpr int max_exponent \ + static _GLIBCXX_USE_CONSTEXPR int max_exponent \ = __glibcxx_concat3 (__FLT, BITSIZE, _MAX_EXP__); \ - static constexpr int max_exponent10 \ + static _GLIBCXX_USE_CONSTEXPR int max_exponent10 \ = __glibcxx_concat3 (__FLT, BITSIZE, _MAX_10_EXP__); \ \ - static constexpr bool has_infinity \ + static _GLIBCXX_USE_CONSTEXPR bool has_infinity \ = __glibcxx_concat3 (__FLT, BITSIZE, _HAS_INFINITY__); \ - static constexpr bool has_quiet_NaN \ + static _GLIBCXX_USE_CONSTEXPR bool has_quiet_NaN \ = __glibcxx_concat3 (__FLT, BITSIZE, _HAS_QUIET_NAN__); \ - static constexpr bool has_signaling_NaN \ + static _GLIBCXX_USE_CONSTEXPR bool has_signaling_NaN \ = has_quiet_NaN; \ - static constexpr float_denorm_style has_denorm \ + static _GLIBCXX_USE_CONSTEXPR float_denorm_style has_denorm \ = bool(__glibcxx_concat3 (__FLT, BITSIZE, _HAS_DENORM__)) \ ? denorm_present : denorm_absent; \ - static constexpr bool has_denorm_loss = false; \ + static _GLIBCXX_USE_CONSTEXPR bool has_denorm_loss = false; \ \ - static constexpr _Float##BITSIZE \ - infinity() noexcept \ + static _GLIBCXX_CONSTEXPR _Float##BITSIZE \ + infinity() _GLIBCXX_USE_NOEXCEPT \ { return __builtin_huge_valf##BITSIZE(); } \ \ - static constexpr _Float##BITSIZE \ - quiet_NaN() noexcept \ + static _GLIBCXX_CONSTEXPR _Float##BITSIZE \ + quiet_NaN() _GLIBCXX_USE_NOEXCEPT \ { return __builtin_nanf##BITSIZE(""); } \ \ - static constexpr _Float##BITSIZE \ - signaling_NaN() noexcept \ + static _GLIBCXX_CONSTEXPR _Float##BITSIZE \ + signaling_NaN() _GLIBCXX_USE_NOEXCEPT \ { return __builtin_nansf##BITSIZE(""); } \ \ - static constexpr _Float##BITSIZE \ - denorm_min() noexcept \ + static _GLIBCXX_CONSTEXPR _Float##BITSIZE \ + denorm_min() _GLIBCXX_USE_NOEXCEPT \ { return __glibcxx_concat3 (__FLT, BITSIZE, _DENORM_MIN__); } \ \ - static constexpr bool is_iec559 \ + static _GLIBCXX_USE_CONSTEXPR bool is_iec559 \ = has_infinity && has_quiet_NaN && has_denorm == denorm_present;\ - static constexpr bool is_bounded = true; \ - static constexpr bool is_modulo = false; \ + static _GLIBCXX_USE_CONSTEXPR bool is_bounded = true; \ + static _GLIBCXX_USE_CONSTEXPR bool is_modulo = false; \ \ - static constexpr bool traps = false; \ - static constexpr bool tinyness_before = false; \ - static constexpr float_round_style round_style \ + static _GLIBCXX_USE_CONSTEXPR bool traps = false; \ + static _GLIBCXX_USE_CONSTEXPR bool tinyness_before = false; \ + static _GLIBCXX_USE_CONSTEXPR float_round_style round_style \ = round_to_nearest; \ }; \ #ifdef __STDCPP_FLOAT16_T__ __glibcxx_float_n(16) #endif -#ifdef __STDCPP_FLOAT32_T__ +#ifdef __FLT32_DIG__ __glibcxx_float_n(32) #endif -#ifdef __STDCPP_FLOAT64_T__ +#ifdef __FLT64_DIG__ __glibcxx_float_n(64) #endif -#ifdef __STDCPP_FLOAT128_T__ +#ifdef __FLT128_DIG__ __glibcxx_float_n(128) #endif #undef __glibcxx_float_n #undef __glibcxx_concat3 #undef __glibcxx_concat3_ +#if __cplusplus >= 201103L +# undef __max_digits10 +#endif + #ifdef __STDCPP_BFLOAT16_T__ __extension__ template<> struct numeric_limits<__gnu_cxx::__bfloat16_t> { - static constexpr bool is_specialized = true; + static _GLIBCXX_USE_CONSTEXPR bool is_specialized = true; - static constexpr __gnu_cxx::__bfloat16_t - min() noexcept + static _GLIBCXX_CONSTEXPR __gnu_cxx::__bfloat16_t + min() _GLIBCXX_USE_NOEXCEPT { return __BFLT16_MIN__; } - static constexpr __gnu_cxx::__bfloat16_t - max() noexcept + static _GLIBCXX_CONSTEXPR __gnu_cxx::__bfloat16_t + max() _GLIBCXX_USE_NOEXCEPT { return __BFLT16_MAX__; } - static constexpr __gnu_cxx::__bfloat16_t - lowest() noexcept + static _GLIBCXX_CONSTEXPR __gnu_cxx::__bfloat16_t + lowest() _GLIBCXX_USE_NOEXCEPT { return -__BFLT16_MAX__; } - static constexpr int digits = __BFLT16_MANT_DIG__; - static constexpr int digits10 = __BFLT16_DIG__; - static constexpr int max_digits10 + static _GLIBCXX_USE_CONSTEXPR int digits = __BFLT16_MANT_DIG__; + static _GLIBCXX_USE_CONSTEXPR int digits10 = __BFLT16_DIG__; +#if __cplusplus >= 201103L + static _GLIBCXX_USE_CONSTEXPR int max_digits10 = __glibcxx_max_digits10 (__BFLT16_MANT_DIG__); - static constexpr bool is_signed = true; - static constexpr bool is_integer = false; - static constexpr bool is_exact = false; - static constexpr int radix = __FLT_RADIX__; +#endif + static _GLIBCXX_USE_CONSTEXPR bool is_signed = true; + static _GLIBCXX_USE_CONSTEXPR bool is_integer = false; + static _GLIBCXX_USE_CONSTEXPR bool is_exact = false; + static _GLIBCXX_USE_CONSTEXPR int radix = __FLT_RADIX__; - static constexpr __gnu_cxx::__bfloat16_t - epsilon() noexcept + static _GLIBCXX_CONSTEXPR __gnu_cxx::__bfloat16_t + epsilon() _GLIBCXX_USE_NOEXCEPT { return __BFLT16_EPSILON__; } - static constexpr __gnu_cxx::__bfloat16_t - round_error() noexcept { return 0.5BF16; } + static _GLIBCXX_CONSTEXPR __gnu_cxx::__bfloat16_t + round_error() _GLIBCXX_USE_NOEXCEPT { return 0.5BF16; } - static constexpr int min_exponent = __BFLT16_MIN_EXP__; - static constexpr int min_exponent10 = __BFLT16_MIN_10_EXP__; - static constexpr int max_exponent = __BFLT16_MAX_EXP__; - static constexpr int max_exponent10 = __BFLT16_MAX_10_EXP__; + static _GLIBCXX_USE_CONSTEXPR int min_exponent = __BFLT16_MIN_EXP__; + static _GLIBCXX_USE_CONSTEXPR int min_exponent10 = __BFLT16_MIN_10_EXP__; + static _GLIBCXX_USE_CONSTEXPR int max_exponent = __BFLT16_MAX_EXP__; + static _GLIBCXX_USE_CONSTEXPR int max_exponent10 = __BFLT16_MAX_10_EXP__; - static constexpr bool has_infinity = __BFLT16_HAS_INFINITY__; - static constexpr bool has_quiet_NaN = __BFLT16_HAS_QUIET_NAN__; - static constexpr bool has_signaling_NaN = has_quiet_NaN; - static constexpr float_denorm_style has_denorm - = bool(__BFLT16_HAS_DENORM__) - ? denorm_present : denorm_absent; - static constexpr bool has_denorm_loss = false; + static _GLIBCXX_USE_CONSTEXPR bool has_infinity + = __BFLT16_HAS_INFINITY__; + static _GLIBCXX_USE_CONSTEXPR bool has_quiet_NaN + = __BFLT16_HAS_QUIET_NAN__; + static _GLIBCXX_USE_CONSTEXPR bool has_signaling_NaN = has_quiet_NaN; + static _GLIBCXX_USE_CONSTEXPR float_denorm_style has_denorm + = bool(__BFLT16_HAS_DENORM__) ? denorm_present : denorm_absent; + static _GLIBCXX_USE_CONSTEXPR bool has_denorm_loss = false; - static constexpr __gnu_cxx::__bfloat16_t - infinity() noexcept + static _GLIBCXX_CONSTEXPR __gnu_cxx::__bfloat16_t + infinity() _GLIBCXX_USE_NOEXCEPT { return __gnu_cxx::__bfloat16_t(__builtin_huge_valf()); } - static constexpr __gnu_cxx::__bfloat16_t - quiet_NaN() noexcept + static _GLIBCXX_CONSTEXPR __gnu_cxx::__bfloat16_t + quiet_NaN() _GLIBCXX_USE_NOEXCEPT { return __gnu_cxx::__bfloat16_t(__builtin_nanf("")); } - static constexpr __gnu_cxx::__bfloat16_t - signaling_NaN() noexcept + static _GLIBCXX_CONSTEXPR __gnu_cxx::__bfloat16_t + signaling_NaN() _GLIBCXX_USE_NOEXCEPT { return __builtin_nansf16b(""); } - static constexpr __gnu_cxx::__bfloat16_t - denorm_min() noexcept + static _GLIBCXX_CONSTEXPR __gnu_cxx::__bfloat16_t + denorm_min() _GLIBCXX_USE_NOEXCEPT { return __BFLT16_DENORM_MIN__; } - static constexpr bool is_iec559 + static _GLIBCXX_USE_CONSTEXPR bool is_iec559 = has_infinity && has_quiet_NaN && has_denorm == denorm_present; - static constexpr bool is_bounded = true; - static constexpr bool is_modulo = false; + static _GLIBCXX_USE_CONSTEXPR bool is_bounded = true; + static _GLIBCXX_USE_CONSTEXPR bool is_modulo = false; - static constexpr bool traps = false; - static constexpr bool tinyness_before = false; - static constexpr float_round_style round_style = round_to_nearest; + static _GLIBCXX_USE_CONSTEXPR bool traps = false; + static _GLIBCXX_USE_CONSTEXPR bool tinyness_before = false; + static _GLIBCXX_USE_CONSTEXPR float_round_style round_style + = round_to_nearest; }; -#endif - -#endif // C++23 +#endif // __STDCPP_BFLOAT16_T__ #if defined(_GLIBCXX_USE_FLOAT128) // We either need Q literal suffixes, or IEEE double. diff --git a/libstdc++-v3/include/std/list b/libstdc++-v3/include/std/list index 48861b9a3400..98415919dd4a 100644 --- a/libstdc++-v3/include/std/list +++ b/libstdc++-v3/include/std/list @@ -69,6 +69,9 @@ # include #endif +#define __glibcxx_want_erase_if +#include + #if __cplusplus >= 201703L #include namespace std _GLIBCXX_VISIBILITY(default) @@ -83,13 +86,10 @@ _GLIBCXX_END_NAMESPACE_VERSION } // namespace std #endif // C++17 -#if __cplusplus > 201703L +#ifdef __cpp_lib_erase_if // C++ >= 20 && HOSTED namespace std _GLIBCXX_VISIBILITY(default) { _GLIBCXX_BEGIN_NAMESPACE_VERSION - -#define __cpp_lib_erase_if 202002L - template inline typename list<_Tp, _Alloc>::size_type erase_if(list<_Tp, _Alloc>& __cont, _Predicate __pred) @@ -106,6 +106,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } _GLIBCXX_END_NAMESPACE_VERSION } // namespace std -#endif // C++20 +#endif // __cpp_lib_erase_if #endif /* _GLIBCXX_LIST */ diff --git a/libstdc++-v3/include/std/memory b/libstdc++-v3/include/std/memory index 85c36d67ee1d..3cce72cc0362 100644 --- a/libstdc++-v3/include/std/memory +++ b/libstdc++-v3/include/std/memory @@ -91,11 +91,9 @@ # include #endif -/* As a hack, we declare __cpp_lib_atomic_value_initialization here even though - we don't include the bit that actually declares it, for consistency. */ -#if !defined(__cpp_lib_atomic_value_initialization) && __cplusplus >= 202002L -# define __cpp_lib_atomic_value_initialization 201911L -#endif +#define __glibcxx_want_atomic_value_initialization +#define __glibcxx_want_parallel_algorithm +#include #if __cplusplus >= 201103L && __cplusplus <= 202002L && _GLIBCXX_HOSTED namespace std _GLIBCXX_VISIBILITY(default) @@ -144,7 +142,7 @@ _GLIBCXX_END_NAMESPACE_VERSION } // namespace #endif // C++11 to C++20 -#if __cplusplus >= 201703L && _GLIBCXX_HOSTED +#ifdef __cpp_lib_parallel_algorithm // C++ >= 17 && HOSTED // Parallel STL algorithms # if _PSTL_EXECUTION_POLICIES_DEFINED // If has already been included, pull in implementations @@ -153,9 +151,6 @@ _GLIBCXX_END_NAMESPACE_VERSION // Otherwise just pull in forward declarations # include # endif - -// Feature test macro for parallel algorithms -# define __cpp_lib_parallel_algorithm 201603L -#endif // C++17 +#endif // __cpp_lib_parallel_algorithm #endif /* _GLIBCXX_MEMORY */ diff --git a/libstdc++-v3/include/std/memory_resource b/libstdc++-v3/include/std/memory_resource index fdfc23c95ed3..229c6a8b1403 100644 --- a/libstdc++-v3/include/std/memory_resource +++ b/libstdc++-v3/include/std/memory_resource @@ -36,6 +36,10 @@ #include // polymorphic allocation +#define __glibcxx_want_polymorphic_allocator +#define __glibcxx_want_memory_resource +#include + #if __cplusplus >= 201703L /** @@ -68,16 +72,8 @@ namespace std _GLIBCXX_VISIBILITY(default) _GLIBCXX_BEGIN_NAMESPACE_VERSION namespace pmr { -#ifdef _GLIBCXX_HAS_GTHREADS - // Header and all contents are present. -# define __cpp_lib_memory_resource 201603L -#else - // The pmr::synchronized_pool_resource type is missing. -# define __cpp_lib_memory_resource 1 -#endif -#if __cplusplus >= 202002L -# define __cpp_lib_polymorphic_allocator 201902L +#ifdef __cpp_lib_polymorphic_allocator // C++ >= 20 && HOSTED template class polymorphic_allocator; #endif @@ -111,7 +107,7 @@ namespace pmr // Pool resource classes struct pool_options; -#ifdef _GLIBCXX_HAS_GTHREADS +#if __cpp_lib_memory_resource >= 201603L // C++ >= 17 && hosted && gthread class synchronized_pool_resource; #endif class unsynchronized_pool_resource; @@ -182,7 +178,7 @@ namespace pmr const int _M_npools; }; -#ifdef _GLIBCXX_HAS_GTHREADS +#if __cpp_lib_memory_resource >= 201603L // C++ >= 17 && hosted && gthread /// A thread-safe memory resource that manages pools of fixed-size blocks. /** * @ingroup pmr @@ -252,7 +248,7 @@ namespace pmr _TPools* _M_tpools = nullptr; mutable shared_mutex _M_mx; }; -#endif +#endif // __cpp_lib_memory_resource >= 201603L /// A non-thread-safe memory resource that manages pools of fixed-size blocks. /** diff --git a/libstdc++-v3/include/std/mutex b/libstdc++-v3/include/std/mutex index 2b0059fcfe89..bd3a1cbd94de 100644 --- a/libstdc++-v3/include/std/mutex +++ b/libstdc++-v3/include/std/mutex @@ -56,6 +56,9 @@ # include // std::function #endif +#define __glibcxx_want_scoped_lock +#include + namespace std _GLIBCXX_VISIBILITY(default) { _GLIBCXX_BEGIN_NAMESPACE_VERSION @@ -728,8 +731,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } } -#if __cplusplus >= 201703L -#define __cpp_lib_scoped_lock 201703L +#ifdef __cpp_lib_scoped_lock // C++ >= 17 && hosted && gthread /** @brief A scoped lock type for multiple lockable objects. * * A scoped_lock controls mutex ownership within a scope, releasing @@ -793,7 +795,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION private: mutex_type& _M_device; }; -#endif // C++17 +#endif // __cpp_lib_scoped_lock #ifdef _GLIBCXX_HAS_GTHREADS /// Flag type used by std::call_once diff --git a/libstdc++-v3/include/std/numbers b/libstdc++-v3/include/std/numbers index d7d9e81e5403..ee717cccf5a0 100644 --- a/libstdc++-v3/include/std/numbers +++ b/libstdc++-v3/include/std/numbers @@ -31,7 +31,10 @@ #pragma GCC system_header -#if __cplusplus > 201703L +#define __glibcxx_want_math_constants +#include + +#ifdef __cpp_lib_math_constants // C++ >= 20 #include @@ -47,7 +50,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION /// Namespace for mathematical constants namespace numbers { -#define __cpp_lib_math_constants 201907L /// @cond undocumented template @@ -230,5 +232,5 @@ __glibcxx_numbers (__float128, Q); _GLIBCXX_END_NAMESPACE_VERSION } // namespace std -#endif // C++20 +#endif // __cpp_lib_math_constants #endif // _GLIBCXX_NUMBERS diff --git a/libstdc++-v3/include/std/numeric b/libstdc++-v3/include/std/numeric index 514db9366231..8c8d200021f5 100644 --- a/libstdc++-v3/include/std/numeric +++ b/libstdc++-v3/include/std/numeric @@ -79,6 +79,14 @@ # include #endif +#define __glibcxx_want_constexpr_numeric +#define __glibcxx_want_gcd +#define __glibcxx_want_gcd_lcm +#define __glibcxx_want_interpolate +#define __glibcxx_want_lcm +#define __glibcxx_want_parallel_algorithm +#include + /** * @defgroup numerics Numerics * @@ -150,14 +158,9 @@ namespace __detail } } } // namespace __detail +#endif // C++14 -#if __cplusplus >= 201703L - -#define __cpp_lib_gcd_lcm 201606L -// These were used in drafts of SD-6: -#define __cpp_lib_gcd 201606L -#define __cpp_lib_lcm 201606L - +#ifdef __cpp_lib_gcd_lcm // C++ >= 17 /// Greatest common divisor template constexpr common_type_t<_Mn, _Nn> @@ -198,14 +201,10 @@ namespace __detail return __r; } -#endif // C++17 -#endif // C++14 - -#if __cplusplus > 201703L +#endif // __cpp_lib_gcd_lcm // midpoint -# define __cpp_lib_interpolate 201902L - +#ifdef __cpp_lib_interpolate // C++ >= 20 template constexpr enable_if_t<__and_v, is_same, _Tp>, @@ -251,14 +250,9 @@ namespace __detail static_assert( sizeof(_Tp) != 0, "type must be complete" ); return __a + (__b - __a) / 2; } -#endif // C++20 +#endif // __cpp_lib_interpolate #if __cplusplus >= 201703L - -#if __cplusplus > 201703L -#define __cpp_lib_constexpr_numeric 201911L -#endif - /// @addtogroup numeric_ops /// @{ @@ -739,9 +733,6 @@ _GLIBCXX_END_NAMESPACE_VERSION # include # define _PSTL_NUMERIC_FORWARD_DECLARED 1 # endif - -// Feature test macro for parallel algorithms -# define __cpp_lib_parallel_algorithm 201603L #endif // C++17 #endif /* _GLIBCXX_NUMERIC */ diff --git a/libstdc++-v3/include/std/optional b/libstdc++-v3/include/std/optional index bcac15227014..4f75eb96f977 100644 --- a/libstdc++-v3/include/std/optional +++ b/libstdc++-v3/include/std/optional @@ -32,7 +32,10 @@ #pragma GCC system_header -#if __cplusplus >= 201703L +#define __glibcxx_want_optional +#include + +#ifdef __cpp_lib_optional // C++ >= 17 #include #include @@ -60,14 +63,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION * @{ */ -#if __cplusplus > 202002L && __cpp_lib_concepts -# define __cpp_lib_optional 202110L -#elif __cplusplus >= 202002L -# define __cpp_lib_optional 202106L -#else -# define __cpp_lib_optional 201606L -#endif - template class optional; @@ -138,7 +133,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION // Constructor used by _Optional_base copy constructor when the // contained value is not trivially copy constructible. constexpr - _Optional_payload_base(bool __engaged, + _Optional_payload_base(bool /* __engaged */, const _Optional_payload_base& __other) { if (__other._M_engaged) @@ -148,7 +143,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION // Constructor used by _Optional_base move constructor when the // contained value is not trivially move constructible. constexpr - _Optional_payload_base(bool __engaged, + _Optional_payload_base(bool /* __engaged */, _Optional_payload_base&& __other) { if (__other._M_engaged) @@ -1507,6 +1502,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _GLIBCXX_END_NAMESPACE_VERSION } // namespace std -#endif // C++17 +#endif // __cpp_lib_optional #endif // _GLIBCXX_OPTIONAL diff --git a/libstdc++-v3/include/std/ostream b/libstdc++-v3/include/std/ostream index 4711b8a3d966..5f973fa11ed6 100644 --- a/libstdc++-v3/include/std/ostream +++ b/libstdc++-v3/include/std/ostream @@ -39,6 +39,7 @@ #include #include +#include // __glibcxx_syncbuf namespace std _GLIBCXX_VISIBILITY(default) { @@ -804,7 +805,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION return std::move(__os); } -#if __cplusplus > 201703L && _GLIBCXX_USE_CXX11_ABI +#ifdef __glibcxx_syncbuf // C++ >= 20 && HOSTED && CXX11ABI template class __syncbuf_base : public basic_streambuf<_CharT, _Traits> { @@ -869,8 +870,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION __os.flush(); return __os; } - -#endif // C++20 +#endif // __glibcxx_syncbuf #endif // C++11 diff --git a/libstdc++-v3/include/std/ranges b/libstdc++-v3/include/std/ranges index c4d4d85bf909..3477323d8711 100644 --- a/libstdc++-v3/include/std/ranges +++ b/libstdc++-v3/include/std/ranges @@ -51,6 +51,21 @@ #include #include +#define __glibcxx_want_ranges_as_const +#define __glibcxx_want_ranges_as_rvalue +#define __glibcxx_want_ranges_cartesian_product +#define __glibcxx_want_ranges_chunk +#define __glibcxx_want_ranges_chunk_by +#define __glibcxx_want_ranges_enumerate +#define __glibcxx_want_ranges_iota +#define __glibcxx_want_ranges_iota +#define __glibcxx_want_ranges_join_with +#define __glibcxx_want_ranges_repeat +#define __glibcxx_want_ranges_slide +#define __glibcxx_want_ranges_stride +#define __glibcxx_want_ranges_zip +#include + /** * @defgroup ranges Ranges * @@ -877,25 +892,35 @@ namespace views::__adaptor // The derived class should define the optional static data member // _S_has_simple_call_op to true if the behavior of this adaptor is // independent of the constness/value category of the adaptor object. - struct _RangeAdaptorClosure - { - // range | adaptor is equivalent to adaptor(range). - template - requires derived_from, _RangeAdaptorClosure> - && __adaptor_invocable<_Self, _Range> - friend constexpr auto - operator|(_Range&& __r, _Self&& __self) - { return std::forward<_Self>(__self)(std::forward<_Range>(__r)); } + template + struct _RangeAdaptorClosure + { }; - // Compose the adaptors __lhs and __rhs into a pipeline, returning - // another range adaptor closure object. - template - requires derived_from<_Lhs, _RangeAdaptorClosure> - && derived_from<_Rhs, _RangeAdaptorClosure> - friend constexpr auto - operator|(_Lhs __lhs, _Rhs __rhs) - { return _Pipe<_Lhs, _Rhs>{std::move(__lhs), std::move(__rhs)}; } - }; + template + requires (!same_as<_Tp, _RangeAdaptorClosure<_Up>>) + void __is_range_adaptor_closure_fn + (const _Tp&, const _RangeAdaptorClosure<_Up>&); // not defined + + template + concept __is_range_adaptor_closure + = requires (_Tp __t) { __adaptor::__is_range_adaptor_closure_fn(__t, __t); }; + + // range | adaptor is equivalent to adaptor(range). + template + requires __is_range_adaptor_closure<_Self> + && __adaptor_invocable<_Self, _Range> + constexpr auto + operator|(_Range&& __r, _Self&& __self) + { return std::forward<_Self>(__self)(std::forward<_Range>(__r)); } + + // Compose the adaptors __lhs and __rhs into a pipeline, returning + // another range adaptor closure object. + template + requires __is_range_adaptor_closure<_Lhs> + && __is_range_adaptor_closure<_Rhs> + constexpr auto + operator|(_Lhs __lhs, _Rhs __rhs) + { return _Pipe<_Lhs, _Rhs>{std::move(__lhs), std::move(__rhs)}; } // The base class of every range adaptor non-closure. // @@ -937,7 +962,7 @@ namespace views::__adaptor // A range adaptor closure that represents partial application of // the range adaptor _Adaptor with arguments _Args. template - struct _Partial : _RangeAdaptorClosure + struct _Partial : _RangeAdaptorClosure<_Partial<_Adaptor, _Args...>> { tuple<_Args...> _M_args; @@ -978,7 +1003,7 @@ namespace views::__adaptor // A lightweight specialization of the above primary template for // the common case where _Adaptor accepts a single extra argument. template - struct _Partial<_Adaptor, _Arg> : _RangeAdaptorClosure + struct _Partial<_Adaptor, _Arg> : _RangeAdaptorClosure<_Partial<_Adaptor, _Arg>> { _Arg _M_arg; @@ -1011,7 +1036,7 @@ namespace views::__adaptor template requires __adaptor_has_simple_extra_args<_Adaptor, _Args...> && (is_trivially_copyable_v<_Args> && ...) - struct _Partial<_Adaptor, _Args...> : _RangeAdaptorClosure + struct _Partial<_Adaptor, _Args...> : _RangeAdaptorClosure<_Partial<_Adaptor, _Args...>> { tuple<_Args...> _M_args; @@ -1041,7 +1066,7 @@ namespace views::__adaptor template requires __adaptor_has_simple_extra_args<_Adaptor, _Arg> && is_trivially_copyable_v<_Arg> - struct _Partial<_Adaptor, _Arg> : _RangeAdaptorClosure + struct _Partial<_Adaptor, _Arg> : _RangeAdaptorClosure<_Partial<_Adaptor, _Arg>> { _Arg _M_arg; @@ -1066,7 +1091,7 @@ namespace views::__adaptor // A range adaptor closure that represents composition of the range // adaptor closures _Lhs and _Rhs. template - struct _Pipe : _RangeAdaptorClosure + struct _Pipe : _RangeAdaptorClosure<_Pipe<_Lhs, _Rhs>> { [[no_unique_address]] _Lhs _M_lhs; [[no_unique_address]] _Rhs _M_rhs; @@ -1102,7 +1127,7 @@ namespace views::__adaptor template requires __closure_has_simple_call_op<_Lhs> && __closure_has_simple_call_op<_Rhs> - struct _Pipe<_Lhs, _Rhs> : _RangeAdaptorClosure + struct _Pipe<_Lhs, _Rhs> : _RangeAdaptorClosure<_Pipe<_Lhs, _Rhs>> { [[no_unique_address]] _Lhs _M_lhs; [[no_unique_address]] _Rhs _M_rhs; @@ -1126,7 +1151,7 @@ namespace views::__adaptor template requires is_class_v<_Derived> && same_as<_Derived, remove_cv_t<_Derived>> class range_adaptor_closure - : public views::__adaptor::_RangeAdaptorClosure + : public views::__adaptor::_RangeAdaptorClosure<_Derived> { }; #endif @@ -1272,7 +1297,7 @@ namespace views::__adaptor concept __can_owning_view = requires { owning_view{std::declval<_Range>()}; }; } // namespace __detail - struct _All : __adaptor::_RangeAdaptorClosure + struct _All : __adaptor::_RangeAdaptorClosure<_All> { template static constexpr bool @@ -2713,6 +2738,14 @@ namespace views::__adaptor inline constexpr _DropWhile drop_while; } // namespace views + namespace __detail + { + template + constexpr _Tp& + __as_lvalue(_Tp&& __t) + { return static_cast<_Tp&>(__t); } + } // namespace __detail + template requires view<_Vp> && input_range> class join_view : public view_interface> @@ -2775,6 +2808,8 @@ namespace views::__adaptor using _Parent = __detail::__maybe_const_t<_Const, join_view>; using _Base = join_view::_Base<_Const>; + friend join_view; + static constexpr bool _S_ref_is_glvalue = join_view::_S_ref_is_glvalue<_Const>; @@ -2788,9 +2823,10 @@ namespace views::__adaptor return _M_parent->_M_inner._M_emplace_deref(__x); }; - for (; _M_outer != ranges::end(_M_parent->_M_base); ++_M_outer) + _Outer_iter& __outer = _M_get_outer(); + for (; __outer != ranges::end(_M_parent->_M_base); ++__outer) { - auto&& __inner = __update_inner(_M_outer); + auto&& __inner = __update_inner(__outer); _M_inner = ranges::begin(__inner); if (_M_inner != ranges::end(__inner)) return; @@ -2819,7 +2855,36 @@ namespace views::__adaptor using _Outer_iter = join_view::_Outer_iter<_Const>; using _Inner_iter = join_view::_Inner_iter<_Const>; - _Outer_iter _M_outer = _Outer_iter(); + constexpr _Outer_iter& + _M_get_outer() + { + if constexpr (forward_range<_Base>) + return _M_outer; + else + return *_M_parent->_M_outer; + } + + constexpr const _Outer_iter& + _M_get_outer() const + { + if constexpr (forward_range<_Base>) + return _M_outer; + else + return *_M_parent->_M_outer; + } + + constexpr + _Iterator(_Parent* __parent, _Outer_iter __outer) requires forward_range<_Base> + : _M_outer(std::move(__outer)), _M_parent(__parent) + { _M_satisfy(); } + + constexpr explicit + _Iterator(_Parent* __parent) requires (!forward_range<_Base>) + : _M_parent(__parent) + { _M_satisfy(); } + + [[no_unique_address]] + __detail::__maybe_present_t, _Outer_iter> _M_outer; optional<_Inner_iter> _M_inner; _Parent* _M_parent = nullptr; @@ -2831,13 +2896,7 @@ namespace views::__adaptor = common_type_t, range_difference_t>>; - _Iterator() requires default_initializable<_Outer_iter> = default; - - constexpr - _Iterator(_Parent* __parent, _Outer_iter __outer) - : _M_outer(std::move(__outer)), - _M_parent(__parent) - { _M_satisfy(); } + _Iterator() = default; constexpr _Iterator(_Iterator __i) @@ -2865,13 +2924,13 @@ namespace views::__adaptor { auto&& __inner_range = [this] () -> auto&& { if constexpr (_S_ref_is_glvalue) - return *_M_outer; + return *_M_get_outer(); else return *_M_parent->_M_inner; }(); if (++*_M_inner == ranges::end(__inner_range)) { - ++_M_outer; + ++_M_get_outer(); _M_satisfy(); } return *this; @@ -2898,9 +2957,9 @@ namespace views::__adaptor && common_range> { if (_M_outer == ranges::end(_M_parent->_M_base)) - _M_inner = ranges::end(*--_M_outer); - while (*_M_inner == ranges::begin(*_M_outer)) - *_M_inner = ranges::end(*--_M_outer); + _M_inner = ranges::end(__detail::__as_lvalue(*--_M_outer)); + while (*_M_inner == ranges::begin(__detail::__as_lvalue(*_M_outer))) + *_M_inner = ranges::end(__detail::__as_lvalue(*--_M_outer)); --*_M_inner; return *this; } @@ -2919,7 +2978,7 @@ namespace views::__adaptor friend constexpr bool operator==(const _Iterator& __x, const _Iterator& __y) requires _S_ref_is_glvalue - && equality_comparable<_Outer_iter> + && forward_range<_Base> && equality_comparable<_Inner_iter> { return (__x._M_outer == __y._M_outer @@ -2951,7 +3010,7 @@ namespace views::__adaptor template constexpr bool __equal(const _Iterator<_Const2>& __i) const - { return __i._M_outer == _M_end; } + { return __i._M_get_outer() == _M_end; } sentinel_t<_Base> _M_end = sentinel_t<_Base>(); @@ -2980,6 +3039,9 @@ namespace views::__adaptor }; _Vp _M_base = _Vp(); + [[no_unique_address]] + __detail::__maybe_present_t, + __detail::__non_propagating_cache>> _M_outer; [[no_unique_address]] __detail::__non_propagating_cache> _M_inner; @@ -3002,16 +3064,25 @@ namespace views::__adaptor constexpr auto begin() { - constexpr bool __use_const - = (__detail::__simple_view<_Vp> - && is_reference_v>); - return _Iterator<__use_const>{this, ranges::begin(_M_base)}; + if constexpr (forward_range<_Vp>) + { + constexpr bool __use_const + = (__detail::__simple_view<_Vp> + && is_reference_v>); + return _Iterator<__use_const>{this, ranges::begin(_M_base)}; + } + else + { + _M_outer = ranges::begin(_M_base); + return _Iterator{this}; + } } constexpr auto begin() const - requires input_range + requires forward_range && is_reference_v> + && input_range> { return _Iterator{this, ranges::begin(_M_base)}; } @@ -3030,11 +3101,11 @@ namespace views::__adaptor constexpr auto end() const - requires input_range + requires forward_range && is_reference_v> + && input_range> { - if constexpr (forward_range - && is_reference_v> + if constexpr (is_reference_v> && forward_range> && common_range && common_range>) @@ -3056,7 +3127,7 @@ namespace views::__adaptor = requires { join_view>{std::declval<_Range>()}; }; } // namespace __detail - struct _Join : __adaptor::_RangeAdaptorClosure + struct _Join : __adaptor::_RangeAdaptorClosure<_Join> { template requires __detail::__can_join_view<_Range> @@ -3850,7 +3921,7 @@ namespace views::__adaptor = requires { common_view{std::declval<_Range>()}; }; } // namespace __detail - struct _Common : __adaptor::_RangeAdaptorClosure + struct _Common : __adaptor::_RangeAdaptorClosure<_Common> { template requires __detail::__already_common<_Range> @@ -3971,7 +4042,7 @@ namespace views::__adaptor = requires { reverse_view{std::declval<_Range>()}; }; } // namespace __detail - struct _Reverse : __adaptor::_RangeAdaptorClosure + struct _Reverse : __adaptor::_RangeAdaptorClosure<_Reverse> { template requires __detail::__is_reverse_view> @@ -4371,7 +4442,7 @@ namespace views::__adaptor } // namespace __detail template - struct _Elements : __adaptor::_RangeAdaptorClosure + struct _Elements : __adaptor::_RangeAdaptorClosure<_Elements<_Nm>> { template requires __detail::__can_elements_view<_Nm, _Range> @@ -4390,10 +4461,7 @@ namespace views::__adaptor inline constexpr auto values = elements<1>; } // namespace views -#if __cplusplus > 202002L - -#define __cpp_lib_ranges_zip 202110L - +#ifdef __cpp_lib_ranges_zip // C++ >= 23 namespace __detail { template @@ -5492,7 +5560,7 @@ namespace views::__adaptor } template - struct _Adjacent : __adaptor::_RangeAdaptorClosure + struct _Adjacent : __adaptor::_RangeAdaptorClosure<_Adjacent<_Nm>> { template requires (_Nm == 0) || __detail::__can_adjacent_view<_Nm, _Range> @@ -5831,9 +5899,9 @@ namespace views::__adaptor inline constexpr auto pairwise_transform = adjacent_transform<2>; } +#endif // __cpp_lib_ranges_zip -#define __cpp_lib_ranges_chunk 202202L - +#ifdef __cpp_lib_ranges_chunk // C++ >= 23 namespace __detail { template @@ -6370,9 +6438,9 @@ namespace views::__adaptor inline constexpr _Chunk chunk; } +#endif // __cpp_lib_ranges_chunk -#define __cpp_lib_ranges_slide 202202L - +#ifdef __cpp_lib_ranges_slide // C++ >= 23 namespace __detail { template @@ -6735,9 +6803,9 @@ namespace views::__adaptor inline constexpr _Slide slide; } +#endif // __cpp_lib_ranges_slide -#define __cpp_lib_ranges_chunk_by 202202L - +#ifdef __cpp_lib_ranges_chunk_by // C++ >= 23 template, iterator_t<_Vp>> _Pred> requires view<_Vp> && is_object_v<_Pred> @@ -6930,9 +6998,9 @@ namespace views::__adaptor inline constexpr _ChunkBy chunk_by; } +#endif // __cpp_lib_ranges_chunk_by -#define __cpp_lib_ranges_join_with 202202L - +#ifdef __cpp_lib_ranges_join_with // C++ >= 23 namespace __detail { template @@ -6956,6 +7024,9 @@ namespace views::__adaptor using _InnerRange = range_reference_t<_Vp>; _Vp _M_base = _Vp(); + [[no_unique_address]] + __detail::__maybe_present_t, + __detail::__non_propagating_cache>> _M_outer_it; __detail::__non_propagating_cache> _M_inner; _Pattern _M_pattern = _Pattern(); @@ -7043,16 +7114,25 @@ namespace views::__adaptor constexpr auto begin() { - constexpr bool __use_const = is_reference_v<_InnerRange> - && __detail::__simple_view<_Vp> && __detail::__simple_view<_Pattern>; - return _Iterator<__use_const>{*this, ranges::begin(_M_base)}; + if constexpr (forward_range<_Vp>) + { + constexpr bool __use_const = is_reference_v<_InnerRange> + && __detail::__simple_view<_Vp> && __detail::__simple_view<_Pattern>; + return _Iterator<__use_const>{*this, ranges::begin(_M_base)}; + } + else + { + _M_outer_it = ranges::begin(_M_base); + return _Iterator{*this}; + } } constexpr auto begin() const - requires input_range + requires forward_range && forward_range && is_reference_v> + && input_range> { return _Iterator{*this, ranges::begin(_M_base)}; } constexpr auto @@ -7070,13 +7150,13 @@ namespace views::__adaptor constexpr auto end() const - requires input_range + requires forward_range && forward_range && is_reference_v> + && input_range> { using _InnerConstRange = range_reference_t; - if constexpr (forward_range - && forward_range<_InnerConstRange> + if constexpr (forward_range<_InnerConstRange> && common_range && common_range<_InnerConstRange>) return _Iterator{*this, ranges::end(_M_base)}; @@ -7113,35 +7193,69 @@ namespace views::__adaptor static constexpr bool _S_ref_is_glvalue = join_with_view::_S_ref_is_glvalue<_Const>; _Parent* _M_parent = nullptr; - _OuterIter _M_outer_it = _OuterIter(); + [[no_unique_address]] + __detail::__maybe_present_t, _OuterIter> _M_outer_it; variant<_PatternIter, _InnerIter> _M_inner_it; + constexpr _OuterIter& + _M_get_outer() + { + if constexpr (forward_range<_Base>) + return _M_outer_it; + else + return *_M_parent->_M_outer_it; + } + + constexpr const _OuterIter& + _M_get_outer() const + { + if constexpr (forward_range<_Base>) + return _M_outer_it; + else + return *_M_parent->_M_outer_it; + } + constexpr - _Iterator(_Parent& __parent, iterator_t<_Base> __outer) + _Iterator(_Parent& __parent, _OuterIter __outer) + requires forward_range<_Base> : _M_parent(std::__addressof(__parent)), _M_outer_it(std::move(__outer)) { - if (_M_outer_it != ranges::end(_M_parent->_M_base)) + if (_M_get_outer() != ranges::end(_M_parent->_M_base)) { - auto&& __inner = _M_update_inner(_M_outer_it); + auto&& __inner = _M_update_inner(); _M_inner_it.template emplace<1>(ranges::begin(__inner)); _M_satisfy(); } } - constexpr auto&& - _M_update_inner(const _OuterIter& __x) + constexpr + _Iterator(_Parent& __parent) + requires (!forward_range<_Base>) + : _M_parent(std::__addressof(__parent)) { - if constexpr (_S_ref_is_glvalue) - return *__x; - else - return _M_parent->_M_inner._M_emplace_deref(__x); + if (_M_get_outer() != ranges::end(_M_parent->_M_base)) + { + auto&& __inner = _M_update_inner(); + _M_inner_it.template emplace<1>(ranges::begin(__inner)); + _M_satisfy(); + } } - constexpr auto&& - _M_get_inner(const _OuterIter& __x) + constexpr auto& + _M_update_inner() + { + _OuterIter& __outer = _M_get_outer(); + if constexpr (_S_ref_is_glvalue) + return __detail::__as_lvalue(*__outer); + else + return _M_parent->_M_inner._M_emplace_deref(__outer); + } + + constexpr auto& + _M_get_inner() { if constexpr (_S_ref_is_glvalue) - return *__x; + return __detail::__as_lvalue(*_M_get_outer()); else return *_M_parent->_M_inner; } @@ -7156,16 +7270,16 @@ namespace views::__adaptor if (std::get<0>(_M_inner_it) != ranges::end(_M_parent->_M_pattern)) break; - auto&& __inner = _M_update_inner(_M_outer_it); + auto&& __inner = _M_update_inner(); _M_inner_it.template emplace<1>(ranges::begin(__inner)); } else { - auto&& __inner = _M_get_inner(_M_outer_it); + auto&& __inner = _M_get_inner(); if (std::get<1>(_M_inner_it) != ranges::end(__inner)) break; - if (++_M_outer_it == ranges::end(_M_parent->_M_base)) + if (++_M_get_outer() == ranges::end(_M_parent->_M_base)) { if constexpr (_S_ref_is_glvalue) _M_inner_it.template emplace<0>(); @@ -7204,7 +7318,7 @@ namespace views::__adaptor iter_difference_t<_InnerIter>, iter_difference_t<_PatternIter>>; - _Iterator() requires default_initializable<_OuterIter> = default; + _Iterator() = default; constexpr _Iterator(_Iterator __i) @@ -7314,7 +7428,7 @@ namespace views::__adaptor friend constexpr bool operator==(const _Iterator& __x, const _Iterator& __y) requires _S_ref_is_glvalue - && equality_comparable<_OuterIter> && equality_comparable<_InnerIter> + && forward_range<_Base> && equality_comparable<_InnerIter> { return __x._M_outer_it == __y._M_outer_it && __x._M_inner_it ==__y._M_inner_it; } friend constexpr common_reference_t, @@ -7381,7 +7495,7 @@ namespace views::__adaptor iterator_t<__detail::__maybe_const_t<_OtherConst, _Vp>>> friend constexpr bool operator==(const _Iterator<_OtherConst>& __x, const _Sentinel& __y) - { return __x._M_outer_it == __y._M_end; } + { return __x._M_get_outer() == __y._M_end; } }; namespace views @@ -7412,9 +7526,9 @@ namespace views::__adaptor inline constexpr _JoinWith join_with; } // namespace views +#endif // __cpp_lib_ranges_join_with -#define __cpp_lib_ranges_repeat 202207L - +#ifdef __cpp_lib_ranges_repeat // C++ >= 32 template requires is_object_v<_Tp> && same_as<_Tp, remove_cv_t<_Tp>> && (__detail::__is_integer_like<_Bound> || same_as<_Bound, unreachable_sentinel_t>) @@ -7666,9 +7780,9 @@ namespace views::__adaptor } } } +#endif // __cpp_lib_ranges_repeat -#define __cpp_lib_ranges_stride 202207L - +#ifdef __cpp_lib_ranges_stride // C++ >= 23 template requires view<_Vp> class stride_view : public view_interface> @@ -8019,9 +8133,9 @@ namespace views::__adaptor inline constexpr _Stride stride; } +#endif // __cpp_lib_ranges_stride -#define __cpp_lib_ranges_cartesian_product 202207L - +#ifdef __cpp_lib_ranges_cartesian_product // C++ >= 23 namespace __detail { template @@ -8542,9 +8656,9 @@ namespace views::__adaptor inline constexpr _CartesianProduct cartesian_product; } +#endif // __cpp_lib_ranges_cartesian_product -#define __cpp_lib_ranges_as_rvalue 202207L - +#ifdef __cpp_lib_ranges_as_rvalue // C++ >= 23 template requires view<_Vp> class as_rvalue_view : public view_interface> @@ -8617,7 +8731,7 @@ namespace views::__adaptor concept __can_as_rvalue_view = requires { as_rvalue_view(std::declval<_Tp>()); }; } - struct _AsRvalue : __adaptor::_RangeAdaptorClosure + struct _AsRvalue : __adaptor::_RangeAdaptorClosure<_AsRvalue> { template requires __detail::__can_as_rvalue_view<_Range> @@ -8634,9 +8748,9 @@ namespace views::__adaptor inline constexpr _AsRvalue as_rvalue; } +#endif // __cpp_lib_as_rvalue -#define __cpp_lib_ranges_enumerate 202302L - +#ifdef __cpp_lib_ranges_enumerate // C++ >= 23 namespace __detail { template @@ -8926,7 +9040,7 @@ namespace views::__adaptor = requires { enumerate_view>(std::declval<_Tp>()); }; } - struct _Enumerate : __adaptor::_RangeAdaptorClosure + struct _Enumerate : __adaptor::_RangeAdaptorClosure<_Enumerate> { template requires __detail::__can_enumerate_view<_Range> @@ -8937,9 +9051,9 @@ namespace views::__adaptor inline constexpr _Enumerate enumerate; } +#endif // __cpp_lib_ranges_enumerate -#define __cpp_lib_ranges_as_const 202207L - +#ifdef __cpp_lib_ranges_as_const // C++ >= 23 template requires input_range<_Vp> class as_const_view : public view_interface> @@ -9012,7 +9126,7 @@ namespace views::__adaptor concept __can_as_const_view = requires { as_const_view(std::declval<_Range>()); }; } - struct _AsConst : __adaptor::_RangeAdaptorClosure + struct _AsConst : __adaptor::_RangeAdaptorClosure<_AsConst> { template constexpr auto @@ -9043,7 +9157,7 @@ namespace views::__adaptor inline constexpr _AsConst as_const; } -#endif // C++23 +#endif // __cpp_lib_as_const } // namespace ranges namespace views = ranges::views; diff --git a/libstdc++-v3/include/std/ratio b/libstdc++-v3/include/std/ratio index 1d285bf916f3..c87f54fe1a2b 100644 --- a/libstdc++-v3/include/std/ratio +++ b/libstdc++-v3/include/std/ratio @@ -39,6 +39,9 @@ #include #include // intmax_t, uintmax_t +#define __glibcxx_want_ratio +#include + namespace std _GLIBCXX_VISIBILITY(default) { _GLIBCXX_BEGIN_NAMESPACE_VERSION @@ -602,23 +605,42 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template using ratio_subtract = typename __ratio_subtract<_R1, _R2>::type; - - typedef ratio<1, 1000000000000000000> atto; - typedef ratio<1, 1000000000000000> femto; - typedef ratio<1, 1000000000000> pico; - typedef ratio<1, 1000000000> nano; - typedef ratio<1, 1000000> micro; - typedef ratio<1, 1000> milli; - typedef ratio<1, 100> centi; - typedef ratio<1, 10> deci; - typedef ratio< 10, 1> deca; - typedef ratio< 100, 1> hecto; - typedef ratio< 1000, 1> kilo; - typedef ratio< 1000000, 1> mega; - typedef ratio< 1000000000, 1> giga; - typedef ratio< 1000000000000, 1> tera; - typedef ratio< 1000000000000000, 1> peta; - typedef ratio< 1000000000000000000, 1> exa; +#if __INTMAX_WIDTH__ >= 96 +# if __cpp_lib_ratio >= 202306L +# if __INTMAX_WIDTH__ >= 128 + using quecto = ratio< 1, 1000000000000000000000000000000>; +# endif + using ronto = ratio< 1, 1000000000000000000000000000>; +# endif + using yocto = ratio< 1, 1000000000000000000000000>; + using zepto = ratio< 1, 1000000000000000000000>; +#endif + using atto = ratio< 1, 1000000000000000000>; + using femto = ratio< 1, 1000000000000000>; + using pico = ratio< 1, 1000000000000>; + using nano = ratio< 1, 1000000000>; + using micro = ratio< 1, 1000000>; + using milli = ratio< 1, 1000>; + using centi = ratio< 1, 100>; + using deci = ratio< 1, 10>; + using deca = ratio< 10, 1>; + using hecto = ratio< 100, 1>; + using kilo = ratio< 1000, 1>; + using mega = ratio< 1000000, 1>; + using giga = ratio< 1000000000, 1>; + using tera = ratio< 1000000000000, 1>; + using peta = ratio< 1000000000000000, 1>; + using exa = ratio< 1000000000000000000, 1>; +#if __INTMAX_WIDTH__ >= 96 + using zetta = ratio< 1000000000000000000000, 1>; + using yotta = ratio<1000000000000000000000000, 1>; +# if __cpp_lib_ratio >= 202306L + using ronna = ratio<1000000000000000000000000000, 1>; +# if __INTMAX_WIDTH__ >= 128 + using quetta = ratio<1000000000000000000000000000000, 1>; +# endif +# endif +#endif /// @} group ratio _GLIBCXX_END_NAMESPACE_VERSION diff --git a/libstdc++-v3/include/std/scoped_allocator b/libstdc++-v3/include/std/scoped_allocator index a11545026bae..8af432ada425 100644 --- a/libstdc++-v3/include/std/scoped_allocator +++ b/libstdc++-v3/include/std/scoped_allocator @@ -104,11 +104,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION __inner_type_impl& operator=(__inner_type_impl&&) = default; template - __inner_type_impl(const __inner_type_impl<_Alloc>& __other) noexcept + __inner_type_impl(const __inner_type_impl<_Alloc>&) noexcept { } template - __inner_type_impl(__inner_type_impl<_Alloc>&& __other) noexcept + __inner_type_impl(__inner_type_impl<_Alloc>&&) noexcept { } __type& @@ -164,7 +164,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { return _M_inner == __other._M_inner; } private: - template friend class __inner_type_impl; + template friend struct __inner_type_impl; template friend class scoped_allocator_adaptor; __type _M_inner; @@ -186,7 +186,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION friend class scoped_allocator_adaptor; template - friend class __inner_type_impl; + friend struct __inner_type_impl; tuple _M_tie() const noexcept diff --git a/libstdc++-v3/include/std/semaphore b/libstdc++-v3/include/std/semaphore index dfc272f6d35e..5ca4da75e507 100644 --- a/libstdc++-v3/include/std/semaphore +++ b/libstdc++-v3/include/std/semaphore @@ -36,13 +36,14 @@ #if __cplusplus > 201703L #include -#if __cpp_lib_atomic_wait || _GLIBCXX_HAVE_POSIX_SEMAPHORE +#define __glibcxx_want_semaphore +#include + +#ifdef __cpp_lib_semaphore // C++ >= 20 && hosted && (atomic_wait || posix_sem) namespace std _GLIBCXX_VISIBILITY(default) { _GLIBCXX_BEGIN_NAMESPACE_VERSION -#define __cpp_lib_semaphore 201907L - template class counting_semaphore { @@ -93,5 +94,5 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _GLIBCXX_END_NAMESPACE_VERSION } // namespace #endif // cpp_lib_atomic_wait || _GLIBCXX_HAVE_POSIX_SEMAPHORE -#endif // C++20 +#endif // __cpp_lib_semaphore #endif // _GLIBCXX_SEMAPHORE diff --git a/libstdc++-v3/include/std/shared_mutex b/libstdc++-v3/include/std/shared_mutex index 124da6140616..4f236a198069 100644 --- a/libstdc++-v3/include/std/shared_mutex +++ b/libstdc++-v3/include/std/shared_mutex @@ -41,6 +41,10 @@ #include // move, __exchange #include // defer_lock_t +#define __glibcxx_want_shared_mutex +#define __glibcxx_want_shared_timed_mutex +#include + #if ! (_GLIBCXX_USE_PTHREAD_RWLOCK_T && _GTHREAD_USE_MUTEX_TIMEDLOCK) # include #endif @@ -56,12 +60,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION #ifdef _GLIBCXX_HAS_GTHREADS -#if __cplusplus >= 201703L -#define __cpp_lib_shared_mutex 201505L +#ifdef __cpp_lib_shared_mutex // C++ >= 17 && hosted && gthread class shared_mutex; #endif -#define __cpp_lib_shared_timed_mutex 201402L class shared_timed_mutex; /// @cond undocumented @@ -407,7 +409,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION #endif /// @endcond -#if __cplusplus >= 201703L +#ifdef __cpp_lib_shared_mutex /// The standard shared mutex type. class shared_mutex { @@ -441,7 +443,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION __shared_mutex_cv _M_impl; #endif }; -#endif // C++17 +#endif // __cpp_lib_shared_mutex /// @cond undocumented #if _GLIBCXX_USE_PTHREAD_RWLOCK_T && _GTHREAD_USE_MUTEX_TIMEDLOCK diff --git a/libstdc++-v3/include/std/source_location b/libstdc++-v3/include/std/source_location index 9f492826268e..10e3c9f2518e 100644 --- a/libstdc++-v3/include/std/source_location +++ b/libstdc++-v3/include/std/source_location @@ -29,15 +29,16 @@ #ifndef _GLIBCXX_SRCLOC #define _GLIBCXX_SRCLOC 1 -#if __cplusplus > 201703L && __has_builtin(__builtin_source_location) +#define __glibcxx_want_source_location +#include + +#if __cpp_lib_source_location // C++ >= 20 && builtin_source_location #include namespace std { _GLIBCXX_BEGIN_NAMESPACE_VERSION -#define __cpp_lib_source_location 201907L - /// A class that describes a location in source code. struct source_location { @@ -88,5 +89,5 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _GLIBCXX_END_NAMESPACE_VERSION } // namespace std -#endif // C++20 && __builtin_source_location +#endif // __cpp_lib_source_location #endif // _GLIBCXX_SRCLOC diff --git a/libstdc++-v3/include/std/span b/libstdc++-v3/include/std/span index 676338996650..d5644a196a2a 100644 --- a/libstdc++-v3/include/std/span +++ b/libstdc++-v3/include/std/span @@ -36,20 +36,18 @@ #pragma GCC system_header -#if __cplusplus > 201703L +#define __glibcxx_want_span +#include +#ifdef __cpp_lib_span // C++ >= 20 && concepts #include #include #include #include - -#if __cpp_lib_concepts namespace std _GLIBCXX_VISIBILITY(default) { _GLIBCXX_BEGIN_NAMESPACE_VERSION -#define __cpp_lib_span 202002L - inline constexpr size_t dynamic_extent = static_cast(-1); template @@ -476,6 +474,5 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } _GLIBCXX_END_NAMESPACE_VERSION } // namespace std -#endif // concepts -#endif // C++20 +#endif // __cpp_lib_span #endif // _GLIBCXX_SPAN diff --git a/libstdc++-v3/include/std/spanstream b/libstdc++-v3/include/std/spanstream index 483996b274f2..1f2d78b79d36 100644 --- a/libstdc++-v3/include/std/spanstream +++ b/libstdc++-v3/include/std/spanstream @@ -33,20 +33,20 @@ #include // iostreams -#if __cplusplus > 202002L +#define __glibcxx_want_spanstream +#include + +#ifdef __cpp_lib_spanstream // C++ >= 23 && hosted && lib_span #include #include #include #include #include -#if __cpp_lib_span namespace std _GLIBCXX_VISIBILITY(default) { _GLIBCXX_BEGIN_NAMESPACE_VERSION -#define __cpp_lib_spanstream 202106L - template class basic_spanbuf : public basic_streambuf<_CharT, _Traits> @@ -451,6 +451,5 @@ using wspanstream = basic_spanstream; _GLIBCXX_END_NAMESPACE_VERSION } // namespace std -#endif // __cpp_lib_span -#endif // C++23 +#endif // __cpp_lib_spanstream #endif // _GLIBCXX_SPANSTREAM diff --git a/libstdc++-v3/include/std/stacktrace b/libstdc++-v3/include/std/stacktrace index 346c7b141421..07949e70861c 100644 --- a/libstdc++-v3/include/std/stacktrace +++ b/libstdc++-v3/include/std/stacktrace @@ -30,7 +30,10 @@ #include -#if __cplusplus > 202002L && _GLIBCXX_HAVE_STACKTRACE +#define __glibcxx_want_stacktrace +#include + +#ifdef __cpp_lib_stacktrace // C++ >= 23 && hosted && HAVE_STACKTRACE #include #include #include @@ -83,8 +86,6 @@ namespace std _GLIBCXX_VISIBILITY(default) { _GLIBCXX_BEGIN_NAMESPACE_VERSION -#define __cpp_lib_stacktrace 202011L - // [stacktrace.entry], class stacktrace_entry class stacktrace_entry { @@ -800,6 +801,5 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _GLIBCXX_END_NAMESPACE_VERSION } // namespace std -#endif // C++23 - +#endif // __cpp_lib_stacktrace #endif /* _GLIBCXX_STACKTRACE */ diff --git a/libstdc++-v3/include/std/stop_token b/libstdc++-v3/include/std/stop_token index c90fc786b63d..3be0f5a3ac48 100644 --- a/libstdc++-v3/include/std/stop_token +++ b/libstdc++-v3/include/std/stop_token @@ -31,6 +31,9 @@ #include // concurrency +#define __glibcxx_want_jthread +#include + #if __cplusplus > 201703L #include @@ -38,8 +41,6 @@ #include -#define __cpp_lib_jthread 201911L - namespace std _GLIBCXX_VISIBILITY(default) { _GLIBCXX_BEGIN_NAMESPACE_VERSION diff --git a/libstdc++-v3/include/std/string b/libstdc++-v3/include/std/string index dd4ece128010..832e9d8915fa 100644 --- a/libstdc++-v3/include/std/string +++ b/libstdc++-v3/include/std/string @@ -54,6 +54,9 @@ #include #include +#define __glibcxx_want_erase_if +#include + #if __cplusplus >= 201703L && _GLIBCXX_USE_CXX11_ABI #include namespace std _GLIBCXX_VISIBILITY(default) @@ -75,13 +78,11 @@ _GLIBCXX_END_NAMESPACE_VERSION } // namespace std #endif // C++17 -#if __cplusplus > 201703L +#ifdef __cpp_lib_erase_if // C++ >= 20 && HOSTED namespace std _GLIBCXX_VISIBILITY(default) { _GLIBCXX_BEGIN_NAMESPACE_VERSION -#define __cpp_lib_erase_if 202002L - template _GLIBCXX20_CONSTEXPR @@ -112,6 +113,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } _GLIBCXX_END_NAMESPACE_VERSION } // namespace std -#endif // C++20 +#endif // __cpp_lib_erase_if #endif /* _GLIBCXX_STRING */ diff --git a/libstdc++-v3/include/std/string_view b/libstdc++-v3/include/std/string_view index be9036a20a30..d103abda6688 100644 --- a/libstdc++-v3/include/std/string_view +++ b/libstdc++-v3/include/std/string_view @@ -35,6 +35,12 @@ #pragma GCC system_header +#define __glibcxx_want_string_view +#define __glibcxx_want_constexpr_string_view +#define __glibcxx_want_starts_ends_with +#define __glibcxx_want_string_contains +#include + #if __cplusplus >= 201703L #include @@ -57,14 +63,6 @@ namespace std _GLIBCXX_VISIBILITY(default) { _GLIBCXX_BEGIN_NAMESPACE_VERSION -#if _GLIBCXX_HOSTED -# define __cpp_lib_string_view 201803L -#endif - -#if __cplusplus > 201703L -# define __cpp_lib_constexpr_string_view 201811L -#endif - // Helper for basic_string and basic_string_view members. constexpr size_t __sv_check(size_t __size, size_t __pos, const char* __s) @@ -380,8 +378,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION .compare(basic_string_view(__str, __n2)); } -#if __cplusplus > 201703L -#define __cpp_lib_starts_ends_with 201711L +#ifdef __cpp_lib_starts_ends_with // C++ >= 20 [[nodiscard]] constexpr bool starts_with(basic_string_view __x) const noexcept @@ -416,13 +413,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION constexpr bool ends_with(const _CharT* __x) const noexcept { return this->ends_with(basic_string_view(__x)); } -#endif // C++20 +#endif // __cpp_lib_starts_ends_with #if __cplusplus > 202002L -#if _GLIBCXX_HOSTED +#if _GLIBCXX_HOSTED && !defined(__cpp_lib_string_contains) // This FTM is not freestanding as it also implies matching // support, and is omitted from the freestanding subset. -# define __cpp_lib_string_contains 202011L +# error "libstdc++ bug: string_contains not defined when it should be" #endif // HOSTED [[nodiscard]] constexpr bool diff --git a/libstdc++-v3/include/std/syncstream b/libstdc++-v3/include/std/syncstream index 3788b71ecddc..7262a9696963 100644 --- a/libstdc++-v3/include/std/syncstream +++ b/libstdc++-v3/include/std/syncstream @@ -29,17 +29,16 @@ #ifndef _GLIBCXX_SYNCSTREAM #define _GLIBCXX_SYNCSTREAM 1 -#if __cplusplus > 201703L - -#include -#if _GLIBCXX_USE_CXX11_ABI - -#define __cpp_lib_syncbuf 201803L - #pragma GCC system_header #include // iostreams +#include + +#define __glibcxx_want_syncbuf +#include + +#ifdef __cpp_lib_syncbuf // C++ >= 20 && HOSTED && CXX11ABI #include #include @@ -314,6 +313,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION using wosyncstream = basic_osyncstream; _GLIBCXX_END_NAMESPACE_VERSION } // namespace std -#endif // _GLIBCXX_USE_CXX11_ABI -#endif // C++2a +#endif // __cpp_lib_syncbuf + #endif /* _GLIBCXX_SYNCSTREAM */ diff --git a/libstdc++-v3/include/std/thread b/libstdc++-v3/include/std/thread index ee2dc36158b7..28582c9df5ce 100644 --- a/libstdc++-v3/include/std/thread +++ b/libstdc++-v3/include/std/thread @@ -45,6 +45,9 @@ #include // std::thread, get_id, yield #include // std::this_thread::sleep_for, sleep_until +#define __glibcxx_want_jthread +#include + namespace std _GLIBCXX_VISIBILITY(default) { _GLIBCXX_BEGIN_NAMESPACE_VERSION @@ -103,7 +106,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } /// @} -#ifdef __cpp_lib_jthread +#ifdef __cpp_lib_jthread // C++ >= 20 /// @cond undocumented #ifndef __STRICT_ANSI__ diff --git a/libstdc++-v3/include/std/tuple b/libstdc++-v3/include/std/tuple index 0e47abed573e..797d8c031125 100644 --- a/libstdc++-v3/include/std/tuple +++ b/libstdc++-v3/include/std/tuple @@ -42,9 +42,14 @@ #if __cplusplus > 201703L # include # include // for std::ranges::subrange -# define __cpp_lib_constexpr_tuple 201811L #endif +#define __glibcxx_want_constexpr_tuple +#define __glibcxx_want_tuples_by_type +#define __glibcxx_want_apply +#define __glibcxx_want_make_from_tuple +#include + namespace std _GLIBCXX_VISIBILITY(default) { _GLIBCXX_BEGIN_NAMESPACE_VERSION @@ -564,14 +569,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template _GLIBCXX20_CONSTEXPR - _Tuple_impl(allocator_arg_t __tag, const _Alloc& __a, + _Tuple_impl(allocator_arg_t, const _Alloc& __a, const _Head& __head) : _Base(__use_alloc<_Head, _Alloc, const _Head&>(__a), __head) { } template _GLIBCXX20_CONSTEXPR - _Tuple_impl(allocator_arg_t __tag, const _Alloc& __a, + _Tuple_impl(allocator_arg_t, const _Alloc& __a, _UHead&& __head) : _Base(__use_alloc<_Head, _Alloc, _UHead>(__a), std::forward<_UHead>(__head)) @@ -579,14 +584,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template _GLIBCXX20_CONSTEXPR - _Tuple_impl(allocator_arg_t __tag, const _Alloc& __a, + _Tuple_impl(allocator_arg_t, const _Alloc& __a, const _Tuple_impl& __in) : _Base(__use_alloc<_Head, _Alloc, const _Head&>(__a), _M_head(__in)) { } template _GLIBCXX20_CONSTEXPR - _Tuple_impl(allocator_arg_t __tag, const _Alloc& __a, + _Tuple_impl(allocator_arg_t, const _Alloc& __a, _Tuple_impl&& __in) : _Base(__use_alloc<_Head, _Alloc, _Head>(__a), std::forward<_Head>(_M_head(__in))) @@ -594,7 +599,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template _GLIBCXX20_CONSTEXPR - _Tuple_impl(allocator_arg_t __tag, const _Alloc& __a, + _Tuple_impl(allocator_arg_t, const _Alloc& __a, const _Tuple_impl<_Idx, _UHead>& __in) : _Base(__use_alloc<_Head, _Alloc, const _UHead&>(__a), _Tuple_impl<_Idx, _UHead>::_M_head(__in)) @@ -602,7 +607,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template _GLIBCXX20_CONSTEXPR - _Tuple_impl(allocator_arg_t __tag, const _Alloc& __a, + _Tuple_impl(allocator_arg_t, const _Alloc& __a, _Tuple_impl<_Idx, _UHead>&& __in) : _Base(__use_alloc<_Head, _Alloc, _UHead>(__a), std::forward<_UHead>(_Tuple_impl<_Idx, _UHead>::_M_head(__in))) @@ -611,7 +616,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION #if __cplusplus > 202002L template constexpr - _Tuple_impl(allocator_arg_t __tag, const _Alloc& __a, + _Tuple_impl(allocator_arg_t, const _Alloc& __a, _Tuple_impl<_Idx, _UHead>& __in) : _Base(__use_alloc<_Head, _Alloc, _UHead&>(__a), _Tuple_impl<_Idx, _UHead>::_M_head(__in)) @@ -619,7 +624,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template constexpr - _Tuple_impl(allocator_arg_t __tag, const _Alloc& __a, + _Tuple_impl(allocator_arg_t, const _Alloc& __a, const _Tuple_impl<_Idx, _UHead>&& __in) : _Base(__use_alloc<_Head, _Alloc, const _UHead>(__a), std::forward(_Tuple_impl<_Idx, _UHead>::_M_head(__in))) @@ -1820,10 +1825,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION get(const tuple<_Elements...>&) = delete; /// @endcond -#if __cplusplus >= 201402L - -#define __cpp_lib_tuples_by_type 201304L - +#ifdef __cpp_lib_tuples_by_type // C++ >= 14 /// Return a reference to the unique element of type _Tp of a tuple. template constexpr _Tp& @@ -2254,8 +2256,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION second(std::forward<_Args2>(std::get<_Indexes2>(__tuple2))...) { } -#if __cplusplus >= 201703L - +#if defined(__cpp_lib_apply) || defined(__cpp_lib_make_from_tuple) // C++ >= 17 // Unpack a std::tuple into a type trait and use its value. // For cv std::tuple<_Up> the result is _Trait<_Tp, cv _Up...>::value. // For cv std::tuple<_Up>& the result is _Trait<_Tp, cv _Up&...>::value. @@ -2278,9 +2279,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template class _Trait, typename _Tp, typename... _Up> inline constexpr bool __unpack_std_tuple<_Trait, _Tp, const tuple<_Up...>&> = _Trait<_Tp, const _Up&...>::value; +#endif -# define __cpp_lib_apply 201603L - +#ifdef __cpp_lib_apply // C++ >= 17 template constexpr decltype(auto) __apply_impl(_Fn&& __f, _Tuple&& __t, index_sequence<_Idx...>) @@ -2300,9 +2301,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION std::forward<_Tuple>(__t), _Indices{}); } +#endif -#define __cpp_lib_make_from_tuple 201606L - +#ifdef __cpp_lib_make_from_tuple // C++ >= 17 template constexpr _Tp __make_from_tuple_impl(_Tuple&& __t, index_sequence<_Idx...>) @@ -2324,7 +2325,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION return __make_from_tuple_impl<_Tp>(std::forward<_Tuple>(__t), make_index_sequence<__n>{}); } -#endif // C++17 +#endif #if __cplusplus > 202002L template +#define __glibcxx_want_bool_constant +#define __glibcxx_want_bounded_array_traits +#define __glibcxx_want_has_unique_object_representations +#define __glibcxx_want_integral_constant_callable +#define __glibcxx_want_is_aggregate +#define __glibcxx_want_is_constant_evaluated +#define __glibcxx_want_is_final +#define __glibcxx_want_is_invocable +#define __glibcxx_want_is_layout_compatible +#define __glibcxx_want_is_nothrow_convertible +#define __glibcxx_want_is_null_pointer +#define __glibcxx_want_is_pointer_interconvertible +#define __glibcxx_want_is_scoped_enum +#define __glibcxx_want_is_swappable +#define __glibcxx_want_logical_traits +#define __glibcxx_want_reference_from_temporary +#define __glibcxx_want_remove_cvref +#define __glibcxx_want_result_of_sfinae +#define __glibcxx_want_transformation_trait_aliases +#define __glibcxx_want_type_identity +#define __glibcxx_want_type_trait_variable_templates +#define __glibcxx_want_unwrap_ref +#define __glibcxx_want_void_t +#include + namespace std _GLIBCXX_VISIBILITY(default) { _GLIBCXX_BEGIN_NAMESPACE_VERSION @@ -65,10 +90,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION using value_type = _Tp; using type = integral_constant<_Tp, __v>; constexpr operator value_type() const noexcept { return value; } -#if __cplusplus > 201103L - -#define __cpp_lib_integral_constant_callable 201304L +#ifdef __cpp_lib_integral_constant_callable // C++ >= 14 constexpr value_type operator()() const noexcept { return value; } #endif }; @@ -78,24 +101,23 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION constexpr _Tp integral_constant<_Tp, __v>::value; #endif - /// The type used as a compile-time boolean with true value. - using true_type = integral_constant; - - /// The type used as a compile-time boolean with false value. - using false_type = integral_constant; - /// @cond undocumented /// bool_constant for C++11 template using __bool_constant = integral_constant; /// @endcond -#if __cplusplus >= 201703L -# define __cpp_lib_bool_constant 201505L + /// The type used as a compile-time boolean with true value. + using true_type = __bool_constant; + + /// The type used as a compile-time boolean with false value. + using false_type = __bool_constant; + +#ifdef __cpp_lib_bool_constant // C++ >= 17 /// Alias template for compile-time boolean constant types. /// @since C++17 template - using bool_constant = integral_constant; + using bool_constant = __bool_constant<__v>; #endif // Metaprogramming helper types. @@ -183,7 +205,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { }; /// @endcond -#if __cplusplus >= 201703L +#ifdef __cpp_lib_logical_traits // C++ >= 17 /// @cond undocumented template @@ -211,8 +233,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } // namespace __detail /// @endcond -#define __cpp_lib_logical_traits 201510L - template struct conjunction : __detail::__conjunction_impl::type @@ -251,7 +271,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION inline constexpr bool negation_v = negation<_Pp>::value; /// @} -#endif // C++17 +#endif // __cpp_lib_logical_traits // Forward declarations template @@ -606,8 +626,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION struct is_function<_Tp&&> : public false_type { }; -#define __cpp_lib_is_null_pointer 201309L - +#ifdef __cpp_lib_is_null_pointer // C++ >= 11 /// is_null_pointer (LWG 2247). template struct is_null_pointer @@ -635,6 +654,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION struct __is_nullptr_t : public is_null_pointer<_Tp> { } _GLIBCXX_DEPRECATED_SUGGEST("std::is_null_pointer"); +#endif // __cpp_lib_is_null_pointer // Composite type categories. @@ -849,8 +869,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION : public __bool_constant<__is_polymorphic(_Tp)> { }; -#if __cplusplus >= 201402L -#define __cpp_lib_is_final 201402L +#ifdef __cpp_lib_is_final // C++ >= 14 /// is_final /// @since C++14 template @@ -1459,8 +1478,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION using __is_array_convertible = is_convertible<_FromElementType(*)[], _ToElementType(*)[]>; -#if __cplusplus >= 202002L -#define __cpp_lib_is_nothrow_convertible 201806L +#ifdef __cpp_lib_is_nothrow_convertible // C++ >= 20 #if __has_builtin(__is_nothrow_convertible) /// is_nothrow_convertible_v @@ -1514,7 +1532,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION inline constexpr bool is_nothrow_convertible_v = is_nothrow_convertible<_From, _To>::value; #endif -#endif // C++2a +#endif // __cpp_lib_is_nothrow_convertible // Const-volatile modifications. @@ -1574,10 +1592,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION struct add_cv { using type = _Tp const volatile; }; -#if __cplusplus > 201103L - -#define __cpp_lib_transformation_trait_aliases 201304L - +#ifdef __cpp_lib_transformation_trait_aliases // C++ >= 14 /// Alias template for remove_const template using remove_const_t = typename remove_const<_Tp>::type; @@ -2396,8 +2411,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION // Sfinae-friendly result_of implementation: -#define __cpp_lib_result_of_sfinae 201210L - /// @cond undocumented struct __invoke_memfun_ref { }; struct __invoke_memfun_deref { }; @@ -2626,8 +2639,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION using result_of_t = typename result_of<_Tp>::type; #endif // C++14 -#if __cplusplus >= 201703L || !defined(__STRICT_ANSI__) // c++17 or gnu++11 -#define __cpp_lib_void_t 201411L +#ifdef __cpp_lib_void_t // C++ >= 17 || GNU++ >= 11 /// A metafunction that always yields void, used for detecting valid types. template using void_t = void; #endif @@ -2784,8 +2796,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { }; /// @endcond -#if __cplusplus > 201402L || !defined(__STRICT_ANSI__) // c++1z or gnu++11 -#define __cpp_lib_is_swappable 201603L +#ifdef __cpp_lib_is_swappable // C++ >= 17 || GNU++ >= 11 /// Metafunctions used for detecting swappable types: p0185r1 /// is_swappable @@ -2914,7 +2925,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION is_nothrow_swappable_with<_Tp, _Up>::value; #endif // __cplusplus >= 201402L -#endif// c++1z or gnu++11 +#endif // __cpp_lib_is_swappable /// @cond undocumented @@ -3053,9 +3064,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION #pragma GCC diagnostic pop /// @endcond -#if __cplusplus >= 201703L -# define __cpp_lib_is_invocable 201703L - +#ifdef __cpp_lib_is_invocable // C++ >= 17 /// std::invoke_result template struct invoke_result @@ -3134,10 +3143,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION static_assert(std::__is_complete_or_unbounded(__type_identity<_Ret>{}), "_Ret must be a complete class or an unbounded array"); }; -#endif // C++17 +#endif // __cpp_lib_is_invocable -#if __cplusplus >= 201703L -# define __cpp_lib_type_trait_variable_templates 201510L +#if __cpp_lib_type_trait_variable_templates // C++ >= 17 /** * @defgroup variable_templates Variable templates for type traits * @ingroup metaprogramming @@ -3373,9 +3381,9 @@ template inline constexpr bool is_nothrow_invocable_r_v = is_nothrow_invocable_r<_Ret, _Fn, _Args...>::value; /// @} +#endif // __cpp_lib_type_trait_variable_templates -#ifdef _GLIBCXX_HAVE_BUILTIN_HAS_UNIQ_OBJ_REP -# define __cpp_lib_has_unique_object_representations 201606L +#ifdef __cpp_lib_has_unique_object_representations // C++ >= 17 && HAS_UNIQ_OBJ_REP /// has_unique_object_representations /// @since C++17 template @@ -3388,14 +3396,15 @@ template "template argument must be a complete class or an unbounded array"); }; +# if __cpp_lib_type_trait_variable_templates // C++ >= 17 /// @ingroup variable_templates template inline constexpr bool has_unique_object_representations_v = has_unique_object_representations<_Tp>::value; +# endif #endif -#ifdef _GLIBCXX_HAVE_BUILTIN_IS_AGGREGATE -# define __cpp_lib_is_aggregate 201703L +#ifdef __cpp_lib_is_aggregate // C++ >= 17 && builtin_is_aggregate /// is_aggregate - true if the type is an aggregate. /// @since C++17 template @@ -3403,28 +3412,26 @@ template : bool_constant<__is_aggregate(remove_cv_t<_Tp>)> { }; +# if __cpp_lib_type_trait_variable_templates // C++ >= 17 /** is_aggregate_v - true if the type is an aggregate. * @ingroup variable_templates * @since C++17 */ template inline constexpr bool is_aggregate_v = __is_aggregate(remove_cv_t<_Tp>); +# endif #endif -#endif // C++17 - -#if __cplusplus >= 202002L /** * Remove references and cv-qualifiers. * @since C++20 * @{ */ -#define __cpp_lib_remove_cvref 201711L - -#if __has_builtin(__remove_cvref) +#ifdef __cpp_lib_remove_cvref // C++ >= 20 +# if __has_builtin(__remove_cvref) template struct remove_cvref { using type = __remove_cvref(_Tp); }; -#else +# else template struct remove_cvref { using type = typename remove_cv<_Tp>::type; }; @@ -3436,26 +3443,27 @@ template template struct remove_cvref<_Tp&&> { using type = typename remove_cv<_Tp>::type; }; -#endif +# endif template using remove_cvref_t = typename remove_cvref<_Tp>::type; /// @} +#endif // __cpp_lib_remove_cvref +#ifdef __cpp_lib_type_identity // C++ >= 20 /** * Identity metafunction. * @since C++20 * @{ */ -#define __cpp_lib_type_identity 201806L template struct type_identity { using type = _Tp; }; template using type_identity_t = typename type_identity<_Tp>::type; /// @} +#endif -#define __cpp_lib_unwrap_ref 201811L - +#ifdef __cpp_lib_unwrap_ref // C++ >= 20 /** Unwrap a reference_wrapper * @since C++20 * @{ @@ -3480,9 +3488,9 @@ template template using unwrap_ref_decay_t = typename unwrap_ref_decay<_Tp>::type; /// @} +#endif // __cpp_lib_unwrap_ref -#define __cpp_lib_bounded_array_traits 201902L - +#ifdef __cpp_lib_bounded_array_traits // C++ >= 20 /// True for a type that is an array of known bound. /// @ingroup variable_templates /// @since C++20 @@ -3514,8 +3522,9 @@ template struct is_unbounded_array : public bool_constant> { }; +#endif // __cpp_lib_bounded_array_traits -#if __has_builtin(__is_layout_compatible) +#if __has_builtin(__is_layout_compatible) && __cplusplus >= 202002L /// @since C++20 template @@ -3530,7 +3539,9 @@ template = __is_layout_compatible(_Tp, _Up); #if __has_builtin(__builtin_is_corresponding_member) -#define __cpp_lib_is_layout_compatible 201907L +# ifndef __cpp_lib_is_layout_compatible +# error "libstdc++ bug: is_corresponding_member and is_layout_compatible are provided but their FTM is not set" +# endif /// @since C++20 template @@ -3540,7 +3551,8 @@ template #endif #endif -#if __has_builtin(__is_pointer_interconvertible_base_of) +#if __has_builtin(__is_pointer_interconvertible_base_of) \ + && __cplusplus >= 202002L /// True if `_Derived` is standard-layout and has a base class of type `_Base` /// @since C++20 template @@ -3555,7 +3567,9 @@ template = __is_pointer_interconvertible_base_of(_Base, _Derived); #if __has_builtin(__builtin_is_pointer_interconvertible_with_class) -#define __cpp_lib_is_pointer_interconvertible 201907L +# ifndef __cpp_lib_is_pointer_interconvertible +# error "libstdc++ bug: is_pointer_interconvertible available but FTM is not set" +# endif /// True if `__mp` points to the first member of a standard-layout type /// @returns true if `s.*__mp` is pointer-interconvertible with `s` @@ -3567,9 +3581,7 @@ template #endif #endif -#if __cplusplus > 202002L -#define __cpp_lib_is_scoped_enum 202011L - +#ifdef __cpp_lib_is_scoped_enum // C++ >= 23 /// True if the type is a scoped enumeration type. /// @since C++23 @@ -3589,12 +3601,9 @@ template /// @since C++23 template inline constexpr bool is_scoped_enum_v = is_scoped_enum<_Tp>::value; +#endif -#if __has_builtin(__reference_constructs_from_temporary) \ - && __has_builtin(__reference_converts_from_temporary) - -#define __cpp_lib_reference_from_temporary 202202L - +#ifdef __cpp_lib_reference_from_temporary // C++ >= 23 && ref_{converts,constructs}_from_temp /// True if _Tp is a reference type, a _Up value can be bound to _Tp in /// direct-initialization, and a temporary object would be bound to /// the reference, false otherwise. @@ -3632,12 +3641,9 @@ template template inline constexpr bool reference_converts_from_temporary_v = reference_converts_from_temporary<_Tp, _Up>::value; -#endif // __has_builtin for reference_from_temporary -#endif // C++23 - -#if _GLIBCXX_HAVE_IS_CONSTANT_EVALUATED -#define __cpp_lib_is_constant_evaluated 201811L +#endif // __cpp_lib_reference_from_temporary +#ifdef __cpp_lib_is_constant_evaluated // C++ >= 20 && HAVE_IS_CONST_EVAL /// Returns true only when called during constant evaluation. /// @since C++20 constexpr inline bool @@ -3651,6 +3657,7 @@ template } #endif +#if __cplusplus >= 202002L /// @cond undocumented template using __copy_cv = typename __match_cv_qualifiers<_From, _To>::__type; diff --git a/libstdc++-v3/include/std/utility b/libstdc++-v3/include/std/utility index 006b19c00fcd..f30e802a88db 100644 --- a/libstdc++-v3/include/std/utility +++ b/libstdc++-v3/include/std/utility @@ -68,6 +68,14 @@ #include #include +#define __glibcxx_want_exchange_function +#define __glibcxx_want_constexpr_algorithms +#define __glibcxx_want_as_const +#define __glibcxx_want_integer_comparison_functions +#define __glibcxx_want_to_underlying +#define __glibcxx_want_unreachable +#include + #if __cplusplus >= 201103L #include @@ -83,13 +91,7 @@ namespace std _GLIBCXX_VISIBILITY(default) { _GLIBCXX_BEGIN_NAMESPACE_VERSION -#if __cplusplus >= 201402L -#define __cpp_lib_exchange_function 201304L - -#if __cplusplus > 201703L -# define __cpp_lib_constexpr_algorithms 201806L -#endif - +#ifdef __cpp_lib_exchange_function // C++ >= 14 /// Assign @p __new_val to @p __obj and return its previous value. template _GLIBCXX20_CONSTEXPR @@ -98,10 +100,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION noexcept(__and_, is_nothrow_assignable<_Tp&, _Up>>::value) { return std::__exchange(__obj, std::forward<_Up>(__new_val)); } +#endif -#if __cplusplus >= 201703L - -#define __cpp_lib_as_const 201510L +#ifdef __cpp_lib_as_const // C++ >= 17 template [[nodiscard]] constexpr add_const_t<_Tp>& @@ -110,10 +111,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template void as_const(const _Tp&&) = delete; +#endif -#if __cplusplus > 201703L -#define __cpp_lib_integer_comparison_functions 202002L - +#ifdef __cpp_lib_integer_comparison_functions // C++ >= 20 template constexpr bool cmp_equal(_Tp __t, _Up __u) noexcept @@ -181,17 +181,18 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION else return __t <= make_unsigned_t<_Up>(__int_traits<_Up>::__max); } +#endif // __cpp_lib_integer_comparison_functions -#if __cplusplus > 202002L -#define __cpp_lib_to_underlying 202102L +#ifdef __cpp_lib_to_underlying // C++ >= 23 /// Convert an object of enumeration type to its underlying type. template [[nodiscard]] constexpr underlying_type_t<_Tp> to_underlying(_Tp __value) noexcept { return static_cast>(__value); } +#endif -#define __cpp_lib_unreachable 202202L +#ifdef __cpp_lib_unreachable // C++ >= 23 /// Informs the compiler that program control flow never reaches this point. /** * Evaluating a call to this function results in undefined behaviour. @@ -216,10 +217,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION __builtin_unreachable(); #endif } -#endif // C++23 -#endif // C++20 -#endif // C++17 -#endif // C++14 +#endif _GLIBCXX_END_NAMESPACE_VERSION } // namespace diff --git a/libstdc++-v3/include/std/valarray b/libstdc++-v3/include/std/valarray index 6bd23e0914b0..f172db6c623e 100644 --- a/libstdc++-v3/include/std/valarray +++ b/libstdc++-v3/include/std/valarray @@ -62,22 +62,22 @@ namespace __detail template class _Meta1, template class _Meta2, class _Dom1, class _Dom2> - class _BinClos; + struct _BinClos; template class _Meta, class _Dom> - class _SClos; + struct _SClos; template class _Meta, class _Dom> - class _GClos; + struct _GClos; template class _Meta, class _Dom> - class _IClos; + struct _IClos; template class _Meta, class _Dom> - class _ValFunClos; + struct _ValFunClos; template class _Meta, class _Dom> - class _RefFunClos; + struct _RefFunClos; } // namespace __detail using __detail::_UnClos; diff --git a/libstdc++-v3/include/std/variant b/libstdc++-v3/include/std/variant index 5155124522f2..7cb7c3b1d4d9 100644 --- a/libstdc++-v3/include/std/variant +++ b/libstdc++-v3/include/std/variant @@ -31,8 +31,10 @@ #pragma GCC system_header -#if __cplusplus >= 201703L +#define __glibcxx_want_variant +#include +#ifdef __cpp_lib_variant // C++ >= 17 #include #include #include @@ -47,14 +49,12 @@ # include #endif -#if __cpp_concepts >= 202002L && __cpp_constexpr >= 201811L -// P2231R1 constexpr needs constexpr unions and constrained destructors. -# define __cpp_lib_variant 202106L -#else +// C++ < 20 || __cpp_concepts < 202002L || __cpp_constexpr < 201811L +#if __cpp_lib_variant < 202106L # include // Use __aligned_membuf instead of union. -# define __cpp_lib_variant 202102L #endif + namespace std _GLIBCXX_VISIBILITY(default) { _GLIBCXX_BEGIN_NAMESPACE_VERSION @@ -1941,6 +1941,5 @@ namespace __variant _GLIBCXX_END_NAMESPACE_VERSION } // namespace std -#endif // C++17 - +#endif // __cpp_lib_variant #endif // _GLIBCXX_VARIANT diff --git a/libstdc++-v3/include/std/vector b/libstdc++-v3/include/std/vector index 712087f1bdd2..ecd9f7108f65 100644 --- a/libstdc++-v3/include/std/vector +++ b/libstdc++-v3/include/std/vector @@ -76,6 +76,9 @@ # include #endif +#define __glibcxx_want_erase_if +#include + #if __cplusplus >= 201703L #include namespace std _GLIBCXX_VISIBILITY(default) @@ -96,13 +99,11 @@ _GLIBCXX_END_NAMESPACE_VERSION } // namespace std #endif // C++17 -#if __cplusplus > 201703L +#ifdef __cpp_lib_erase_if // C++ >= 20 && HOSTED namespace std _GLIBCXX_VISIBILITY(default) { _GLIBCXX_BEGIN_NAMESPACE_VERSION -#define __cpp_lib_erase_if 202002L - template _GLIBCXX20_CONSTEXPR inline typename vector<_Tp, _Alloc>::size_type @@ -146,6 +147,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } _GLIBCXX_END_NAMESPACE_VERSION } // namespace std -#endif // C++20 +#endif // __cpp_lib_erase_if #endif /* _GLIBCXX_VECTOR */ diff --git a/libstdc++-v3/include/std/version b/libstdc++-v3/include/std/version index 02ead8f1443e..4963e4058f6e 100644 --- a/libstdc++-v3/include/std/version +++ b/libstdc++-v3/include/std/version @@ -30,353 +30,9 @@ #ifndef _GLIBCXX_VERSION_INCLUDED #define _GLIBCXX_VERSION_INCLUDED -// To facilitate testsuite/17_intro/versionconflict.cc -#ifndef _GLIBCXX_TESTING_SYSHDR -# pragma GCC system_header -#endif +#pragma GCC system_header -#include - -// c++03 -#if _GLIBCXX_HOSTED -# define __cpp_lib_incomplete_container_elements 201505L -#endif - -#if !defined(__STRICT_ANSI__) -// gnu++03 -# define __cpp_lib_uncaught_exceptions 201411L -#endif - -#if __cplusplus >= 201103L -// c++11 -#define __cpp_lib_allocator_traits_is_always_equal 201411L -#define __cpp_lib_is_null_pointer 201309L -#define __cpp_lib_result_of_sfinae 201210L - -#if _GLIBCXX_HOSTED -#if __cplusplus <= 201703L // N.B. updated value in C++20 -# define __cpp_lib_shared_ptr_arrays 201611L -#endif -#endif - -#if !defined(__STRICT_ANSI__) -// gnu++11 -# define __cpp_lib_is_swappable 201603L -# define __cpp_lib_void_t 201411L -# if _GLIBCXX_HOSTED -# define __cpp_lib_enable_shared_from_this 201603L -# endif -#endif - -// For C++11 and later we support ISO/IEC 29124 Mathematical Special Functions -#define __STDCPP_MATH_SPEC_FUNCS__ 201003L - -#if __cplusplus >= 201402L -// c++14 -#if __cpp_impl_coroutine -# define __cpp_lib_coroutine 201902L -#endif -#define __cpp_lib_exchange_function 201304L -#define __cpp_lib_integer_sequence 201304L -#define __cpp_lib_integral_constant_callable 201304L -#define __cpp_lib_is_final 201402L -#define __cpp_lib_make_reverse_iterator 201402L -#ifndef _GLIBCXX_DEBUG // PR libstdc++/70303 -# define __cpp_lib_null_iterators 201304L -#endif -#define __cpp_lib_robust_nonmodifying_seq_ops 201304L -#define __cpp_lib_transformation_trait_aliases 201304L -#define __cpp_lib_transparent_operators 201510L -#define __cpp_lib_tuple_element_t 201402L -#define __cpp_lib_tuples_by_type 201304L - -#if _GLIBCXX_FLOAT_IS_IEEE_BINARY32 && _GLIBCXX_DOUBLE_IS_IEEE_BINARY64 \ - && __SIZE_WIDTH__ >= 32 -# define __cpp_lib_to_chars 201611L -#endif - -#if _GLIBCXX_HOSTED -# define __cpp_lib_chrono_udls 201304L -# define __cpp_lib_complex_udls 201309L -# define __cpp_lib_generic_associative_lookup 201304L -# define __cpp_lib_make_unique 201304L -# define __cpp_lib_quoted_string_io 201304L -# ifdef _GLIBCXX_HAS_GTHREADS -# define __cpp_lib_shared_timed_mutex 201402L -# endif -# define __cpp_lib_string_udls 201304L -#endif - -#if __cplusplus >= 201703L -// c++17 -#define __cpp_lib_addressof_constexpr 201603L -#define __cpp_lib_any 201606L -#define __cpp_lib_apply 201603L -#define __cpp_lib_as_const 201510L -#define __cpp_lib_atomic_is_always_lock_free 201603L -#define __cpp_lib_bool_constant 201505L -#define __cpp_lib_byte 201603L -#define __cpp_lib_clamp 201603L -#define __cpp_lib_gcd 201606L -#define __cpp_lib_gcd_lcm 201606L -#ifdef _GLIBCXX_HAVE_BUILTIN_HAS_UNIQ_OBJ_REP -# define __cpp_lib_has_unique_object_representations 201606L -#endif -#ifdef __GCC_DESTRUCTIVE_SIZE -# define __cpp_lib_hardware_interference_size 201703L -#endif -#define __cpp_lib_invoke 201411L -#ifdef _GLIBCXX_HAVE_BUILTIN_IS_AGGREGATE -# define __cpp_lib_is_aggregate 201703L -#endif -#define __cpp_lib_is_invocable 201703L -#define __cpp_lib_is_swappable 201603L -#ifdef _GLIBCXX_HAVE_BUILTIN_LAUNDER -# define __cpp_lib_launder 201606L -#endif -#define __cpp_lib_lcm 201606L -#define __cpp_lib_logical_traits 201510L -#define __cpp_lib_make_from_tuple 201606L -#define __cpp_lib_nonmember_container_access 201411L -#define __cpp_lib_not_fn 201603L -#if __cplusplus == 201703L // N.B. updated value in C++20 -# define __cpp_lib_optional 201606L -#endif -#define __cpp_lib_raw_memory_algorithms 201606L -#define __cpp_lib_sample 201603L -#define __cpp_lib_type_trait_variable_templates 201510L -#define __cpp_lib_uncaught_exceptions 201411L -#if !(__cpp_concepts >= 202002L && __cpp_constexpr >= 201811L) -// N.B. updated value in C++20 -# define __cpp_lib_variant 202102L -#endif -#define __cpp_lib_void_t 201411L -#if __cplusplus == 201703L // N.B. updated value in C++20 -# define __cpp_lib_array_constexpr 201803L -#endif -#if __cplusplus == 201703L // N.B. updated value in C++20 -# if _GLIBCXX_HAVE_IS_CONSTANT_EVALUATED -# define __cpp_lib_constexpr_char_traits 201611L -# define __cpp_lib_constexpr_string 201611L -# endif -#endif - -#if _GLIBCXX_HOSTED -#define __cpp_lib_boyer_moore_searcher 201603L -#define __cpp_lib_chrono 201611L -#define __cpp_lib_enable_shared_from_this 201603L -#define __cpp_lib_execution 201902L // FIXME: should be 201603L -#define __cpp_lib_filesystem 201703L -#define __cpp_lib_hypot 201603L -#define __cpp_lib_map_try_emplace 201411L -#define __cpp_lib_math_special_functions 201603L -#ifdef _GLIBCXX_HAS_GTHREADS -# define __cpp_lib_memory_resource 201603L -#else -# define __cpp_lib_memory_resource 1 -#endif -#define __cpp_lib_node_extract 201606L -#define __cpp_lib_parallel_algorithm 201603L -#ifdef _GLIBCXX_HAS_GTHREADS -# define __cpp_lib_scoped_lock 201703L -# define __cpp_lib_shared_mutex 201505L -#endif -#define __cpp_lib_shared_ptr_weak_type 201606L -#define __cpp_lib_string_view 201803L -#define __cpp_lib_unordered_map_try_emplace 201411L -#endif - -#if __cplusplus >= 202002L -// c++20 -#define __cpp_lib_assume_aligned 201811L -#define __cpp_lib_atomic_flag_test 201907L -#define __cpp_lib_atomic_float 201711L -#define __cpp_lib_atomic_lock_free_type_aliases 201907L -#define __cpp_lib_atomic_ref 201806L -#define __cpp_lib_atomic_value_initialization 201911L -#define __cpp_lib_bind_front 201907L -#define __cpp_lib_starts_ends_with 201711L -#if __has_builtin(__builtin_bit_cast) -# define __cpp_lib_bit_cast 201806L -#endif -#define __cpp_lib_bitops 201907L -#define __cpp_lib_bounded_array_traits 201902L -// __cpp_lib_char8_t is defined in -#if __cpp_concepts >= 201907L -# define __cpp_lib_concepts 202002L -#endif -#if __cpp_impl_destroying_delete -# define __cpp_lib_destroying_delete 201806L -#endif -#define __cpp_lib_constexpr_string_view 201811L -#define __cpp_lib_endian 201907L -#define __cpp_lib_int_pow2 202002L -#define __cpp_lib_integer_comparison_functions 202002L -#ifdef _GLIBCXX_HAVE_IS_CONSTANT_EVALUATED -# define __cpp_lib_is_constant_evaluated 201811L -#endif -#if __has_builtin(__is_layout_compatible) \ - && __has_builtin(__builtin_is_corresponding_member) -# define __cpp_lib_is_layout_compatible 201907L -#endif -#define __cpp_lib_is_nothrow_convertible 201806L -#if __has_builtin(__is_pointer_interconvertible_base_of) \ - && __has_builtin(__builtin_is_pointer_interconvertible_with_class) -# define __cpp_lib_is_pointer_interconvertible 201907L -#endif -#define __cpp_lib_math_constants 201907L -#if __cpp_lib_concepts -# define __cpp_lib_make_obj_using_allocator 201811L -#endif -#if __cplusplus <= 202002L // N.B. updated value in C++23 -# define __cpp_lib_optional 202106L -#endif -#define __cpp_lib_remove_cvref 201711L -#if __has_builtin(__builtin_source_location) -# define __cpp_lib_source_location 201907L -#endif -#if __cpp_lib_concepts -# define __cpp_lib_span 202002L -#endif -#define __cpp_lib_ssize 201902L -#if __cpp_impl_three_way_comparison >= 201907L && __cpp_lib_concepts -# define __cpp_lib_three_way_comparison 201907L -#endif -#define __cpp_lib_to_address 201711L -#define __cpp_lib_to_array 201907L -#define __cpp_lib_type_identity 201806L -#define __cpp_lib_unwrap_ref 201811L -#if __cpp_concepts >= 202002L && __cpp_constexpr >= 201811L -# define __cpp_lib_variant 202106L -#endif -#define __cpp_lib_constexpr_algorithms 201806L -#define __cpp_lib_constexpr_functional 201907L -#if __cplusplus <= 202002L // N.B. updated value in C++23 -# define __cpp_lib_constexpr_memory 201811L -#endif // C++20 -#define __cpp_lib_constexpr_numeric 201911L -#define __cpp_lib_constexpr_tuple 201811L -#define __cpp_lib_array_constexpr 201811L -#ifdef __cpp_lib_is_constant_evaluated -# define __cpp_lib_constexpr_char_traits 201811L -#endif -#define __cpp_lib_constexpr_iterator 201811L -#define __cpp_lib_constexpr_utility 201811L -#define __cpp_lib_interpolate 201902L -#if __cpp_lib_concepts -# define __cpp_lib_move_iterator_concept 202207L -#if __cplusplus <= 202002L // N.B. updated value in C++23 -# define __cpp_lib_ranges 202110L -#endif -#endif -#define __cpp_lib_shift 201806L - -#if _GLIBCXX_HOSTED -#define __cpp_lib_atomic_shared_ptr 201711L -#if defined _GLIBCXX_HAS_GTHREADS || defined _GLIBCXX_HAVE_LINUX_FUTEX -# define __cpp_lib_atomic_wait 201907L -# if __cpp_aligned_new -# define __cpp_lib_barrier 201907L -# endif -#endif -// #undef __cpp_lib_chrono -// #define __cpp_lib_chrono 201907L -// FIXME: #define __cpp_lib_execution 201902L -#define __cpp_lib_constexpr_complex 201711L -#define __cpp_lib_constexpr_dynamic_alloc 201907L -#define __cpp_lib_constexpr_tuple 201811L -#ifdef __cpp_lib_is_constant_evaluated -# if _GLIBCXX_USE_CXX11_ABI -# define __cpp_lib_constexpr_string 201907L -# else -# define __cpp_lib_constexpr_string 201811L -# endif -#endif -#define __cpp_lib_constexpr_vector 201907L -#define __cpp_lib_erase_if 202002L -#define __cpp_lib_format 202106L -#define __cpp_lib_generic_unordered_lookup 201811L -#ifdef _GLIBCXX_HAS_GTHREADS -# define __cpp_lib_jthread 201911L -#endif -#if __cpp_lib_atomic_wait -# define __cpp_lib_latch 201907L -#endif -#define __cpp_lib_list_remove_return_type 201806L -#define __cpp_lib_polymorphic_allocator 201902L -#if __cpp_lib_atomic_wait || _GLIBCXX_HAVE_POSIX_SEMAPHORE -# define __cpp_lib_semaphore 201907L -#endif -#define __cpp_lib_shared_ptr_arrays 201707L -#define __cpp_lib_smart_ptr_for_overwrite 202002L -# if _GLIBCXX_USE_CXX11_ABI -// Only supported with cxx11-abi -# define __cpp_lib_syncbuf 201803L -# endif -#endif - -#if __cplusplus > 202002L -// c++23 -#define __cpp_lib_byteswap 202110L -#define __cpp_lib_constexpr_charconv 202207L -#define __cpp_lib_constexpr_typeinfo 202106L -#if __cpp_concepts >= 202002L -# define __cpp_lib_expected 202211L -#endif -#define __cpp_lib_invoke_r 202106L -#define __cpp_lib_is_scoped_enum 202011L -#if __cpp_lib_concepts -# undef __cpp_lib_optional -# define __cpp_lib_optional 202110L -#endif -#define __cpp_lib_reference_from_temporary 202202L -#define __cpp_lib_to_underlying 202102L -#define __cpp_lib_unreachable 202202L -#define __cpp_lib_ranges 202202L -#define __cpp_lib_ranges_zip 202110L -#define __cpp_lib_ranges_chunk 202202L -#define __cpp_lib_ranges_slide 202202L -#define __cpp_lib_ranges_chunk_by 202202L -#define __cpp_lib_ranges_join_with 202202L -#define __cpp_lib_ranges_repeat 202207L -#define __cpp_lib_ranges_stride 202207L -#define __cpp_lib_ranges_cartesian_product 202207L -#define __cpp_lib_ranges_as_rvalue 202207L -#define __cpp_lib_ranges_as_const 202207L -#define __cpp_lib_ranges_enumerate 202302L -#define __cpp_lib_ranges_contains 202207L -#define __cpp_lib_ranges_iota 202202L -#define __cpp_lib_ranges_find_last 202207L -#define __cpp_lib_ranges_fold 202207L -#if __cpp_constexpr_dynamic_alloc -# if _GLIBCXX_HOSTED -# define __cpp_lib_constexpr_bitset 202202L -# endif -# undef __cpp_lib_constexpr_memory -# define __cpp_lib_constexpr_memory 202202L -#endif -#define __cpp_lib_stdatomic_h 202011L - -#if _GLIBCXX_HOSTED -#define __cpp_lib_adaptor_iterator_pair_constructor 202106L -#define __cpp_lib_ios_noreplace 202207L -#define __cpp_lib_move_only_function 202110L -#if __cpp_lib_span -# define __cpp_lib_spanstream 202106L -#endif -#if _GLIBCXX_HAVE_STACKTRACE -# define __cpp_lib_stacktrace 202011L -#endif -#define __cpp_lib_stdatomic_h 202011L -#define __cpp_lib_string_contains 202011L -#if _GLIBCXX_USE_CXX11_ABI // Only supported with cxx11-abi -# define __cpp_lib_string_resize_and_overwrite 202110L -#endif -#endif -#endif // C++23 -#endif // C++20 -#endif // C++17 -#endif // C++14 -#endif // C++11 +#define __glibcxx_want_all +#include #endif // _GLIBCXX_VERSION_INCLUDED diff --git a/libstdc++-v3/libsupc++/compare b/libstdc++-v3/libsupc++/compare index 8fa960eff470..9215f51e94bf 100644 --- a/libstdc++-v3/libsupc++/compare +++ b/libstdc++-v3/libsupc++/compare @@ -32,14 +32,13 @@ #pragma GCC system_header +#define __glibcxx_want_three_way_comparison +#include + #if __cplusplus > 201703L && __cpp_impl_three_way_comparison >= 201907L #include -#if __cpp_lib_concepts -# define __cpp_lib_three_way_comparison 201907L -#endif - namespace std _GLIBCXX_VISIBILITY(default) { // [cmp.categories], comparison category types @@ -54,7 +53,7 @@ namespace std _GLIBCXX_VISIBILITY(default) struct __unspec { - constexpr __unspec(__unspec*) noexcept { } + consteval __unspec(__unspec*) noexcept { } }; } @@ -448,7 +447,8 @@ namespace std _GLIBCXX_VISIBILITY(default) using common_comparison_category_t = typename common_comparison_category<_Ts...>::type; -#if __cpp_lib_concepts +#if __cpp_lib_three_way_comparison >= 201907L + // C++ >= 20 && impl_3way_comparison >= 201907 && lib_concepts namespace __detail { template @@ -1239,7 +1239,7 @@ namespace std _GLIBCXX_VISIBILITY(default) = decltype(__detail::__synth3way(std::declval<_Tp&>(), std::declval<_Up&>())); } // namespace __detail -#endif // concepts +#endif // __cpp_lib_three_way_comparison >= 201907L } // namespace std #endif // C++20 diff --git a/libstdc++-v3/libsupc++/exception b/libstdc++-v3/libsupc++/exception index 00a6347ebe52..9f5adae13f6c 100644 --- a/libstdc++-v3/libsupc++/exception +++ b/libstdc++-v3/libsupc++/exception @@ -35,6 +35,9 @@ #include #include +#define __glibcxx_want_uncaught_exceptions +#include + extern "C++" { namespace std _GLIBCXX_VISIBILITY(default) @@ -121,8 +124,7 @@ namespace std _GLIBCXX_VISIBILITY(default) _GLIBCXX17_DEPRECATED_SUGGEST("std::uncaught_exceptions()") bool uncaught_exception() _GLIBCXX_USE_NOEXCEPT __attribute__ ((__pure__)); -#if __cplusplus >= 201703L || !defined(__STRICT_ANSI__) // c++17 or gnu++98 -#define __cpp_lib_uncaught_exceptions 201411L +#ifdef __cpp_lib_uncaught_exceptions // C++ >= 17 || GNU++ >= 03 /** The number of uncaught exceptions. * @since C++17, or any non-strict mode, e.g. `-std=gnu++98` * @see uncaught_exception() diff --git a/libstdc++-v3/libsupc++/new b/libstdc++-v3/libsupc++/new index 082053fc4d97..e937e5bbe0e7 100644 --- a/libstdc++-v3/libsupc++/new +++ b/libstdc++-v3/libsupc++/new @@ -40,6 +40,11 @@ #include #include +#define __glibcxx_want_launder +#define __glibcxx_want_hardware_interference_size +#define __glibcxx_want_destroying_delete +#include + #pragma GCC visibility push(default) extern "C++" { @@ -185,8 +190,7 @@ inline void operator delete[](void*, void*) _GLIBCXX_USE_NOEXCEPT { } #if __cplusplus >= 201703L namespace std { -#ifdef _GLIBCXX_HAVE_BUILTIN_LAUNDER -#define __cpp_lib_launder 201606L +#ifdef __cpp_lib_launder // C++ >= 17 && HAVE_BUILTIN_LAUNDER /// Pointer optimization barrier [ptr.launder] template [[nodiscard]] constexpr _Tp* @@ -205,16 +209,16 @@ namespace std void launder(const void*) = delete; void launder(volatile void*) = delete; void launder(const volatile void*) = delete; -#endif // _GLIBCXX_HAVE_BUILTIN_LAUNDER +#endif // __cpp_lib_launder -#ifdef __GCC_DESTRUCTIVE_SIZE -# define __cpp_lib_hardware_interference_size 201703L +#ifdef __cpp_lib_hardware_interference_size // C++ >= 17 && defined(gcc_dest_sz) inline constexpr size_t hardware_destructive_interference_size = __GCC_DESTRUCTIVE_SIZE; inline constexpr size_t hardware_constructive_interference_size = __GCC_CONSTRUCTIVE_SIZE; -#endif // __GCC_DESTRUCTIVE_SIZE +#endif // __cpp_lib_hardware_interference_size } #endif // C++17 +// Emitted despite the FTM potentially being undefined. #if __cplusplus > 201703L namespace std { @@ -227,10 +231,6 @@ namespace std /// Tag variable of type destroying_delete_t. inline constexpr destroying_delete_t destroying_delete{}; } -// Only define the feature test macro if the compiler supports the feature: -#if __cpp_impl_destroying_delete -# define __cpp_lib_destroying_delete 201806L -#endif #endif // C++20 #pragma GCC visibility pop diff --git a/libstdc++-v3/libsupc++/typeinfo b/libstdc++-v3/libsupc++/typeinfo index 4cce6cb414bb..bb4ed438dd6a 100644 --- a/libstdc++-v3/libsupc++/typeinfo +++ b/libstdc++-v3/libsupc++/typeinfo @@ -36,11 +36,10 @@ #include #endif -#pragma GCC visibility push(default) +#define __glibcxx_want_constexpr_typeinfo +#include -#if __cplusplus >= 202100L -# define __cpp_lib_constexpr_typeinfo 202106L -#endif +#pragma GCC visibility push(default) extern "C++" { diff --git a/libstdc++-v3/python/libstdcxx/v6/printers.py b/libstdc++-v3/python/libstdcxx/v6/printers.py index b4c427d487cd..37a447b514b5 100644 --- a/libstdc++-v3/python/libstdcxx/v6/printers.py +++ b/libstdc++-v3/python/libstdcxx/v6/printers.py @@ -1343,7 +1343,7 @@ class StdExpOptionalPrinter(SingleObjContainerPrinter): def __init__ (self, typename, val): valtype = self._recognize (val.type.template_argument(0)) typename = strip_versioned_namespace(typename) - self.typename = re.sub('^std::(experimental::|)(fundamentals_v\d::|)(.*)', r'std::\1\3<%s>' % valtype, typename, 1) + self.typename = re.sub('^std::(experimental::|)(fundamentals_v\d::|)(.*)', r'std::\1\3', typename, 1) payload = val['_M_payload'] if self.typename.startswith('std::experimental'): engaged = val['_M_engaged'] @@ -1375,7 +1375,6 @@ class StdVariantPrinter(SingleObjContainerPrinter): def __init__(self, typename, val): alternatives = get_template_arg_list(val.type) self.typename = strip_versioned_namespace(typename) - self.typename = "%s<%s>" % (self.typename, ', '.join([self._recognize(alt) for alt in alternatives])) self.index = val['_M_index'] if self.index >= len(alternatives): self.contained_type = None @@ -2021,11 +2020,16 @@ class StdChronoCalendarPrinter: if typ == 'std::chrono::day': return '{}'.format(int(val['_M_d'])) if typ == 'std::chrono::month': + if m < 1 or m >= len(months): + return "%d is not a valid month" % m return months[m] if typ == 'std::chrono::year': return '{}y'.format(y) if typ == 'std::chrono::weekday': - return '{}'.format(weekdays[val['_M_wd']]) + wd = val['_M_wd'] + if wd < 0 or wd >= len(weekdays): + return "%d is not a valid weekday" % wd + return '{}'.format(weekdays[wd]) if typ == 'std::chrono::weekday_indexed': return '{}[{}]'.format(val['_M_wd'], int(val['_M_index'])) if typ == 'std::chrono::weekday_last': @@ -2127,6 +2131,50 @@ class StdChronoTimeZoneRulePrinter: return 'time_zone rule {} from {} to {} starting on {}'.format( self.val['name'], self.val['from'], self.val['to'], start) +class StdLocalePrinter: + "Print a std::locale" + + def __init__(self, typename, val): + self.val = val + self.typename = typename + + def to_string(self): + names = self.val['_M_impl']['_M_names'] + mod = '' + if names[0] == 0: + name = '*' + else: + cats = gdb.parse_and_eval(self.typename + '::_S_categories') + ncat = gdb.parse_and_eval(self.typename + '::_S_categories_size') + n = names[0].string(); + cat = cats[0].string() + name = '{}={}'.format(cat, n) + cat_names = {cat: n} + i = 1 + while i < ncat and names[i] != 0: + n = names[i].string() + cat = cats[i].string() + name = '{};{}={}'.format(name, cat, n) + cat_names[cat] = n + i = i + 1 + uniq_names = set(cat_names.values()) + if len(uniq_names) == 1: + name = n + elif len(uniq_names) == 2: + n1, n2 = (uniq_names) + name_list = list(cat_names.values()) + other = None + if name_list.count(n1) == 1: + name = n2 + other = n1 + elif name_list.count(n2) == 1: + name = n1 + other = n2 + if other is not None: + cat = next(c for c,n in cat_names.items() if n == other) + mod = ' with "{}={}"'.format(cat, other) + return 'std::locale = "{}"{}'.format(name, mod) + # A "regular expression" printer which conforms to the # "SubPrettyPrinter" protocol from gdb.printing. @@ -2581,6 +2629,7 @@ def build_libstdcxx_dictionary (): libstdcxx_printer.add_version('std::', 'unique_ptr', UniquePointerPrinter) libstdcxx_printer.add_container('std::', 'vector', StdVectorPrinter) # vector + libstdcxx_printer.add_version('std::', 'locale', StdLocalePrinter) if hasattr(gdb.Value, 'dynamic_type'): libstdcxx_printer.add_version('std::', 'error_code', diff --git a/libstdc++-v3/src/c++17/fs_ops.cc b/libstdc++-v3/src/c++17/fs_ops.cc index c94d260632f6..6cdeac17c33c 100644 --- a/libstdc++-v3/src/c++17/fs_ops.cc +++ b/libstdc++-v3/src/c++17/fs_ops.cc @@ -112,18 +112,17 @@ fs::absolute(const path& p, error_code& ec) wstring buf; do { - buf.resize(len); - len = GetFullPathNameW(s.data(), len, buf.data(), nullptr); + buf.__resize_and_overwrite(len, [&s, &len](wchar_t* p, unsigned n) { + len = GetFullPathNameW(s.data(), n, p, nullptr); + return len > n ? 0 : len; + }); } while (len > buf.size()); if (len == 0) ec = __last_system_error(); else - { - buf.resize(len); - ret = std::move(buf); - } + ret = std::move(buf); #else ret = current_path(ec); ret /= p; @@ -1187,31 +1186,33 @@ fs::path fs::read_symlink(const path& p, error_code& ec) return result; } - std::string buf(st.st_size ? st.st_size + 1 : 128, '\0'); + std::string buf; + size_t bufsz = st.st_size ? st.st_size + 1 : 128; do { - ssize_t len = ::readlink(p.c_str(), buf.data(), buf.size()); - if (len == -1) + ssize_t len; + buf.__resize_and_overwrite(bufsz, [&p, &len](char* ptr, size_t n) { + len = ::readlink(p.c_str(), ptr, n); + return size_t(len) < n ? len : 0; + }); + if (buf.size()) + { + result.assign(std::move(buf)); + ec.clear(); + break; + } + else if (len == -1) { ec.assign(errno, std::generic_category()); return result; } - else if (len == (ssize_t)buf.size()) + else if (bufsz > 4096) { - if (buf.size() > 4096) - { - ec.assign(ENAMETOOLONG, std::generic_category()); - return result; - } - buf.resize(buf.size() * 2); + ec.assign(ENAMETOOLONG, std::generic_category()); + return result; } else - { - buf.resize(len); - result.assign(buf); - ec.clear(); - break; - } + bufsz *= 2; } while (true); #else diff --git a/libstdc++-v3/src/c++20/tzdb.cc b/libstdc++-v3/src/c++20/tzdb.cc index 8d27726016ec..d22cea7e0709 100644 --- a/libstdc++-v3/src/c++20/tzdb.cc +++ b/libstdc++-v3/src/c++20/tzdb.cc @@ -1078,8 +1078,8 @@ namespace std::chrono } // N.B. Leading slash as required by zoneinfo_file function. - const string tzdata_file = "/tzdata.zi"; - const string leaps_file = "/leapseconds"; + const string_view tzdata_file = "/tzdata.zi"; + const string_view leaps_file = "/leapseconds"; #ifdef _GLIBCXX_STATIC_TZDATA // Static copy of tzdata.zi embedded in the library as tzdata_chars[] @@ -1635,6 +1635,9 @@ namespace std::chrono // TODO cache this function's result? #ifndef _AIX + // Repeat the preprocessor condition used by filesystem::read_symlink, + // to avoid a dependency on src/c++17/fs_ops.o if it won't work anyway. +#if defined(_GLIBCXX_HAVE_READLINK) && defined(_GLIBCXX_HAVE_SYS_STAT_H) error_code ec; // This should be a symlink to e.g. /usr/share/zoneinfo/Europe/London auto path = filesystem::read_symlink("/etc/localtime", ec); @@ -1653,6 +1656,7 @@ namespace std::chrono return tz; } } +#endif // Otherwise, look for a file naming the time zone. string_view files[] { "/etc/timezone", // Debian derivates diff --git a/libstdc++-v3/src/c++98/localename.cc b/libstdc++-v3/src/c++98/localename.cc index 25e6d966dca5..68cb81d0709a 100644 --- a/libstdc++-v3/src/c++98/localename.cc +++ b/libstdc++-v3/src/c++98/localename.cc @@ -36,24 +36,37 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION using namespace __gnu_cxx; + static inline bool + is_C_locale(const char* s) + { + switch (s[0]) + { + case 'C': + return s[1] == '\0'; + case 'P': + return !std::strcmp(s+1, "OSIX"); + default: + return false; + } + } + locale::locale(const char* __s) : _M_impl(0) { if (__s) { _S_initialize(); - if (std::strcmp(__s, "C") == 0 || std::strcmp(__s, "POSIX") == 0) + if (is_C_locale(__s)) (_M_impl = _S_classic)->_M_add_reference(); - else if (std::strcmp(__s, "") != 0) + else if (*__s) _M_impl = new _Impl(__s, 1); else { // Get it from the environment. char* __env = std::getenv("LC_ALL"); // If LC_ALL is set we are done. - if (__env && std::strcmp(__env, "") != 0) + if (__env && *__env) { - if (std::strcmp(__env, "C") == 0 - || std::strcmp(__env, "POSIX") == 0) + if (is_C_locale(__env)) (_M_impl = _S_classic)->_M_add_reference(); else _M_impl = new _Impl(__env, 1); @@ -63,9 +76,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION // LANG may set a default different from "C". string __lang; __env = std::getenv("LANG"); - if (!__env || std::strcmp(__env, "") == 0 - || std::strcmp(__env, "C") == 0 - || std::strcmp(__env, "POSIX") == 0) + if (!__env || !*__env || is_C_locale(__env)) __lang = "C"; else __lang = __env; @@ -77,17 +88,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION for (; __i < _S_categories_size; ++__i) { __env = std::getenv(_S_categories[__i]); - if (__env && std::strcmp(__env, "") != 0 - && std::strcmp(__env, "C") != 0 - && std::strcmp(__env, "POSIX") != 0) + if (__env && *__env && !is_C_locale(__env)) break; } else for (; __i < _S_categories_size; ++__i) { __env = std::getenv(_S_categories[__i]); - if (__env && std::strcmp(__env, "") != 0 - && __lang != __env) + if (__env && *__env && __lang != __env) break; } @@ -113,14 +121,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { __env = std::getenv(_S_categories[__i]); __str += _S_categories[__i]; - if (!__env || std::strcmp(__env, "") == 0) + if (!__env || !*__env) { __str += '='; __str += __lang; __str += ';'; } - else if (std::strcmp(__env, "C") == 0 - || std::strcmp(__env, "POSIX") == 0) + else if (is_C_locale(__env)) __str += "=C;"; else { diff --git a/libstdc++-v3/src/filesystem/ops-common.h b/libstdc++-v3/src/filesystem/ops-common.h index 2e4331bb6829..79dcb756453f 100644 --- a/libstdc++-v3/src/filesystem/ops-common.h +++ b/libstdc++-v3/src/filesystem/ops-common.h @@ -700,8 +700,10 @@ _GLIBCXX_BEGIN_NAMESPACE_FILESYSTEM std::wstring buf; do { - buf.resize(len); - len = GetTempPathW(buf.size(), buf.data()); + buf.__resize_and_overwrite(len, [&len](wchar_t* p, unsigned n) { + len = GetTempPathW(n, p); + return len > n ? 0 : len; + }); } while (len > buf.size()); @@ -710,7 +712,6 @@ _GLIBCXX_BEGIN_NAMESPACE_FILESYSTEM else ec.clear(); - buf.resize(len); return buf; } #else diff --git a/libstdc++-v3/testsuite/17_intro/no_library_allocation.cc b/libstdc++-v3/testsuite/17_intro/no_library_allocation.cc new file mode 100644 index 000000000000..278d4757c939 --- /dev/null +++ b/libstdc++-v3/testsuite/17_intro/no_library_allocation.cc @@ -0,0 +1,8 @@ +#include +#include + +int main() +{ + VERIFY( __gnu_test::counter::count() == 0 ); + return 0; +} diff --git a/libstdc++-v3/testsuite/18_support/comparisons/categories/zero_neg.cc b/libstdc++-v3/testsuite/18_support/comparisons/categories/zero_neg.cc index 7daf799f71d8..17a129bcb75a 100644 --- a/libstdc++-v3/testsuite/18_support/comparisons/categories/zero_neg.cc +++ b/libstdc++-v3/testsuite/18_support/comparisons/categories/zero_neg.cc @@ -34,6 +34,11 @@ test01() std::weak_ordering::equivalent == 1; // { dg-error "invalid conversion" } std::strong_ordering::equivalent == 1; // { dg-error "invalid conversion" } + constexpr int z = 0; + std::partial_ordering::equivalent == z; // { dg-error "invalid conversion" } + std::weak_ordering::equivalent == z; // { dg-error "invalid conversion" } + std::strong_ordering::equivalent == z; // { dg-error "invalid conversion" } + constexpr void* p = nullptr; std::partial_ordering::equivalent == p; // { dg-error "invalid conversion" } std::weak_ordering::equivalent == p; // { dg-error "invalid conversion" } @@ -44,3 +49,6 @@ test01() std::weak_ordering::equivalent == nullptr; std::strong_ordering::equivalent == nullptr; } + +// { dg-prune-output "reinterpret_cast.* is not a constant expression" } +// { dg-prune-output "cast from 'void.' is not allowed" } diff --git a/libstdc++-v3/testsuite/18_support/nested_exception/rethrow_if_nested-term.cc b/libstdc++-v3/testsuite/18_support/nested_exception/rethrow_if_nested-term.cc index 3bfc7ab99436..b221eea3178f 100644 --- a/libstdc++-v3/testsuite/18_support/nested_exception/rethrow_if_nested-term.cc +++ b/libstdc++-v3/testsuite/18_support/nested_exception/rethrow_if_nested-term.cc @@ -4,25 +4,33 @@ #include #include -[[noreturn]] void terminate_cleanly() noexcept { std::exit(0); } +int exit_status = 1; +[[noreturn]] void terminate_cleanly() noexcept { std::exit(exit_status); } struct A { virtual ~A() = default; }; int main() { + std::set_terminate(terminate_cleanly); try { // At this point std::current_exception() == nullptr so the // std::nested_exception object is empty. std::throw_with_nested(A{}); + + // Should not reach this point. + std::abort(); } catch (const A& a) { - std::set_terminate(terminate_cleanly); + // This means the expected std::terminate() call will exit cleanly, + // so this test will PASS. + exit_status = 0; + std::rethrow_if_nested(a); #if __cpp_rtti // No nested exception, so trying to rethrow it calls std::terminate() - // which calls std::exit(0). Shoud not reach this point. + // which calls std::exit(0). Should not reach this point. std::abort(); #else // Without RTTI we can't dynamic_cast(&a) diff --git a/libstdc++-v3/testsuite/20_util/auto_ptr/1.cc b/libstdc++-v3/testsuite/20_util/auto_ptr/1.cc index b498711da765..64c0cf97e2ff 100644 --- a/libstdc++-v3/testsuite/20_util/auto_ptr/1.cc +++ b/libstdc++-v3/testsuite/20_util/auto_ptr/1.cc @@ -15,9 +15,9 @@ // with this library; see the file COPYING3. If not see // . -// 20.4.5 Template class auto_ptr [lib.auto.ptr] +// C++03 20.4.5 Template class auto_ptr [lib.auto.ptr] -// { dg-options "-std=c++98" } +// { dg-add-options using-deprecated } #include #include @@ -63,21 +63,21 @@ test01() { reset_count_struct __attribute__((unused)) reset; - std::auto_ptr A_default; + std::auto_ptr A_default; // { dg-warning "deprecated" "" { target c++11 } } VERIFY( A_default.get() == 0 ); VERIFY( A::ctor_count == 0 ); VERIFY( A::dtor_count == 0 ); VERIFY( B::ctor_count == 0 ); VERIFY( B::dtor_count == 0 ); - std::auto_ptr A_from_A(new A); + std::auto_ptr A_from_A(new A); // { dg-warning "deprecated" "" { target c++11 } } VERIFY( A_from_A.get() != 0 ); VERIFY( A::ctor_count == 1 ); VERIFY( A::dtor_count == 0 ); VERIFY( B::ctor_count == 0 ); VERIFY( B::dtor_count == 0 ); - std::auto_ptr A_from_B(new B); + std::auto_ptr A_from_B(new B); // { dg-warning "deprecated" "" { target c++11 } } VERIFY( A_from_B.get() != 0 ); VERIFY( A::ctor_count == 2 ); VERIFY( A::dtor_count == 0 ); diff --git a/libstdc++-v3/testsuite/20_util/auto_ptr/2.cc b/libstdc++-v3/testsuite/20_util/auto_ptr/2.cc index 0d5aabe61a42..9cbab139068b 100644 --- a/libstdc++-v3/testsuite/20_util/auto_ptr/2.cc +++ b/libstdc++-v3/testsuite/20_util/auto_ptr/2.cc @@ -15,9 +15,10 @@ // with this library; see the file COPYING3. If not see // . -// 20.4.5 Template class auto_ptr [lib.auto.ptr] +// C++03 20.4.5 Template class auto_ptr [lib.auto.ptr] -// { dg-options "-std=c++98" } +// { dg-add-options using-deprecated } +// { dg-warning "auto_ptr. is deprecated" "" { target c++11 } 0 } #include #include diff --git a/libstdc++-v3/testsuite/20_util/auto_ptr/3.cc b/libstdc++-v3/testsuite/20_util/auto_ptr/3.cc index afac4013b59d..ce020406cb8b 100644 --- a/libstdc++-v3/testsuite/20_util/auto_ptr/3.cc +++ b/libstdc++-v3/testsuite/20_util/auto_ptr/3.cc @@ -15,9 +15,10 @@ // with this library; see the file COPYING3. If not see // . -// 20.4.5 Template class auto_ptr [lib.auto.ptr] +// C++03 20.4.5 Template class auto_ptr [lib.auto.ptr] -// { dg-options "-std=c++98" } +// { dg-add-options using-deprecated } +// { dg-warning "auto_ptr. is deprecated" "" { target c++11 } 0 } #include #include diff --git a/libstdc++-v3/testsuite/20_util/auto_ptr/3946.cc b/libstdc++-v3/testsuite/20_util/auto_ptr/3946.cc index d6d755ac9113..42ccf99c1812 100644 --- a/libstdc++-v3/testsuite/20_util/auto_ptr/3946.cc +++ b/libstdc++-v3/testsuite/20_util/auto_ptr/3946.cc @@ -15,9 +15,10 @@ // with this library; see the file COPYING3. If not see // . -// 20.4.5 Template class auto_ptr [lib.auto.ptr] +// C++03 20.4.5 Template class auto_ptr [lib.auto.ptr] -// { dg-options "-std=c++98" } +// { dg-add-options using-deprecated } +// { dg-warning "auto_ptr. is deprecated" "" { target c++11 } 0 } #include #include diff --git a/libstdc++-v3/testsuite/20_util/auto_ptr/4.cc b/libstdc++-v3/testsuite/20_util/auto_ptr/4.cc index fb896e11f024..7cf59965d7aa 100644 --- a/libstdc++-v3/testsuite/20_util/auto_ptr/4.cc +++ b/libstdc++-v3/testsuite/20_util/auto_ptr/4.cc @@ -15,9 +15,10 @@ // with this library; see the file COPYING3. If not see // . -// 20.4.5 Template class auto_ptr [lib.auto.ptr] +// C++03 20.4.5 Template class auto_ptr [lib.auto.ptr] -// { dg-options "-std=c++98" } +// { dg-add-options using-deprecated } +// { dg-warning "auto_ptr. is deprecated" "" { target c++11 } 0 } #include #include diff --git a/libstdc++-v3/testsuite/20_util/auto_ptr/5.cc b/libstdc++-v3/testsuite/20_util/auto_ptr/5.cc index 8a766e6ec239..1e60f13a20d9 100644 --- a/libstdc++-v3/testsuite/20_util/auto_ptr/5.cc +++ b/libstdc++-v3/testsuite/20_util/auto_ptr/5.cc @@ -15,9 +15,10 @@ // with this library; see the file COPYING3. If not see // . -// 20.4.5 Template class auto_ptr [lib.auto.ptr] +// C++03 20.4.5 Template class auto_ptr [lib.auto.ptr] -// { dg-options "-std=c++98" } +// { dg-add-options using-deprecated } +// { dg-warning "auto_ptr. is deprecated" "" { target c++11 } 0 } #include #include diff --git a/libstdc++-v3/testsuite/20_util/auto_ptr/6.cc b/libstdc++-v3/testsuite/20_util/auto_ptr/6.cc index cd1f0547f5b2..d888301c7668 100644 --- a/libstdc++-v3/testsuite/20_util/auto_ptr/6.cc +++ b/libstdc++-v3/testsuite/20_util/auto_ptr/6.cc @@ -15,9 +15,10 @@ // with this library; see the file COPYING3. If not see // . -// 20.4.5 Template class auto_ptr [lib.auto.ptr] +// C++03 20.4.5 Template class auto_ptr [lib.auto.ptr] -// { dg-options "-std=c++98" } +// { dg-add-options using-deprecated } +// { dg-warning "auto_ptr. is deprecated" "" { target c++11 } 0 } #include #include diff --git a/libstdc++-v3/testsuite/20_util/auto_ptr/7.cc b/libstdc++-v3/testsuite/20_util/auto_ptr/7.cc index 86338c7e2590..fd3f78a46cda 100644 --- a/libstdc++-v3/testsuite/20_util/auto_ptr/7.cc +++ b/libstdc++-v3/testsuite/20_util/auto_ptr/7.cc @@ -15,9 +15,10 @@ // with this library; see the file COPYING3. If not see // . -// 20.4.5 Template class auto_ptr [lib.auto.ptr] +// C++03 20.4.5 Template class auto_ptr [lib.auto.ptr] -// { dg-options "-std=c++98" } +// { dg-add-options using-deprecated } +// { dg-warning "auto_ptr. is deprecated" "" { target c++11 } 0 } #include #include diff --git a/libstdc++-v3/testsuite/20_util/auto_ptr/assign_neg.cc b/libstdc++-v3/testsuite/20_util/auto_ptr/assign_neg.cc index 5ff2ddb9113d..fa890fa4fcd8 100644 --- a/libstdc++-v3/testsuite/20_util/auto_ptr/assign_neg.cc +++ b/libstdc++-v3/testsuite/20_util/auto_ptr/assign_neg.cc @@ -1,4 +1,6 @@ // { dg-do compile } +// { dg-add-options using-deprecated } +// { dg-warning "auto_ptr. is deprecated" "" { target c++11 } 0 } // Copyright (C) 2002-2023 Free Software Foundation, Inc. // @@ -17,9 +19,7 @@ // with this library; see the file COPYING3. If not see // . -// 20.4.5 Template class auto_ptr negative tests [lib.auto.ptr] - -// { dg-options "-std=c++98" } +// C++03 20.4.5 Template class auto_ptr negative tests [lib.auto.ptr] #include #include diff --git a/libstdc++-v3/testsuite/20_util/auto_ptr/requirements/explicit_instantiation/1.cc b/libstdc++-v3/testsuite/20_util/auto_ptr/requirements/explicit_instantiation/1.cc index be7fb4822505..b26b784fd4ff 100644 --- a/libstdc++-v3/testsuite/20_util/auto_ptr/requirements/explicit_instantiation/1.cc +++ b/libstdc++-v3/testsuite/20_util/auto_ptr/requirements/explicit_instantiation/1.cc @@ -1,4 +1,6 @@ // { dg-do compile } +// { dg-add-options using-deprecated } +// { dg-warning "auto_ptr. is deprecated" "" { target c++11 } 0 } // Copyright (C) 2007-2023 Free Software Foundation, Inc. // @@ -18,9 +20,7 @@ // . -// This file tests explicit instantiation of library containers. - -// { dg-options "-std=c++98" } +// This file tests explicit instantiation of library templates. #include diff --git a/libstdc++-v3/testsuite/20_util/bitset/107037.cc b/libstdc++-v3/testsuite/20_util/bitset/107037.cc index b4560dd37752..3b2bb80277e7 100644 --- a/libstdc++-v3/testsuite/20_util/bitset/107037.cc +++ b/libstdc++-v3/testsuite/20_util/bitset/107037.cc @@ -1,5 +1,5 @@ // { dg-options "-std=c++03" } -// { dg-do compile } +// { dg-do compile { target c++98_only } } // PR libstdc++/107037 bitset::_M_do_reset fails for strict -std=c++03 mode #include template class std::bitset<0>; diff --git a/libstdc++-v3/testsuite/20_util/duration/arithmetic/constexpr_c++17.cc b/libstdc++-v3/testsuite/20_util/duration/arithmetic/constexpr_c++17.cc index 8ccce356a2a4..6fe5475caf02 100644 --- a/libstdc++-v3/testsuite/20_util/duration/arithmetic/constexpr_c++17.cc +++ b/libstdc++-v3/testsuite/20_util/duration/arithmetic/constexpr_c++17.cc @@ -22,7 +22,7 @@ #ifndef __cpp_lib_chrono # error "Feature-test macro for constexpr missing" -#elif __cpp_lib_chrono != 201611 +#elif __cpp_lib_chrono < 201611 # error "Feature-test macro for constexpr has wrong value" #endif diff --git a/libstdc++-v3/testsuite/20_util/duration/io.cc b/libstdc++-v3/testsuite/20_util/duration/io.cc index ea94b062d969..5cbc050e2101 100644 --- a/libstdc++-v3/testsuite/20_util/duration/io.cc +++ b/libstdc++-v3/testsuite/20_util/duration/io.cc @@ -97,10 +97,110 @@ test_format() } } +void +test_parse() +{ + using namespace std::chrono; + seconds s; + milliseconds ms; + microseconds us; + + std::istringstream is(" 2023-07-24 13:05"); + VERIFY( is >> parse(" %Y-%m-%d %H:%M", s) ); + VERIFY( is.good() ); + VERIFY( s == 13h + 5min ); + + s = 999s; + + is.clear(); + is.str("Thursday July 2023"); + VERIFY( !(is >> parse("%a %b %C%y", s)) ); + VERIFY( ! is.eof() ); + VERIFY( s == 999s ); + + is.clear(); + is.str("27"); + VERIFY( is >> parse("%j", s) ); + VERIFY( is.eof() ); + VERIFY( s == 24h * 27 ); + + is.clear(); + is.str("027"); + VERIFY( is >> parse("%j", s) ); + VERIFY( ! is.eof() ); + VERIFY( s == 24h * 27 ); + + is.clear(); + is.str("0027"); + VERIFY( is >> parse("%j", s) ); // defaults to %3j + VERIFY( is.get() == '7' ); + VERIFY( s == 24h * 2 ); + + is.clear(); + is.str("1234"); + VERIFY( is >> parse("%2j", s) ); + VERIFY( is.get() == '3' ); + VERIFY( s == 24h * 12 ); + + is.clear(); + is.str("001234"); + VERIFY( is >> parse("%4j", s) ); + VERIFY( is.get() == '3' ); + VERIFY( s == 24h * 12 ); + + is.clear(); + is.str("1234"); + VERIFY( is >> parse("%4j", s) ); + VERIFY( ! is.eof() ); + VERIFY( s == 24h * 1234 ); + + is.clear(); + is.str("125"); + VERIFY( is >> parse("%S", s) ); + VERIFY( s == 12s ); + VERIFY( is.get() == '5' ); + + is.clear(); + is.str("0.125"); + VERIFY( is >> parse("%S", s) ); + VERIFY( s == 0s ); + VERIFY( is.get() == '.' ); + + is.clear(); + is.str("0.125"); + VERIFY( is >> parse("%S", ms) ); + VERIFY( ms == 125ms ); + VERIFY( ! is.eof() ); + + is.clear(); + is.str("00.125"); + VERIFY( is >> parse("%S", ms) ); + VERIFY( ms == 125ms ); + VERIFY( ! is.eof() ); + + is.clear(); + is.str("012.345"); + VERIFY( is >> parse("%S", ms) ); + VERIFY( ms == 1000ms ); + VERIFY( is.get() == '2' ); + + is.clear(); + is.str("0.1256"); + VERIFY( is >> parse("%S", ms) ); + VERIFY( ms == 125ms ); + VERIFY( is.get() == '6' ); + + is.clear(); + is.str("0.0009765"); + VERIFY( is >> parse("%S", us) ); + VERIFY( us == 976us ); + VERIFY( is.get() == '5' ); +} + int main() { test01(); test02(); test_format(); - // TODO: test_parse(); + test_parse(); } diff --git a/libstdc++-v3/testsuite/20_util/expected/bad.cc b/libstdc++-v3/testsuite/20_util/expected/bad.cc index 17bc6d69e886..e5d7ba4afb04 100644 --- a/libstdc++-v3/testsuite/20_util/expected/bad.cc +++ b/libstdc++-v3/testsuite/20_util/expected/bad.cc @@ -1,5 +1,5 @@ // { dg-options "-std=gnu++23" } -// { dg-do compile } +// { dg-do compile { target c++23 } } #include diff --git a/libstdc++-v3/testsuite/20_util/ratio/operations/ops_overflow_neg.cc b/libstdc++-v3/testsuite/20_util/ratio/operations/ops_overflow_neg.cc index 2e2a59c164cb..62034e42a752 100644 --- a/libstdc++-v3/testsuite/20_util/ratio/operations/ops_overflow_neg.cc +++ b/libstdc++-v3/testsuite/20_util/ratio/operations/ops_overflow_neg.cc @@ -43,9 +43,9 @@ test02() // { dg-error "expected initializer" "" { target *-*-* } 35 } // { dg-error "expected initializer" "" { target *-*-* } 37 } // { dg-error "overflow in addition" "" { target *-*-* } 0 } -// { dg-error "overflow in multiplication" "" { target *-*-* } 98 } -// { dg-error "overflow in multiplication" "" { target *-*-* } 100 } -// { dg-error "overflow in multiplication" "" { target *-*-* } 102 } +// { dg-error "overflow in multiplication" "" { target *-*-* } 101 } +// { dg-error "overflow in multiplication" "" { target *-*-* } 103 } +// { dg-error "overflow in multiplication" "" { target *-*-* } 105 } // { dg-error "overflow in constant expression" "" { target *-*-* } 0 } // { dg-error "narrowing conversion" "" { target *-*-* } 0 } // { dg-prune-output "out of range" } diff --git a/libstdc++-v3/testsuite/21_strings/basic_string/capacity/char/resize_and_overwrite.cc b/libstdc++-v3/testsuite/21_strings/basic_string/capacity/char/resize_and_overwrite.cc index f716030dad7f..3265ebc34869 100644 --- a/libstdc++-v3/testsuite/21_strings/basic_string/capacity/char/resize_and_overwrite.cc +++ b/libstdc++-v3/testsuite/21_strings/basic_string/capacity/char/resize_and_overwrite.cc @@ -1,13 +1,15 @@ // { dg-options "-std=gnu++23" } -// { dg-do run { target { c++23 && cxx11_abi } } } +// { dg-do run { target c++23 } } #include +#if __cplusplus >= 202302L #ifndef __cpp_lib_string_resize_and_overwrite #error "Feature test macro for resize_and_overwrite is missing in " #elif __cpp_lib_string_resize_and_overwrite != 202110L # error "Feature test macro for resize_and_overwrite has wrong value in " #endif +#endif #include @@ -34,8 +36,8 @@ test01() s.resize_and_overwrite(50, [](char* p, int n) -> unsigned { VERIFY( n == 50 ); - VERIFY( !std::strncmp(p, "monkey", 3) ); - std::strcpy(p, "Partridge among the pidgeons"); + VERIFY( !std::strncmp(p, "monkey", 6) ); + std::strcpy(p, "Partridge among the pigeons"); return 9; }); VERIFY( s.data() == str ); // No reallocation @@ -48,21 +50,21 @@ test02() { std::string s; auto p = s.data(); - s.resize_and_overwrite(0, [](auto...) { return 0; }); + s.resize_and_overwrite(0, [](char*, int) { return 0; }); VERIFY( s.empty() ); VERIFY( s[0] == '\0' ); VERIFY( s.data() == p ); s = "short string"; p = s.data(); - s.resize_and_overwrite(0, [](auto...) { return 0; }); + s.resize_and_overwrite(0, [](char*, int) { return 0; }); VERIFY( s.empty() ); VERIFY( s[0] == '\0' ); VERIFY( s.data() == p ); s = "a string that is long enough to not be a short string"; p = s.data(); - s.resize_and_overwrite(0, [](auto...) { return 0; }); + s.resize_and_overwrite(0, [](char*, int) { return 0; }); VERIFY( s.empty() ); VERIFY( s[0] == '\0' ); VERIFY( s.data() == p ); @@ -71,26 +73,43 @@ test02() void test03() { + using size_type = std::string::size_type; + + // Op must be invoked as std::move(op)(p, m) to use &&-qualified overload. + // The value category and cv-qualification of the arguments is unspecified. struct Op { - int operator()(char*, int) & = delete; - int operator()(char*, int) const & = delete; - int operator()(char* p, int n) && { std::memset(p, 'a', n+1); return n; } - int operator()(char*, int) const && = delete; + int operator()(char* p, size_type n) && + { + // N.B. this intentionally writes to p[n], see below, and test06(). + std::memset(p, 'a', n+1); + return n; + } + + // Wrong ref-quals: + int operator()(char*, size_type) & = delete; + int operator()(char*, size_type) const & = delete; + int operator()(char*, size_type) const && = delete; + + // Wrong types: + int operator()(char* p, int n) && = delete; + int operator()(char* p, long n) && = delete; + int operator()(char* p, long long n) && = delete; + +#ifdef _GLIBCXX_RELEASE + // This overload was used prior to the resolution of LWG 3645: + // resize_and_overwrite is overspecified to call its callback with lvalues. + // A conforming implementation might still pass lvalues to the op, but the + // libstdc++ implementation passes prvalues and so this overload should + // not be selected now. + int operator()(char*&, std::string::size_type&) && = delete; // (*) +#endif }; std::string s; s.resize_and_overwrite(42, Op{}); VERIFY( s.size() == 42 ); VERIFY( s == std::string(42, 'a') ); - VERIFY( s[42] == '\0' ); - - s.resize_and_overwrite(0, [](auto p, auto n) { - // N.B. these requirements were relaxed by LWG 3645: - // resize_and_overwrite is overspecified to call its callback with lvalues - static_assert( std::is_same_v ); - static_assert( std::is_same_v ); - return 0; - }); + VERIFY( s[42] == '\0' ); // Callback wrote to p[n] but it's null now. } void @@ -99,7 +118,7 @@ test04() std::string s = "this tests how the library copes with undefined behaviour"; try { - s.resize_and_overwrite(13, [](auto...) -> int { throw "undefined"; }); + s.resize_and_overwrite(13, [](...) -> int { throw "undefined"; }); } catch (...) { // The standard doesn't require this, but we leave the string empty: VERIFY( s.size() == 0 ); @@ -110,6 +129,7 @@ test04() constexpr bool test05() { +#if __cpp_lib_constexpr_string >= 201907 std::string s; s.resize_and_overwrite(20, [](char* p, auto n) { *p = '!'; // direct assignment should be OK @@ -117,9 +137,65 @@ test05() return 9; }); VERIFY( s == "constexpr" ); +#endif return true; } +void +test06() +{ + std::string s = "0123456789"; + s.resize_and_overwrite(16, [](char* p, int n) { + // Even though s.capacity() == 20 this callback still gets n==16: + VERIFY( n == 16 ); + // Standard requires [p, p+n] to be a valid range, so this sets p[16]='6': + std::char_traits::copy(p + 10, "0123456798", 7); + return n; + }); + VERIFY( s.size() == 16 ); + VERIFY( s == "0123456789012345" ); + // Although p[16] was written to by the callback, it must be set to '\0' + // to maintain the invariant that the string is null-terminated: + VERIFY( s[16] == '\0' ); + + s.resize_and_overwrite(4, [](char* p, int n) { + VERIFY( n == 4 ); + std::char_traits::copy(p, "abcde", 5); // Writes to p[n]. + return n; + }); + VERIFY( s.size() == 4 ); + VERIFY( s[4] == '\0' ); + + std::string short_string; + // For the SSO string this won't need to allocate anything, + // but all the same checks should pass. + short_string.resize_and_overwrite(4, [](char* p, int n) { + VERIFY( n == 4 ); + std::char_traits::copy(p, "abcde", 5); // Writes to p[n]. + return n; + }); + VERIFY( short_string.size() == 4 ); + VERIFY( short_string[4] == '\0' ); + +} + +void +test07() +{ +#if __cpp_guaranteed_copy_elision + // Non-copyable, non-movable type can be used as the callable. + struct Op + { + Op() = default; + Op(Op&&) = delete; + Op& operator=(Op&&) = delete; + int operator()(char* p, int n) && { return 0; } + }; + std::string s; + s.resize_and_overwrite(0, Op()); +#endif +} + int main() { test01(); @@ -127,4 +203,6 @@ int main() test03(); test04(); static_assert( test05() ); + test06(); + test07(); } diff --git a/libstdc++-v3/testsuite/21_strings/basic_string/capacity/char/resize_and_overwrite_ext.cc b/libstdc++-v3/testsuite/21_strings/basic_string/capacity/char/resize_and_overwrite_ext.cc new file mode 100644 index 000000000000..ebc2afbe1a6e --- /dev/null +++ b/libstdc++-v3/testsuite/21_strings/basic_string/capacity/char/resize_and_overwrite_ext.cc @@ -0,0 +1,6 @@ +// { dg-do run { target c++11 } } + +#include +// Run ./resize_and_overwrite.cc tests using __resize_and_overwrite instead. +#define resize_and_overwrite __resize_and_overwrite +#include "resize_and_overwrite.cc" diff --git a/libstdc++-v3/testsuite/21_strings/basic_string/numeric_conversions/char/dr1261.cc b/libstdc++-v3/testsuite/21_strings/basic_string/numeric_conversions/char/dr1261.cc index 49998b54f634..b952c26c328a 100644 --- a/libstdc++-v3/testsuite/21_strings/basic_string/numeric_conversions/char/dr1261.cc +++ b/libstdc++-v3/testsuite/21_strings/basic_string/numeric_conversions/char/dr1261.cc @@ -46,14 +46,19 @@ void test01() const string six(to_string(400ull)); VERIFY( six == "400" ); + string tail; +#if __cpp_lib_to_string < 202306L + tail = ".000000"; +#endif + const string seven(to_string(-1.0F)); - VERIFY( seven == "-1.000000" ); + VERIFY( seven == "-1" + tail ); const string eight(to_string(2.0)); - VERIFY( eight == "2.000000" ); + VERIFY( eight == "2" + tail ); const string nine(to_string(-4.0L)); - VERIFY( nine == "-4.000000" ); + VERIFY( nine == "-4" + tail ); } int main() diff --git a/libstdc++-v3/testsuite/21_strings/basic_string/numeric_conversions/char/to_string.cc b/libstdc++-v3/testsuite/21_strings/basic_string/numeric_conversions/char/to_string.cc index dc7b87b85f55..c770b4f9bdbf 100644 --- a/libstdc++-v3/testsuite/21_strings/basic_string/numeric_conversions/char/to_string.cc +++ b/libstdc++-v3/testsuite/21_strings/basic_string/numeric_conversions/char/to_string.cc @@ -46,13 +46,18 @@ test01() string four(to_string(ull2)); VERIFY( four == "3000" ); + string tail; +#if __cpp_lib_to_string < 202306L + tail = ".000000"; +#endif + long double ld1 = 2.0L; string five(to_string(ld1)); - VERIFY( five == "2.000000" ); + VERIFY( five == "2" + tail ); long double ld2 = -4.0L; string six(to_string(ld2)); - VERIFY( six == "-4.000000" ); + VERIFY( six == "-4" + tail ); } int main() diff --git a/libstdc++-v3/testsuite/21_strings/basic_string/numeric_conversions/char/to_string_float.cc b/libstdc++-v3/testsuite/21_strings/basic_string/numeric_conversions/char/to_string_float.cc new file mode 100644 index 000000000000..3837c896f6b0 --- /dev/null +++ b/libstdc++-v3/testsuite/21_strings/basic_string/numeric_conversions/char/to_string_float.cc @@ -0,0 +1,148 @@ +// { dg-do run { target c++11 } } +// { dg-require-namedlocale "de_DE.ISO8859-15" } + +// C++11 21.5 Numeric Conversions [string.conversions] + +#include +#include +#include +#include +#include +#include + +namespace test +{ +// Canonical version of std::to_string(double) as specified in the standard. + +#if __cplusplus > 202302L + +#ifndef __cpp_lib_to_string +# error "Feature-test macro for std::to_string missing in " +#elif __cpp_lib_to_string != 202306L +# error "Feature-test macro for std::to_string has wrong value in " +#endif + +static std::string to_string(float val) { return std::format("{}", val); } +static std::string to_string(double val) { return std::format("{}", val); } +static std::string to_string(long double val) { return std::format("{}", val); } + +#else + +#ifdef __cpp_lib_to_string +# error "__cpp_lib_to_string should not be defined for C++23" +#endif + +static std::string to_string(double val) +{ + std::string str(100, '9'); +retry: + const int size = str.size(); + const int len = std::snprintf(&str[0], size + 1, "%f", val); + str.resize(len); + if (len > size) + goto retry; + return str; +} + +// snprintf promotes float to double +static std::string to_string(float val) { return to_string((double)val); } + +static std::string to_string(long double val) +{ + std::string str(100, '9'); +retry: + const int size = str.size(); + const int len = std::snprintf(&str[0], size + 1, "%Lf", val); + str.resize(len); + if (len > size) + goto retry; + return str; +} +#endif +} // namespace test + +template + void check_value(T val) + { + const std::string s = std::to_string(val); + const std::string expected = test::to_string(val); + VERIFY( s == expected ); + VERIFY( s[s.size()] == '\0' ); // null-terminator not overwritten + } + +template + void check_values() + { + const T values[] = { + 0.0, 0.0625, 0.25, 0.5, 1.25, 1e2, 1e7, 1e8, 1e-2, 1e-7, 1e-8, + 2e38, 4.4e+19, 6.25e-12, 7.89e+23, + 12345.6789, (T) 1234567890123456.e100L, (T) 1213141516e-99L, + std::numeric_limits::min(), + std::numeric_limits::max(), + std::numeric_limits::epsilon(), + std::numeric_limits::infinity(), + std::numeric_limits::quiet_NaN(), + }; + + std::locale::global(std::locale::classic()); + + for (auto v : values) + { + check_value(v); + check_value(-v); + } + + std::locale::global(std::locale(ISO_8859(15,de_DE))); + + for (auto v : values) + { + check_value(v); + check_value(-v); + } + + std::locale::global(std::locale::classic()); + } + +void test01() +{ + // Examples from P2587R3 `to_string` or not `to_string` + + + VERIFY( std::to_string(42) == "42" ); + VERIFY( std::to_string(12345) == "12345" ); + auto max = std::to_string(1.7976931348623157e+308); + +#if __cplusplus <= 202302L + VERIFY( std::to_string(0.42) == "0.420000" ); + VERIFY( std::to_string(1e-7) == "0.000000" ); + VERIFY( std::to_string(-1e-7) == "-0.000000" ); + VERIFY( max.substr(0, 17) == "17976931348623157" ); + VERIFY( max.substr(max.size() - 7) == ".000000" ); +#else + VERIFY( std::to_string(0.42) == "0.42" ); + VERIFY( std::to_string(1e-7) == "1e-07" ); + VERIFY( std::to_string(-1e-7) == "-1e-07" ); + VERIFY( max == "1.7976931348623157e+308" ); +#endif + + std::locale::global(std::locale(ISO_8859(15,de_DE))); +#if __cplusplus <= 202302L + VERIFY( std::to_string(1234.5) == "1234,500000" ); +#else + VERIFY( std::to_string(1234.5) == "1234.5" ); +#endif + std::locale::global(std::locale::classic()); +} + +void test02() +{ + check_values(); + check_values(); + check_values(); +} + +int main() +{ + test01(); + test02(); +} diff --git a/libstdc++-v3/testsuite/21_strings/basic_string/numeric_conversions/char/to_string_int.cc b/libstdc++-v3/testsuite/21_strings/basic_string/numeric_conversions/char/to_string_int.cc index 53e6e81f93cf..eae983cebb46 100644 --- a/libstdc++-v3/testsuite/21_strings/basic_string/numeric_conversions/char/to_string_int.cc +++ b/libstdc++-v3/testsuite/21_strings/basic_string/numeric_conversions/char/to_string_int.cc @@ -104,8 +104,6 @@ template const std::string expected = test::to_string(val); VERIFY( s == expected ); VERIFY( s[s.size()] == '\0' ); // null-terminator not overwritten! - if (s.size() > empty_string_capacity) - VERIFY( s.capacity() == s.size() ); // GNU-specific guarantee } #ifdef SIMULATOR_TEST diff --git a/libstdc++-v3/testsuite/21_strings/basic_string/numeric_conversions/version.cc b/libstdc++-v3/testsuite/21_strings/basic_string/numeric_conversions/version.cc new file mode 100644 index 000000000000..630e06fff8ff --- /dev/null +++ b/libstdc++-v3/testsuite/21_strings/basic_string/numeric_conversions/version.cc @@ -0,0 +1,18 @@ +// { dg-do compile } +#include + +#if __cplusplus > 202302L + +#ifndef __cpp_lib_to_string +# error "Feature-test macro for std::to_string missing in " +#elif __cpp_lib_to_string != 202306L +# error "Feature-test macro for std::to_string has wrong value in " +#endif + +#else + +#ifdef __cpp_lib_to_string +# error "__cpp_lib_to_string should not be defined for C++23" +#endif + +#endif diff --git a/libstdc++-v3/testsuite/21_strings/basic_string/numeric_conversions/wchar_t/dr1261.cc b/libstdc++-v3/testsuite/21_strings/basic_string/numeric_conversions/wchar_t/dr1261.cc index 8dbdd7bf29bb..c2b36fd6c247 100644 --- a/libstdc++-v3/testsuite/21_strings/basic_string/numeric_conversions/wchar_t/dr1261.cc +++ b/libstdc++-v3/testsuite/21_strings/basic_string/numeric_conversions/wchar_t/dr1261.cc @@ -46,14 +46,19 @@ void test01() const wstring six(to_wstring(400ull)); VERIFY( six == L"400" ); + wstring tail; +#if __cpp_lib_to_string < 202306L + tail = L".000000"; +#endif + const wstring seven(to_wstring(-1.0F)); - VERIFY( seven == L"-1.000000" ); + VERIFY( seven == L"-1" + tail ); const wstring eight(to_wstring(2.0)); - VERIFY( eight == L"2.000000" ); + VERIFY( eight == L"2" + tail ); const wstring nine(to_wstring(-4.0L)); - VERIFY( nine == L"-4.000000" ); + VERIFY( nine == L"-4" + tail ); } int main() diff --git a/libstdc++-v3/testsuite/21_strings/basic_string/numeric_conversions/wchar_t/to_wstring.cc b/libstdc++-v3/testsuite/21_strings/basic_string/numeric_conversions/wchar_t/to_wstring.cc index dbfb639765ec..66987835bbb1 100644 --- a/libstdc++-v3/testsuite/21_strings/basic_string/numeric_conversions/wchar_t/to_wstring.cc +++ b/libstdc++-v3/testsuite/21_strings/basic_string/numeric_conversions/wchar_t/to_wstring.cc @@ -47,13 +47,18 @@ test01() wstring four(to_wstring(ull2)); VERIFY( four == L"3000" ); + wstring tail; +#if __cpp_lib_to_string < 202306L + tail = L".000000"; +#endif + long double ld1 = 2.0L; wstring five(to_wstring(ld1)); - VERIFY( five == L"2.000000" ); + VERIFY( five == L"2" + tail ); long double ld2 = -4.0L; wstring six(to_wstring(ld2)); - VERIFY( six == L"-4.000000" ); + VERIFY( six == L"-4" + tail ); #endif } diff --git a/libstdc++-v3/testsuite/21_strings/basic_string/numeric_conversions/wchar_t/to_wstring_float.cc b/libstdc++-v3/testsuite/21_strings/basic_string/numeric_conversions/wchar_t/to_wstring_float.cc new file mode 100644 index 000000000000..83f5bb1cb193 --- /dev/null +++ b/libstdc++-v3/testsuite/21_strings/basic_string/numeric_conversions/wchar_t/to_wstring_float.cc @@ -0,0 +1,145 @@ +// { dg-do run { target c++11 } } +// { dg-require-namedlocale "de_DE.ISO8859-15" } +// { dg-require-string-conversions "" } + +// C++11 21.5 Numeric Conversions [string.conversions] + +#include +#include +#include +#include +#include +#include + +namespace test +{ +// Canonical version of std::to_wstring(double) as specified in the standard. + +#if __cplusplus > 202302L + +std::wstring to_wstring(float val) { return std::format(L"{}", val); } +std::wstring to_wstring(double val) { return std::format(L"{}", val); } +std::wstring to_wstring(long double val) { return std::format(L"{}", val); } + +#else + +std::wstring to_wstring(double val) +{ + std::wstring str(100, L'9'); +retry: + const int size = str.size(); + const int len = std::swprintf(&str[0], size + 1, L"%f", val); + if (len == -1) // N.B. swprintf just returns -1 if the buffer is too small. + { + str.resize(size * 2); + goto retry; + } + str.resize(len); + return str; +} + +// snprintf promotes float to double +std::wstring to_wstring(float val) { return to_wstring((double)val); } + +std::wstring to_wstring(long double val) +{ + std::wstring str(100, L'9'); +retry: + const int size = str.size(); + const int len = std::swprintf(&str[0], size + 1, L"%Lf", val); + if (len == -1) // N.B. swprintf just returns -1 if the buffer is too small. + { + str.resize(size * 2); + goto retry; + } + str.resize(len); + return str; +} +#endif +} // namespace test + +template + void check_value(T val) + { + const std::wstring s = std::to_wstring(val); + const std::wstring expected = test::to_wstring(val); + VERIFY( s == expected ); + VERIFY( s[s.size()] == L'\0' ); // null-terminator not overwritten + } + +template + void check_values() + { + const T values[] = { + 0.0, 0.0625, 0.25, 0.5, 1.25, 1e2, 1e7, 1e8, 1e-2, 1e-7, 1e-8, + 2e38, 4.4e+19, 6.25e-12, 7.89e+23, + 12345.6789, (T) 1234567890123456.e100L, (T) 1213141516e-99L, + std::numeric_limits::min(), + std::numeric_limits::max(), + std::numeric_limits::epsilon(), + std::numeric_limits::infinity(), + std::numeric_limits::quiet_NaN(), + }; + + std::locale::global(std::locale::classic()); + + for (auto v : values) + { + check_value(v); + check_value(-v); + } + + std::locale::global(std::locale(ISO_8859(15,de_DE))); + + for (auto v : values) + { + check_value(v); + check_value(-v); + } + + std::locale::global(std::locale::classic()); + } + +void test01() +{ + // Examples from P2587R3 `to_string` or not `to_string` + + + VERIFY( std::to_wstring(42) == L"42" ); + VERIFY( std::to_wstring(12345) == L"12345" ); + auto max = std::to_wstring(1.7976931348623157e+308); + +#if __cplusplus <= 202302L + VERIFY( std::to_wstring(0.42) == L"0.420000" ); + VERIFY( std::to_wstring(1e-7) == L"0.000000" ); + VERIFY( std::to_wstring(-1e-7) == L"-0.000000" ); + VERIFY( max.substr(0, 17) == L"17976931348623157" ); + VERIFY( max.substr(max.size() - 7) == L".000000" ); +#else + VERIFY( std::to_wstring(0.42) == L"0.42" ); + VERIFY( std::to_wstring(1e-7) == L"1e-07" ); + VERIFY( std::to_wstring(-1e-7) == L"-1e-07" ); + VERIFY( max == L"1.7976931348623157e+308" ); +#endif + + std::locale::global(std::locale(ISO_8859(15,de_DE))); +#if __cplusplus <= 202302L + VERIFY( std::to_wstring(1234.5) == L"1234,500000" ); +#else + VERIFY( std::to_wstring(1234.5) == L"1234.5" ); +#endif + std::locale::global(std::locale::classic()); +} + +void test02() +{ + check_values(); + check_values(); + check_values(); +} + +int main() +{ + test01(); + test02(); +} diff --git a/libstdc++-v3/testsuite/23_containers/array/tuple_interface/get_neg.cc b/libstdc++-v3/testsuite/23_containers/array/tuple_interface/get_neg.cc index 7d99b331fde5..889d4aa2e0b4 100644 --- a/libstdc++-v3/testsuite/23_containers/array/tuple_interface/get_neg.cc +++ b/libstdc++-v3/testsuite/23_containers/array/tuple_interface/get_neg.cc @@ -26,6 +26,6 @@ int n1 = std::get<1>(a); int n2 = std::get<1>(std::move(a)); int n3 = std::get<1>(ca); -// { dg-error "static assertion failed" "" { target *-*-* } 386 } -// { dg-error "static assertion failed" "" { target *-*-* } 395 } -// { dg-error "static assertion failed" "" { target *-*-* } 404 } +// { dg-error "static assertion failed" "" { target *-*-* } 389 } +// { dg-error "static assertion failed" "" { target *-*-* } 398 } +// { dg-error "static assertion failed" "" { target *-*-* } 407 } diff --git a/libstdc++-v3/testsuite/23_containers/deque/requirements/explicit_instantiation/2.cc b/libstdc++-v3/testsuite/23_containers/deque/requirements/explicit_instantiation/2.cc index 3afa9fb4403f..6e6ceabad21f 100644 --- a/libstdc++-v3/testsuite/23_containers/deque/requirements/explicit_instantiation/2.cc +++ b/libstdc++-v3/testsuite/23_containers/deque/requirements/explicit_instantiation/2.cc @@ -21,6 +21,7 @@ #include #include +// { dg-options "-std=gnu++98" } // { dg-do compile { target c++98_only } } // N.B. Since C++11 we cannot instantiate with T == NonDefaultConstructible diff --git a/libstdc++-v3/testsuite/23_containers/list/requirements/explicit_instantiation/2.cc b/libstdc++-v3/testsuite/23_containers/list/requirements/explicit_instantiation/2.cc index b8f393983b1f..463ec507bd94 100644 --- a/libstdc++-v3/testsuite/23_containers/list/requirements/explicit_instantiation/2.cc +++ b/libstdc++-v3/testsuite/23_containers/list/requirements/explicit_instantiation/2.cc @@ -21,6 +21,7 @@ #include #include +// { dg-options "-std=gnu++98" } // { dg-do compile { target c++98_only } } // N.B. Since C++11 we cannot instantiate with T == NonDefaultConstructible diff --git a/libstdc++-v3/testsuite/23_containers/unordered_map/96088.cc b/libstdc++-v3/testsuite/23_containers/unordered_map/96088.cc index c6d50c20fbf6..cdf00c93d80e 100644 --- a/libstdc++-v3/testsuite/23_containers/unordered_map/96088.cc +++ b/libstdc++-v3/testsuite/23_containers/unordered_map/96088.cc @@ -268,6 +268,7 @@ test03() int main() { + __gnu_test::counter::scope s; test01(); test02(); test11(); diff --git a/libstdc++-v3/testsuite/23_containers/unordered_multimap/96088.cc b/libstdc++-v3/testsuite/23_containers/unordered_multimap/96088.cc index 214bc91a559a..d8b9a40c1746 100644 --- a/libstdc++-v3/testsuite/23_containers/unordered_multimap/96088.cc +++ b/libstdc++-v3/testsuite/23_containers/unordered_multimap/96088.cc @@ -61,6 +61,7 @@ test02() int main() { + __gnu_test::counter::scope s; test01(); test02(); return 0; diff --git a/libstdc++-v3/testsuite/23_containers/unordered_multiset/96088.cc b/libstdc++-v3/testsuite/23_containers/unordered_multiset/96088.cc index 838ce8d5bc53..db17cda0ddd8 100644 --- a/libstdc++-v3/testsuite/23_containers/unordered_multiset/96088.cc +++ b/libstdc++-v3/testsuite/23_containers/unordered_multiset/96088.cc @@ -61,6 +61,7 @@ test02() int main() { + __gnu_test::counter::scope s; test01(); test02(); return 0; diff --git a/libstdc++-v3/testsuite/23_containers/unordered_set/96088.cc b/libstdc++-v3/testsuite/23_containers/unordered_set/96088.cc index 0f7dce2b38c5..831f2aa1210c 100644 --- a/libstdc++-v3/testsuite/23_containers/unordered_set/96088.cc +++ b/libstdc++-v3/testsuite/23_containers/unordered_set/96088.cc @@ -269,6 +269,7 @@ test03() int main() { + __gnu_test::counter::scope s; test01(); test02(); test11(); diff --git a/libstdc++-v3/testsuite/23_containers/vector/26412-1.cc b/libstdc++-v3/testsuite/23_containers/vector/26142-1.cc similarity index 92% rename from libstdc++-v3/testsuite/23_containers/vector/26412-1.cc rename to libstdc++-v3/testsuite/23_containers/vector/26142-1.cc index 943032c2377c..2c078c7a04dc 100644 --- a/libstdc++-v3/testsuite/23_containers/vector/26412-1.cc +++ b/libstdc++-v3/testsuite/23_containers/vector/26142-1.cc @@ -21,7 +21,7 @@ #include -// libstdc++26412 +// PR libstdc++/26142 global debug namespace clashes everywhere namespace debug { int i; diff --git a/libstdc++-v3/testsuite/23_containers/vector/26412-2.cc b/libstdc++-v3/testsuite/23_containers/vector/26142-2.cc similarity index 92% rename from libstdc++-v3/testsuite/23_containers/vector/26412-2.cc rename to libstdc++-v3/testsuite/23_containers/vector/26142-2.cc index 807f6075ab7a..d4a5fe422749 100644 --- a/libstdc++-v3/testsuite/23_containers/vector/26412-2.cc +++ b/libstdc++-v3/testsuite/23_containers/vector/26142-2.cc @@ -23,4 +23,4 @@ #include -// libstdc++26412 +// PR libstdc++/26142 global debug namespace clashes everywhere diff --git a/libstdc++-v3/testsuite/24_iterators/move_iterator/p2520r0.cc b/libstdc++-v3/testsuite/24_iterators/move_iterator/p2520r0.cc index 883d6cc09e00..e36ac574a8ec 100644 --- a/libstdc++-v3/testsuite/24_iterators/move_iterator/p2520r0.cc +++ b/libstdc++-v3/testsuite/24_iterators/move_iterator/p2520r0.cc @@ -1,5 +1,6 @@ // { dg-options "-std=gnu++20" } // { dg-do compile { target c++20 } } +// { dg-add-options no_pch } // Verify P2520R0 changes to move_iterator's iterator_concept, which we treat // as a DR against C++20. diff --git a/libstdc++-v3/testsuite/25_algorithms/copy/debug/constexpr_neg.cc b/libstdc++-v3/testsuite/25_algorithms/copy/debug/constexpr_neg.cc index 6981c4706661..bf3c4939bfb7 100644 --- a/libstdc++-v3/testsuite/25_algorithms/copy/debug/constexpr_neg.cc +++ b/libstdc++-v3/testsuite/25_algorithms/copy/debug/constexpr_neg.cc @@ -34,6 +34,7 @@ test1() } static_assert(test1()); // { dg-error "non-constant condition" } +// { dg-error "builtin_unreachable" "" { target *-*-* } 0 } constexpr bool test2() @@ -46,8 +47,5 @@ test2() return out6 == ma0.begin() + 18; } -static_assert(test2()); // { dg-error "is outside the bounds" } - -// { dg-prune-output "in 'constexpr' expansion" } -// { dg-prune-output "builtin_unreachable" } -// { dg-prune-output "non-constant condition" } +static_assert(test2()); // { dg-error "non-constant condition" } +// { dg-error "is outside the bounds" "" { target *-*-* } 0 } diff --git a/libstdc++-v3/testsuite/25_algorithms/equal/debug/constexpr_neg.cc b/libstdc++-v3/testsuite/25_algorithms/equal/debug/constexpr_neg.cc index bb613bef03b4..f5e46e58e496 100644 --- a/libstdc++-v3/testsuite/25_algorithms/equal/debug/constexpr_neg.cc +++ b/libstdc++-v3/testsuite/25_algorithms/equal/debug/constexpr_neg.cc @@ -32,7 +32,8 @@ test01() return outa; } -static_assert(test01()); // { dg-error } +static_assert(test01()); // { dg-error "non-constant condition" } +// { dg-error "builtin_unreachable" "" { target *-*-* } 0 } constexpr bool test02() @@ -44,8 +45,5 @@ test02() return outa; } -static_assert(test02()); // { dg-error "outside the bounds" } - -// { dg-prune-output "non-constant condition" } -// { dg-prune-output "in 'constexpr'" } -// { dg-prune-output "builtin_unreachable" } +static_assert(test02()); // { dg-error "non-constant condition" } +// { dg-error "is outside the bounds" "" { target *-*-* } 0 } diff --git a/libstdc++-v3/testsuite/25_algorithms/pstl/alg_sorting/set_difference.cc b/libstdc++-v3/testsuite/25_algorithms/pstl/alg_sorting/set_difference.cc index a05fad8c47e4..3849c73b734f 100644 --- a/libstdc++-v3/testsuite/25_algorithms/pstl/alg_sorting/set_difference.cc +++ b/libstdc++-v3/testsuite/25_algorithms/pstl/alg_sorting/set_difference.cc @@ -12,7 +12,7 @@ // //===----------------------------------------------------------------------===// -// Note: This file was derived from set.pass.cc which is part of the upstream +// Note: This file was derived from set.pass.cpp which is part of the upstream // source. #include "pstl/pstl_test_config.h" diff --git a/libstdc++-v3/testsuite/25_algorithms/pstl/alg_sorting/set_intersection.cc b/libstdc++-v3/testsuite/25_algorithms/pstl/alg_sorting/set_intersection.cc index 4d63fa14da67..8e34c135279d 100644 --- a/libstdc++-v3/testsuite/25_algorithms/pstl/alg_sorting/set_intersection.cc +++ b/libstdc++-v3/testsuite/25_algorithms/pstl/alg_sorting/set_intersection.cc @@ -12,7 +12,7 @@ // //===----------------------------------------------------------------------===// -// Note: This file was derived from set.pass.cc which is part of the upstream +// Note: This file was derived from set.pass.cpp which is part of the upstream // source. #include "pstl/pstl_test_config.h" diff --git a/libstdc++-v3/testsuite/25_algorithms/pstl/alg_sorting/set_symmetric_difference.cc b/libstdc++-v3/testsuite/25_algorithms/pstl/alg_sorting/set_symmetric_difference.cc index aaa52f8089d0..1cc598560865 100644 --- a/libstdc++-v3/testsuite/25_algorithms/pstl/alg_sorting/set_symmetric_difference.cc +++ b/libstdc++-v3/testsuite/25_algorithms/pstl/alg_sorting/set_symmetric_difference.cc @@ -12,7 +12,7 @@ // //===----------------------------------------------------------------------===// -// Note: This file was derived from set.pass.cc which is part of the upstream +// Note: This file was derived from set.pass.cpp which is part of the upstream // source. #include "pstl/pstl_test_config.h" diff --git a/libstdc++-v3/testsuite/25_algorithms/pstl/alg_sorting/set_union.cc b/libstdc++-v3/testsuite/25_algorithms/pstl/alg_sorting/set_union.cc index 85cde6b0b413..2ea9c9a8a52b 100644 --- a/libstdc++-v3/testsuite/25_algorithms/pstl/alg_sorting/set_union.cc +++ b/libstdc++-v3/testsuite/25_algorithms/pstl/alg_sorting/set_union.cc @@ -12,7 +12,7 @@ // //===----------------------------------------------------------------------===// -// Note: This file was derived from set.pass.cc which is part of the upstream +// Note: This file was derived from set.pass.cpp which is part of the upstream // source. #include "pstl/pstl_test_config.h" diff --git a/libstdc++-v3/testsuite/25_algorithms/pstl/alg_sorting/set_util.h b/libstdc++-v3/testsuite/25_algorithms/pstl/alg_sorting/set_util.h index cd54fc7a6a3a..ecf5cd1c89db 100644 --- a/libstdc++-v3/testsuite/25_algorithms/pstl/alg_sorting/set_util.h +++ b/libstdc++-v3/testsuite/25_algorithms/pstl/alg_sorting/set_util.h @@ -8,7 +8,7 @@ // //===----------------------------------------------------------------------===// -// Note: This file was derived from set.pass.cc which is part of the upstream +// Note: This file was derived from set.pass.cpp which is part of the upstream // source. #ifndef __PSTL_TEST_SET_UTIL_H diff --git a/libstdc++-v3/testsuite/26_numerics/complex/56111.cc b/libstdc++-v3/testsuite/26_numerics/complex/56111.cc index e583b190ee19..0237ed356e12 100644 --- a/libstdc++-v3/testsuite/26_numerics/complex/56111.cc +++ b/libstdc++-v3/testsuite/26_numerics/complex/56111.cc @@ -1,5 +1,5 @@ -// { dg-do compile } // { dg-options "-std=c++98" } +// { dg-do compile { target c++98_only } } // Copyright (C) 2013-2023 Free Software Foundation, Inc. // diff --git a/libstdc++-v3/testsuite/26_numerics/complex/literals/types.cc b/libstdc++-v3/testsuite/26_numerics/complex/literals/types.cc index 5cc46d741ef7..69c6781d7399 100644 --- a/libstdc++-v3/testsuite/26_numerics/complex/literals/types.cc +++ b/libstdc++-v3/testsuite/26_numerics/complex/literals/types.cc @@ -1,7 +1,4 @@ -// Use -std=c++14 explicitly, because -std=gnu++14 enables GNU extension for -// complex literals, so 1.0if is __complex__ float not std::complex. -// { dg-options "-std=c++14" } -// { dg-do compile } +// { dg-do compile { target c++14 } } // Copyright (C) 2013-2023 Free Software Foundation, Inc. // diff --git a/libstdc++-v3/testsuite/27_io/filesystem/iterators/91067.cc b/libstdc++-v3/testsuite/27_io/filesystem/iterators/91067.cc index b960ee7c798e..2bf1e081c25b 100644 --- a/libstdc++-v3/testsuite/27_io/filesystem/iterators/91067.cc +++ b/libstdc++-v3/testsuite/27_io/filesystem/iterators/91067.cc @@ -17,6 +17,7 @@ // { dg-do link { target c++17 } } // { dg-require-filesystem-ts "" } +// { dg-options "-Wno-self-move" } #include diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/108636.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/108636.cc index d58de461090d..73742df93b05 100644 --- a/libstdc++-v3/testsuite/27_io/filesystem/path/108636.cc +++ b/libstdc++-v3/testsuite/27_io/filesystem/path/108636.cc @@ -1,5 +1,6 @@ // { dg-do link { target c++17 } } // { dg-options "-fkeep-inline-functions" } +// { dg-require-filesystem-ts "" } #include int main() diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/assign/copy.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/assign/copy.cc index dc147b1cf3bd..6ec347531bcb 100644 --- a/libstdc++-v3/testsuite/27_io/filesystem/path/assign/copy.cc +++ b/libstdc++-v3/testsuite/27_io/filesystem/path/assign/copy.cc @@ -1,4 +1,5 @@ // { dg-do run { target c++17 } } +// { dg-options "-Wno-self-move" } // Copyright (C) 2014-2023 Free Software Foundation, Inc. // diff --git a/libstdc++-v3/testsuite/29_atomics/atomic_ref/compare_exchange_padding.cc b/libstdc++-v3/testsuite/29_atomics/atomic_ref/compare_exchange_padding.cc index e9f8a4bdf2ac..0dab8a23e109 100644 --- a/libstdc++-v3/testsuite/29_atomics/atomic_ref/compare_exchange_padding.cc +++ b/libstdc++-v3/testsuite/29_atomics/atomic_ref/compare_exchange_padding.cc @@ -6,39 +6,68 @@ #include -struct S { char c; short s; }; +struct S +{ + char c; + alignas(2) short s; +}; void __attribute__((noinline,noipa)) -fill_struct(S& s) -{ __builtin_memset(&s, 0xff, sizeof(S)); } +set_padding(S& s, unsigned char x) +{ reinterpret_cast(&s)[1] = x; } -bool -compare_struct(const S& a, const S& b) -{ return __builtin_memcmp(&a, &b, sizeof(S)) == 0; } +unsigned char __attribute__((noinline,noipa)) +get_padding(S& s) +{ return reinterpret_cast(&s)[1]; } -int -main () +void +test01() { S s; - S ss{ s }; - fill_struct(ss); + S ss; ss.c = 'a'; ss.s = 42; + set_padding(ss, 0xff); - std::atomic_ref as{ s }; - as.store(ss); - auto ts = as.load(); - VERIFY( !compare_struct(ss, ts) ); // padding cleared on store - as.exchange(ss); - auto es = as.load(); - VERIFY( compare_struct(ts, es) ); // padding cleared on exchange + { + std::atomic_ref as{ s }; + as.store(ss); // copy value bits, clear padding bits + } + VERIFY( get_padding(s) == 0 ); // padding was cleared on store + ss.c = 'b'; + set_padding(ss, 0x11); + VERIFY( get_padding(ss) == 0x11 ); + { + std::atomic_ref as{ s }; + as.exchange(ss); // copy value bits, clear padding bits + } + VERIFY( get_padding(s) == 0 ); // padding was cleared on store + + S exp = s; + set_padding(exp, 0xaa); + set_padding(s, 0xbb); S n; - fill_struct(n); - n.c = 'b'; + n.c = 'c'; n.s = 71; - // padding cleared on compexchg - VERIFY( as.compare_exchange_weak(s, n) ); - VERIFY( as.compare_exchange_strong(n, s) ); - return 0; + set_padding(n, 0xcc); + + // padding cleared on cmpexchg + { + std::atomic_ref as{ s }; + // This assumes no spurious failures, hopefully true without contention. + VERIFY( as.compare_exchange_weak(exp, n) ); // padding in exp ignored + } + VERIFY( get_padding(s) == 0 ); // padding in n was not copied to s + + { + std::atomic_ref as{ s }; + VERIFY( as.compare_exchange_strong(n, exp) ); // padding in n ignored + } + VERIFY( get_padding(s) == 0 ); // padding in exp was not copied to s +} + +int main() +{ + test01(); } diff --git a/libstdc++-v3/testsuite/ext/malloc_allocator/deallocate_local.cc b/libstdc++-v3/testsuite/ext/malloc_allocator/deallocate_local.cc index 79b583bd716c..29eb4032ad9b 100644 --- a/libstdc++-v3/testsuite/ext/malloc_allocator/deallocate_local.cc +++ b/libstdc++-v3/testsuite/ext/malloc_allocator/deallocate_local.cc @@ -27,6 +27,7 @@ typedef std::basic_string string_t; int main() { + __gnu_test::counter::scope s; { string_t s; s += "bayou bend"; @@ -34,5 +35,6 @@ int main() if (__gnu_test::counter::count() != 0) throw std::runtime_error("count not zero"); + return 0; } diff --git a/libstdc++-v3/testsuite/ext/new_allocator/deallocate_local.cc b/libstdc++-v3/testsuite/ext/new_allocator/deallocate_local.cc index fcde46e6e10c..e4a94604f438 100644 --- a/libstdc++-v3/testsuite/ext/new_allocator/deallocate_local.cc +++ b/libstdc++-v3/testsuite/ext/new_allocator/deallocate_local.cc @@ -27,6 +27,7 @@ typedef std::basic_string string_t; int main() { + __gnu_test::counter::scope s; { string_t s; s += "bayou bend"; @@ -34,5 +35,6 @@ int main() if (__gnu_test::counter::count() != 0) throw std::runtime_error("count not zero"); + return 0; } diff --git a/libstdc++-v3/testsuite/ext/pool_allocator/allocate_chunk.cc b/libstdc++-v3/testsuite/ext/pool_allocator/allocate_chunk.cc index 17f8e3c7dcbc..b11b450bf9e3 100644 --- a/libstdc++-v3/testsuite/ext/pool_allocator/allocate_chunk.cc +++ b/libstdc++-v3/testsuite/ext/pool_allocator/allocate_chunk.cc @@ -32,16 +32,29 @@ struct big char c[64]; }; +bool started = false; + void* operator new(size_t n) THROW(std::bad_alloc) { - static bool first = true; - if (!first) - throw std::bad_alloc(); - first = false; + if (started) + { + static bool first = true; + if (!first) + throw std::bad_alloc(); + first = false; + } + return std::malloc(n); } +void +operator delete(void* p) throw() +{ + if (p) + std::free(p); +} + // http://gcc.gnu.org/ml/libstdc++/2004-10/msg00098.html void test01() { @@ -59,5 +72,7 @@ void test01() int main() { + started = true; test01(); + started = false; } diff --git a/libstdc++-v3/testsuite/ext/throw_allocator/deallocate_local.cc b/libstdc++-v3/testsuite/ext/throw_allocator/deallocate_local.cc index c6fd3538b825..2a675e8b6b47 100644 --- a/libstdc++-v3/testsuite/ext/throw_allocator/deallocate_local.cc +++ b/libstdc++-v3/testsuite/ext/throw_allocator/deallocate_local.cc @@ -30,6 +30,7 @@ typedef std::basic_string string_t; int main() { + __gnu_test::counter::scope s; { string_t s; s += "bayou bend"; diff --git a/libstdc++-v3/testsuite/lib/dg-options.exp b/libstdc++-v3/testsuite/lib/dg-options.exp index 73c1552e682d..15e34f8a6461 100644 --- a/libstdc++-v3/testsuite/lib/dg-options.exp +++ b/libstdc++-v3/testsuite/lib/dg-options.exp @@ -269,8 +269,10 @@ proc dg-require-target-fs-lwt { args } { } proc add_options_for_no_pch { flags } { + # Remove any inclusion of bits/stdc++.h from the options. + regsub -all -- "-include bits/stdc...h" $flags "" flags # This forces any generated and possibly included PCH to be invalid. - return "-D__GLIBCXX__=99999999" + return "$flags -D__GLIBCXX__=99999999" } # Add to FLAGS all the target-specific flags needed for networking. diff --git a/libstdc++-v3/testsuite/libstdc++-prettyprinters/chrono.cc b/libstdc++-v3/testsuite/libstdc++-prettyprinters/chrono.cc index b5314e025cce..9aa284aea2f3 100644 --- a/libstdc++-v3/testsuite/libstdc++-prettyprinters/chrono.cc +++ b/libstdc++-v3/testsuite/libstdc++-prettyprinters/chrono.cc @@ -75,6 +75,13 @@ main() [[maybe_unused]] year_month_weekday_last donnerstag = 2017y/July/Thursday[last]; // { dg-final { note-test donnerstag {2017y/July/Thursday[last]} } } + [[maybe_unused]] month nam(13); + // { dg-final { note-test nam {13 is not a valid month} } } + [[maybe_unused]] month nam0(0); + // { dg-final { note-test nam0 {0 is not a valid month} } } + [[maybe_unused]] weekday nawd(8); + // { dg-final { note-test nawd {8 is not a valid weekday} } } + // hh_mm_ss hms(4h + 3min + 2s); // { dg-final { note-test hms {04:03:02} } } diff --git a/libstdc++-v3/testsuite/libstdc++-prettyprinters/compat.cc b/libstdc++-v3/testsuite/libstdc++-prettyprinters/compat.cc index 34022cf1459a..acc20a30d8e7 100644 --- a/libstdc++-v3/testsuite/libstdc++-prettyprinters/compat.cc +++ b/libstdc++-v3/testsuite/libstdc++-prettyprinters/compat.cc @@ -102,13 +102,13 @@ main() using std::optional; optional o; -// { dg-final { note-test o {std::optional [no contained value]} } } +// { dg-final { note-test o {std::optional [no contained value]} } } optional ob{false}; -// { dg-final { note-test ob {std::optional = {[contained value] = false}} } } +// { dg-final { note-test ob {std::optional = {[contained value] = false}} } } optional oi{5}; -// { dg-final { note-test oi {std::optional = {[contained value] = 5}} } } +// { dg-final { note-test oi {std::optional = {[contained value] = 5}} } } optional op{nullptr}; -// { dg-final { note-test op {std::optional = {[contained value] = 0x0}} } } +// { dg-final { note-test op {std::optional = {[contained value] = 0x0}} } } __builtin_puts(""); return 0; // Mark SPOT diff --git a/libstdc++-v3/testsuite/libstdc++-prettyprinters/cxx17.cc b/libstdc++-v3/testsuite/libstdc++-prettyprinters/cxx17.cc index 3962a5e9b7ef..eb8dc957a43e 100644 --- a/libstdc++-v3/testsuite/libstdc++-prettyprinters/cxx17.cc +++ b/libstdc++-v3/testsuite/libstdc++-prettyprinters/cxx17.cc @@ -50,18 +50,18 @@ main() // { dg-final { note-test str "\"string\"" } } optional o; -// { dg-final { note-test o {std::optional [no contained value]} } } +// { dg-final { note-test o {std::optional [no contained value]} } } optional ob{false}; -// { dg-final { note-test ob {std::optional = {[contained value] = false}} } } +// { dg-final { note-test ob {std::optional = {[contained value] = false}} } } optional oi{5}; -// { dg-final { note-test oi {std::optional = {[contained value] = 5}} } } +// { dg-final { note-test oi {std::optional = {[contained value] = 5}} } } optional op{nullptr}; -// { dg-final { note-test op {std::optional = {[contained value] = 0x0}} } } +// { dg-final { note-test op {std::optional = {[contained value] = 0x0}} } } optional> om; om = std::map{ {1, 2.}, {3, 4.}, {5, 6.} }; -// { dg-final { regexp-test om {std::optional> containing std::(__debug::)?map with 3 elements = {\[1\] = 2, \[3\] = 4, \[5\] = 6}} } } +// { dg-final { regexp-test om {std::optional containing std::(__debug::)?map with 3 elements = {\[1\] = 2, \[3\] = 4, \[5\] = 6}} } } optional os{ "stringy" }; -// { dg-final { note-test os {std::optional = {[contained value] = "stringy"}} } } +// { dg-final { note-test os {std::optional = {[contained value] = "stringy"}} } } any a; // { dg-final { note-test a {std::any [no contained value]} } } @@ -83,18 +83,18 @@ main() struct S { operator int() { throw 42; }}; variant v0; -// { dg-final { note-test v0 {std::variant [index 0] = {0}} } } +// { dg-final { note-test v0 {std::variant [index 0] = {0}} } } variant v1{ 0.5f }; -// { dg-final { note-test v1 {std::variant [index 0] = {0.5}} } } +// { dg-final { note-test v1 {std::variant [index 0] = {0.5}} } } variant v2; try { v2.emplace<1>(S()); } catch (int) { } -// { dg-final { note-test v2 {std::variant [no contained value]} } } +// { dg-final { note-test v2 {std::variant [no contained value]} } } variant v3{ 3 }; -// { dg-final { note-test v3 {std::variant [index 1] = {3}} } } +// { dg-final { note-test v3 {std::variant [index 1] = {3}} } } variant v4{ str }; -// { dg-final { note-test v4 {std::variant [index 2] = {"string"}} } } +// { dg-final { note-test v4 {std::variant [index 2] = {"string"}} } } map m{ {1, "one"} }; map::node_type n0; diff --git a/libstdc++-v3/testsuite/libstdc++-prettyprinters/libfundts.cc b/libstdc++-v3/testsuite/libstdc++-prettyprinters/libfundts.cc index 29e8bc8f194e..8f70f3fd1516 100644 --- a/libstdc++-v3/testsuite/libstdc++-prettyprinters/libfundts.cc +++ b/libstdc++-v3/testsuite/libstdc++-prettyprinters/libfundts.cc @@ -42,18 +42,18 @@ main() // { dg-final { note-test str "\"string\"" } } optional o; -// { dg-final { note-test o {std::experimental::optional [no contained value]} } } +// { dg-final { note-test o {std::experimental::optional [no contained value]} } } optional ob{false}; -// { dg-final { note-test ob {std::experimental::optional = {[contained value] = false}} } } +// { dg-final { note-test ob {std::experimental::optional = {[contained value] = false}} } } optional oi{5}; -// { dg-final { note-test oi {std::experimental::optional = {[contained value] = 5}} } } +// { dg-final { note-test oi {std::experimental::optional = {[contained value] = 5}} } } optional op{nullptr}; -// { dg-final { note-test op {std::experimental::optional = {[contained value] = 0x0}} } } +// { dg-final { note-test op {std::experimental::optional = {[contained value] = 0x0}} } } optional> om; om = std::map{ {1, 2.}, {3, 4.}, {5, 6.} }; -// { dg-final { regexp-test om {std::experimental::optional> containing std::(__debug::)?map with 3 elements = {\[1\] = 2, \[3\] = 4, \[5\] = 6}} } } +// { dg-final { regexp-test om {std::experimental::optional containing std::(__debug::)?map with 3 elements = {\[1\] = 2, \[3\] = 4, \[5\] = 6}} } } optional os{ "stringy" }; -// { dg-final { note-test os {std::experimental::optional = {[contained value] = "stringy"}} } } +// { dg-final { note-test os {std::experimental::optional = {[contained value] = "stringy"}} } } any a; // { dg-final { note-test a {std::experimental::any [no contained value]} } } diff --git a/libstdc++-v3/testsuite/libstdc++-prettyprinters/locale.cc b/libstdc++-v3/testsuite/libstdc++-prettyprinters/locale.cc new file mode 100644 index 000000000000..66d42f994327 --- /dev/null +++ b/libstdc++-v3/testsuite/libstdc++-prettyprinters/locale.cc @@ -0,0 +1,36 @@ +// { dg-do run } +// { dg-options "-g -O0" } +// { dg-require-namedlocale "fr_FR.ISO8859-15" } +// { dg-require-namedlocale "de_DE.ISO8859-15" } +// { dg-require-namedlocale "en_US.ISO8859-1" } + +#include +#include // for ISO_8859 macro + +int main() +{ + std::locale l1 = std::locale::classic(); +// { dg-final { note-test l1 {std::locale = "C"} } } + + std::locale l2(ISO_8859(15,fr_FR)); +// { dg-final { regexp-test l2 {std::locale = "fr_FR.ISO8859-15(@euro)?"} } } + + std::locale l3(l2, ISO_8859(15,de_DE), std::locale::time); +// { dg-final { regexp-test l3 {std::locale = "fr_FR.ISO8859-15(@euro)?" with "LC_TIME=de_DE.ISO8859-15(@euro)?"} } } + + std::locale l4(l3, ISO_8859(1,en_US), std::locale::monetary); +// We don't know which order the categories will occur in the string, +// so test three times, checking for the required substring each time: +// { dg-final { regexp-test l4 {std::locale = "(.*;)?LC_CTYPE=fr_FR.ISO8859-15(@euro)?(;.*)?"} } } + std::locale l5 = l4; +// { dg-final { regexp-test l5 {std::locale = "(.*;)?LC_TIME=de_DE.ISO8859-15(@euro)?(;.*)?"} } } + std::locale l6 = l5; +// { dg-final { regexp-test l6 {std::locale = "(.*;)?LC_MONETARY=en_US.ISO8859-1(;.*)?"} } } + + std::locale l7(l1, &std::use_facet >(l1)); +// { dg-final { regexp-test l7 {std::locale = "\*"} } } + + return 0; // Mark SPOT +} + +// { dg-final { gdb-test SPOT } } diff --git a/libstdc++-v3/testsuite/std/format/formatter/ext_float.cc b/libstdc++-v3/testsuite/std/format/formatter/ext_float.cc new file mode 100644 index 000000000000..89810295b643 --- /dev/null +++ b/libstdc++-v3/testsuite/std/format/formatter/ext_float.cc @@ -0,0 +1,92 @@ +// { dg-options "-std=gnu++20" } +// { dg-do run { target c++20 } } + +#include +#include + +template +bool format_float() +{ + auto s = std::format("{:#} != {:<+7.3f}", (T)-0.0, (T)0.5); + return s == "-0. != +0.500 "; +} + +#if __cplusplus > 202002L +template +concept formattable = std::formattable; +#else +template +concept formattable = std::semiregular>; +#endif + +void +test_float16() +{ +#if __FLT16_DIG__ + if constexpr (formattable<_Float16>) + VERIFY( format_float<_Float16>() ); + else + std::puts("Cannot format _Float16 on this target"); +#endif +} + +void +test_float32() +{ +#if __FLT32_DIG__ + if constexpr (formattable<_Float32>) + VERIFY( format_float<_Float32>() ); + else + std::puts("Cannot format _Float32 on this target"); +#endif +} + +void +test_float64() +{ +#if __FLT64_DIG__ + if constexpr (formattable<_Float64>) + VERIFY( format_float<_Float64>() ); + else + std::puts("Cannot format _Float64 on this target"); +#endif +} + +void +test_float128() +{ +#ifdef __SIZEOF_FLOAT128__ + if constexpr (formattable<__float128>) + VERIFY( format_float<__float128>() ); + else + std::puts("Cannot format __float128 on this target"); +#endif +#if __FLT128_DIG__ + if constexpr (formattable<_Float128>) + VERIFY( format_float<_Float128>() ); + else + std::puts("Cannot format _Float128 on this target"); +#endif +} + +void +test_bfloat16() +{ +#if __BFLT16_DIG__ + using bfloat16_t = decltype(0.0bf16); + + if constexpr (formattable) + VERIFY( format_float() ); + else + std::puts("Cannot format bfloat16_t on this target"); +#endif +} + +int main() +{ + test_float16(); + test_float32(); + test_float64(); + test_float128(); + test_bfloat16(); +} diff --git a/libstdc++-v3/testsuite/std/format/functions/format.cc b/libstdc++-v3/testsuite/std/format/functions/format.cc index bd914df6d7c8..5141cbd11bf5 100644 --- a/libstdc++-v3/testsuite/std/format/functions/format.cc +++ b/libstdc++-v3/testsuite/std/format/functions/format.cc @@ -1,5 +1,6 @@ // { dg-options "-std=gnu++20" } // { dg-do run { target c++20 } } +// { dg-add-options no_pch } #include @@ -158,6 +159,18 @@ test_alternate_forms() VERIFY( s == "1.e+01 1.e+01 1.e+01" ); } +void +test_infnan() +{ + double inf = std::numeric_limits::infinity(); + double nan = std::numeric_limits::quiet_NaN(); + std::string s; + s = std::format("{0} {0:e} {0:E} {0:f} {0:F} {0:g} {0:G} {0:a} {0:A}", inf); + VERIFY( s == "inf inf INF inf INF inf INF inf INF" ); + s = std::format("{0} {0:e} {0:E} {0:f} {0:F} {0:g} {0:G} {0:a} {0:A}", nan); + VERIFY( s == "nan nan NAN nan NAN nan NAN nan NAN" ); +} + struct euro_punc : std::numpunct { std::string do_grouping() const override { return "\3\3"; } @@ -197,6 +210,9 @@ test_locale() s = std::format(eloc, "{0:#Lg} {0:+#.3Lg} {0:#08.4Lg}", -1234.); VERIFY( s == "-1.234,00 -1,23e+03 -01.234," ); + s = std::format(cloc, "{:05L}", -1.0); // PR libstdc++/110968 + VERIFY( s == "-0001" ); + // Restore std::locale::global(cloc); } @@ -253,6 +269,21 @@ test_wchar() std::locale loc; s = std::format(loc, L"{:L} {:.3s}{:Lc}", true, L"data"sv, '.'); VERIFY( s == L"true dat." ); + + s = std::format(L"{}", 0.0625); + VERIFY( s == L"0.0625" ); + s = std::format(L"{}", 0.25); + VERIFY( s == L"0.25" ); + s = std::format(L"{:+a} {:A}", 0x1.23p45, -0x1.abcdefp-15); + VERIFY( s == L"+1.23p+45 -1.ABCDEFP-15" ); + + double inf = std::numeric_limits::infinity(); + double nan = std::numeric_limits::quiet_NaN(); + s = std::format(L"{0} {0:F} {1} {1:E}", -inf, -nan); + VERIFY( s == L"-inf -INF -nan -NAN" ); + + s = std::format(L"{0:#b} {0:#B} {0:#x} {0:#X}", 99); + VERIFY( s == L"0b1100011 0B1100011 0x63 0X63" ); } void @@ -316,38 +347,6 @@ test_p1652r1() // printf corner cases in std::format VERIFY( s == "3.31" ); } -template -bool format_float() -{ - auto s = std::format("{:#} != {:<+7.3f}", (T)-0.0, (T)0.5); - return s == "-0. != +0.500 "; -} - -#if __cplusplus > 202002L -template -concept formattable = std::formattable; -#else -template -concept formattable = requires (T t, char* p) { std::to_chars(p, p, t); }; -#endif - -void -test_float128() -{ -#ifdef __SIZEOF_FLOAT128__ - if constexpr (formattable<__float128>) - VERIFY( format_float<__float128>() ); - else - std::puts("Cannot format __float128 on this target"); -#endif -#if __FLT128_DIG__ - if constexpr (formattable<_Float128>) - VERIFY( format_float<_Float128>() ); - else - std::puts("Cannot format _Float128 on this target"); -#endif -} - void test_pointer() { @@ -398,6 +397,5 @@ int main() test_wchar(); test_minmax(); test_p1652r1(); - test_float128(); test_pointer(); } diff --git a/libstdc++-v3/testsuite/std/format/functions/format_c++23.cc b/libstdc++-v3/testsuite/std/format/functions/format_c++23.cc new file mode 100644 index 000000000000..3caa70fcdf2d --- /dev/null +++ b/libstdc++-v3/testsuite/std/format/functions/format_c++23.cc @@ -0,0 +1,5 @@ +// { dg-do run { target c++23 } } +// { dg-add-options no_pch } +// This test does not have -std=gnu++20 in dg-options so that format.cc +// can be tested for e.g. -std=c++26 +#include "format.cc" diff --git a/libstdc++-v3/testsuite/std/format/functions/format_to.cc b/libstdc++-v3/testsuite/std/format/functions/format_to.cc new file mode 100644 index 000000000000..c5c3c503625c --- /dev/null +++ b/libstdc++-v3/testsuite/std/format/functions/format_to.cc @@ -0,0 +1,100 @@ +// { dg-options "-std=gnu++20" } +// { dg-do run { target c++20 } } + +#include +#include +#include +#include +#include + +struct punct : std::numpunct +{ + std::string do_grouping() const override { return "\2"; } +}; + +void +test() +{ + char buf[32] = { }; + auto out = std::format_to(buf, "test"); + VERIFY( out == buf+4 ); + + std::locale loc({}, new punct); + auto out2 = std::format_to(buf, loc, "{:Ld}", 12345); + VERIFY( out2 == buf+7 ); + VERIFY( std::string_view(buf, out2 - buf) == "1,23,45" ); +} + +struct wpunct : std::numpunct +{ + std::string do_grouping() const override { return "\2"; } +}; + +void +test_wchar() +{ + wchar_t buf[32] = { }; + auto out = std::format_to(buf, L"123 + 456 = {}", 579); + VERIFY( out == buf+15 ); + + std::locale loc({}, new wpunct); + auto out2 = std::format_to(buf, loc, L"{:Ld}", 12345); + VERIFY( out2 == buf+7 ); + VERIFY( std::wstring_view(buf, out2 - buf) == L"1,23,45" ); +} + +template +struct move_only_iterator +{ + using iterator = I; + using value_type = iterator::value_type; + using difference_type = iterator::difference_type; + using iterator_category = std::output_iterator_tag; + + move_only_iterator(iterator b) : base_(b) { } + move_only_iterator(move_only_iterator&&) = default; + move_only_iterator& operator=(move_only_iterator&&) = default; + + move_only_iterator& operator++() { ++base_; return *this; } + move_only_iterator operator++(int) { auto tmp = *this; ++base_; return tmp; } + + decltype(auto) operator*() { return *base_; } + +private: + iterator base_; +}; + +void +test_move_only() +{ + std::string str; + move_only_iterator mo(std::back_inserter(str)); + [[maybe_unused]] auto res + = std::format_to(std::move(mo), "for{:.3} that{:c}", "matte", (int)'!'); + VERIFY( str == "format that!" ); + + std::vector vec; + move_only_iterator wmo(std::back_inserter(vec)); + [[maybe_unused]] auto wres + = std::format_to(std::move(wmo), L"for{:.3} hat{:c}", L"matte", (long)L'!'); + VERIFY( std::wstring_view(vec.data(), vec.size()) == L"format hat!" ); +} + +void +test_pr110917() +{ + // PR libstdc++/110917 + // std::format_to(int*, ...) fails to compile because of _S_make_span + unsigned char buf[7]; + auto res = std::format_to(buf, "{} {}", "abc", 123); + VERIFY( res == buf + 7 ); + VERIFY( ! std::memcmp(buf, "abc 123", 7) ); +} + +int main() +{ + test(); + test_wchar(); + test_move_only(); + test_pr110917(); +} diff --git a/libstdc++-v3/testsuite/std/format/functions/format_to_n.cc b/libstdc++-v3/testsuite/std/format/functions/format_to_n.cc index 846bda30fdf3..f7df3ed36dc2 100644 --- a/libstdc++-v3/testsuite/std/format/functions/format_to_n.cc +++ b/libstdc++-v3/testsuite/std/format/functions/format_to_n.cc @@ -88,9 +88,26 @@ test_move_only() VERIFY( wlen == 11 ); } +void +test_pr110990() +{ + // PR libstdc++/110990 - format_to_n returns wrong value + + char buf[2]; + auto [ptr, len] = std::format_to_n(buf, 2, "x"); + VERIFY( len == 1 ); + VERIFY( ptr == buf + len ); + + wchar_t wbuf[3]; + auto [wptr, wlen] = std::format_to_n(wbuf, 3, L"yz"); + VERIFY( wlen == 2 ); + VERIFY( wptr == wbuf + wlen ); +} + int main() { test(); test_wchar(); test_move_only(); + test_pr110990(); } diff --git a/libstdc++-v3/testsuite/std/format/string.cc b/libstdc++-v3/testsuite/std/format/string.cc index d28135ec260b..a472f8d588c2 100644 --- a/libstdc++-v3/testsuite/std/format/string.cc +++ b/libstdc++-v3/testsuite/std/format/string.cc @@ -16,6 +16,18 @@ is_format_string_for(const char* str, Args&&... args) } } +template +bool +is_format_string_for(const wchar_t* str, Args&&... args) +{ + try { + (void) std::vformat(str, std::make_wformat_args(args...)); + return true; + } catch (const std::format_error&) { + return false; + } +} + void test_no_args() { @@ -124,8 +136,41 @@ test_format_spec() // Maximum integer value supported for widths and precisions is USHRT_MAX. VERIFY( is_format_string_for("{:65535}", 1) ); + VERIFY( is_format_string_for(L"{:65535}", 1) ); VERIFY( ! is_format_string_for("{:65536}", 1) ); + VERIFY( ! is_format_string_for(L"{:65536}", 1) ); VERIFY( ! is_format_string_for("{:9999999}", 1) ); + VERIFY( ! is_format_string_for(L"{:9999999}", 1) ); +} + +void +test_pr110862() +{ + try { + // PR libstdc++/110862 out-of-bounds read on invalid format string + (void) std::vformat("{0:{0}", std::make_format_args(1)); + VERIFY( false ); + } catch (const std::format_error& e) { + std::string_view what = e.what(); + VERIFY( what.find("unmatched '{'") != what.npos ); + } +} + +void +test_pr110974() +{ + try { + // PR libstdc++/110974 out of bounds read on invalid format string "{:{}." + std::string_view fmt{"{:{}.0", 5}; // "0" is not part of the format string. + (void) std::vformat(fmt, std::make_format_args(1.0, 1)); + VERIFY( false ); + } catch (const std::format_error& e) { + std::string_view what = e.what(); + // GCC 13.2 throws "invalid width or precision in format-spec" after + // trying to parse the "0" past-the-end of the format string. + // There should be an exception before even trying that: + VERIFY( what.find("missing precision after '.'") != what.npos ); + } } int main() @@ -133,4 +178,6 @@ int main() test_no_args(); test_indexing(); test_format_spec(); + test_pr110862(); + test_pr110974(); } diff --git a/libstdc++-v3/testsuite/std/ranges/adaptors/all.cc b/libstdc++-v3/testsuite/std/ranges/adaptors/all.cc index 57cb542174b1..6bbaf73a20a9 100644 --- a/libstdc++-v3/testsuite/std/ranges/adaptors/all.cc +++ b/libstdc++-v3/testsuite/std/ranges/adaptors/all.cc @@ -105,12 +105,6 @@ static_assert(std::is_empty_v); -#if 0 -// Adding empty range adaptor closure objects to a pipeline used to not -// increase the size of the pipeline, but now that our range adaptor closure -// objects derive from a common empty base class, [[no_unique_address]] can no -// longer make two empty adjacent range adaptor closure objects occupy the same -// data member address. static_assert(sizeof(decltype(views::take(5) | views::drop(5))) == sizeof(decltype(views::take(5) | views::join @@ -119,7 +113,6 @@ static_assert(sizeof(decltype(views::take(5) | views::drop(5))) | views::keys | views::drop(5) | views::reverse))); -#endif template void diff --git a/libstdc++-v3/testsuite/std/ranges/adaptors/p2770r0.cc b/libstdc++-v3/testsuite/std/ranges/adaptors/p2770r0.cc new file mode 100644 index 000000000000..15d71b2faa91 --- /dev/null +++ b/libstdc++-v3/testsuite/std/ranges/adaptors/p2770r0.cc @@ -0,0 +1,110 @@ +// { dg-options "-std=gnu++20" } +// { dg-do run { target c++20 } } + +#include +#include +#include +#include +#include + +namespace ranges = std::ranges; +namespace views = std::views; + +void +test01() +{ + // Test case from LWG 3698 + char const text[] = "Hello"; + std::regex regex{"[a-z]"}; + + auto lower + = ranges::subrange(std::cregex_iterator(ranges::begin(text), + ranges::end(text), + regex), + std::cregex_iterator{}) + | views::join + | views::transform([](auto const& sm) { + return std::string_view(sm.first, sm.second); + }); + + VERIFY( ranges::equal(lower, (std::string_view[]){"e", "l", "l", "o"})); +} + +void +test02() +{ +#if __cpp_lib_ranges_join_with + // Analogous test case from LWG 3698 for join_with_view + char const text[] = "Hello"; + std::regex regex{"[a-z]"}; + + auto lower + = ranges::subrange(std::cregex_iterator(ranges::begin(text), + ranges::end(text), + regex), + std::cregex_iterator{}) + | views::join_with(views::empty>) + | views::transform([](auto const& sm) { + return std::string_view(sm.first, sm.second); + }); + + VERIFY( ranges::equal(lower, (std::string_view[]){"e", "l", "l", "o"})); +#endif +} + +void +test03() +{ + // Test case from LWG 3700 + auto r = views::iota(0, 5) | views::split(1); + auto s = views::single(r); + auto j = s | views::join; + auto f = j.front(); +} + +void +test04() +{ +#if __cpp_lib_ranges_join_with + // Analogous test case from LWG 3700 for join_with_view + auto r = views::iota(0, 5) | views::split(1); + auto s = views::single(r); + auto j = s | views::join_with(views::empty>); + auto f = j.front(); +#endif +} + +void +test05() +{ + // Test case from LWG 3791 + std::vector> v = {{1}}; + auto r = v + | views::transform([](auto& x) -> auto&& { return std::move(x); }) + | views::join; + auto e = --r.end(); +} + +void +test06() +{ +#if __cpp_lib_ranges_join_with + // Analogous test case from LWG 3791 for join_with_view + std::vector> v = {{1}}; + auto r = v + | views::transform([](auto& x) -> auto&& { return std::move(x); }) + | views::join_with(views::empty); + auto e = --r.end(); +#endif +} + +int +main() +{ + test01(); + test02(); + test03(); + test04(); + test05(); + test06(); +} diff --git a/libstdc++-v3/testsuite/std/time/clock/file/io.cc b/libstdc++-v3/testsuite/std/time/clock/file/io.cc index c8e82bb111c2..a6c7c71cfd3a 100644 --- a/libstdc++-v3/testsuite/std/time/clock/file/io.cc +++ b/libstdc++-v3/testsuite/std/time/clock/file/io.cc @@ -17,7 +17,25 @@ test_ostream() VERIFY( ss1.str() == ss2.str() ); } +void +test_parse() +{ + using namespace std::chrono; + const sys_seconds expected = sys_days(2023y/August/9) + 20h + 44min; + file_time tp; + + minutes offset; + std::string abbrev; + std::istringstream is("002023-08-09 21:44 +01 BST!"); + VERIFY( is >> parse("%6F %R %z %Z", tp, abbrev, offset) ); + VERIFY( ! is.eof() ); + VERIFY( tp == clock_cast(expected) ); + VERIFY( abbrev == "BST" ); + VERIFY( offset == 60min ); +} + int main() { test_ostream(); + test_parse(); } diff --git a/libstdc++-v3/testsuite/std/time/clock/gps/io.cc b/libstdc++-v3/testsuite/std/time/clock/gps/io.cc index 29f3148cf14b..c4fe9bee0f1e 100644 --- a/libstdc++-v3/testsuite/std/time/clock/gps/io.cc +++ b/libstdc++-v3/testsuite/std/time/clock/gps/io.cc @@ -6,7 +6,7 @@ #include void -test01() +test_ostream() { using std::format; using namespace std::chrono; @@ -18,7 +18,25 @@ test01() VERIFY( s == "2000-01-01 00:00:00 UTC == 2000-01-01 00:00:13 GPS" ); } +void +test_parse() +{ + using namespace std::chrono; + const sys_seconds expected = sys_days(2023y/August/9) + 20h + 44min + 3s; + gps_seconds tp; + + minutes offset; + std::string abbrev; + std::istringstream is("2023-8-9 21:44:3 +1 BST#"); + VERIFY( is >> parse("%9F %T %Oz %Z", tp, abbrev, offset) ); + VERIFY( ! is.eof() ); + VERIFY( tp == clock_cast(expected) ); + VERIFY( abbrev == "BST" ); + VERIFY( offset == 60min ); +} + int main() { - test01(); + test_ostream(); + test_parse(); } diff --git a/libstdc++-v3/testsuite/std/time/clock/local/io.cc b/libstdc++-v3/testsuite/std/time/clock/local/io.cc new file mode 100644 index 000000000000..a7c018d95d4d --- /dev/null +++ b/libstdc++-v3/testsuite/std/time/clock/local/io.cc @@ -0,0 +1,42 @@ +// { dg-options "-std=gnu++20" } +// { dg-do run { target c++20 } } + +#include +#include +#include + +void +test_ostream() +{ + using std::format; + using namespace std::chrono; + + auto st = sys_days{2000y/January/1}; + auto tt = clock_cast(st); + + auto s = format("{0:%F %T %Z} == {1:%F %T %Z}", st, tt); + VERIFY( s == "2000-01-01 00:00:00 UTC == 2000-01-01 00:00:32 TAI" ); +} + +void +test_parse() +{ + using namespace std::chrono; + const sys_seconds expected = sys_days(2023y/August/9) + 21h + 44min; + local_seconds tp; + + minutes offset; + std::string abbrev; + std::istringstream is("2023-8-9 21:44 +1 BST#"); // Not adjusted for offset. + VERIFY( is >> parse("%F %R %Oz %Z", tp, abbrev, offset) ); + VERIFY( ! is.eof() ); + VERIFY( tp == local_seconds(expected.time_since_epoch()) ); + VERIFY( abbrev == "BST" ); + VERIFY( offset == 60min ); +} + +int main() +{ + test_ostream(); + test_parse(); +} diff --git a/libstdc++-v3/testsuite/std/time/clock/system/io.cc b/libstdc++-v3/testsuite/std/time/clock/system/io.cc index 7bb6851c7dec..8bfaad3278ea 100644 --- a/libstdc++-v3/testsuite/std/time/clock/system/io.cc +++ b/libstdc++-v3/testsuite/std/time/clock/system/io.cc @@ -73,8 +73,81 @@ test_format() VERIFY( smod == s ); } +void +test_parse() +{ + using namespace std::chrono; + sys_seconds tp, expected = sys_days(2023y/July/24) + 13h + 05min; + + std::istringstream is("24-hour time: 2023-07-24 13:05"); + VERIFY( is >> parse("24-hour time: %Y-%m-%d %H:%M", tp) ); + VERIFY( ! is.eof() ); + VERIFY( tp == expected ); + + tp = {}; + is.clear(); + is.str("12-hour time: 2023-07-24 1.05 PM "); + VERIFY( is >> parse("12-hour time: %F %I.%M %p", tp) ); + VERIFY( ! is.eof() ); + VERIFY( tp == expected ); + + tp = {}; + is.clear(); + is.str("2023-07-24 14:05 +01"); + VERIFY( is >> parse("%F %H:%M %z", tp) ); // %z is used even without offset + VERIFY( is.eof() ); + VERIFY( tp == expected ); + + tp = {}; + minutes offset{}; + is.clear(); + is.str("2023-07-24 15:35 0230"); + VERIFY( is >> parse("%F %H:%M %z", tp, offset) ); + VERIFY( ! is.eof() ); + VERIFY( tp == expected ); + + tp = {}; + std::string abbrev; + is.clear(); + is.str("2023-07-24 08:05 -5:00 EST EST"); + VERIFY( is >> parse("%F %H:%M %Ez %Z %Z", tp, abbrev) ); + VERIFY( is.eof() ); + VERIFY( tp == expected ); + VERIFY( abbrev == "EST" ); + + tp = {}; + abbrev = {}; + offset = {}; + is.clear(); + is.str("2023-07-24 07:05 -06:00 ABC/+123/-456/_="); + VERIFY( is >> parse("%F %H:%M %Ez %Z", tp, abbrev, offset) ); + VERIFY( ! is.eof() ); + VERIFY( tp == expected ); + VERIFY( offset == -360min ); + VERIFY( abbrev == "ABC/+123/-456/_" ); + + tp = sys_seconds(99s); + offset = 99min; + is.clear(); + is.str("-02:00 "); + VERIFY( ! (is >> parse("%Ez ", tp, offset)) ); + VERIFY( is.fail() ); + VERIFY( tp == sys_seconds(99s) ); // tp is only updated on successful parse. + VERIFY( offset == 99min ); // offset is only updated on successful parse. + + tp = sys_seconds(99s); + abbrev = "99"; + is.clear(); + is.str("GMT "); + VERIFY( ! (is >> parse("%Z ", tp, abbrev)) ); + VERIFY( is.fail() ); + VERIFY( tp == sys_seconds(99s) ); // tp is only updated on successful parse. + VERIFY( abbrev == "99" ); // abbrev is only updated on successful parse. +} + int main() { test_ostream(); test_format(); + test_parse(); } diff --git a/libstdc++-v3/testsuite/std/time/clock/tai/io.cc b/libstdc++-v3/testsuite/std/time/clock/tai/io.cc index d0255f5431af..530af75442b3 100644 --- a/libstdc++-v3/testsuite/std/time/clock/tai/io.cc +++ b/libstdc++-v3/testsuite/std/time/clock/tai/io.cc @@ -6,7 +6,7 @@ #include void -test01() +test_ostream() { using std::format; using namespace std::chrono; @@ -18,7 +18,25 @@ test01() VERIFY( s == "2000-01-01 00:00:00 UTC == 2000-01-01 00:00:32 TAI" ); } +void +test_parse() +{ + using namespace std::chrono; + const sys_seconds expected = sys_days(2023y/August/9) + 20h + 44min + 3s; + tai_seconds tp; + + minutes offset; + std::string abbrev; + std::istringstream is("8/9/23 214403 +1 BST#"); + VERIFY( is >> parse("%D %2H%2M%2S %Oz %Z", tp, abbrev, offset) ); + VERIFY( ! is.eof() ); + VERIFY( tp == clock_cast(expected) ); + VERIFY( abbrev == "BST" ); + VERIFY( offset == 60min ); +} + int main() { - test01(); + test_ostream(); + test_parse(); } diff --git a/libstdc++-v3/testsuite/std/time/clock/utc/io.cc b/libstdc++-v3/testsuite/std/time/clock/utc/io.cc index 977643f11478..c49f6f7e22cf 100644 --- a/libstdc++-v3/testsuite/std/time/clock/utc/io.cc +++ b/libstdc++-v3/testsuite/std/time/clock/utc/io.cc @@ -114,8 +114,39 @@ test_format() VERIFY( s == "00:00:00" ); } +void +test_parse() +{ + using namespace std::chrono; + const sys_seconds expected = sys_days(2023y/August/9) + 20h + 44min + 3s; + utc_seconds tp; + + minutes offset; + std::string abbrev; + std::istringstream is("23 2210 21:44:3 +1 BST#"); + VERIFY( is >> parse("%y %j0 %4H:%5M:%6S %Oz %Z", tp, abbrev, offset) ); + VERIFY( ! is.eof() ); + VERIFY( tp == clock_cast(expected) ); + VERIFY( abbrev == "BST" ); + VERIFY( offset == 60min ); + + tp = {}; + is.clear(); + is.str("20230809214403 0100 BST:"); + VERIFY( is >> parse("%Y%m%d%H%M%S %z %Z:", tp) ); + VERIFY( ! is.eof() ); + VERIFY( tp == clock_cast(expected) ); + + is.clear(); + is.str("2023-W32-3 20:44:03"); + VERIFY( is >> parse("%G-W%V-%u %T", tp) ); + VERIFY( ! is.eof() ); + VERIFY( tp == clock_cast(expected) ); +} + int main() { test_ostream(); test_format(); + test_parse(); } diff --git a/libstdc++-v3/testsuite/std/time/day/io.cc b/libstdc++-v3/testsuite/std/time/day/io.cc index 6158230f2884..d8691b72066f 100644 --- a/libstdc++-v3/testsuite/std/time/day/io.cc +++ b/libstdc++-v3/testsuite/std/time/day/io.cc @@ -67,9 +67,67 @@ test_format() } } +void +test_parse() +{ + using namespace std::chrono; + day d(0); + minutes offset; + std::string abbrev; + std::istringstream is("2023-08-10 12:46 +01 BST<"); + VERIFY( is >> parse("%F %R %z %Z", d, abbrev, offset) ); + VERIFY( ! is.eof() ); + VERIFY( d == 10d ); + VERIFY( abbrev == "BST" ); + VERIFY( offset == 60min ); + + abbrev = "nope"; + offset = 999min; + is.clear(); + is.str("30"); + VERIFY( is >> parse("%d", d, abbrev, offset) ); + VERIFY( ! is.eof() ); + VERIFY( d == 30d ); + VERIFY( abbrev == "nope" ); + VERIFY( offset == 999min ); + + d = day(255); + is.clear(); + is.str("2023-02-30"); + is >> parse("%F", d); // Feb 30 is not a valid day + VERIFY( is.fail() ); + VERIFY( d == day(255) ); + + is.clear(); + is.str("February 30"); + is >> parse("%B %d", d); // Feb 30 is not a valid day + VERIFY( is.fail() ); + VERIFY( d == day(255) ); + + is.clear(); + is.str("February 29"); + is >> parse("%B %d", d); // But Feb 29 could be valid. + VERIFY( is.good() ); + VERIFY( d == 29d ); + + d = day(255); + is.clear(); + is.str("2023 Feb 29"); + is >> parse("%Y %B %d", d); // But 2023 is not a leap year. + VERIFY( is.fail() ); + VERIFY( d == day(255) ); + + d = day(255); + is.clear(); + is.str("20 Feb 29"); + is >> parse("%y %B %d", d); // But 2020 is a leap year. + VERIFY( is.good() ); + VERIFY( d == 29d ); +} + int main() { test_ostream(); test_format(); - // TODO: test_parse(); + test_parse(); } diff --git a/libstdc++-v3/testsuite/std/time/month/io.cc b/libstdc++-v3/testsuite/std/time/month/io.cc index 7ceeafd725a8..9cf5b053f2bf 100644 --- a/libstdc++-v3/testsuite/std/time/month/io.cc +++ b/libstdc++-v3/testsuite/std/time/month/io.cc @@ -90,9 +90,129 @@ test_format() } } +void +test_parse() +{ + using namespace std::chrono; + std::istringstream is; + month m{}; + + is.str("JUL"); + VERIFY( is >> parse("%B", m) ); + VERIFY( is.eof() ); + VERIFY( m == July ); + + is.clear(); + is.str("junE bug"); + VERIFY( is >> parse(" %b bug ", m) ); + VERIFY( is.eof() ); + VERIFY( m == June ); + + is.clear(); + is.str("012"); + VERIFY( is >> parse("%m", m) ); + VERIFY( ! is.eof() ); + VERIFY( is.peek() == '2' ); + VERIFY( m == January ); + + is.clear(); + is.str("012"); + VERIFY( is >> parse("%4m", m) ); + VERIFY( is.eof() ); + VERIFY( m == December ); + + m = month(15); + is.clear(); + is.str("Janvember"); + VERIFY( is >> parse("%B", m) ); // Stops parsing after "Jan" + VERIFY( ! is.eof() ); + VERIFY( is.peek() == 'v' ); + VERIFY( m == January ); + + m = month(15); + is.clear(); + is.str("Junuary"); + VERIFY( is >> parse("%B", m) ); // Stops parsing after "Jun" + VERIFY( ! is.eof() ); + VERIFY( is.peek() == 'u' ); + VERIFY( m == June ); + + m = month(15); + is.clear(); + is.str("Jebruary"); + VERIFY( ! (is >> parse("%B", m)) ); + VERIFY( is.fail() ); + VERIFY( ! is.eof() ); + is.clear(); + VERIFY( is.peek() == 'e' ); + VERIFY( m == month(15) ); + + m = month(13); + is.clear(); + is.str("2023-6-31"); + VERIFY( ! (is >> parse("%F", m)) ); // June only has 30 days. + VERIFY( ! is.eof() ); + VERIFY( m == month(13) ); + + m = month(14); + is.clear(); + is.str("2023-2-29"); + VERIFY( ! (is >> parse("%Y-%m-%e", m)) ); // Feb only has 28 days in 2023. + VERIFY( ! is.eof() ); + VERIFY( m == month(14) ); + + is.clear(); + is.str("2-29"); + VERIFY( is >> parse("%m-%d", m) ); // But Feb has 29 days in some years. + VERIFY( ! is.eof() ); + VERIFY( m == February ); + + m = month(14); + is.clear(); + is.str("6-31"); + VERIFY( ! (is >> parse("%m-%d", m)) ); // June only has 30 days in all years. + VERIFY( ! is.eof() ); + VERIFY( m == month(14) ); + + m = month(15); + is.clear(); + is.str("2023-13-1"); + VERIFY( ! (is >> parse("%F", m)) ); + VERIFY( is.eof() ); + VERIFY( m == month(15) ); + + m = month(16); + is.clear(); + is.str("13/1/23"); + VERIFY( ! (is >> parse("%D", m)) ); + VERIFY( m == month(16) ); + + m = month(17); + is.clear(); + is.str("13"); + VERIFY( ! (is >> parse("%m", m)) ); + VERIFY( ! is.eof() ); + VERIFY( m == month(17) ); + + m = month(18); + is.clear(); + is.str("1234"); + VERIFY( ! (is >> parse("%3m", m)) ); + VERIFY( ! is.eof() ); + is.clear(); + VERIFY( is.peek() == '4' ); + VERIFY( m == month(18) ); + + is.clear(); + is.str("2023-W32-5"); + VERIFY( is >> parse("%G-W%V-%u", m) ); + VERIFY( ! is.eof() ); + VERIFY( m == August ); +} + int main() { test_ostream(); test_format(); - // TODO: test_parse(); + test_parse(); } diff --git a/libstdc++-v3/testsuite/std/time/month_day/io.cc b/libstdc++-v3/testsuite/std/time/month_day/io.cc index 454231dd7243..a3f4599fb4e4 100644 --- a/libstdc++-v3/testsuite/std/time/month_day/io.cc +++ b/libstdc++-v3/testsuite/std/time/month_day/io.cc @@ -22,9 +22,86 @@ test_ostream() VERIFY( ss.str() == "juil./27" ); } +void +test_parse() +{ + using namespace std::chrono; + std::istringstream is; + month_day md{}; + + is.str("jul 0123"); + VERIFY( is >> parse("%B %3e", md) ); + VERIFY( ! is.eof() ); + VERIFY( is.peek() == '3' ); + VERIFY( md == July/12 ); + + is.str("August 11"); + VERIFY( is >> parse("%b %d", md) ); + VERIFY( ! is.eof() ); + VERIFY( md == August/11 ); + + is.clear(); + is.str("012"); + VERIFY( is >> parse("%m%2d", md) ); + VERIFY( is.eof() ); + VERIFY( md == January/2 ); + + is.clear(); + is.str("012/311"); + VERIFY( is >> parse("%4m/%d", md) ); + VERIFY( ! is.eof() ); + VERIFY( md == December/31 ); + + is.clear(); + is.str("2023-7-31"); + VERIFY( is >> parse("%F", md) ); + VERIFY( ! is.eof() ); + VERIFY( md == July/31 ); + + md = month(13)/day(32); + is.clear(); + is.str("2023-13-1"); + VERIFY( ! (is >> parse("%F", md)) ); + VERIFY( is.eof() ); + VERIFY( md == month(13)/day(32) ); + + md = month(13)/day(33); + is.clear(); + is.str("2023-6-31"); + VERIFY( ! (is >> parse("%F", md)) ); // June only has 30 days. + VERIFY( ! is.eof() ); + VERIFY( md == month(13)/day(33) ); + + md = month(13)/day(34); + is.clear(); + is.str("6-31"); + VERIFY( ! (is >> parse("%m-%d", md)) ); // June only has 30 days in any year. + VERIFY( ! is.eof() ); + VERIFY( md == month(13)/day(34) ); + + md = month(13)/day(35); + is.clear(); + is.str("2023-2-29"); + VERIFY( ! (is >> parse("%Y-%m-%e", md)) ); // Feb only has 28 days in 2023. + VERIFY( ! is.eof() ); + VERIFY( md == month(13)/day(35) ); + + is.clear(); + is.str("2-29"); + VERIFY( is >> parse("%m-%d", md) ); // But Feb has 29 days in some years. + VERIFY( ! is.eof() ); + VERIFY( md == February/29 ); + + is.clear(); + is.str("2023-W32-5"); + VERIFY( is >> parse("%G-W%V-%u", md) ); + VERIFY( ! is.eof() ); + VERIFY( md == August/11 ); +} + int main() { test_ostream(); // TODO: test_format(); - // TODO: test_parse(); + test_parse(); } diff --git a/libstdc++-v3/testsuite/std/time/parse.cc b/libstdc++-v3/testsuite/std/time/parse.cc new file mode 100644 index 000000000000..86222d595967 --- /dev/null +++ b/libstdc++-v3/testsuite/std/time/parse.cc @@ -0,0 +1,328 @@ +// { dg-do run { target c++20 } } +// { dg-options "-std=gnu++20" } + +#include +#include +#include +#include + +template + concept stream_extractable + = requires (std::basic_istream& is) { is >> std::declval(); }; + +void +test_recommended_practice() +{ + std::chrono::seconds s; + using parse_manip = decltype(std::chrono::parse("", s)); + static_assert( stream_extractable ); + static_assert( not stream_extractable ); + using wparse_manip = decltype(std::chrono::parse(L"", s)); + static_assert( stream_extractable ); + static_assert( not stream_extractable ); + + // These properties are recommended by the standard, to avoid using a + // parse manipulator that has a dangling reference to a format string. + static_assert( not std::is_move_constructible_v ); + static_assert( not std::is_move_assignable_v ); + static_assert( not stream_extractable ); + static_assert( not stream_extractable ); + static_assert( not stream_extractable ); + static_assert( not stream_extractable ); +} + +template + concept parsable = requires(Args... args) { std::chrono::parse(args...); }; + +const std::string f = "format string"; + +namespace N +{ + struct A { }; + + void + from_stream(std::istream&, const char* fmt, A&) + { + VERIFY( fmt == f.c_str() ); + } + + template + void + from_stream(std::istream&, const char*, A&, void*, void*) = delete; + + struct B { }; + + void + from_stream(std::istream&, const char* fmt, B&, std::string* abbrev) + { + VERIFY( fmt == f.c_str() ); + VERIFY( abbrev != nullptr ); + } + + void + from_stream(std::istream&, const char*, B&, std::string*, void*) = delete; + + struct C { }; + + void + from_stream(std::istream&, const char* fmt, C&, std::string* abbrev, + std::chrono::minutes* offset) + { + VERIFY( fmt == f.c_str() ); + VERIFY( abbrev == nullptr ); + VERIFY( offset != nullptr ); + } + + struct D { }; + + void + from_stream(std::istream&, const char* fmt, D&, std::string* abbrev, + std::chrono::minutes* offset) + { + VERIFY( fmt == f.c_str() ); + VERIFY( abbrev != nullptr ); + VERIFY( offset != nullptr ); + } + + struct E { }; + + void + from_stream(std::wistream&, const wchar_t*, E&, std::wstring* = nullptr, + std::chrono::minutes* = nullptr) + { } +} + +void +test_adl() +{ + using std::string; + using std::wstring; + using std::chrono::minutes; + + string abbrev; + minutes offset; + + // Check that valid calls are well-formed. + N::A a; + (void) std::chrono::parse(f, a); + N::B b; + (void) std::chrono::parse(f, b, abbrev); + N::C c; + (void) std::chrono::parse(f, c, offset); + // This satisfies the concept, but would fail the VERIFY assertion: + static_assert( parsable ); + N::D d; + (void) std::chrono::parse(f, d, abbrev, offset); + // This satisfies the concept, but would fail the VERIFY assertion: + static_assert( parsable ); + + // Wide strings. + static_assert( parsable ); + static_assert( parsable ); + static_assert( parsable ); + static_assert( parsable ); + + // Check that invalid calls are properly constrained. + + // from_stream is only overloaded for N::A without abbrev or offset. + static_assert( not parsable ); + static_assert( not parsable ); + static_assert( not parsable ); + // from_stream is only overloaded for N::B with abbrev. + static_assert( not parsable ); + static_assert( not parsable ); + static_assert( not parsable ); + // from_stream is only overloaded for N::C with abbrev and minutes. + static_assert( not parsable ); + static_assert( not parsable ); + // from_stream is only overloaded for N::D with abbrev and minutes. + static_assert( not parsable ); + static_assert( not parsable ); + + // Mismatched strings + static_assert( not parsable ); + static_assert( not parsable ); + + using Alloc = __gnu_test::SimpleAllocator; + using String = std::basic_string, Alloc>; + // Custom allocator + static_assert( parsable ); + static_assert( parsable ); + static_assert( parsable ); + static_assert( parsable ); + static_assert( parsable ); + static_assert( parsable ); + // Mismatched allocators + static_assert( not parsable ); + static_assert( not parsable ); + static_assert( not parsable ); + static_assert( not parsable ); +} + +void +test_whitespace() +{ + using namespace std::chrono_literals; + std::chrono::minutes min; + std::istringstream is; + is.str(" a b 1 "); + is >> parse(" a b %M", min); + VERIFY( is.good() ); + VERIFY( min == 1min ); + is.str(" a b 1 "); + is >> parse(" a b %M ", min); + VERIFY( is.eof() && !is.fail() ); + VERIFY( min == 1min ); + is.clear(); + is.str(" 1"); + is >> parse(" %n%M%n", min); + VERIFY( is.fail() ); + is.clear(); + is.str(" a b 1 "); + is >> parse("%n a%n%nb %t%M%n", min); + VERIFY( is.good() ); + VERIFY( min == 1min ); + is.str("a b 1 "); + is >> parse("%ta b %M%n%t", min); + VERIFY( is.good() ); + VERIFY( min == 1min ); + is.str("1 "); + is >> parse("%M%n%t%t", min); + VERIFY( is.eof() && !is.fail() ); + VERIFY( min == 1min ); + is.clear(); + is.str("1 "); + is >> parse("%M%n%t%t", min); + VERIFY( is.eof() && !is.fail() ); + VERIFY( min == 1min ); + is.clear(); + is.str("1 "); + is >> parse("%M%n%t%n", min); + VERIFY( is.eof() && is.fail() ); + VERIFY( min == 1min ); +} + +void +test_errors() +{ + using namespace std::chrono_literals; + std::chrono::minutes min(999); + std::chrono::year y(-1); + std::istringstream is; + + is.str("x"); + is >> parse("x", min); // Matches expected pattern, but no minutes present. + VERIFY( !is.eof() && is.fail() ); + VERIFY( min == 999min ); + + is.clear(); + is.str("x"); + is >> parse("%M", min); // Doesn't match expected pattern. + VERIFY( !is.eof() && is.fail() ); + VERIFY( min == 999min ); + + is.clear(); + is.str("001:002"); + is >> parse("%H:%M", min); // Extracts "00" then fails to find ':' next. + VERIFY( !is.eof() && is.fail() ); + VERIFY( min == 999min ); + + is.clear(); + is.str("12:61"); + is >> parse("%H:%M", min); // 61min is out of range. + VERIFY( !is.eof() && is.fail() ); + VERIFY( min == 999min ); + + is.clear(); + is.str("12:15 100"); + is >> parse("%H:%M %3y", min); // 100y is out of range for %y but not needed + VERIFY( is.good() ); + VERIFY( min == (12h + 15min) ); + + min = 999min; + is.clear(); + is.str("12:15 100"); + is >> parse("%H:%M %3y", y); // 100y is out of range for %y and needed + VERIFY( is.fail() ); + VERIFY( y == -1y ); + + is.clear(); + is.str("23:61 10"); + is >> parse("%H:%M %3y", y); // 61min is out of range but not needed + VERIFY( is.eof() && ! is.fail() ); + VERIFY( y == 2010y ); + + min = -1min; + is.clear(); + is.str("25:59"); + is >> parse("%H:%M", min); // 25h is out of range and needed + VERIFY( is.fail() ); + VERIFY( min == -1min ); + + is.clear(); + is.str("328 00"); + is >> parse("%3C %y", y); // 328 is out of range for %C (PR libstdc++/111162) + VERIFY( is.fail() ); + VERIFY( y == 2010y ); + + is.clear(); + is.str("-328 00"); + is >> parse("%3C %y", y); // -328 is out of range for %C + VERIFY( is.fail() ); + VERIFY( y == 2010y ); +} + +void +test_modifiers() +{ + using namespace std::chrono_literals; + std::chrono::minutes min; + std::istringstream is; + + is.str("0001:000002"); + is >> parse("%4H:%5M", min); + VERIFY( is.good() ); + VERIFY( min == 60min ); + + is.str("0001:000002"); + is >> parse("%6H:%6M", min); + VERIFY( is.good() ); + VERIFY( min == 62min ); + + is.str("002"); + is >> parse("%4M", min); + VERIFY( is.eof() && !is.fail() ); + VERIFY( min == 2min ); + + is.clear(); + is.str("0061"); + is >> parse("%3M", min); + VERIFY( is.good() ); + VERIFY( min == 6min ); + + is.clear(); + is.str("0061"); + is >> parse("%4M", min); + VERIFY( !is.eof() && is.fail() ); + + is.clear(); + is.str("0061"); + is >> parse("%5M", min); + VERIFY( is.eof() && is.fail() ); + + std::chrono::seconds s; + is.clear(); + is.str("000000000012345"); + is >> parse("%12S", s); // Read more than 10 digits to check overflow logic. + VERIFY( is.good() ); + VERIFY( s == 12s ); +} + +int main() +{ + test_recommended_practice(); + test_adl(); + test_whitespace(); + test_errors(); + test_modifiers(); +} diff --git a/libstdc++-v3/testsuite/std/time/syn_c++20.cc b/libstdc++-v3/testsuite/std/time/syn_c++20.cc index 570471aacc71..307d84e54357 100644 --- a/libstdc++-v3/testsuite/std/time/syn_c++20.cc +++ b/libstdc++-v3/testsuite/std/time/syn_c++20.cc @@ -22,9 +22,8 @@ #ifndef __cpp_lib_chrono # error "Feature test macro for chrono is missing in " -// FIXME -// #elif __cpp_lib_chrono < 201907L -// # error "Feature test macro for chrono has wrong value in " +#elif __cpp_lib_chrono < 201907L +# error "Feature test macro for chrono has wrong value in " #endif namespace __gnu_test @@ -126,8 +125,8 @@ namespace __gnu_test using std::chrono::local_time_format; - // FIXME - // using std::chrono::parse; + using std::chrono::from_stream; + using std::chrono::parse; using std::chrono::last; using std::chrono::Sunday; diff --git a/libstdc++-v3/testsuite/std/time/weekday/io.cc b/libstdc++-v3/testsuite/std/time/weekday/io.cc index 6cdb98467b13..ba9dce00f6ce 100644 --- a/libstdc++-v3/testsuite/std/time/weekday/io.cc +++ b/libstdc++-v3/testsuite/std/time/weekday/io.cc @@ -93,9 +93,85 @@ test_format() } } +void +test_parse() +{ + using namespace std::chrono; + std::istringstream is; + weekday wd{}; + + is.str("fRi funday"); + VERIFY( is >> std::chrono::parse(" %A funday", wd) ); + VERIFY( wd == Friday ); + + is.str("MONDAY xxx"); + VERIFY( is >> std::chrono::parse(" %a xxx ", wd) ); + VERIFY( wd == Monday ); + + is.clear(); + is.str("1"); + VERIFY( is >> std::chrono::parse("%u", wd) ); + VERIFY( wd == Monday ); + is.clear(); + is.str("7"); + VERIFY( is >> std::chrono::parse("%u", wd) ); + VERIFY( wd == Sunday ); + wd = weekday(99); + is.clear(); + is.str("0"); + VERIFY( ! (is >> std::chrono::parse("%u", wd)) ); + VERIFY( wd == weekday(99) ); + is.clear(); + is.str("8"); + VERIFY( ! (is >> std::chrono::parse("%u", wd)) ); + VERIFY( wd == weekday(99) ); + + is.clear(); + is.str("003"); + VERIFY( is >> std::chrono::parse("%3u", wd) ); + VERIFY( wd == Wednesday ); + wd = weekday(99); + is.clear(); + is.str("004"); + VERIFY( ! (is >> std::chrono::parse("%2u", wd)) ); + VERIFY( wd == weekday(99) ); + + is.clear(); + is.str("1"); + VERIFY( is >> std::chrono::parse("%w", wd) ); + VERIFY( wd == Monday ); + is.clear(); + is.str("0"); + VERIFY( is >> std::chrono::parse("%w", wd) ); + VERIFY( wd == Sunday ); + wd = weekday(99); + is.clear(); + is.str("7"); + VERIFY( ! (is >> std::chrono::parse("%w", wd)) ); + VERIFY( wd == weekday(99) ); + is.clear(); + is.str("8"); + VERIFY( ! (is >> std::chrono::parse("%w", wd)) ); + VERIFY( wd == weekday(99) ); + + is.clear(); + is.str("003"); + VERIFY( is >> std::chrono::parse("%3w", wd) ); + VERIFY( wd == Wednesday ); + is.clear(); + is.str("004"); + VERIFY( is >> std::chrono::parse("%2w", wd) ); + VERIFY( wd == Sunday ); + + is.clear(); + is.str("2023-8-11"); + VERIFY( is >> std::chrono::parse("%F", wd) ); + VERIFY( wd == Friday ); +} + int main() { test_ostream(); test_format(); - // TODO: test_parse(); + test_parse(); } diff --git a/libstdc++-v3/testsuite/std/time/year/io.cc b/libstdc++-v3/testsuite/std/time/year/io.cc index 07316e98aa52..0c4746479213 100644 --- a/libstdc++-v3/testsuite/std/time/year/io.cc +++ b/libstdc++-v3/testsuite/std/time/year/io.cc @@ -81,9 +81,81 @@ test_format() } } +void +test_parse() +{ + using namespace std::chrono; + year y; + + std::istringstream is("2023"); + VERIFY( is >> parse("%Y", y) ); + VERIFY( ! is.eof() ); + VERIFY( y == year(2023) ); + + is.clear(); + is.str("2023"); + VERIFY( is >> parse("%5Y", y) ); + VERIFY( is.eof() ); + VERIFY( y == year(2023) ); + + is.clear(); + is.str("2023"); + VERIFY( is >> parse("%2Y", y) ); + VERIFY( ! is.eof() ); + VERIFY( y == year(20) ); + + is.clear(); + is.str("2023"); + VERIFY( is >> parse("%y", y) ); + VERIFY( ! is.eof() ); + VERIFY( y == year(2020) ); + + minutes offset; + std::string abbrev; + + is.clear(); + is.str("23 20 25:61 +1:30 WAT"); // Invalid %H:%M doesn't matter for year. + VERIFY( is >> parse("%y %C %H:%M %Oz %Z", y, abbrev, offset) ); + VERIFY( is.eof() ); + VERIFY( y == year(2023) ); + VERIFY( abbrev == "WAT" ); + VERIFY( offset == 90min ); + + is.clear(); + is.str("2022 367"); + VERIFY( is >> parse("%Y %j", y) ); // Invalid day-of-year doesn't matter. + VERIFY( ! is.eof() ); + VERIFY( y == 2022y ); + + y = 999y; + is.clear(); + is.str("2023"); + VERIFY( ! (is >> parse("%G", y)) ); // ISO year not aligned with Gregorian. + VERIFY( y == 999y ); + + is.clear(); + is.str("2023-W01-1"); // 2023-1-2 + is >> parse("%G-W%V-%u", y); // Can get Gregorian year from full ISO date. + VERIFY( ! is.eof() ); + VERIFY( y == 2023y ); + + is.clear(); + is.str("2022-W052-7"); // 2023-1-1 + is >> parse("%G-W%3V-%2u", y); + VERIFY( is.eof() ); + VERIFY( y == 2023y ); + + y = year(1); + is.clear(); + is.str("2023 01"); + VERIFY( !( is >> parse("%Y %z xx", y)) ); // Gets EOF and can't parse " xx". + VERIFY( is.eof() ); + VERIFY( y == year(1) ); +} + int main() { test_ostream(); test_format(); - // TODO: test_parse(); + test_parse(); } diff --git a/libstdc++-v3/testsuite/std/time/year_month/io.cc b/libstdc++-v3/testsuite/std/time/year_month/io.cc index 8c0eb9b65794..8dac24861885 100644 --- a/libstdc++-v3/testsuite/std/time/year_month/io.cc +++ b/libstdc++-v3/testsuite/std/time/year_month/io.cc @@ -22,9 +22,57 @@ test_ostream() VERIFY( ss.str() == "2023/juil." ); } +void +test_parse() +{ + using namespace std::chrono; + year_month ym; + + std::istringstream is("20238"); + VERIFY( is >> parse("%Y%m", ym) ); + VERIFY( is.eof() ); + VERIFY( ym == 2023y/August ); + + ym = 1y/January; + is.clear(); + is.str("20238"); + VERIFY( ! (is >> parse("%5Y%m", ym)) ); + VERIFY( is.eof() ); + VERIFY( ym == 1y/January ); + + is.clear(); + is.str("2023"); + VERIFY( is >> parse("%2Y%1m", ym) ); + VERIFY( ! is.eof() ); + VERIFY( ym == 20y/February ); + + is.clear(); + is.str("2012"); + VERIFY( is >> parse("%y%m", ym) ); + VERIFY( ! is.eof() ); + VERIFY( ym == 2020y/December ); + + minutes offset; + std::string abbrev; + + is.clear(); + is.str("4/1/20 25:61 +1:30 WAT"); // Invalid %H:%M doesn't matter for year_mon + VERIFY( is >> parse("%D %H:%M %Oz %Z", ym, abbrev, offset) ); + VERIFY( is.eof() ); + VERIFY( ym == 2020y/April ); + VERIFY( abbrev == "WAT" ); + VERIFY( offset == 90min ); + + is.clear(); + is.str("02022-W052-7"); + is >> parse("%6G-W%4V-%2u", ym); + VERIFY( is.eof() ); + VERIFY( ym == 2023y/January ); +} + int main() { test_ostream(); // TODO: test_format(); - // TODO: test_parse(); + test_parse(); } diff --git a/libstdc++-v3/testsuite/std/time/year_month_day/io.cc b/libstdc++-v3/testsuite/std/time/year_month_day/io.cc index 688885b37a1d..6c30a8721ea8 100644 --- a/libstdc++-v3/testsuite/std/time/year_month_day/io.cc +++ b/libstdc++-v3/testsuite/std/time/year_month_day/io.cc @@ -113,9 +113,72 @@ test_format() } } +void +test_parse() +{ + using namespace std::chrono; + const year_month_day expected = 2023y/August/10; + year_month_day ymd; + + minutes offset; + std::string abbrev; + std::istringstream is("23 2220 21:44:3 +1 'BST'"); + VERIFY( is >> parse("%y %j0 %4H:%5M:%6S %Oz '%Z'", ymd, abbrev, offset) ); + VERIFY( ! is.eof() ); + VERIFY( ymd == expected ); + VERIFY( abbrev == "BST" ); + VERIFY( offset == 60min ); + + is.clear(); + is.str("2023 365"); + VERIFY( is >> parse("%Y %j", ymd) ); + VERIFY( ymd == 2023y/December/31 ); + + ymd = 1970y/January/1; + is.clear(); + is.str("2023 366"); + VERIFY( ! (is >> parse("%Y %j", ymd)) ); // Not a leap year, no 366th day. + VERIFY( ymd == 1970y/January/1 ); + + is.clear(); + is.str("2020 366"); + VERIFY( is >> parse("%Y %j", ymd) ); + VERIFY( ! is.eof() ); + VERIFY( ymd == 2020y/December/31 ); + + ymd = 1970y/January/1; + is.clear(); + is.str("2020 0"); + VERIFY( ! (is >> parse("%Y %j", ymd)) ); // zero is invalid for day-of-year + VERIFY( is.eof() ); + VERIFY( ymd == 1970y/January/1 ); + + is.clear(); + is.str("2023-01-01 00:30 0100"); + VERIFY( is >> parse("%F %R %z", ymd) ); + VERIFY( ! is.eof() ); + VERIFY( ymd == 2023y/January/1 ); // Date not adjusted by TZ offset. + + ymd = {}; + is.clear(); + is.str("2022-W52-6"); + VERIFY( is >> parse("%G-W%V-%u", ymd) ); + VERIFY( ymd == 2022y/December/31 ); + + is.clear(); + is.str("2022-W52-8"); + VERIFY( ! (is >> parse("%G-W%V-%u", ymd)) ); // 8 is not a valid weekday + is.clear(); + is.str("2022-W52-0"); + VERIFY( ! (is >> parse("%G-W%V-%u", ymd)) ); // 0 is not a valid weekday + is.clear(); + is.str("2022-W53-1"); + VERIFY( ! (is >> parse("%G-W%V-%u", ymd)) ); // W53 is not valid for 2022 +} + int main() { test_ostream(); test_format(); - // TODO: test_parse(); + test_parse(); } diff --git a/libstdc++-v3/testsuite/tr1/2_general_utilities/shared_ptr/assign/auto_ptr.cc b/libstdc++-v3/testsuite/tr1/2_general_utilities/shared_ptr/assign/auto_ptr.cc index c3ac4af7b7f3..ad39e18eeeee 100644 --- a/libstdc++-v3/testsuite/tr1/2_general_utilities/shared_ptr/assign/auto_ptr.cc +++ b/libstdc++-v3/testsuite/tr1/2_general_utilities/shared_ptr/assign/auto_ptr.cc @@ -17,7 +17,8 @@ // TR1 2.2.2 Template class shared_ptr [tr.util.smartptr.shared] -// { dg-options "-std=c++98" } +// { dg-add-options using-deprecated } +// { dg-warning "auto_ptr. is deprecated" "" { target c++11 } 0 } #include #include diff --git a/libstdc++-v3/testsuite/tr1/2_general_utilities/shared_ptr/assign/auto_ptr_neg.cc b/libstdc++-v3/testsuite/tr1/2_general_utilities/shared_ptr/assign/auto_ptr_neg.cc index 56cc149fd685..2f8697a3fa2d 100644 --- a/libstdc++-v3/testsuite/tr1/2_general_utilities/shared_ptr/assign/auto_ptr_neg.cc +++ b/libstdc++-v3/testsuite/tr1/2_general_utilities/shared_ptr/assign/auto_ptr_neg.cc @@ -19,7 +19,8 @@ // TR1 2.2.2 Template class shared_ptr [tr.util.smartptr.shared] -// { dg-options "-std=c++98" } +// { dg-add-options using-deprecated } +// { dg-warning "auto_ptr. is deprecated" "" { target c++11 } 0 } #include #include diff --git a/libstdc++-v3/testsuite/tr1/2_general_utilities/shared_ptr/assign/auto_ptr_rvalue_neg.cc b/libstdc++-v3/testsuite/tr1/2_general_utilities/shared_ptr/assign/auto_ptr_rvalue_neg.cc index b77208a620ee..2efc9dee8239 100644 --- a/libstdc++-v3/testsuite/tr1/2_general_utilities/shared_ptr/assign/auto_ptr_rvalue_neg.cc +++ b/libstdc++-v3/testsuite/tr1/2_general_utilities/shared_ptr/assign/auto_ptr_rvalue_neg.cc @@ -19,7 +19,8 @@ // TR1 2.2.2 Template class shared_ptr [tr.util.smartptr.shared] -// { dg-options "-std=c++98" } +// { dg-add-options using-deprecated } +// { dg-warning "auto_ptr. is deprecated" "" { target c++11 } 0 } #include #include diff --git a/libstdc++-v3/testsuite/tr1/2_general_utilities/shared_ptr/cons/43820_neg.cc b/libstdc++-v3/testsuite/tr1/2_general_utilities/shared_ptr/cons/43820_neg.cc index f6ba60aa824f..3229a52c6369 100644 --- a/libstdc++-v3/testsuite/tr1/2_general_utilities/shared_ptr/cons/43820_neg.cc +++ b/libstdc++-v3/testsuite/tr1/2_general_utilities/shared_ptr/cons/43820_neg.cc @@ -17,7 +17,8 @@ // with this library; see the file COPYING3. If not see // . -// { dg-options "-std=c++98 -fno-show-column" } +// { dg-add-options using-deprecated } +// { dg-warning "auto_ptr. is deprecated" "" { target c++11 } 0 } // 2.2.3 Class template shared_ptr [tr.util.smartptr.shared] diff --git a/libstdc++-v3/testsuite/tr1/2_general_utilities/shared_ptr/cons/auto_ptr.cc b/libstdc++-v3/testsuite/tr1/2_general_utilities/shared_ptr/cons/auto_ptr.cc index 371b2a8c96ef..d885597798aa 100644 --- a/libstdc++-v3/testsuite/tr1/2_general_utilities/shared_ptr/cons/auto_ptr.cc +++ b/libstdc++-v3/testsuite/tr1/2_general_utilities/shared_ptr/cons/auto_ptr.cc @@ -15,7 +15,8 @@ // with this library; see the file COPYING3. If not see // . -// { dg-options "-std=c++98" } +// { dg-add-options using-deprecated } +// { dg-warning "auto_ptr. is deprecated" "" { target c++11 } 0 } // TR1 2.2.2 Template class shared_ptr [tr.util.smartptr.shared] diff --git a/libstdc++-v3/testsuite/tr1/2_general_utilities/shared_ptr/cons/auto_ptr_neg.cc b/libstdc++-v3/testsuite/tr1/2_general_utilities/shared_ptr/cons/auto_ptr_neg.cc index 88c896cc17f8..8b2fff2e387b 100644 --- a/libstdc++-v3/testsuite/tr1/2_general_utilities/shared_ptr/cons/auto_ptr_neg.cc +++ b/libstdc++-v3/testsuite/tr1/2_general_utilities/shared_ptr/cons/auto_ptr_neg.cc @@ -17,7 +17,8 @@ // with this library; see the file COPYING3. If not see // . -// { dg-options "-std=c++98" } +// { dg-add-options using-deprecated } +// { dg-warning "auto_ptr. is deprecated" "" { target c++11 } 0 } // TR1 2.2.2 Template class shared_ptr [tr.util.smartptr.shared] diff --git a/libstdc++-v3/testsuite/tr1/6_containers/utility/pair.cc b/libstdc++-v3/testsuite/tr1/6_containers/utility/pair.cc index 4d4dcdb7a02b..904b38c2b647 100644 --- a/libstdc++-v3/testsuite/tr1/6_containers/utility/pair.cc +++ b/libstdc++-v3/testsuite/tr1/6_containers/utility/pair.cc @@ -17,8 +17,6 @@ // with this library; see the file COPYING3. If not see // . -// { dg-options "-std=c++98" } - // tr1 additions to pair #include @@ -42,15 +40,14 @@ main() tuple_element<1, pair >::type blank3 __attribute__((unused)) = blank; pair test_pair(1, 2); - VERIFY(get<0>(test_pair) == 1); - VERIFY(get<1>(test_pair) == 2); - get<0>(test_pair) = 3; - get<1>(test_pair) = 4; - VERIFY(get<0>(test_pair) == 3); - VERIFY(get<1>(test_pair) == 4); + VERIFY(std::tr1::get<0>(test_pair) == 1); + VERIFY(std::tr1::get<1>(test_pair) == 2); + std::tr1::get<0>(test_pair) = 3; + std::tr1::get<1>(test_pair) = 4; + VERIFY(std::tr1::get<0>(test_pair) == 3); + VERIFY(std::tr1::get<1>(test_pair) == 4); const pair test_pair2(1,2); - VERIFY(get<0>(test_pair2) == 1); - VERIFY(get<1>(test_pair2) == 2); + VERIFY(std::tr1::get<0>(test_pair2) == 1); + VERIFY(std::tr1::get<1>(test_pair2) == 2); } - diff --git a/libstdc++-v3/testsuite/tr1/8_c_compatibility/cmath/pow_cmath.cc b/libstdc++-v3/testsuite/tr1/8_c_compatibility/cmath/pow_cmath.cc index bc89ab2f6fe0..63891bf4ba07 100644 --- a/libstdc++-v3/testsuite/tr1/8_c_compatibility/cmath/pow_cmath.cc +++ b/libstdc++-v3/testsuite/tr1/8_c_compatibility/cmath/pow_cmath.cc @@ -17,8 +17,6 @@ // with this library; see the file COPYING3. If not see // . -// { dg-options "-std=c++98" } - #include using std::pow; #include @@ -30,6 +28,11 @@ test01() using namespace __gnu_test; float x = 2080703.375F; +#if __cplusplus < 201103L check_ret_type(std::pow(x, 2)); +#else + // LWG 550 What should the return type of pow(float,int) be? + check_ret_type(std::pow(x, 2)); +#endif check_ret_type(std::tr1::pow(x, 2)); } diff --git a/libstdc++-v3/testsuite/util/replacement_memory_operators.h b/libstdc++-v3/testsuite/util/replacement_memory_operators.h index 6b1b3a82364c..6f19fbb8f6f6 100644 --- a/libstdc++-v3/testsuite/util/replacement_memory_operators.h +++ b/libstdc++-v3/testsuite/util/replacement_memory_operators.h @@ -75,12 +75,32 @@ namespace __gnu_test counter& cntr = get(); cntr._M_increments = cntr._M_decrements = 0; } + + struct scope + { + scope() : _M_count(counter::count()) + { counter::get()._M_count = 0; } + ~scope() + { counter::get()._M_count = _M_count; } + + private: + std::size_t _M_count; + +#if __cplusplus >= 201103L + scope(const scope&) = delete; + scope& operator=(const scope&) = delete; +#else + scope(const scope&); + scope& operator=(const scope&); +#endif + }; }; template bool check_new(Alloc a = Alloc()) { + __gnu_test::counter::scope s; __gnu_test::counter::exceptions(false); (void) a.allocate(10); const bool __b((__gnu_test::counter::count() > 0) == uses_global_new); diff --git a/libvtv/ChangeLog b/libvtv/ChangeLog index 88705423c4b0..a1c115ec32ee 100644 --- a/libvtv/ChangeLog +++ b/libvtv/ChangeLog @@ -1,3 +1,27 @@ +2023-08-07 Nick Alcock + + * configure: Regenerate. + +2023-08-07 Alexander von Gluck IV + + * configure: Regenerate. + +2023-08-07 Nick Alcock + + * configure: Regenerate. + +2023-08-07 Nick Alcock + + * configure: Regenerate. + +2023-08-07 H.J. Lu + + * configure: Regenerate. + +2023-08-07 H.J. Lu + + * configure: Regenerate. + 2023-01-07 LIU Hao PR middle-end/108300 diff --git a/lto-plugin/ChangeLog b/lto-plugin/ChangeLog index 25d4577e72b3..b90023600587 100644 --- a/lto-plugin/ChangeLog +++ b/lto-plugin/ChangeLog @@ -1,3 +1,27 @@ +2023-08-07 Nick Alcock + + * configure: Regenerate. + +2023-08-07 Alexander von Gluck IV + + * configure: Regenerate. + +2023-08-07 Nick Alcock + + * configure: Regenerate. + +2023-08-07 Nick Alcock + + * configure: Regenerate. + +2023-08-07 H.J. Lu + + * configure: Regenerate. + +2023-08-07 H.J. Lu + + * configure: Regenerate. + 2023-06-30 Martin Jambor * Makefile.in: Regenerate. diff --git a/zlib/ChangeLog b/zlib/ChangeLog index aee8a6895053..3f972615fdea 100644 --- a/zlib/ChangeLog +++ b/zlib/ChangeLog @@ -1,3 +1,27 @@ +2023-08-07 Nick Alcock + + * configure: Regenerate. + +2023-08-07 Alexander von Gluck IV + + * configure: Regenerate. + +2023-08-07 Nick Alcock + + * configure: Regenerate. + +2023-08-07 Nick Alcock + + * configure: Regenerate. + +2023-08-07 H.J. Lu + + * configure: Regenerate. + +2023-08-07 H.J. Lu + + * configure: Regenerated. + 2023-06-16 Martin Jambor * Makefile.in: Regenerate.