diff options
493 files changed, 17411 insertions, 1485 deletions
@@ -1,3 +1,7 @@ +2025-04-16 Waffl3x <waffl3x@baylibre.com> + + * MAINTAINERS: Add myself. + 2025-04-02 Iain Sandoe <iain@sandoe.co.uk> * configure: Regenerate. diff --git a/MAINTAINERS b/MAINTAINERS index 756227e..6ff4770 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -862,6 +862,7 @@ Ville Voutilainen ville <ville.voutilainen@gmail.com> Tom de Vries vries <tdevries@suse.de> Nenad Vukicevic nenadv <nenad@intrepid.com> Dmitry Vyukov dvyukov <dvyukov@google.com> +Waffl3x waffl3x <waffl3x@baylibre.com> Jonathan Wakely redi <jwakely@redhat.com> Krister Walfridsson kristerw <krister.walfridsson@gmail.com> Feng Wang - <wangfeng@eswincomputing.com> diff --git a/config/ChangeLog b/config/ChangeLog index 9268a8e..2551f82 100644 --- a/config/ChangeLog +++ b/config/ChangeLog @@ -1,3 +1,7 @@ +2025-04-15 Kyrylo Tkachov <ktkachov@nvidia.com> + + * bootstrap-lto-locality.mk: New file. + 2024-11-25 Sandra Loosemore <sloosemore@baylibre.com> * mt-nios2-elf: Deleted. diff --git a/config/bootstrap-lto-locality.mk b/config/bootstrap-lto-locality.mk new file mode 100644 index 0000000..b31565c --- /dev/null +++ b/config/bootstrap-lto-locality.mk @@ -0,0 +1,20 @@ +# This option enables LTO and locality partitioning for stage2 and stage3 in slim mode + +STAGE2_CFLAGS += -flto=jobserver -frandom-seed=1 -fipa-reorder-for-locality +STAGE3_CFLAGS += -flto=jobserver -frandom-seed=1 -fipa-reorder-for-locality +STAGEprofile_CFLAGS += -flto=jobserver -frandom-seed=1 -fipa-reorder-for-locality +STAGEtrain_CFLAGS += -flto=jobserver -frandom-seed=1 -fipa-reorder-for-locality +STAGEfeedback_CFLAGS += -flto=jobserver -frandom-seed=1 -fipa-reorder-for-locality + +# assumes the host supports the linker plugin +LTO_AR = $$r/$(HOST_SUBDIR)/prev-gcc/gcc-ar$(exeext) -B$$r/$(HOST_SUBDIR)/prev-gcc/ +LTO_RANLIB = $$r/$(HOST_SUBDIR)/prev-gcc/gcc-ranlib$(exeext) -B$$r/$(HOST_SUBDIR)/prev-gcc/ +LTO_NM = $$r/$(HOST_SUBDIR)/prev-gcc/gcc-nm$(exeext) -B$$r/$(HOST_SUBDIR)/prev-gcc/ + +LTO_EXPORTS = AR="$(LTO_AR)"; export AR; \ + RANLIB="$(LTO_RANLIB)"; export RANLIB; \ + NM="$(LTO_NM)"; export NM; +LTO_FLAGS_TO_PASS = AR="$(LTO_AR)" RANLIB="$(LTO_RANLIB)" NM="$(LTO_NM)" + +do-compare = $(SHELL) $(srcdir)/contrib/compare-lto $$f1 $$f2 +extra-compare = gcc/lto1$(exeext) diff --git a/contrib/ChangeLog b/contrib/ChangeLog index 334d1e4..e7a4cab 100644 --- a/contrib/ChangeLog +++ b/contrib/ChangeLog @@ -1,3 +1,8 @@ +2025-04-17 Jakub Jelinek <jakub@redhat.com> + + * gcc-changelog/git_update_version.py (active_refs): Add + releases/gcc-15. + 2025-04-11 Tomasz Kamiński <tkaminsk@redhat.com> PR libstdc++/109162 diff --git a/contrib/gcc-changelog/git_update_version.py b/contrib/gcc-changelog/git_update_version.py index 8e36c74..aa9adee 100755 --- a/contrib/gcc-changelog/git_update_version.py +++ b/contrib/gcc-changelog/git_update_version.py @@ -85,8 +85,8 @@ def prepend_to_changelog_files(repo, folder, git_commit, add_to_git): repo.git.add(full_path) -active_refs = ['master', - 'releases/gcc-12', 'releases/gcc-13', 'releases/gcc-14'] +active_refs = ['master', 'releases/gcc-12', + 'releases/gcc-13', 'releases/gcc-14', 'releases/gcc-15'] parser = argparse.ArgumentParser(description='Update DATESTAMP and generate ' 'ChangeLog entries') diff --git a/gcc/BASE-VER b/gcc/BASE-VER index 2bbd2b4..946789e 100644 --- a/gcc/BASE-VER +++ b/gcc/BASE-VER @@ -1 +1 @@ -15.0.1 +16.0.0 diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 1530dcb..5b54c5a 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,645 @@ +2025-04-21 Jan Hubicka <hubicka@ucw.cz> + + PR target/119879 + * config/i386/i386.cc (fp_conversion_stmt_cost): Inline to ... + (ix86_vector_costs::add_stmt_cost): ... here; fix handling of NOP_EXPR. + +2025-04-21 Matthew Fortune <matthew.fortune@imgtec.com> + + * config/mips/mips.cc (mips_option_override): Error out for + -mmicromips -mmsa. + +2025-04-21 Andrew Pinski <quic_apinski@quicinc.com> + + PR middle-end/119507 + * except.cc (switch_to_exception_section): Don't use the cached section if + the current function is in comdat. + +2025-04-21 Andrew Pinski <quic_apinski@quicinc.com> + + * vec.h (array_slice::begin): Assert that the + slice is valid. + (array_slice::end): Likewise. + +2025-04-21 hongtao.liu <hongtao.liu@intel.com> + + * config/i386/i386-expand.cc (ix86_emit_swdivsf): Generate 2 + FMA instructions when TARGET_FMA. + +2025-04-19 Jeff Law <jlaw@ventanamicro.com> + + PR target/119865 + * config/riscv/riscv.cc (parse_features_for_version): Do not + explicitly free the architecture string. + +2025-04-19 Jeff Law <jlaw@ventanamicro.com> + + PR target/118410 + * config/riscv/bitmanip.md (logical with constant argument): New + splitter for cases where synthesizing ~C is cheaper than synthesizing + the original constant C. + +2025-04-19 Jan Hubicka <hubicka@ucw.cz> + + * config/i386/i386.cc (vec_fp_conversion_cost): New function. + (ix86_rtx_costs): Use it for SSE/AVX FP conversoins. + (ix86_builtin_vectorization_cost): Fix indentation; + and use vec_fp_conversion_cost in vec_promote_demote. + (fp_conversion_stmt_cost): New function. + (ix86_vector_costs::add_stmt_cost): Use it to cost NOP_EXPR + and vec_promote_demote. + * config/i386/i386.h (struct processor_costs): + * config/i386/x86-tune-costs.h (struct processor_costs): + +2025-04-19 Andrew Pinski <quic_apinski@quicinc.com> + + PR rtl-optimization/111949 + * combine.cc (find_split_point): Add a split point + for `(and (not X) Y)` if not in the outer set already. + +2025-04-19 Jiaxun Yang <jiaxun.yang@flygoat.com> + + PR target/111814 + * config/sh/sh-modes.def (RESET_FLOAT_FORMAT): Use mips format. + (FLOAT_MODE): Use mips mode. + +2025-04-19 Maciej W. Rozycki <macro@orcam.me.uk> + + * config/alpha/alpha.cc + (alpha_get_mem_rtx_alignment_and_offset): Recurse into + COMPONENT_REF nodes. + +2025-04-18 Jeff Law <jlaw@ventanamicro.com> + + * config/riscv/bitmanip.md (*bext<mode>_mask_pos): New pattern + for extracting a single bit at masked bit position. + +2025-04-18 Andrew Pinski <quic_apinski@quicinc.com> + + PR tree-optimization/87901 + * tree-ssa-dse.cc (maybe_trim_constructor_store): Add was_integer_cst argument. + Check for was_integer_cst instead of `{}` when was_integer_cst is true. + (maybe_trim_partially_dead_store): Handle INTEGER_CST stores of 0 as stores of `{}`. + Udpate call to maybe_trim_constructor_store for CONSTRUCTOR. + +2025-04-18 Andrew Pinski <quic_apinski@quicinc.com> + + PR tree-optimization/87901 + * tree-ssa-dse.cc (maybe_trim_constructor_store): Strip over useless type + conversions after taking the address of the MEM_REF. + +2025-04-18 Andrew Pinski <quic_apinski@quicinc.com> + + PR tree-optimization/118902 + * fold-const.cc (tree_swap_operands_p): Place invariants in the first operand + if not used with constants. + +2025-04-18 Andrew Pinski <quic_apinski@quicinc.com> + + PR tree-optimization/118947 + * gimple-fold.cc (optimize_memcpy_to_memset): Walk back until we get a + statement that may clobber the read. + +2025-04-18 Andrew Pinski <quic_apinski@quicinc.com> + + PR tree-optimization/78408 + PR tree-optimization/118947 + * gimple-fold.cc (optimize_memcpy_to_memset): Handle STRING_CST case too. + +2025-04-18 Richard Braun <rbraun@sceen.net> + + * config/c6x/c6x.h (ASM_PREFERRED_EH_DATA_FORMAT): Remove the + DW_EH_PE_indirect flag. + +2025-04-18 Richard Biener <rguenther@suse.de> + + PR tree-optimization/119858 + * tree-vect-loop.cc (vectorizable_live_operation): Convert + pointer offset to sizetype. + +2025-04-18 Hakan Candar <hakancandar@protonmail.com> + + * config.gcc: Recognize riscv*-*-gnu* targets. + * config/riscv/gnu.h: New file. + +2025-04-18 Alexey Merzlyakov <alexey.merzlyakov@samsung.com> + + PR middle-end/108016 + PR middle-end/108016 + * config/riscv/riscv.md (addv<mode>4, uaddv<mode>4, subv<mode>4, + usubv<mode>4): Tunes for unnecessary sext.w elimination. + +2025-04-18 kelefth <konstantinos.eleftheriou@vrull.eu> + + PR rtl-optimization/119160 + * avoid-store-forwarding.cc (process_store_forwarding): + Zero-extend the value stored in the base register, in case + of load-elimination, only when the mode of the destination + is wider. + +2025-04-18 kelefth <konstantinos.eleftheriou@vrull.eu> + + * doc/cfg.texi: Update the exception handling section for the + REG_EH_REGION notes to make it clear that the note is attached + to the instruction throwing the exception. + +2025-04-17 翁愷邑 <kaiweng9487@gmail.com> + + * config/riscv/riscv-target-attr.cc + (riscv_target_attr_parser::update_settings): + Do not manually free any arch string. + +2025-04-17 Eric Botcazou <ebotcazou@gcc.gnu.org> + + * tree.def (BOOLEAN_TYPE): Add more details. + +2025-04-17 Sam James <sam@gentoo.org> + + * doc/invoke.texi: Use "compatible types" term. Rephrase to be + more precise (and correct). + +2025-04-17 Tamar Christina <tamar.christina@arm.com> + + PR tree-optimization/119351 + * tree-vect-stmts.cc (vectorizable_early_exit): Mask both operands of + the gcond for partial masking support. + +2025-04-17 Jakub Jelinek <jakub@redhat.com> + + PR target/119834 + * config/s390/s390.md (define_split after *cpymem_short): Use + (clobber (match_scratch N)) instead of (clobber (scratch)). Use + (match_dup 4) and operands[4] instead of (match_dup 3) and operands[3] + in the last of those. + (define_split after *clrmem_short): Use (clobber (match_scratch N)) + instead of (clobber (scratch)). + (define_split after *cmpmem_short): Likewise. + +2025-04-17 Thomas Schwinge <tschwinge@baylibre.com> + + * config/nvptx/nvptx.cc (TARGET_ASM_NEED_VAR_DECL_BEFORE_USE): + Don't '#define'. + +2025-04-17 Hans-Peter Nilsson <hp@axis.com> + + * combine.cc: Correct comments about combine_validate_cost. + +2025-04-16 Sandra Loosemore <sloosemore@baylibre.com> + + PR c/88382 + * doc/extend.texi (Syntax Extensions): Adjust menu. + (Raw String Literals): New section. + +2025-04-16 Keith Packard <keithp@keithp.com> + + * config/rx/rx.md (cmpstrnsi): Allow constant length. For + static length 0, just store 0 into the output register. + For dynamic zero, set C/Z appropriately. + (rxcmpstrn): No longer set C/Z. + +2025-04-16 Eric Botcazou <ebotcazou@gcc.gnu.org> + + * tree-ssa-phiopt.cc (factor_out_conditional_operation): Do not + bypass the int_fits_type_p test for boolean types whose precision + is not 1. + +2025-04-16 Sandra Loosemore <sloosemore@baylibre.com> + + * common.opt.urls: Regenerated. + +2025-04-16 Ard Biesheuvel <ardb@kernel.org> + + PR target/119386 + * config/i386/i386-options.cc: Permit -mnop-mcount when + using -fpic with PLTs. + +2025-04-16 Ard Biesheuvel <ardb@kernel.org> + + PR target/119386 + * config/i386/i386.cc (x86_print_call_or_nop): Add @PLT suffix + where appropriate. + (x86_function_profiler): Fall through to x86_print_call_or_nop() + for PIC codegen when flag_plt is set. + +2025-04-16 Sandra Loosemore <sloosemore@baylibre.com> + + PR driver/90465 + * doc/invoke.texi (Overall Options): Add a @cindex for -Q in + connection with --help=. + (Developer Options): Point at --help= documentation for the + other use of -Q. + +2025-04-16 Thomas Schwinge <tschwinge@baylibre.com> + + PR target/97106 + * config/nvptx/nvptx.cc (nvptx_asm_output_def_from_decls) + [ACCEL_COMPILER]: Make sure to emit C++ constructor, destructor + aliases. + +2025-04-16 Jan Hubicka <hubicka@ucw.cz> + + PR tree-optimization/119614 + * ipa-prop.cc (ipa_write_return_summaries): New function. + (ipa_record_return_value_range_1): Break out from .... + (ipa_record_return_value_range): ... here. + (ipa_read_return_summaries): New function. + (ipa_prop_read_section): Read return summaries. + (read_ipcp_transformation_info): Read return summaries. + (ipcp_write_transformation_summaries): Write return summaries; + do not stream stray 0. + +2025-04-16 Tamar Christina <tamar.christina@arm.com> + + PR tree-optimization/119351 + * tree-vectorizer.h (LOOP_VINFO_MASK_NITERS_PFA_OFFSET, + LOOP_VINFO_NON_LINEAR_IV): New. + (class _loop_vec_info): Add mask_skip_niters_pfa_offset and + nonlinear_iv. + * tree-vect-loop.cc (_loop_vec_info::_loop_vec_info): Initialize them. + (vect_analyze_scalar_cycles_1): Record non-linear inductions. + (vectorizable_induction): If early break and PFA using masking create a + new phi which tracks where the scalar code needs to start... + (vectorizable_live_operation): ...and generate the adjustments here. + (vect_use_loop_mask_for_alignment_p): Reject non-linear inductions and + early break needing peeling. + +2025-04-16 Jakub Jelinek <jakub@redhat.com> + + PR middle-end/119808 + * gimple-lower-bitint.cc (gimple_lower_bitint): Don't set + m_single_use_names bits for SSA_NAMEs which have single use but + their SSA_NAME_DEF_STMT is a copy from another SSA_NAME which doesn't + have a single use, or single use which is such a copy etc. + +2025-04-16 Jesse Huang <jesse.huang@sifive.com> + + * config/riscv/riscv.cc (riscv_file_end): Fix .p2align value. + +2025-04-16 Kito Cheng <kito.cheng@sifive.com> + + * config/riscv/riscv.h (JUMP_TABLES_IN_TEXT_SECTION): Check if + large code model. + +2025-04-16 Tejas Belagod <tejas.belagod@arm.com> + + * config/aarch64/aarch64-sve.md (vec_extract<vpred><Vel>): Fix operand + order to gen_vcond_mask_*. + +2025-04-16 Alice Carlotti <alice.carlotti@arm.com> + + * config/aarch64/aarch64.cc + (aarch64_valid_sysreg_name_p): Remove feature check. + (aarch64_retrieve_sysreg): Ditto. + +2025-04-15 Sandra Loosemore <sloosemore@baylibre.com> + + PR tree-optimization/71094 + * doc/invoke.texi (Optimize Options): Document that -fivopts is + enabled at -O1 and higher. Add blurb about -O0 causing GCC to + completely ignore most optimization options. + +2025-04-15 Iain Sandoe <iain@sandoe.co.uk> + + * configure: Regenerate. + * configure.ac: Recognise PROJECT:ld-mmmm.nn.aa as an identifier + for Darwin's static linker. + +2025-04-15 Iain Sandoe <iainsandoe@mini-05-seq.local> + + PR target/116827 + * ginclude/stddef.h: Undefine __PTRDIFF_T and __SIZE_T for module- + enabled c++ on Darwin/macOS platforms. + +2025-04-15 Kyrylo Tkachov <ktkachov@nvidia.com> + + * common.opt.urls: Regenerate. + +2025-04-15 Jan Hubicka <hubicka@ucw.cz> + + * config/i386/x86-tune-sched.cc (ix86_issue_rate): Set + to 4 for znver5. + +2025-04-15 Jan Hubicka <hubicka@ucw.cz> + + PR target/119298 + * config/i386/x86-tune-costs.h (znver5_cost): Set ADDSS cost to 3. + +2025-04-15 Vineet Gupta <vineetg@rivosinc.com> + + PR target/119533 + * config/riscv/riscv-vsetvl.cc (invalid_opt_bb_p): Check for + EDGE_ABNOMAL. + (pre_vsetvl::compute_lcm_local_properties): Initialize kill + bitmap. + Debug dump skipped edge. + +2025-04-15 Robin Dapp <rdapp@ventanamicro.com> + + PR target/119547 + * config/riscv/riscv-vsetvl.cc (pre_vsetvl::earliest_fuse_vsetvl_info): + Do not perform lift if block is not transparent. + +2025-04-15 Kyrylo Tkachov <ktkachov@nvidia.com> + + * Makefile.in (OBJS): Add ipa-locality-cloning.o. + * cgraph.h (set_new_clone_decl_and_node_flags): Declare prototype. + * cgraphclones.cc (set_new_clone_decl_and_node_flags): Remove static + qualifier. + * common.opt (fipa-reorder-for-locality): New flag. + (LTO_PARTITION_DEFAULT): Declare. + (flto-partition): Change default to LTO_PARTITION_DFEAULT. + * doc/invoke.texi: Document -fipa-reorder-for-locality. + * flag-types.h (enum lto_locality_cloning_model): Declare. + (lto_partitioning_model): Add LTO_PARTITION_DEFAULT. + * lto-cgraph.cc (lto_set_symtab_encoder_in_partition): Add dumping of + node and index. + * opts.cc (validate_ipa_reorder_locality_lto_partition): Define. + (finish_options): Handle LTO_PARTITION_DEFAULT. + * params.opt (lto_locality_cloning_model): New enum. + (lto-partition-locality-cloning): New param. + (lto-partition-locality-frequency-cutoff): Likewise. + (lto-partition-locality-size-cutoff): Likewise. + (lto-max-locality-partition): Likewise. + * passes.def: Register pass_ipa_locality_cloning. + * timevar.def (TV_IPA_LC): New timevar. + * tree-pass.h (make_pass_ipa_locality_cloning): Declare. + * ipa-locality-cloning.cc: New file. + * ipa-locality-cloning.h: New file. + +2025-04-15 Martin Jambor <mjambor@suse.cz> + Jakub Jelinek <jakub@redhat.com> + + PR ipa/119803 + * ipa-cp.cc (ipcp_bits_lattice::meet_with_1): Move m_value adjustmed + according to m_mask below the adjustment of the latter according to + cap_mask. Optimize the calculation of cap_mask a bit. + (ipcp_bits_lattice::meet_with): Optimize the calculation of cap_mask a + bit. + +2025-04-15 Jakub Jelinek <jakub@redhat.com> + + * ipa-cp.cc (ipcp_print_widest_int): Print values with all ones in + bits 128+ with "0xf..f" prefix instead of "all ones folled by ". + Simplify wide_int check for -1 or all ones above least significant + 128 bits. + +2025-04-15 Jakub Jelinek <jakub@redhat.com> + + PR sanitizer/119801 + * sanitizer.def (BUILT_IN_TSAN_FUNC_EXIT): Use BT_FN_VOID rather + than BT_FN_VOID_PTR. + * tree-tailcall.cc: Include attribs.h and asan.h. + (struct tailcall): Add has_tsan_func_exit member. + (empty_eh_cleanup): Add eh_has_tsan_func_exit argument, set what + it points to to 1 if there is exactly one __tsan_func_exit call + and ignore that call otherwise. Adjust recursive call. + (find_tail_calls): Add RETRY_TSAN_FUNC_EXIT argument, pass it + to recursive calls. When seeing __tsan_func_exit call with + RETRY_TSAN_FUNC_EXIT 0, set it to -1. If RETRY_TSAN_FUNC_EXIT + is 1, initially ignore __tsan_func_exit calls. Adjust + empty_eh_cleanup caller. When looking through stmts after the call, + ignore exactly one __tsan_func_exit call but remember it in + t->has_tsan_func_exit. Diagnose if EH cleanups didn't have + __tsan_func_exit and normal path did or vice versa. + (optimize_tail_call): Emit __tsan_func_exit before the tail call + or tail recursion. + (tree_optimize_tail_calls_1): Adjust find_tail_calls callers. If + find_tail_calls changes retry_tsan_func_exit to -1, set it to 1 + and call it again with otherwise the same arguments. + +2025-04-15 Sandra Loosemore <sloosemore@baylibre.com> + + PR ipa/113203 + * doc/extend.texi (Common Function Attributes): Explain how to + use always_inline in programs that have multiple translation + units, and that LTO inlining additionally needs optimization + enabled. + +2025-04-15 liuhongt <hongtao.liu@intel.com> + + PR target/108134 + * doc/extend.texi: Remove documents from r11-344-g0fec3f62b9bfc0. + +2025-04-15 Sandra Loosemore <sloosemore@baylibre.com> + + PR target/42683 + * doc/invoke.texi (x86 Options): Clarify that -march=pentiumpro + doesn't include MMX. + +2025-04-14 Thomas Schwinge <tschwinge@baylibre.com> + + PR target/118794 + * config/gcn/gcn.opt (-mfake-exceptions): Support. + * config/nvptx/nvptx.opt (-mfake-exceptions): Likewise. + * config/gcn/gcn.md (define_expand "exception_receiver"): Use it. + * config/nvptx/nvptx.md (define_expand "exception_receiver"): + Likewise. + * config/gcn/mkoffload.cc (main): Set it. + * config/nvptx/mkoffload.cc (main): Likewise. + * config/nvptx/nvptx.cc (nvptx_assemble_integer) + <in_section == exception_section>: Special handling for + 'SYMBOL_REF's. + * except.cc (expand_dw2_landing_pad_for_region): Don't generate + bogus code for (default) + '#define EH_RETURN_DATA_REGNO(N) INVALID_REGNUM'. + +2025-04-14 Jakub Jelinek <jakub@redhat.com> + + PR rtl-optimization/119785 + * expmed.cc (init_expmed): Always pass QImode rather than mode to + set_src_cost passed to set_zero_cost. + +2025-04-14 Jakub Jelinek <jakub@redhat.com> + + PR tree-optimization/119718 + * tree-pretty-print.cc (dump_generic_node) <case CALL_EXPR>: Dump + also CALL_EXPR_MUST_TAIL_CALL flag. + * calls.cc (maybe_complain_about_tail_call): Emit error about + CALL_EXPR_MUST_TAIL_CALL only after emitting dump message, not before + it. + +2025-04-14 Arthur Cohen <arthur.cohen@embecosm.com> + + * doc/install.texi: Add requirements for building gccrs. + +2025-04-14 H.J. Lu <hjl.tools@gmail.com> + + PR target/119784 + * config/i386/i386.cc (ix86_using_red_zone): Don't use red-zone + with 32 GPRs and no caller-saved registers. + +2025-04-14 Martin Jambor <mjambor@suse.cz> + + PR ipa/118097 + * ipa-cp.cc (ipa_get_jf_arith_result): Require res_operand for + anything except NOP_EXPR or ADDR_EXPR, document it and remove the code + trying to deduce it. + (ipa_value_from_jfunc): Use the stored and streamed type of arithmetic + pass-through functions. + (ipa_agg_value_from_jfunc): Use the stored and streamed type of + arithmetic pass-through functions, convert to the type used to store + the value if necessary. + (get_val_across_arith_op): New parameter op_type, pass it to + ipa_get_jf_arith_result. + (propagate_vals_across_arith_jfunc): New parameter op_type, pass it to + get_val_across_arith_op. + (propagate_vals_across_pass_through): Use the stored and streamed type + of arithmetic pass-through functions. + (propagate_aggregate_lattice): Likewise. + (push_agg_values_for_index_from_edge): Use the stored and streamed + type of arithmetic pass-through functions, convert to the type used to + store the value if necessary. + +2025-04-14 Martin Jambor <mjambor@suse.cz> + + PR ipa/118785 + * ipa-cp.cc (ipa_vr_intersect_with_arith_jfunc): Use the stored + and streamed type of arithmetic pass-through functions. + +2025-04-14 Martin Jambor <mjambor@suse.cz> + + * ipa-cp.cc (ipcp_print_widest_int): Also add a truncated form of + dumping of widest ints which only have zeros in the lowest 128 bits. + Update the comment. + (ipcp_bits_lattice::print): Also dump the mask using + ipcp_print_widest_int. + (ipcp_store_vr_results): Likewise. + +2025-04-14 Martin Jambor <mjambor@suse.cz> + + PR ipa/119318 + * ipa-cp.cc (ipcp_bits_lattice::meet_with_1): Set all mask bits + not covered by precision to one. + (ipcp_bits_lattice::meet_with): Likewise. + (propagate_bits_across_jump_function): Use the stored operation + type to perform meet with other lattices. + +2025-04-14 Martin Jambor <mjambor@suse.cz> + + PR ipa/118097 + PR ipa/118785 + PR ipa/119318 + * lto-streamer.h (lto_variably_modified_type_p): Declare. + * ipa-prop.h (ipa_pass_through_data): New field op_type. + (ipa_get_jf_pass_through_op_type): New function. + * ipa-prop.cc: Include lto-streamer.h. + (ipa_dump_jump_function): Dump also pass-through + operation types, if any. Dump pass-through operands only if not NULL. + (ipa_set_jf_simple_pass_through): Set op_type accordingly. + (compute_complex_assign_jump_func): Set op_type of arithmetic + pass-through jump_functions. + (analyze_agg_content_value): Update lhs when walking assighment + copies. Set op_type of aggregate arithmetic pass-through + jump_functions. + (update_jump_functions_after_inlining): Also transfer the operation + type from the source arithmentic pass-through jump function to the + destination jump function. + (ipa_write_jump_function): Stream also the op_type when necessary. + (ipa_read_jump_function): Likewise. + (ipa_agg_pass_through_jf_equivalent_p): Also compare operation types. + * lto-streamer-out.cc (lto_variably_modified_type_p): Make public. + +2025-04-14 Richard Biener <rguenther@suse.de> + + PR tree-optimization/119757 + * tree-vect-slp.cc (vect_build_slp_tree_1): Record and compare + whether a stmt uses a maks. + +2025-04-14 Richard Biener <rguenther@suse.de> + + PR tree-optimization/119778 + * tree-inline.cc (copy_edges_for_bb): Mark calls that are + source of abnormal edges as altering control-flow. + +2025-04-14 Gaius Mulley <gaiusmod2@gmail.com> + + PR modula2/119779 + * doc/gm2.texi (Interface to assembly language): Use eax + rather than rax in both examples. + +2025-04-14 Jakub Jelinek <jakub@redhat.com> + + PR driver/119727 + * configure.ac (HOST_HAS_PERSONALITY_ADDR_NO_RANDOMIZE): New check. + * gcc.cc: Include sys/personality.h if + HOST_HAS_PERSONALITY_ADDR_NO_RANDOMIZE is defined. + (try_generate_repro): Call + personality (personality (0xffffffffU) | ADDR_NO_RANDOMIZE) + if HOST_HAS_PERSONALITY_ADDR_NO_RANDOMIZE is defined. + * config.in: Regenerate. + * configure: Regenerate. + +2025-04-13 Stefan Schulze Frielinghaus <stefansf@gcc.gnu.org> + + * config/s390/s390.cc: Add z17 scheduler description. + * config/s390/s390.h: Ditto. + * config/s390/s390.md: Ditto. + * config/s390/9175.md: New file. + +2025-04-13 Stefan Schulze Frielinghaus <stefansf@gcc.gnu.org> + + * common/config/s390/s390-common.cc: Rename arch15 to z17. + * config.gcc: Add z17. + * config/s390/driver-native.cc: Detect z17 machine. + * config/s390/s390-builtins.def (B_VXE3): Rename arch15 to z17. + * config/s390/s390-c.cc (s390_resolve_overloaded_builtin): Ditto. + * config/s390/s390-opts.h (enum processor_type): Ditto. + * config/s390/s390.cc: Ditto. + * config/s390/s390.h: Ditto. + * config/s390/s390.md: Ditto. + * config/s390/s390.opt: Add z17. + * doc/invoke.texi: Ditto. + +2025-04-12 Sandra Loosemore <sloosemore@baylibre.com> + + PR target/97585 + * doc/invoke.texi (x86 Options): Document list of extensions + supported by -march=x86_64, according to the declaration of + PTA_X86_64_BASELINE in config/i386/i386.h. + +2025-04-12 Jakub Jelinek <jakub@redhat.com> + + PR driver/119727 + * gcc.cc (files_equal_p): Rewritten using fopen/fgets/fclose instead + of open/fstat/read/close. At the start of lines, ignore lowercase + hexadecimal addresses followed by space. + +2025-04-12 Jakub Jelinek <jakub@redhat.com> + + PR tree-optimization/119722 + * gimple-lower-bitint.h (build_bitint_stmt_ssa_conflicts): Add + CLEAR argument. + * gimple-lower-bitint.cc (build_bitint_stmt_ssa_conflicts): Add + CLEAR argument. Call clear on gimple_assign_copy_p rhs1 if lhs + is large/huge bitint unless lhs is not in names. + * tree-ssa-coalesce.cc (build_ssa_conflict_graph): Adjust + build_bitint_stmt_ssa_conflicts caller. Move gimple_assign_copy_p + handling to after the build_bitint_stmt_ssa_conflicts call. + +2025-04-12 Jakub Jelinek <jakub@redhat.com> + + PR tree-optimization/119718 + * tree-tailcall.cc (maybe_error_musttail): Dump the GIMPLE at the + end of the Cannot tail-call line rather than on the line before it. + * calls.cc (maybe_complain_about_tail_call): Dump the GENERIC + at the end of the ;; Cannot tail-call line rather than on the + line before it. + +2025-04-12 Jakub Jelinek <jakub@redhat.com> + + PR tree-optimization/119718 + * tree-tailcall.cc (maybe_error_musttail): Only dump into dump_file + if dump_flags & TDF_DETAILS. Use "Cannot tail-call: " prefix instead + of "Cannot convert: ". + (find_tail_calls, tree_optimize_tail_calls_1): Formatting fixes + for maybe_error_musttail calls. + * calls.cc (maybe_complain_about_tail_call): Emit also a message + into dump_file when dump_flags & TDF_DETAILS for CALL_EXPR_TAILCALL + calls. + (initialize_argument_information): Formatting fix for + maybe_complain_about_tail_call calls. + (can_implement_as_sibling_call_p, expand_call): Likewise. + 2025-04-11 Sandra Loosemore <sloosemore@baylibre.com> PR c++/106618 diff --git a/gcc/DATESTAMP b/gcc/DATESTAMP index d986e55..fa0255d 100644 --- a/gcc/DATESTAMP +++ b/gcc/DATESTAMP @@ -1 +1 @@ -20250412 +20250422 diff --git a/gcc/Makefile.in b/gcc/Makefile.in index ebfcd8a..55b4cd7 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -1555,6 +1555,7 @@ OBJS = \ incpath.o \ init-regs.o \ internal-fn.o \ + ipa-locality-cloning.o \ ipa-cp.o \ ipa-sra.o \ ipa-devirt.o \ @@ -3026,6 +3027,7 @@ GTFILES = $(CPPLIB_H) $(srcdir)/input.h $(srcdir)/coretypes.h \ $(srcdir)/ipa-param-manipulation.h $(srcdir)/ipa-sra.cc \ $(srcdir)/ipa-modref.h $(srcdir)/ipa-modref.cc \ $(srcdir)/ipa-modref-tree.h \ + $(srcdir)/ipa-locality-cloning.cc \ $(srcdir)/signop.h \ $(srcdir)/diagnostic-spec.h $(srcdir)/diagnostic-spec.cc \ $(srcdir)/dwarf2out.h \ diff --git a/gcc/ada/ChangeLog b/gcc/ada/ChangeLog index f7a9025..650de8b 100644 --- a/gcc/ada/ChangeLog +++ b/gcc/ada/ChangeLog @@ -1,3 +1,13 @@ +2025-04-17 Jakub Jelinek <jakub@redhat.com> + + * gnatvsn.ads: Bump Library_Version to 16. + +2025-04-12 Eric Botcazou <ebotcazou@adacore.com> + + PR ada/119643 + * sem_ch8.adb (Inherit_Renamed_Profile): Add guard against the + peculiarities of Natural and Positive. + 2025-04-07 Eric Botcazou <ebotcazou@adacore.com> * gcc-interface/utils.cc (convert) <POINTER_TYPE>: Use fold_convert diff --git a/gcc/ada/gnatvsn.ads b/gcc/ada/gnatvsn.ads index 176f88a..ad11c30 100644 --- a/gcc/ada/gnatvsn.ads +++ b/gcc/ada/gnatvsn.ads @@ -32,7 +32,7 @@ package Gnatvsn is -- Static string identifying this version, that can be used as an argument -- to e.g. pragma Ident. - Library_Version : constant String := "15"; + Library_Version : constant String := "16"; -- Library version. It needs to be updated whenever the major version -- number is changed. -- diff --git a/gcc/avoid-store-forwarding.cc b/gcc/avoid-store-forwarding.cc index 34a7bba..ded8d7e 100644 --- a/gcc/avoid-store-forwarding.cc +++ b/gcc/avoid-store-forwarding.cc @@ -238,10 +238,15 @@ process_store_forwarding (vec<store_fwd_info> &stores, rtx_insn *load_insn, { start_sequence (); - rtx ext0 = gen_rtx_ZERO_EXTEND (GET_MODE (dest), it->mov_reg); - if (ext0) + machine_mode dest_mode = GET_MODE (dest); + rtx base_reg = it->mov_reg; + if (known_gt (GET_MODE_BITSIZE (dest_mode), + GET_MODE_BITSIZE (GET_MODE (it->mov_reg)))) + base_reg = gen_rtx_ZERO_EXTEND (dest_mode, it->mov_reg); + + if (base_reg) { - rtx_insn *move0 = emit_move_insn (dest, ext0); + rtx_insn *move0 = emit_move_insn (dest, base_reg); if (recog_memoized (move0) >= 0) { insns = get_insns (); diff --git a/gcc/c/ChangeLog b/gcc/c/ChangeLog index dec9f16..f75a0f6 100644 --- a/gcc/c/ChangeLog +++ b/gcc/c/ChangeLog @@ -1,3 +1,9 @@ +2025-04-15 Qing Zhao <qing.zhao@oracle.com> + + PR c/119717 + * c-typeck.cc (build_access_with_size_for_counted_by): Fully fold the + parameters for call to .ACCESS_WITH_SIZE. + 2025-04-08 Martin Uecker <uecker@tugraz.at> PR c/119612 diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc index 3870e8a..55d896e 100644 --- a/gcc/c/c-typeck.cc +++ b/gcc/c/c-typeck.cc @@ -3013,12 +3013,16 @@ build_access_with_size_for_counted_by (location_t loc, tree ref, gcc_assert (c_flexible_array_member_type_p (TREE_TYPE (ref))); /* The result type of the call is a pointer to the flexible array type. */ tree result_type = c_build_pointer_type (TREE_TYPE (ref)); + tree first_param + = c_fully_fold (array_to_pointer_conversion (loc, ref), false, NULL); + tree second_param + = c_fully_fold (counted_by_ref, false, NULL); tree call = build_call_expr_internal_loc (loc, IFN_ACCESS_WITH_SIZE, result_type, 6, - array_to_pointer_conversion (loc, ref), - counted_by_ref, + first_param, + second_param, build_int_cst (integer_type_node, 1), build_int_cst (counted_by_type, 0), build_int_cst (integer_type_node, -1), diff --git a/gcc/calls.cc b/gcc/calls.cc index 372fab3..076e046 100644 --- a/gcc/calls.cc +++ b/gcc/calls.cc @@ -1273,11 +1273,6 @@ void maybe_complain_about_tail_call (tree call_expr, const char *reason) { gcc_assert (TREE_CODE (call_expr) == CALL_EXPR); - if (CALL_EXPR_MUST_TAIL_CALL (call_expr)) - { - error_at (EXPR_LOCATION (call_expr), "cannot tail-call: %s", reason); - CALL_EXPR_MUST_TAIL_CALL (call_expr) = 0; - } if (CALL_EXPR_TAILCALL (call_expr) && dump_file && (dump_flags & TDF_DETAILS)) @@ -1286,6 +1281,11 @@ maybe_complain_about_tail_call (tree call_expr, const char *reason) print_generic_expr (dump_file, call_expr, TDF_SLIM); fprintf (dump_file, "\n"); } + if (CALL_EXPR_MUST_TAIL_CALL (call_expr)) + { + error_at (EXPR_LOCATION (call_expr), "cannot tail-call: %s", reason); + CALL_EXPR_MUST_TAIL_CALL (call_expr) = 0; + } } /* Fill in ARGS_SIZE and ARGS array based on the parameters found in diff --git a/gcc/cgraph.h b/gcc/cgraph.h index 065fcc7..abde770 100644 --- a/gcc/cgraph.h +++ b/gcc/cgraph.h @@ -2627,6 +2627,7 @@ void tree_function_versioning (tree, tree, vec<ipa_replace_map *, va_gc> *, void dump_callgraph_transformation (const cgraph_node *original, const cgraph_node *clone, const char *suffix); +void set_new_clone_decl_and_node_flags (cgraph_node *new_node); /* In cgraphbuild.cc */ int compute_call_stmt_bb_frequency (tree, basic_block bb); void record_references_in_initializer (tree, bool); diff --git a/gcc/cgraphclones.cc b/gcc/cgraphclones.cc index 5332a43..e6223fa 100644 --- a/gcc/cgraphclones.cc +++ b/gcc/cgraphclones.cc @@ -158,7 +158,7 @@ cgraph_edge::clone (cgraph_node *n, gcall *call_stmt, unsigned stmt_uid, /* Set flags of NEW_NODE and its decl. NEW_NODE is a newly created private clone or its thunk. */ -static void +void set_new_clone_decl_and_node_flags (cgraph_node *new_node) { DECL_EXTERNAL (new_node->decl) = 0; diff --git a/gcc/cobol/ChangeLog b/gcc/cobol/ChangeLog index a792b3a..27c31c1 100644 --- a/gcc/cobol/ChangeLog +++ b/gcc/cobol/ChangeLog @@ -1,3 +1,77 @@ +2025-04-16 Bob Dubner <rdubner@symas.com> + + PR cobol/119759 + * LICENSE: Deleted. + +2025-04-15 Richard Biener <rguenther@suse.de> + + PR cobol/119302 + * Make-lang.in (GCOBOLIO_INSTALL_NAME): Define. + Use $(GCOBOLIO_INSTALL_NAME) for gcobol.3 manpage source + upon install. + +2025-04-14 Jakub Jelinek <jakub@redhat.com> + + PR cobol/119776 + * lang.opt (fmax-errors): Remove. + * lang.opt.urls: Regenerate. + * cobol1.cc (cobol_langhook_handle_option) <case OPT_fmax_errors>: + Remove. + * gcobol.1: Document -fmax-errors=nerror rather than + -fmax-errors nerror. + +2025-04-14 Jakub Jelinek <jakub@redhat.com> + + PR cobol/119777 + * lang.opt (include): Remove Var(cobol_include). + * cobol1.cc (cobol_langhook_handle_option) <case OPT_include>: Use + arg instead of cobol_include. + +2025-04-14 Jakub Jelinek <jakub@redhat.com> + + PR cobol/119777 + * lang.opt (fsyntax-only): Remove. + * lang.opt.urls: Regenerate. + +2025-04-13 Rainer Orth <ro@CeBiTec.Uni-Bielefeld.DE> + Simon Sobisch <simonsobisch@gnu.org> + + PR cobol/119217 + * parse.y: Rename OVERFLOW to OVERFLOW_kw. + Specify type name in %token directive. + * scan.l: Likewise. + * token_names.h: Regenerate. + +2025-04-13 Rainer Orth <ro@CeBiTec.Uni-Bielefeld.DE> + + PR cobol/119217 + * util.cc (class timespec_t): Rename to cbl_timespec. + +2025-04-13 Rainer Orth <ro@CeBiTec.Uni-Bielefeld.DE> + + * genapi.cc: Include target.h. + (section_label): Use ASM_COMMENT_START. + (paragraph_label): Likewise. + (parser_perform): Likewise. + (internal_perform_through): Likewise. + (hijack_for_development): Likewise. + +2025-04-12 Bob Dubner <rdubner@symas.com> + + PR cobol/119694 + * cbldiag.h: Eliminate getenv() calls. + * cdf.y: Likewise. + * cobol1.cc: Likewise. + * except.cc: Likewise. + * genapi.cc: Likewise. + * lexio.cc: Likewise. + * parse.y: Likewise. + * scan_ante.h: Likewise. + * show_parse.h: Likewise. + * symbols.cc: Likewise. + * symfind.cc: Likewise. + * util.cc: Likewise. + 2025-04-09 Bob Dubner <rdubner@symas.com> PR cobol/119682 diff --git a/gcc/cobol/LICENSE b/gcc/cobol/LICENSE deleted file mode 100644 index aa5ba60..0000000 --- a/gcc/cobol/LICENSE +++ /dev/null @@ -1,29 +0,0 @@ -######################################################################### -# -# Copyright (c) 2021-2025 Symas Corporation -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: -# -# * Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# * Redistributions in binary form must reproduce the above -# copyright notice, this list of conditions and the following disclaimer -# in the documentation and/or other materials provided with the -# distribution. -# * Neither the name of the Symas Corporation nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/gcc/cobol/Make-lang.in b/gcc/cobol/Make-lang.in index 422ebe2..9b74dd3 100644 --- a/gcc/cobol/Make-lang.in +++ b/gcc/cobol/Make-lang.in @@ -35,6 +35,7 @@ # - define the names for selecting the language in LANGUAGES. GCOBOL_INSTALL_NAME := $(shell echo gcobol|sed '$(program_transform_name)') +GCOBOLIO_INSTALL_NAME := $(shell echo gcobol-io|sed '$(program_transform_name)') GCOBOL_TARGET_INSTALL_NAME := $(target_noncanonical)-$(shell echo gcobol|sed '$(program_transform_name)') GCOBC_INSTALL_NAME := $(shell echo gcobc|sed '$(program_transform_name)') @@ -293,7 +294,7 @@ cobol.install-common: installdirs cobol.install-man: installdirs $(INSTALL_DATA) $(srcdir)/cobol/gcobol.1 $(DESTDIR)$(man1dir)/$(GCOBOL_INSTALL_NAME)$(man1ext) - $(INSTALL_DATA) $(srcdir)/cobol/gcobol.3 $(DESTDIR)$(man3dir)/ + $(INSTALL_DATA) $(srcdir)/cobol/gcobol.3 $(DESTDIR)$(man3dir)/$(GCOBOLIO_INSTALL_NAME)$(man3ext) cobol.install-info: @@ -342,8 +343,8 @@ cobol.uninstall: rm -rf $(DESTDIR)$(bindir)/$(GCOBOL_INSTALL_NAME)$(exeext) \ $(DESTDIR)$(bindir)/$(GCOBC_INSTALL_NAME) \ $(DESTDIR)$(datadir)/gcobol/ \ - $(DESTDIR)$(man1dir)/$(GCOBOL_INSTALL_NAME).1 \ - $(DESTDIR)$(man3dir)/gcobol.3 + $(DESTDIR)$(man1dir)/$(GCOBOL_INSTALL_NAME)$(man1ext) \ + $(DESTDIR)$(man3dir)/$(GCOBOLIO_INSTALL_NAME)$(man3ext) cobol.man: cobol.srcman: diff --git a/gcc/cobol/cobol1.cc b/gcc/cobol/cobol1.cc index 98d15a8..3bd21c7 100644 --- a/gcc/cobol/cobol1.cc +++ b/gcc/cobol/cobol1.cc @@ -385,10 +385,6 @@ cobol_langhook_handle_option (size_t scode, return true; } - case OPT_fmax_errors: - flag_max_errors = atoi(arg); - return true; - case OPT_ffixed_form: cobol_set_indicator_column(-7); return true; @@ -413,8 +409,8 @@ cobol_langhook_handle_option (size_t scode, } return true; case OPT_include: - if( ! include_file_add(cobol_include) ) { - cbl_errx( "could not include %s", cobol_include); + if( ! include_file_add(arg) ) { + cbl_errx( "could not include %s", arg); } return true; diff --git a/gcc/cobol/gcobol.1 b/gcc/cobol/gcobol.1 index 64c017c..4377c14 100644 --- a/gcc/cobol/gcobol.1 +++ b/gcc/cobol/gcobol.1 @@ -224,7 +224,7 @@ had appeared. Not all exception conditions are implemented. Any that are not produce a warning message. . -.It Fl fmax-errors Ar nerror +.It Fl fmax-errors Ns Li = Ns Ar nerror .Ar nerror represents the number of error messages produced. Without this option, .Nm diff --git a/gcc/cobol/genapi.cc b/gcc/cobol/genapi.cc index 622387f..c8911f9 100644 --- a/gcc/cobol/genapi.cc +++ b/gcc/cobol/genapi.cc @@ -34,6 +34,7 @@ #include "tree-iterator.h" #include "stringpool.h" #include "diagnostic-core.h" +#include "target.h" #include "../../libgcobol/ec.h" #include "../../libgcobol/common-defs.h" @@ -2357,7 +2358,8 @@ section_label(struct cbl_proc_t *procedure) cbl_label_t *label = procedure->label; // The _initialize_program section isn't relevant. - char *psz = xasprintf("# SECTION %s in %s (%ld)", + char *psz = xasprintf("%s SECTION %s in %s (%ld)", + ASM_COMMENT_START, label->name, current_function->our_unmangled_name, deconflictor); @@ -2408,7 +2410,8 @@ paragraph_label(struct cbl_proc_t *procedure) char *psz1 = xasprintf( - "# PARAGRAPH %s of %s in %s (%ld)", + "%s PARAGRAPH %s of %s in %s (%ld)", + ASM_COMMENT_START, para_name ? para_name: "" , section_name ? section_name: "(null)" , current_function->our_unmangled_name ? current_function->our_unmangled_name: "" , @@ -3006,7 +3009,8 @@ parser_perform(cbl_label_t *label, bool suppress_nexting) para_name = label->name; sect_name = section_label->name; sprintf(ach, - "# PERFORM %s of %s of %s (%ld)", + "%s PERFORM %s of %s of %s (%ld)", + ASM_COMMENT_START, para_name, sect_name, program_name, @@ -3018,7 +3022,8 @@ parser_perform(cbl_label_t *label, bool suppress_nexting) { sect_name = label->name; sprintf(ach, - "# PERFORM %s of %s (%ld)", + "%s PERFORM %s of %s (%ld)", + ASM_COMMENT_START, sect_name, program_name, deconflictor); @@ -3170,8 +3175,8 @@ internal_perform_through( cbl_label_t *proc_1, pseudo_return_push(proc2, return_addr); // Create the code that will launch the first procedure - gg_insert_into_assembler("# PERFORM %s THROUGH %s", - proc_1->name, proc_2->name); + gg_insert_into_assembler("%s PERFORM %s THROUGH %s", + ASM_COMMENT_START, proc_1->name, proc_2->name); if( !suppress_nexting ) { @@ -13606,7 +13611,7 @@ hijack_for_development(const char *funcname) // Assume that funcname is lowercase with no hyphens enter_program_common(funcname, funcname); parser_display_literal("You have been hijacked by a program named \"dubner\""); - gg_insert_into_assembler("# HIJACKED DUBNER CODE START"); + gg_insert_into_assembler("%s HIJACKED DUBNER CODE START", ASM_COMMENT_START); for(int i=0; i<10; i++) { @@ -13619,7 +13624,7 @@ hijack_for_development(const char *funcname) NULL_TREE); } - gg_insert_into_assembler("# HIJACKED DUBNER CODE END"); + gg_insert_into_assembler("%s HIJACKED DUBNER CODE END", ASM_COMMENT_START); gg_return(0); } diff --git a/gcc/cobol/lang.opt b/gcc/cobol/lang.opt index 42c4020..59278a1 100644 --- a/gcc/cobol/lang.opt +++ b/gcc/cobol/lang.opt @@ -77,10 +77,6 @@ ffixed-form Cobol RejectNegative Assume that the source file is fixed form. -fsyntax-only -Cobol RejectNegative -; Documented in c.opt - ffree-form Cobol RejectNegative Assume that the source file is free form. @@ -93,10 +89,6 @@ finternal-ebcdic Cobol Var(cobol_ebcdic, 1) Init(0) -finternal-ebcdic Internal processing is in EBCDIC Code Page 1140 -fmax-errors -Cobol Joined Separate -; Documented in C - fstatic-call Cobol Var(cobol_static_call, 1) Init(1) Enable/disable static linkage for CALL literals @@ -118,7 +110,7 @@ Cobol Joined Separate ; Documented in C include -Cobol Joined Separate Var(cobol_include) +Cobol Joined Separate ; Documented in C isysroot diff --git a/gcc/cobol/lang.opt.urls b/gcc/cobol/lang.opt.urls index 6a5dc1c..69f5297 100644 --- a/gcc/cobol/lang.opt.urls +++ b/gcc/cobol/lang.opt.urls @@ -13,15 +13,9 @@ UrlSuffix(gcc/Directory-Options.html#index-I) LangUrlSuffix_D(gdc/Directory-Opti ffixed-form LangUrlSuffix_Fortran(gfortran/Fortran-Dialect-Options.html#index-ffixed-form) -fsyntax-only -UrlSuffix(gcc/Warning-Options.html#index-fsyntax-only) LangUrlSuffix_D(gdc/Warnings.html#index-fno-syntax-only) LangUrlSuffix_Fortran(gfortran/Error-and-Warning-Options.html#index-fsyntax-only) - ffree-form LangUrlSuffix_Fortran(gfortran/Fortran-Dialect-Options.html#index-ffree-form) -fmax-errors -UrlSuffix(gcc/Warning-Options.html#index-fmax-errors) LangUrlSuffix_D(gdc/Warnings.html#index-fmax-errors) - iprefix UrlSuffix(gcc/Directory-Options.html#index-iprefix) LangUrlSuffix_D(gdc/Directory-Options.html#index-iprefix) LangUrlSuffix_Fortran(gfortran/Preprocessing-Options.html#index-iprefix) diff --git a/gcc/cobol/parse.y b/gcc/cobol/parse.y index d14cc31..55c26fe 100644 --- a/gcc/cobol/parse.y +++ b/gcc/cobol/parse.y @@ -338,7 +338,7 @@ %token <number> INVALID %token <number> NUMBER NEGATIVE %token <numstr> NUMSTR "numeric literal" -%token <number> OVERFLOW +%token <number> OVERFLOW_kw "OVERFLOW" %token <computational> COMPUTATIONAL %token <boolean> PERFORM BACKWARD @@ -997,7 +997,7 @@ DELETE DISPLAY DIVIDE EVALUATE END EOP EXIT FILLER_kw GOBACK GOTO INITIALIZE INSPECT - MERGE MOVE MULTIPLY OPEN OVERFLOW PARAGRAPH PERFORM + MERGE MOVE MULTIPLY OPEN OVERFLOW_kw PARAGRAPH PERFORM READ RELEASE RETURN REWRITE SEARCH SET SELECT SORT SORT_MERGE STRING_kw STOP SUBTRACT START @@ -9488,7 +9488,7 @@ call_except: EXCEPTION std::swap($$.on_error, $$.not_error); } } - | OVERFLOW + | OVERFLOW_kw { $$.not_error = NULL; $$.on_error = label_add(LblArith, @@ -9496,7 +9496,7 @@ call_except: EXCEPTION if( !$$.on_error ) YYERROR; parser_call_exception( $$.on_error ); - assert( $1 == OVERFLOW || $1 == NOT ); + assert( $1 == OVERFLOW_kw || $1 == NOT ); if( $1 == NOT ) { std::swap($$.on_error, $$.not_error); } @@ -9751,7 +9751,7 @@ on_overflows: on_overflow[over] statements %prec ADD } ; -on_overflow: OVERFLOW +on_overflow: OVERFLOW_kw { $$.not_error = NULL; $$.on_error = label_add(LblString, @@ -9759,7 +9759,7 @@ on_overflow: OVERFLOW if( !$$.on_error ) YYERROR; parser_string_overflow( $$.on_error ); - assert( $1 == OVERFLOW || $1 == NOT ); + assert( $1 == OVERFLOW_kw || $1 == NOT ); if( $1 == NOT ) { std::swap($$.on_error, $$.not_error); } diff --git a/gcc/cobol/scan.l b/gcc/cobol/scan.l index 2cb7d30..e30634d 100644 --- a/gcc/cobol/scan.l +++ b/gcc/cobol/scan.l @@ -1543,9 +1543,9 @@ USE({SPC}FOR)? { return USE; } NOT{SPC}(ON{SPC})?EXCEPTION { yylval.number = NOT; return EXCEPTION; } - (ON{SPC})?OVERFLOW { yylval.number = OVERFLOW; return OVERFLOW; } + (ON{SPC})?OVERFLOW { yylval.number = OVERFLOW_kw; return OVERFLOW_kw; } NOT{SPC}(ON{SPC})?OVERFLOW { - yylval.number = NOT; return OVERFLOW; } + yylval.number = NOT; return OVERFLOW_kw; } (AT{SPC})?END/[[:space:]] { yylval.number = END; return END; } @@ -2312,7 +2312,7 @@ BASIS { yy_push_state(basis); return BASIS; } ORGANIZATION { return ORGANIZATION; } OTHER { return OTHER; } OUTPUT { return OUTPUT; } - OVERFLOW { return OVERFLOW; } + OVERFLOW { return OVERFLOW_kw; } OVERRIDE { return OVERRIDE; } PACKED-DECIMAL { return PACKED_DECIMAL; } PAGE { return PAGE; } diff --git a/gcc/cobol/token_names.h b/gcc/cobol/token_names.h index a082078..d1e3b5d 100644 --- a/gcc/cobol/token_names.h +++ b/gcc/cobol/token_names.h @@ -49,7 +49,7 @@ tokens = { { "number", NUMBER }, // 302 { "negative", NEGATIVE }, // 303 { "numstr", NUMSTR }, // 304 - { "overflow", OVERFLOW }, // 305 + { "overflow", OVERFLOW_kw }, // 305 { "computational", COMPUTATIONAL }, // 306 { "perform", PERFORM }, // 307 { "backward", BACKWARD }, // 308 diff --git a/gcc/cobol/util.cc b/gcc/cobol/util.cc index f7b89b8..f28fddf 100644 --- a/gcc/cobol/util.cc +++ b/gcc/cobol/util.cc @@ -2099,20 +2099,20 @@ cobol_fileline_set( const char line[] ) { return file.name; } -class timespec_t { +class cbl_timespec { struct timespec now; public: - timespec_t() { + cbl_timespec() { clock_gettime(CLOCK_MONOTONIC, &now); } double ns() const { return now.tv_sec * 1000000000 + now.tv_nsec; } - friend double operator-( const timespec_t& now, const timespec_t& then ); + friend double operator-( const cbl_timespec& now, const cbl_timespec& then ); }; double -operator-( const timespec_t& then, const timespec_t& now ) { +operator-( const cbl_timespec& then, const cbl_timespec& now ) { return (now.ns() - then.ns()) / 1000000000; } @@ -2125,11 +2125,11 @@ parse_file( const char filename[] ) parser_enter_file(filename); - timespec_t start; + cbl_timespec start; int erc = yyparse(); - timespec_t finish; + cbl_timespec finish; double dt = finish - start; parser_leave_file(); diff --git a/gcc/combine.cc b/gcc/combine.cc index 5f08518..873c2bd 100644 --- a/gcc/combine.cc +++ b/gcc/combine.cc @@ -815,7 +815,7 @@ do_SUBST_LINK (struct insn_link **into, struct insn_link *newval) #define SUBST_LINK(oldval, newval) do_SUBST_LINK (&oldval, newval) /* Subroutine of try_combine. Determine whether the replacement patterns - NEWPAT, NEWI2PAT and NEWOTHERPAT are cheaper according to insn_cost + NEWPAT, NEWI2PAT and NEWOTHERPAT are more expensive according to insn_cost than the original sequence I0, I1, I2, I3 and undobuf.other_insn. Note that I0, I1 and/or NEWI2PAT may be NULL_RTX. Similarly, NEWOTHERPAT and undobuf.other_insn may also both be NULL_RTX. Return false if the cost @@ -4129,8 +4129,8 @@ try_combine (rtx_insn *i3, rtx_insn *i2, rtx_insn *i1, rtx_insn *i0, } } - /* Only allow this combination if insn_cost reports that the - replacement instructions are cheaper than the originals. */ + /* Reject this combination if insn_cost reports that the replacement + instructions are more expensive than the originals. */ if (!combine_validate_cost (i0, i1, i2, i3, newpat, newi2pat, other_pat)) { undo_all (); @@ -5280,6 +5280,12 @@ find_split_point (rtx *loc, rtx_insn *insn, bool set_src) SUBST (XEXP (x, 0), XEXP (x, 1)); SUBST (XEXP (x, 1), tem); } + /* Many targets have a `(and (not X) Y)` and/or `(ior (not X) Y)` instructions. + Split at that insns. However if this is + the SET_SRC, we likely do not have such an instruction and it's + worthless to try this split. */ + if (!set_src && GET_CODE (XEXP (x, 0)) == NOT) + return loc; break; case PLUS: diff --git a/gcc/common.opt b/gcc/common.opt index 2c8fdde..88d987e 100644 --- a/gcc/common.opt +++ b/gcc/common.opt @@ -2116,6 +2116,10 @@ fipa-modref Common Var(flag_ipa_modref) Optimization Perform interprocedural modref analysis. +fipa-reorder-for-locality +Common Var(flag_ipa_reorder_for_locality) Init(0) Optimization +Perform reordering and cloning of functions to maximize locality. + fipa-profile Common Var(flag_ipa_profile) Init(0) Optimization Perform interprocedural profile propagation. @@ -2275,6 +2279,9 @@ Enum Name(lto_partition_model) Type(enum lto_partition_model) UnknownError(unknown LTO partitioning model %qs) EnumValue +Enum(lto_partition_model) String(default) Value(LTO_PARTITION_DEFAULT) + +EnumValue Enum(lto_partition_model) String(none) Value(LTO_PARTITION_NONE) EnumValue @@ -2293,7 +2300,7 @@ EnumValue Enum(lto_partition_model) String(cache) Value(LTO_PARTITION_CACHE) flto-partition= -Common Joined RejectNegative Enum(lto_partition_model) Var(flag_lto_partition) Init(LTO_PARTITION_BALANCED) +Common Joined RejectNegative Enum(lto_partition_model) Var(flag_lto_partition) Init(LTO_PARTITION_DEFAULT) Specify the algorithm to partition symbols and vars at linktime. ; The initial value of -1 comes from Z_DEFAULT_COMPRESSION in zlib.h. diff --git a/gcc/common.opt.urls b/gcc/common.opt.urls index a4b14f5..0077511 100644 --- a/gcc/common.opt.urls +++ b/gcc/common.opt.urls @@ -31,8 +31,9 @@ UrlSuffix(gcc/Optimize-Options.html#index-Og) Oz UrlSuffix(gcc/Optimize-Options.html#index-Oz) -Q -UrlSuffix(gcc/Developer-Options.html#index-Q) +; skipping UrlSuffix for 'Q' due to multiple URLs: +; duplicate: 'gcc/Developer-Options.html#index-Q-1' +; duplicate: 'gcc/Overall-Options.html#index-Q' Qn UrlSuffix(gcc/System-V-Options.html#index-Qn) @@ -868,6 +869,9 @@ UrlSuffix(gcc/Optimize-Options.html#index-fipa-bit-cp) fipa-modref UrlSuffix(gcc/Optimize-Options.html#index-fipa-modref) +fipa-reorder-for-locality +UrlSuffix(gcc/Optimize-Options.html#index-fipa-reorder-for-locality) + fipa-profile UrlSuffix(gcc/Optimize-Options.html#index-fipa-profile) diff --git a/gcc/common/config/s390/s390-common.cc b/gcc/common/config/s390/s390-common.cc index 4b0691d..8a147d7 100644 --- a/gcc/common/config/s390/s390-common.cc +++ b/gcc/common/config/s390/s390-common.cc @@ -54,10 +54,10 @@ EXPORTED_CONST int processor_flags_table[] = | PF_EXTIMM | PF_DFP | PF_Z10 | PF_Z196 | PF_ZEC12 | PF_TX | PF_Z13 | PF_VX | PF_VXE | PF_Z14 | PF_VXE2 | PF_Z15 | PF_NNPA | PF_Z16, - /* arch15 */ PF_IEEE_FLOAT | PF_ZARCH | PF_LONG_DISPLACEMENT + /* z17 */ PF_IEEE_FLOAT | PF_ZARCH | PF_LONG_DISPLACEMENT | PF_EXTIMM | PF_DFP | PF_Z10 | PF_Z196 | PF_ZEC12 | PF_TX | PF_Z13 | PF_VX | PF_VXE | PF_Z14 | PF_VXE2 | PF_Z15 - | PF_NNPA | PF_Z16 | PF_VXE3 | PF_ARCH15 + | PF_NNPA | PF_Z16 | PF_VXE3 | PF_Z17 }; /* Change optimizations to be performed, depending on the diff --git a/gcc/config.gcc b/gcc/config.gcc index f7f2002..d98df88 100644 --- a/gcc/config.gcc +++ b/gcc/config.gcc @@ -2540,6 +2540,20 @@ riscv*-*-linux*) gcc_cv_initfini_array=yes with_tls=${with_tls:-trad} ;; +riscv*-*-gnu*) + tm_file="elfos.h gnu-user.h gnu.h glibc-stdint.h ${tm_file} riscv/gnu.h" + tmake_file="${tmake_file} riscv/t-riscv" + gnu_ld=yes + gas=yes + case $target in + riscv32be-*|riscv64be-*) + tm_defines="${tm_defines} TARGET_BIG_ENDIAN_DEFAULT=1" + ;; + esac + # Force .init_array support. The configure script cannot always + # automatically detect that GAS supports it, yet we require it. + gcc_cv_initfini_array=yes + ;; riscv*-*-elf* | riscv*-*-rtems*) tm_file="elfos.h newlib-stdint.h ${tm_file} riscv/elf.h" case ${target} in @@ -5756,7 +5770,7 @@ case "${target}" in for which in arch tune; do eval "val=\$with_$which" case ${val} in - "" | native | z900 | z990 | z9-109 | z9-ec | z10 | z196 | zEC12 | z13 | z14 | z15 | z16 | arch5 | arch6 | arch7 | arch8 | arch9 | arch10 | arch11 | arch12 | arch13 | arch14 | arch15 ) + "" | native | z900 | z990 | z9-109 | z9-ec | z10 | z196 | zEC12 | z13 | z14 | z15 | z16 | z17 | arch5 | arch6 | arch7 | arch8 | arch9 | arch10 | arch11 | arch12 | arch13 | arch14 | arch15 ) # OK ;; *) diff --git a/gcc/config.in b/gcc/config.in index 7c89cab..a79c51a 100644 --- a/gcc/config.in +++ b/gcc/config.in @@ -2320,6 +2320,13 @@ #endif +/* Define if personality and ADDR_NO_RANDOMIZE are declared in + sys/personality.h. */ +#ifndef USED_FOR_TARGET +#undef HOST_HAS_PERSONALITY_ADDR_NO_RANDOMIZE +#endif + + /* Define which stat syscall is able to handle 64bit indodes. */ #ifndef USED_FOR_TARGET #undef HOST_STAT_FOR_64BIT_INODES diff --git a/gcc/config/aarch64/aarch64-sve.md b/gcc/config/aarch64/aarch64-sve.md index 3dbd659..d4af370 100644 --- a/gcc/config/aarch64/aarch64-sve.md +++ b/gcc/config/aarch64/aarch64-sve.md @@ -3133,9 +3133,9 @@ "TARGET_SVE" { rtx tmp = gen_reg_rtx (<MODE>mode); - emit_insn (gen_vcond_mask_<mode><vpred> (tmp, operands[1], - CONST1_RTX (<MODE>mode), - CONST0_RTX (<MODE>mode))); + emit_insn (gen_vcond_mask_<mode><vpred> (tmp, CONST1_RTX (<MODE>mode), + CONST0_RTX (<MODE>mode), + operands[1])); emit_insn (gen_vec_extract<mode><Vel> (operands[0], tmp, operands[2])); DONE; } diff --git a/gcc/config/aarch64/aarch64.cc b/gcc/config/aarch64/aarch64.cc index 4e80114..433ec97 100644 --- a/gcc/config/aarch64/aarch64.cc +++ b/gcc/config/aarch64/aarch64.cc @@ -31073,8 +31073,6 @@ aarch64_valid_sysreg_name_p (const char *regname) const sysreg_t *sysreg = aarch64_lookup_sysreg_map (regname); if (sysreg == NULL) return aarch64_is_implem_def_reg (regname); - if (sysreg->arch_reqs) - return bool (aarch64_isa_flags & sysreg->arch_reqs); return true; } @@ -31098,8 +31096,6 @@ aarch64_retrieve_sysreg (const char *regname, bool write_p, bool is128op) if ((write_p && (sysreg->properties & F_REG_READ)) || (!write_p && (sysreg->properties & F_REG_WRITE))) return NULL; - if ((~aarch64_isa_flags & sysreg->arch_reqs) != 0) - return NULL; return sysreg->encoding; } diff --git a/gcc/config/alpha/alpha.cc b/gcc/config/alpha/alpha.cc index ba470d9..14e7da5 100644 --- a/gcc/config/alpha/alpha.cc +++ b/gcc/config/alpha/alpha.cc @@ -4291,14 +4291,10 @@ alpha_get_mem_rtx_alignment_and_offset (rtx expr, int &a, HOST_WIDE_INT &o) tree mem = MEM_EXPR (expr); if (mem != NULL_TREE) - switch (TREE_CODE (mem)) - { - case MEM_REF: - tree_offset = mem_ref_offset (mem).force_shwi (); - tree_align = get_object_alignment (get_base_address (mem)); - break; + { + HOST_WIDE_INT comp_offset = 0; - case COMPONENT_REF: + for (; TREE_CODE (mem) == COMPONENT_REF; mem = TREE_OPERAND (mem, 0)) { tree byte_offset = component_ref_field_offset (mem); tree bit_offset = DECL_FIELD_BIT_OFFSET (TREE_OPERAND (mem, 1)); @@ -4307,14 +4303,15 @@ alpha_get_mem_rtx_alignment_and_offset (rtx expr, int &a, HOST_WIDE_INT &o) || !poly_int_tree_p (byte_offset, &offset) || !tree_fits_shwi_p (bit_offset)) break; - tree_offset = offset + tree_to_shwi (bit_offset) / BITS_PER_UNIT; + comp_offset += offset + tree_to_shwi (bit_offset) / BITS_PER_UNIT; } - tree_align = get_object_alignment (get_base_address (mem)); - break; - default: - break; - } + if (TREE_CODE (mem) == MEM_REF) + { + tree_offset = comp_offset + mem_ref_offset (mem).force_shwi (); + tree_align = get_object_alignment (get_base_address (mem)); + } + } if (reg_align > mem_align) { diff --git a/gcc/config/c6x/c6x.h b/gcc/config/c6x/c6x.h index e7da250..50bad27 100644 --- a/gcc/config/c6x/c6x.h +++ b/gcc/config/c6x/c6x.h @@ -444,11 +444,9 @@ struct GTY(()) machine_function #define TARG_VEC_PERMUTE_COST 1 #endif -/* ttype entries (the only interesting data references used) are - sb-relative got-indirect (aka .ehtype). */ +/* .ehtype ttype entries are sb-relative. */ #define ASM_PREFERRED_EH_DATA_FORMAT(code, data) \ - (((code) == 0 && (data) == 1) ? (DW_EH_PE_datarel | DW_EH_PE_indirect) \ - : DW_EH_PE_absptr) + (((code) == 0 && (data) == 1) ? DW_EH_PE_datarel : DW_EH_PE_absptr) /* This should be the same as the definition in elfos.h, plus the call to output special unwinding directives. */ diff --git a/gcc/config/gcn/gcn.md b/gcc/config/gcn/gcn.md index 695656f..e0fb735 100644 --- a/gcc/config/gcn/gcn.md +++ b/gcc/config/gcn/gcn.md @@ -1018,7 +1018,9 @@ [(const_int 0)] "" { - sorry ("exception handling not supported"); + if (!fake_exceptions) + sorry ("exception handling not supported"); + DONE; }) ;; }}} diff --git a/gcc/config/gcn/gcn.opt b/gcc/config/gcn/gcn.opt index 142b439..99d6aeb 100644 --- a/gcc/config/gcn/gcn.opt +++ b/gcc/config/gcn/gcn.opt @@ -101,3 +101,11 @@ Enum(gcn_preferred_vectorization_factor) String(32) Value(32) EnumValue Enum(gcn_preferred_vectorization_factor) String(64) Value(64) + +mfake-exceptions +Target Var(fake_exceptions) Init(0) Undocumented +; With '-mfake-exceptions' enabled, the user-visible behavior in presence of +; exception handling constructs changes such that the compile-time +; 'sorry, unimplemented: exception handling not supported' is skipped, code +; generation proceeds, and instead, exception handling constructs 'abort' at +; run time. (..., or don't, if they're in dead code.) diff --git a/gcc/config/gcn/mkoffload.cc b/gcc/config/gcn/mkoffload.cc index f5b89c9..b284ff4 100644 --- a/gcc/config/gcn/mkoffload.cc +++ b/gcc/config/gcn/mkoffload.cc @@ -1160,6 +1160,9 @@ main (int argc, char **argv) obstack_ptr_grow (&cc_argv_obstack, "-xlto"); if (fopenmp) obstack_ptr_grow (&cc_argv_obstack, "-mgomp"); + /* The host code may contain exception handling constructs. + Handle these as good as we can. */ + obstack_ptr_grow (&cc_argv_obstack, "-mfake-exceptions"); for (int ix = 1; ix != argc; ix++) { diff --git a/gcc/config/i386/i386-expand.cc b/gcc/config/i386/i386-expand.cc index cdfd94d..36f71eb 100644 --- a/gcc/config/i386/i386-expand.cc +++ b/gcc/config/i386/i386-expand.cc @@ -19256,8 +19256,6 @@ ix86_emit_swdivsf (rtx res, rtx a, rtx b, machine_mode mode) e1 = gen_reg_rtx (mode); x1 = gen_reg_rtx (mode); - /* a / b = a * ((rcp(b) + rcp(b)) - (b * rcp(b) * rcp (b))) */ - b = force_reg (mode, b); /* x0 = rcp(b) estimate */ @@ -19270,20 +19268,42 @@ ix86_emit_swdivsf (rtx res, rtx a, rtx b, machine_mode mode) emit_insn (gen_rtx_SET (x0, gen_rtx_UNSPEC (mode, gen_rtvec (1, b), UNSPEC_RCP))); - /* e0 = x0 * b */ - emit_insn (gen_rtx_SET (e0, gen_rtx_MULT (mode, x0, b))); + unsigned vector_size = GET_MODE_SIZE (mode); + + /* (a - (rcp(b) * a * b)) * rcp(b) + rcp(b) * a + N-R step with 2 fma implementation. */ + if (TARGET_FMA + || (TARGET_AVX512F && vector_size == 64) + || (TARGET_AVX512VL && (vector_size == 32 || vector_size == 16))) + { + /* e0 = x0 * a */ + emit_insn (gen_rtx_SET (e0, gen_rtx_MULT (mode, x0, a))); + /* e1 = e0 * b - a */ + emit_insn (gen_rtx_SET (e1, gen_rtx_FMA (mode, e0, b, + gen_rtx_NEG (mode, a)))); + /* res = - e1 * x0 + e0 */ + emit_insn (gen_rtx_SET (res, gen_rtx_FMA (mode, + gen_rtx_NEG (mode, e1), + x0, e0))); + } + else + /* a / b = a * ((rcp(b) + rcp(b)) - (b * rcp(b) * rcp (b))) */ + { + /* e0 = x0 * b */ + emit_insn (gen_rtx_SET (e0, gen_rtx_MULT (mode, x0, b))); - /* e0 = x0 * e0 */ - emit_insn (gen_rtx_SET (e0, gen_rtx_MULT (mode, x0, e0))); + /* e1 = x0 + x0 */ + emit_insn (gen_rtx_SET (e1, gen_rtx_PLUS (mode, x0, x0))); - /* e1 = x0 + x0 */ - emit_insn (gen_rtx_SET (e1, gen_rtx_PLUS (mode, x0, x0))); + /* e0 = x0 * e0 */ + emit_insn (gen_rtx_SET (e0, gen_rtx_MULT (mode, x0, e0))); - /* x1 = e1 - e0 */ - emit_insn (gen_rtx_SET (x1, gen_rtx_MINUS (mode, e1, e0))); + /* x1 = e1 - e0 */ + emit_insn (gen_rtx_SET (x1, gen_rtx_MINUS (mode, e1, e0))); - /* res = a * x1 */ - emit_insn (gen_rtx_SET (res, gen_rtx_MULT (mode, a, x1))); + /* res = a * x1 */ + emit_insn (gen_rtx_SET (res, gen_rtx_MULT (mode, a, x1))); + } } /* Output code to perform a Newton-Rhapson approximation of a diff --git a/gcc/config/i386/i386-options.cc b/gcc/config/i386/i386-options.cc index a9fac01..964449f 100644 --- a/gcc/config/i386/i386-options.cc +++ b/gcc/config/i386/i386-options.cc @@ -2828,8 +2828,8 @@ ix86_option_override_internal (bool main_args_p, if (flag_nop_mcount) error ("%<-mnop-mcount%> is not compatible with this target"); #endif - if (flag_nop_mcount && flag_pic) - error ("%<-mnop-mcount%> is not implemented for %<-fPIC%>"); + if (flag_nop_mcount && flag_pic && !flag_plt) + error ("%<-mnop-mcount%> is not implemented for %<-fno-plt%>"); /* Accept -msseregparm only if at least SSE support is enabled. */ if (TARGET_SSEREGPARM_P (opts->x_target_flags) diff --git a/gcc/config/i386/i386.cc b/gcc/config/i386/i386.cc index 4f8380c4..d15f91d 100644 --- a/gcc/config/i386/i386.cc +++ b/gcc/config/i386/i386.cc @@ -100,6 +100,7 @@ along with GCC; see the file COPYING3. If not see #include "i386-features.h" #include "function-abi.h" #include "rtl-error.h" +#include "gimple-pretty-print.h" /* This file should be included last. */ #include "target-def.h" @@ -458,6 +459,9 @@ int ix86_arch_specified; indirect thunk pushes the return address onto stack, destroying red-zone. + NB: Don't use red-zone for functions with no_caller_saved_registers + and 32 GPRs since 128-byte red-zone is too small for 31 GPRs. + TODO: If we can reserve the first 2 WORDs, for PUSH and, another for CALL, in red-zone, we can allow local indirect jumps with indirect thunk. */ @@ -467,6 +471,9 @@ ix86_using_red_zone (void) { return (TARGET_RED_ZONE && !TARGET_64BIT_MS_ABI + && (!TARGET_APX_EGPR + || (cfun->machine->call_saved_registers + != TYPE_NO_CALLER_SAVED_REGISTERS)) && (!cfun->machine->has_local_indirect_jump || cfun->machine->indirect_branch_type == indirect_branch_keep)); } @@ -21810,6 +21817,25 @@ ix86_insn_cost (rtx_insn *insn, bool speed) return insn_cost + pattern_cost (PATTERN (insn), speed); } +/* Return cost of SSE/AVX FP->FP conversion (extensions and truncates). */ + +static int +vec_fp_conversion_cost (const struct processor_costs *cost, int size) +{ + if (size < 128) + return cost->cvtss2sd; + else if (size < 256) + { + if (TARGET_SSE_SPLIT_REGS) + return cost->cvtss2sd * size / 64; + return cost->cvtss2sd; + } + if (size < 512) + return cost->vcvtps2pd256; + else + return cost->vcvtps2pd512; +} + /* Compute a (partial) cost for rtx X. Return true if the complete cost has been computed, and false if subexpressions should be scanned. In either case, *TOTAL contains the cost result. */ @@ -22473,17 +22499,18 @@ ix86_rtx_costs (rtx x, machine_mode mode, int outer_code_i, int opno, return false; case FLOAT_EXTEND: + /* x87 represents all values extended to 80bit. */ if (!SSE_FLOAT_MODE_SSEMATH_OR_HFBF_P (mode)) *total = 0; else - *total = ix86_vec_cost (mode, cost->addss); + *total = vec_fp_conversion_cost (cost, GET_MODE_BITSIZE (mode)); return false; case FLOAT_TRUNCATE: if (!SSE_FLOAT_MODE_SSEMATH_OR_HFBF_P (mode)) *total = cost->fadd; else - *total = ix86_vec_cost (mode, cost->addss); + *total = vec_fp_conversion_cost (cost, GET_MODE_BITSIZE (mode)); return false; case ABS: @@ -23158,6 +23185,12 @@ x86_print_call_or_nop (FILE *file, const char *target) if (flag_nop_mcount || !strcmp (target, "nop")) /* 5 byte nop: nopl 0(%[re]ax,%[re]ax,1) */ fprintf (file, "1:" ASM_BYTE "0x0f, 0x1f, 0x44, 0x00, 0x00\n"); + else if (!TARGET_PECOFF && flag_pic) + { + gcc_assert (flag_plt); + + fprintf (file, "1:\tcall\t%s@PLT\n", target); + } else fprintf (file, "1:\tcall\t%s\n", target); } @@ -23321,7 +23354,7 @@ x86_function_profiler (FILE *file, int labelno ATTRIBUTE_UNUSED) break; case CM_SMALL_PIC: case CM_MEDIUM_PIC: - if (!ix86_direct_extern_access) + if (!flag_plt) { if (ASSEMBLER_DIALECT == ASM_INTEL) fprintf (file, "1:\tcall\t[QWORD PTR %s@GOTPCREL[rip]]\n", @@ -23352,7 +23385,9 @@ x86_function_profiler (FILE *file, int labelno ATTRIBUTE_UNUSED) "\tleal\t%sP%d@GOTOFF(%%ebx), %%" PROFILE_COUNT_REGISTER "\n", LPREFIX, labelno); #endif - if (ASSEMBLER_DIALECT == ASM_INTEL) + if (flag_plt) + x86_print_call_or_nop (file, mcount_name); + else if (ASSEMBLER_DIALECT == ASM_INTEL) fprintf (file, "1:\tcall\t[DWORD PTR %s@GOT[ebx]]\n", mcount_name); else fprintf (file, "1:\tcall\t*%s@GOT(%%ebx)\n", mcount_name); @@ -24669,7 +24704,7 @@ ix86_builtin_vectorization_cost (enum vect_cost_for_stmt type_of_cost, switch (type_of_cost) { case scalar_stmt: - return fp ? ix86_cost->addss : COSTS_N_INSNS (1); + return fp ? ix86_cost->addss : COSTS_N_INSNS (1); case scalar_load: /* load/store costs are relative to register move which is 2. Recompute @@ -24740,7 +24775,11 @@ ix86_builtin_vectorization_cost (enum vect_cost_for_stmt type_of_cost, return ix86_cost->cond_not_taken_branch_cost; case vec_perm: + return ix86_vec_cost (mode, ix86_cost->sse_op); + case vec_promote_demote: + if (fp) + return vec_fp_conversion_cost (ix86_tune_cost, mode); return ix86_vec_cost (mode, ix86_cost->sse_op); case vec_construct: @@ -25328,6 +25367,9 @@ ix86_vector_costs::add_stmt_cost (int count, vect_cost_for_stmt kind, (TREE_TYPE (gimple_assign_lhs (stmt_info->stmt)), TREE_TYPE (gimple_assign_rhs1 (stmt_info->stmt)))) stmt_cost = 0; + else if (fp) + stmt_cost = vec_fp_conversion_cost + (ix86_tune_cost, GET_MODE_BITSIZE (mode)); break; case BIT_IOR_EXPR: @@ -25369,6 +25411,29 @@ ix86_vector_costs::add_stmt_cost (int count, vect_cost_for_stmt kind, break; } + if (kind == vec_promote_demote + && fp && FLOAT_TYPE_P (TREE_TYPE (gimple_assign_rhs1 (stmt_info->stmt)))) + { + int outer_size + = tree_to_uhwi + (TYPE_SIZE + (TREE_TYPE (gimple_assign_lhs (stmt_info->stmt)))); + int inner_size + = tree_to_uhwi + (TYPE_SIZE + (TREE_TYPE (gimple_assign_rhs1 (stmt_info->stmt)))); + int stmt_cost = vec_fp_conversion_cost + (ix86_tune_cost, GET_MODE_BITSIZE (mode)); + /* VEC_PACK_TRUNC_EXPR: If inner size is greater than outer size we will end + up doing two conversions and packing them. */ + if (inner_size > outer_size) + { + int n = inner_size / outer_size; + stmt_cost = stmt_cost * n + + (n - 1) * ix86_vec_cost (mode, ix86_cost->sse_op); + } + } + /* If we do elementwise loads into a vector then we are bound by latency and execution resources for the many scalar loads (AGU and load ports). Try to account for this by scaling the diff --git a/gcc/config/i386/i386.h b/gcc/config/i386/i386.h index 8507243..18aa42d 100644 --- a/gcc/config/i386/i386.h +++ b/gcc/config/i386/i386.h @@ -207,6 +207,12 @@ struct processor_costs { const int divsd; /* cost of DIVSD instructions. */ const int sqrtss; /* cost of SQRTSS instructions. */ const int sqrtsd; /* cost of SQRTSD instructions. */ + const int cvtss2sd; /* cost SSE FP conversions, + such as CVTSS2SD. */ + const int vcvtps2pd256; /* cost 256bit packed FP conversions, + such as VCVTPD2PS with larger reg in ymm. */ + const int vcvtps2pd512; /* cost 512bit packed FP conversions, + such as VCVTPD2PS with larger reg in zmm. */ const int reassoc_int, reassoc_fp, reassoc_vec_int, reassoc_vec_fp; /* Specify reassociation width for integer, fp, vector integer and vector fp diff --git a/gcc/config/i386/x86-tune-costs.h b/gcc/config/i386/x86-tune-costs.h index 7c8cb73..cddcf61 100644 --- a/gcc/config/i386/x86-tune-costs.h +++ b/gcc/config/i386/x86-tune-costs.h @@ -121,16 +121,19 @@ struct processor_costs ix86_size_cost = {/* costs for tuning for size */ COSTS_N_BYTES (2), /* cost of FCHS instruction. */ COSTS_N_BYTES (2), /* cost of FSQRT instruction. */ - COSTS_N_BYTES (2), /* cost of cheap SSE instruction. */ - COSTS_N_BYTES (2), /* cost of ADDSS/SD SUBSS/SD insns. */ - COSTS_N_BYTES (2), /* cost of MULSS instruction. */ - COSTS_N_BYTES (2), /* cost of MULSD instruction. */ - COSTS_N_BYTES (2), /* cost of FMA SS instruction. */ - COSTS_N_BYTES (2), /* cost of FMA SD instruction. */ - COSTS_N_BYTES (2), /* cost of DIVSS instruction. */ - COSTS_N_BYTES (2), /* cost of DIVSD instruction. */ - COSTS_N_BYTES (2), /* cost of SQRTSS instruction. */ - COSTS_N_BYTES (2), /* cost of SQRTSD instruction. */ + COSTS_N_BYTES (4), /* cost of cheap SSE instruction. */ + COSTS_N_BYTES (4), /* cost of ADDSS/SD SUBSS/SD insns. */ + COSTS_N_BYTES (4), /* cost of MULSS instruction. */ + COSTS_N_BYTES (4), /* cost of MULSD instruction. */ + COSTS_N_BYTES (4), /* cost of FMA SS instruction. */ + COSTS_N_BYTES (4), /* cost of FMA SD instruction. */ + COSTS_N_BYTES (4), /* cost of DIVSS instruction. */ + COSTS_N_BYTES (4), /* cost of DIVSD instruction. */ + COSTS_N_BYTES (4), /* cost of SQRTSS instruction. */ + COSTS_N_BYTES (4), /* cost of SQRTSD instruction. */ + COSTS_N_BYTES (4), /* cost of CVTSS2SD etc. */ + COSTS_N_BYTES (4), /* cost of 256bit VCVTPS2PD etc. */ + COSTS_N_BYTES (6), /* cost of 512bit VCVTPS2PD etc. */ 1, 1, 1, 1, /* reassoc int, fp, vec_int, vec_fp. */ ix86_size_memcpy, ix86_size_memset, @@ -243,6 +246,9 @@ struct processor_costs i386_cost = { /* 386 specific costs */ COSTS_N_INSNS (88), /* cost of DIVSD instruction. */ COSTS_N_INSNS (122), /* cost of SQRTSS instruction. */ COSTS_N_INSNS (122), /* cost of SQRTSD instruction. */ + COSTS_N_INSNS (27), /* cost of CVTSS2SD etc. */ + COSTS_N_INSNS (54), /* cost of 256bit VCVTPS2PD etc. */ + COSTS_N_INSNS (108), /* cost of 512bit VCVTPS2PD etc. */ 1, 1, 1, 1, /* reassoc int, fp, vec_int, vec_fp. */ i386_memcpy, i386_memset, @@ -356,6 +362,9 @@ struct processor_costs i486_cost = { /* 486 specific costs */ COSTS_N_INSNS (74), /* cost of DIVSD instruction. */ COSTS_N_INSNS (83), /* cost of SQRTSS instruction. */ COSTS_N_INSNS (83), /* cost of SQRTSD instruction. */ + COSTS_N_INSNS (8), /* cost of CVTSS2SD etc. */ + COSTS_N_INSNS (16), /* cost of 256bit VCVTPS2PD etc. */ + COSTS_N_INSNS (32), /* cost of 512bit VCVTPS2PD etc. */ 1, 1, 1, 1, /* reassoc int, fp, vec_int, vec_fp. */ i486_memcpy, i486_memset, @@ -467,6 +476,9 @@ struct processor_costs pentium_cost = { COSTS_N_INSNS (39), /* cost of DIVSD instruction. */ COSTS_N_INSNS (70), /* cost of SQRTSS instruction. */ COSTS_N_INSNS (70), /* cost of SQRTSD instruction. */ + COSTS_N_INSNS (3), /* cost of CVTSS2SD etc. */ + COSTS_N_INSNS (6), /* cost of 256bit VCVTPS2PD etc. */ + COSTS_N_INSNS (12), /* cost of 512bit VCVTPS2PD etc. */ 1, 1, 1, 1, /* reassoc int, fp, vec_int, vec_fp. */ pentium_memcpy, pentium_memset, @@ -571,6 +583,9 @@ struct processor_costs lakemont_cost = { COSTS_N_INSNS (60), /* cost of DIVSD instruction. */ COSTS_N_INSNS (31), /* cost of SQRTSS instruction. */ COSTS_N_INSNS (63), /* cost of SQRTSD instruction. */ + COSTS_N_INSNS (5), /* cost of CVTSS2SD etc. */ + COSTS_N_INSNS (10), /* cost of 256bit VCVTPS2PD etc. */ + COSTS_N_INSNS (20), /* cost of 512bit VCVTPS2PD etc. */ 1, 1, 1, 1, /* reassoc int, fp, vec_int, vec_fp. */ pentium_memcpy, pentium_memset, @@ -690,6 +705,9 @@ struct processor_costs pentiumpro_cost = { COSTS_N_INSNS (18), /* cost of DIVSD instruction. */ COSTS_N_INSNS (31), /* cost of SQRTSS instruction. */ COSTS_N_INSNS (31), /* cost of SQRTSD instruction. */ + COSTS_N_INSNS (3), /* cost of CVTSS2SD etc. */ + COSTS_N_INSNS (6), /* cost of 256bit VCVTPS2PD etc. */ + COSTS_N_INSNS (12), /* cost of 512bit VCVTPS2PD etc. */ 1, 1, 1, 1, /* reassoc int, fp, vec_int, vec_fp. */ pentiumpro_memcpy, pentiumpro_memset, @@ -800,6 +818,9 @@ struct processor_costs geode_cost = { COSTS_N_INSNS (47), /* cost of DIVSD instruction. */ COSTS_N_INSNS (54), /* cost of SQRTSS instruction. */ COSTS_N_INSNS (54), /* cost of SQRTSD instruction. */ + COSTS_N_INSNS (6), /* cost of CVTSS2SD etc. */ + COSTS_N_INSNS (12), /* cost of 256bit VCVTPS2PD etc. */ + COSTS_N_INSNS (24), /* cost of 512bit VCVTPS2PD etc. */ 1, 1, 1, 1, /* reassoc int, fp, vec_int, vec_fp. */ geode_memcpy, geode_memset, @@ -913,6 +934,9 @@ struct processor_costs k6_cost = { COSTS_N_INSNS (56), /* cost of DIVSD instruction. */ COSTS_N_INSNS (56), /* cost of SQRTSS instruction. */ COSTS_N_INSNS (56), /* cost of SQRTSD instruction. */ + COSTS_N_INSNS (2), /* cost of CVTSS2SD etc. */ + COSTS_N_INSNS (4), /* cost of 256bit VCVTPS2PD etc. */ + COSTS_N_INSNS (8), /* cost of 512bit VCVTPS2PD etc. */ 1, 1, 1, 1, /* reassoc int, fp, vec_int, vec_fp. */ k6_memcpy, k6_memset, @@ -1027,6 +1051,9 @@ struct processor_costs athlon_cost = { COSTS_N_INSNS (24), /* cost of DIVSD instruction. */ COSTS_N_INSNS (19), /* cost of SQRTSS instruction. */ COSTS_N_INSNS (19), /* cost of SQRTSD instruction. */ + COSTS_N_INSNS (4), /* cost of CVTSS2SD etc. */ + COSTS_N_INSNS (8), /* cost of 256bit VCVTPS2PD etc. */ + COSTS_N_INSNS (16), /* cost of 512bit VCVTPS2PD etc. */ 1, 1, 1, 1, /* reassoc int, fp, vec_int, vec_fp. */ athlon_memcpy, athlon_memset, @@ -1150,6 +1177,9 @@ struct processor_costs k8_cost = { COSTS_N_INSNS (20), /* cost of DIVSD instruction. */ COSTS_N_INSNS (19), /* cost of SQRTSS instruction. */ COSTS_N_INSNS (27), /* cost of SQRTSD instruction. */ + COSTS_N_INSNS (4), /* cost of CVTSS2SD etc. */ + COSTS_N_INSNS (8), /* cost of 256bit VCVTPS2PD etc. */ + COSTS_N_INSNS (16), /* cost of 512bit VCVTPS2PD etc. */ 1, 1, 1, 1, /* reassoc int, fp, vec_int, vec_fp. */ k8_memcpy, k8_memset, @@ -1281,6 +1311,9 @@ struct processor_costs amdfam10_cost = { COSTS_N_INSNS (20), /* cost of DIVSD instruction. */ COSTS_N_INSNS (19), /* cost of SQRTSS instruction. */ COSTS_N_INSNS (27), /* cost of SQRTSD instruction. */ + COSTS_N_INSNS (4), /* cost of CVTSS2SD etc. */ + COSTS_N_INSNS (8), /* cost of 256bit VCVTPS2PD etc. */ + COSTS_N_INSNS (16), /* cost of 512bit VCVTPS2PD etc. */ 1, 1, 1, 1, /* reassoc int, fp, vec_int, vec_fp. */ amdfam10_memcpy, amdfam10_memset, @@ -1405,6 +1438,9 @@ const struct processor_costs bdver_cost = { COSTS_N_INSNS (27), /* cost of DIVSD instruction. */ COSTS_N_INSNS (15), /* cost of SQRTSS instruction. */ COSTS_N_INSNS (26), /* cost of SQRTSD instruction. */ + COSTS_N_INSNS (4), /* cost of CVTSS2SD etc. */ + COSTS_N_INSNS (7), /* cost of 256bit VCVTPS2PD etc. */ + COSTS_N_INSNS (14), /* cost of 512bit VCVTPS2PD etc. */ 1, 2, 1, 1, /* reassoc int, fp, vec_int, vec_fp. */ bdver_memcpy, bdver_memset, @@ -1553,6 +1589,10 @@ struct processor_costs znver1_cost = { COSTS_N_INSNS (13), /* cost of DIVSD instruction. */ COSTS_N_INSNS (10), /* cost of SQRTSS instruction. */ COSTS_N_INSNS (15), /* cost of SQRTSD instruction. */ + COSTS_N_INSNS (3), /* cost of CVTSS2SD etc. */ + /* Real latency is 4, but for split regs multiply cost of half op by 2. */ + COSTS_N_INSNS (6), /* cost of 256bit VCVTPS2PD etc. */ + COSTS_N_INSNS (12), /* cost of 512bit VCVTPS2PD etc. */ /* Zen can execute 4 integer operations per cycle. FP operations take 3 cycles and it can execute 2 integer additions and 2 multiplications thus reassociation may make sense up to with of 6. SPEC2k6 bencharks suggests @@ -1712,6 +1752,9 @@ struct processor_costs znver2_cost = { COSTS_N_INSNS (13), /* cost of DIVSD instruction. */ COSTS_N_INSNS (10), /* cost of SQRTSS instruction. */ COSTS_N_INSNS (15), /* cost of SQRTSD instruction. */ + COSTS_N_INSNS (3), /* cost of CVTSS2SD etc. */ + COSTS_N_INSNS (5), /* cost of 256bit VCVTPS2PD etc. */ + COSTS_N_INSNS (10), /* cost of 512bit VCVTPS2PD etc. */ /* Zen can execute 4 integer operations per cycle. FP operations take 3 cycles and it can execute 2 integer additions and 2 multiplications thus reassociation may make sense up to with of 6. @@ -1847,6 +1890,9 @@ struct processor_costs znver3_cost = { COSTS_N_INSNS (13), /* cost of DIVSD instruction. */ COSTS_N_INSNS (10), /* cost of SQRTSS instruction. */ COSTS_N_INSNS (15), /* cost of SQRTSD instruction. */ + COSTS_N_INSNS (3), /* cost of CVTSS2SD etc. */ + COSTS_N_INSNS (5), /* cost of 256bit VCVTPS2PD etc. */ + COSTS_N_INSNS (10), /* cost of 512bit VCVTPS2PD etc. */ /* Zen can execute 4 integer operations per cycle. FP operations take 3 cycles and it can execute 2 integer additions and 2 multiplications thus reassociation may make sense up to with of 6. @@ -1984,6 +2030,10 @@ struct processor_costs znver4_cost = { COSTS_N_INSNS (13), /* cost of DIVSD instruction. */ COSTS_N_INSNS (15), /* cost of SQRTSS instruction. */ COSTS_N_INSNS (21), /* cost of SQRTSD instruction. */ + COSTS_N_INSNS (3), /* cost of CVTSS2SD etc. */ + COSTS_N_INSNS (5), /* cost of 256bit VCVTPS2PD etc. */ + /* Real latency is 6, but for split regs multiply cost of half op by 2. */ + COSTS_N_INSNS (10), /* cost of 512bit VCVTPS2PD etc. */ /* Zen can execute 4 integer operations per cycle. FP operations take 3 cycles and it can execute 2 integer additions and 2 multiplications thus reassociation may make sense up to with of 6. @@ -2120,7 +2170,7 @@ struct processor_costs znver5_cost = { COSTS_N_INSNS (1), /* cost of cheap SSE instruction. */ /* ADDSS has throughput 2 and latency 2 (in some cases when source is another addition). */ - COSTS_N_INSNS (2), /* cost of ADDSS/SD SUBSS/SD insns. */ + COSTS_N_INSNS (3), /* cost of ADDSS/SD SUBSS/SD insns. */ /* MULSS has throughput 2 and latency 3. */ COSTS_N_INSNS (3), /* cost of MULSS instruction. */ COSTS_N_INSNS (3), /* cost of MULSD instruction. */ @@ -2135,6 +2185,9 @@ struct processor_costs znver5_cost = { COSTS_N_INSNS (14), /* cost of SQRTSS instruction. */ /* DIVSD has throughtput 0.13 and latency 20. */ COSTS_N_INSNS (20), /* cost of SQRTSD instruction. */ + COSTS_N_INSNS (3), /* cost of CVTSS2SD etc. */ + COSTS_N_INSNS (5), /* cost of 256bit VCVTPS2PD etc. */ + COSTS_N_INSNS (5), /* cost of 512bit VCVTPS2PD etc. */ /* Zen5 can execute: - integer ops: 6 per cycle, at most 3 multiplications. latency 1 for additions, 3 for multiplications (pipelined) @@ -2274,6 +2327,9 @@ struct processor_costs skylake_cost = { COSTS_N_INSNS (14), /* cost of DIVSD instruction. */ COSTS_N_INSNS (12), /* cost of SQRTSS instruction. */ COSTS_N_INSNS (18), /* cost of SQRTSD instruction. */ + COSTS_N_INSNS (2), /* cost of CVTSS2SD etc. */ + COSTS_N_INSNS (2), /* cost of 256bit VCVTPS2PD etc. */ + COSTS_N_INSNS (4), /* cost of 512bit VCVTPS2PD etc. */ 1, 4, 2, 2, /* reassoc int, fp, vec_int, vec_fp. */ skylake_memcpy, skylake_memset, @@ -2403,6 +2459,9 @@ struct processor_costs icelake_cost = { COSTS_N_INSNS (14), /* cost of DIVSD instruction. */ COSTS_N_INSNS (12), /* cost of SQRTSS instruction. */ COSTS_N_INSNS (18), /* cost of SQRTSD instruction. */ + COSTS_N_INSNS (2), /* cost of CVTSS2SD etc. */ + COSTS_N_INSNS (2), /* cost of 256bit VCVTPS2PD etc. */ + COSTS_N_INSNS (2), /* cost of 512bit VCVTPS2PD etc. */ 1, 4, 2, 2, /* reassoc int, fp, vec_int, vec_fp. */ icelake_memcpy, icelake_memset, @@ -2526,6 +2585,9 @@ struct processor_costs alderlake_cost = { COSTS_N_INSNS (17), /* cost of DIVSD instruction. */ COSTS_N_INSNS (14), /* cost of SQRTSS instruction. */ COSTS_N_INSNS (18), /* cost of SQRTSD instruction. */ + COSTS_N_INSNS (2), /* cost of CVTSS2SD etc. */ + COSTS_N_INSNS (2), /* cost of 256bit VCVTPS2PD etc. */ + COSTS_N_INSNS (2), /* cost of 512bit VCVTPS2PD etc. */ 1, 4, 3, 3, /* reassoc int, fp, vec_int, vec_fp. */ alderlake_memcpy, alderlake_memset, @@ -2642,6 +2704,9 @@ const struct processor_costs btver1_cost = { COSTS_N_INSNS (17), /* cost of DIVSD instruction. */ COSTS_N_INSNS (14), /* cost of SQRTSS instruction. */ COSTS_N_INSNS (48), /* cost of SQRTSD instruction. */ + COSTS_N_INSNS (4), /* cost of CVTSS2SD etc. */ + COSTS_N_INSNS (7), /* cost of 256bit VCVTPS2PD etc. */ + COSTS_N_INSNS (14), /* cost of 512bit VCVTPS2PD etc. */ 1, 1, 1, 1, /* reassoc int, fp, vec_int, vec_fp. */ btver1_memcpy, btver1_memset, @@ -2755,6 +2820,9 @@ const struct processor_costs btver2_cost = { COSTS_N_INSNS (19), /* cost of DIVSD instruction. */ COSTS_N_INSNS (16), /* cost of SQRTSS instruction. */ COSTS_N_INSNS (21), /* cost of SQRTSD instruction. */ + COSTS_N_INSNS (4), /* cost of CVTSS2SD etc. */ + COSTS_N_INSNS (7), /* cost of 256bit VCVTPS2PD etc. */ + COSTS_N_INSNS (14), /* cost of 512bit VCVTPS2PD etc. */ 1, 1, 1, 1, /* reassoc int, fp, vec_int, vec_fp. */ btver2_memcpy, btver2_memset, @@ -2867,6 +2935,9 @@ struct processor_costs pentium4_cost = { COSTS_N_INSNS (38), /* cost of DIVSD instruction. */ COSTS_N_INSNS (23), /* cost of SQRTSS instruction. */ COSTS_N_INSNS (38), /* cost of SQRTSD instruction. */ + COSTS_N_INSNS (10), /* cost of CVTSS2SD etc. */ + COSTS_N_INSNS (20), /* cost of 256bit VCVTPS2PD etc. */ + COSTS_N_INSNS (40), /* cost of 512bit VCVTPS2PD etc. */ 1, 1, 1, 1, /* reassoc int, fp, vec_int, vec_fp. */ pentium4_memcpy, pentium4_memset, @@ -2982,6 +3053,9 @@ struct processor_costs nocona_cost = { COSTS_N_INSNS (40), /* cost of DIVSD instruction. */ COSTS_N_INSNS (32), /* cost of SQRTSS instruction. */ COSTS_N_INSNS (41), /* cost of SQRTSD instruction. */ + COSTS_N_INSNS (10), /* cost of CVTSS2SD etc. */ + COSTS_N_INSNS (20), /* cost of 256bit VCVTPS2PD etc. */ + COSTS_N_INSNS (40), /* cost of 512bit VCVTPS2PD etc. */ 1, 1, 1, 1, /* reassoc int, fp, vec_int, vec_fp. */ nocona_memcpy, nocona_memset, @@ -3095,6 +3169,9 @@ struct processor_costs atom_cost = { COSTS_N_INSNS (60), /* cost of DIVSD instruction. */ COSTS_N_INSNS (31), /* cost of SQRTSS instruction. */ COSTS_N_INSNS (63), /* cost of SQRTSD instruction. */ + COSTS_N_INSNS (6), /* cost of CVTSS2SD etc. */ + COSTS_N_INSNS (12), /* cost of 256bit VCVTPS2PD etc. */ + COSTS_N_INSNS (24), /* cost of 512bit VCVTPS2PD etc. */ 2, 2, 2, 2, /* reassoc int, fp, vec_int, vec_fp. */ atom_memcpy, atom_memset, @@ -3208,6 +3285,9 @@ struct processor_costs slm_cost = { COSTS_N_INSNS (69), /* cost of DIVSD instruction. */ COSTS_N_INSNS (20), /* cost of SQRTSS instruction. */ COSTS_N_INSNS (35), /* cost of SQRTSD instruction. */ + COSTS_N_INSNS (3), /* cost of CVTSS2SD etc. */ + COSTS_N_INSNS (6), /* cost of 256bit VCVTPS2PD etc. */ + COSTS_N_INSNS (12), /* cost of 512bit VCVTPS2PD etc. */ 1, 2, 1, 1, /* reassoc int, fp, vec_int, vec_fp. */ slm_memcpy, slm_memset, @@ -3335,6 +3415,9 @@ struct processor_costs tremont_cost = { COSTS_N_INSNS (17), /* cost of DIVSD instruction. */ COSTS_N_INSNS (14), /* cost of SQRTSS instruction. */ COSTS_N_INSNS (18), /* cost of SQRTSD instruction. */ + COSTS_N_INSNS (3), /* cost of CVTSS2SD etc. */ + COSTS_N_INSNS (6), /* cost of 256bit VCVTPS2PD etc. */ + COSTS_N_INSNS (12), /* cost of 512bit VCVTPS2PD etc. */ 1, 4, 3, 3, /* reassoc int, fp, vec_int, vec_fp. */ tremont_memcpy, tremont_memset, @@ -3448,6 +3531,9 @@ struct processor_costs intel_cost = { COSTS_N_INSNS (20), /* cost of DIVSD instruction. */ COSTS_N_INSNS (40), /* cost of SQRTSS instruction. */ COSTS_N_INSNS (40), /* cost of SQRTSD instruction. */ + COSTS_N_INSNS (8), /* cost of CVTSS2SD etc. */ + COSTS_N_INSNS (16), /* cost of 256bit VCVTPS2PD etc. */ + COSTS_N_INSNS (32), /* cost of 512bit VCVTPS2PD etc. */ 1, 4, 1, 1, /* reassoc int, fp, vec_int, vec_fp. */ intel_memcpy, intel_memset, @@ -3566,6 +3652,9 @@ struct processor_costs lujiazui_cost = { COSTS_N_INSNS (17), /* cost of DIVSD instruction. */ COSTS_N_INSNS (32), /* cost of SQRTSS instruction. */ COSTS_N_INSNS (60), /* cost of SQRTSD instruction. */ + COSTS_N_INSNS (3), /* cost of CVTSS2SD etc. */ + COSTS_N_INSNS (6), /* cost of 256bit VCVTPS2PD etc. */ + COSTS_N_INSNS (12), /* cost of 512bit VCVTPS2PD etc. */ 1, 4, 3, 3, /* reassoc int, fp, vec_int, vec_fp. */ lujiazui_memcpy, lujiazui_memset, @@ -3682,6 +3771,9 @@ struct processor_costs yongfeng_cost = { COSTS_N_INSNS (14), /* cost of DIVSD instruction. */ COSTS_N_INSNS (20), /* cost of SQRTSS instruction. */ COSTS_N_INSNS (35), /* cost of SQRTSD instruction. */ + COSTS_N_INSNS (3), /* cost of CVTSS2SD etc. */ + COSTS_N_INSNS (6), /* cost of 256bit VCVTPS2PD etc. */ + COSTS_N_INSNS (12), /* cost of 512bit VCVTPS2PD etc. */ 4, 4, 4, 4, /* reassoc int, fp, vec_int, vec_fp. */ yongfeng_memcpy, yongfeng_memset, @@ -3798,6 +3890,9 @@ struct processor_costs shijidadao_cost = { COSTS_N_INSNS (14), /* cost of DIVSD instruction. */ COSTS_N_INSNS (11), /* cost of SQRTSS instruction. */ COSTS_N_INSNS (18), /* cost of SQRTSD instruction. */ + COSTS_N_INSNS (3), /* cost of CVTSS2SD etc. */ + COSTS_N_INSNS (6), /* cost of 256bit VCVTPS2PD etc. */ + COSTS_N_INSNS (12), /* cost of 512bit VCVTPS2PD etc. */ 4, 4, 4, 4, /* reassoc int, fp, vec_int, vec_fp. */ shijidadao_memcpy, shijidadao_memset, @@ -3922,6 +4017,9 @@ struct processor_costs generic_cost = { COSTS_N_INSNS (17), /* cost of DIVSD instruction. */ COSTS_N_INSNS (14), /* cost of SQRTSS instruction. */ COSTS_N_INSNS (18), /* cost of SQRTSD instruction. */ + COSTS_N_INSNS (3), /* cost of CVTSS2SD etc. */ + COSTS_N_INSNS (4), /* cost of 256bit VCVTPS2PD etc. */ + COSTS_N_INSNS (5), /* cost of 512bit VCVTPS2PD etc. */ 1, 4, 3, 3, /* reassoc int, fp, vec_int, vec_fp. */ generic_memcpy, generic_memset, @@ -4051,6 +4149,9 @@ struct processor_costs core_cost = { COSTS_N_INSNS (32), /* cost of DIVSD instruction. */ COSTS_N_INSNS (30), /* cost of SQRTSS instruction. */ COSTS_N_INSNS (58), /* cost of SQRTSD instruction. */ + COSTS_N_INSNS (2), /* cost of CVTSS2SD etc. */ + COSTS_N_INSNS (2), /* cost of 256bit VCVTPS2PD etc. */ + COSTS_N_INSNS (2), /* cost of 512bit VCVTPS2PD etc. */ 1, 4, 2, 2, /* reassoc int, fp, vec_int, vec_fp. */ core_memcpy, core_memset, diff --git a/gcc/config/i386/x86-tune-sched.cc b/gcc/config/i386/x86-tune-sched.cc index 685a83c..15d3d91 100644 --- a/gcc/config/i386/x86-tune-sched.cc +++ b/gcc/config/i386/x86-tune-sched.cc @@ -81,6 +81,14 @@ ix86_issue_rate (void) case PROCESSOR_YONGFENG: case PROCESSOR_SHIJIDADAO: case PROCESSOR_GENERIC: + /* For znver5 decoder can handle 4 or 8 instructions per cycle, + op cache 12 instruction/cycle, dispatch 8 instructions + integer rename 8 instructions and Fp 6 instructions. + + The scheduler, without understanding out of order nature of the CPU + is not going to be able to use more than 4 instructions since that + is limits of the decoders. */ + case PROCESSOR_ZNVER5: return 4; case PROCESSOR_ICELAKE_CLIENT: @@ -91,13 +99,6 @@ ix86_issue_rate (void) return 5; case PROCESSOR_SAPPHIRERAPIDS: - /* For znver5 decoder can handle 4 or 8 instructions per cycle, - op cache 12 instruction/cycle, dispatch 8 instructions - integer rename 8 instructions and Fp 6 instructions. - - The scheduler, without understanding out of order nature of the CPU - is unlikely going to be able to fill all of these. */ - case PROCESSOR_ZNVER5: return 6; default: diff --git a/gcc/config/mips/mips.cc b/gcc/config/mips/mips.cc index 24a28dc..0d3d026 100644 --- a/gcc/config/mips/mips.cc +++ b/gcc/config/mips/mips.cc @@ -20678,6 +20678,9 @@ mips_option_override (void) "-mcompact-branches=never"); } + if (is_micromips && TARGET_MSA) + error ("unsupported combination: %s", "-mmicromips -mmsa"); + /* Require explicit relocs for MIPS R6 onwards. This enables simplification of the compact branch and jump support through the backend. */ if (!TARGET_EXPLICIT_RELOCS && mips_isa_rev >= 6) diff --git a/gcc/config/nvptx/mkoffload.cc b/gcc/config/nvptx/mkoffload.cc index bdfe7f5..e7ec0ef 100644 --- a/gcc/config/nvptx/mkoffload.cc +++ b/gcc/config/nvptx/mkoffload.cc @@ -778,6 +778,9 @@ main (int argc, char **argv) } if (fopenmp) obstack_ptr_grow (&argv_obstack, "-mgomp"); + /* The host code may contain exception handling constructs. + Handle these as good as we can. */ + obstack_ptr_grow (&argv_obstack, "-mfake-exceptions"); for (int ix = 1; ix != argc; ix++) { diff --git a/gcc/config/nvptx/nvptx.cc b/gcc/config/nvptx/nvptx.cc index 87364bf..f893971 100644 --- a/gcc/config/nvptx/nvptx.cc +++ b/gcc/config/nvptx/nvptx.cc @@ -2359,7 +2359,25 @@ nvptx_assemble_integer (rtx x, unsigned int size, int ARG_UNUSED (aligned_p)) { gcc_checking_assert (!init_frag.active); /* Just use the default machinery; it's not getting used, anyway. */ - return default_assemble_integer (x, size, aligned_p); + bool ok = default_assemble_integer (x, size, aligned_p); + /* ..., but a few cases need special handling. */ + switch (GET_CODE (x)) + { + case SYMBOL_REF: + /* The default machinery won't work: we don't define the necessary + operations; don't use them outside of this. */ + gcc_checking_assert (!ok); + { + /* Just emit something; it's not getting used, anyway. */ + const char *op = "\t.symbol_ref\t"; + ok = (assemble_integer_with_op (op, x), true); + } + break; + + default: + break; + } + return ok; } gcc_checking_assert (init_frag.active); @@ -7771,6 +7789,18 @@ nvptx_asm_output_def_from_decls (FILE *stream, tree name, #endif cgraph_node *cnode = cgraph_node::get (name); +#ifdef ACCEL_COMPILER + /* For nvptx offloading, make sure to emit C++ constructor, destructor aliases [PR97106] + + For some reason (yet to be analyzed), they're not 'cnode->referred_to_p ()'. + (..., or that's not the right approach at all; + <https://inbox.sourceware.org/87v7rx8lbx.fsf@euler.schwinge.ddns.net> + "Re: [committed][nvptx] Use .alias directive for mptx >= 6.3"). */ + if (DECL_CXX_CONSTRUCTOR_P (name) + || DECL_CXX_DESTRUCTOR_P (name)) + ; + else +#endif if (!cnode->referred_to_p ()) /* Prevent "Internal error: reference to deleted section". */ return; @@ -7875,8 +7905,6 @@ nvptx_asm_output_def_from_decls (FILE *stream, tree name, #define TARGET_ASM_DECLARE_CONSTANT_NAME nvptx_asm_declare_constant_name #undef TARGET_USE_BLOCKS_FOR_CONSTANT_P #define TARGET_USE_BLOCKS_FOR_CONSTANT_P hook_bool_mode_const_rtx_true -#undef TARGET_ASM_NEED_VAR_DECL_BEFORE_USE -#define TARGET_ASM_NEED_VAR_DECL_BEFORE_USE true #undef TARGET_MACHINE_DEPENDENT_REORG #define TARGET_MACHINE_DEPENDENT_REORG nvptx_reorg diff --git a/gcc/config/nvptx/nvptx.md b/gcc/config/nvptx/nvptx.md index 3201247..7c3bd69 100644 --- a/gcc/config/nvptx/nvptx.md +++ b/gcc/config/nvptx/nvptx.md @@ -1644,7 +1644,9 @@ [(const_int 0)] "" { - sorry ("exception handling not supported"); + if (!fake_exceptions) + sorry ("exception handling not supported"); + DONE; }) (define_expand "nonlocal_goto" diff --git a/gcc/config/nvptx/nvptx.opt b/gcc/config/nvptx/nvptx.opt index 9be81ae..ce9fbc7 100644 --- a/gcc/config/nvptx/nvptx.opt +++ b/gcc/config/nvptx/nvptx.opt @@ -168,6 +168,14 @@ Target Var(nvptx_alias) Init(0) Undocumented mexperimental Target Var(nvptx_experimental) Init(0) Undocumented +mfake-exceptions +Target Var(fake_exceptions) Init(0) Undocumented +; With '-mfake-exceptions' enabled, the user-visible behavior in presence of +; exception handling constructs changes such that the compile-time +; 'sorry, unimplemented: exception handling not supported' is skipped, code +; generation proceeds, and instead, exception handling constructs 'abort' at +; run time. (..., or don't, if they're in dead code.) + mfake-ptx-alloca Target Var(nvptx_fake_ptx_alloca) Init(0) Undocumented ; With '-mfake-ptx-alloca' enabled, the user-visible behavior changes only diff --git a/gcc/config/riscv/bitmanip.md b/gcc/config/riscv/bitmanip.md index 5ed5e18..d0919ec 100644 --- a/gcc/config/riscv/bitmanip.md +++ b/gcc/config/riscv/bitmanip.md @@ -908,6 +908,24 @@ "bext\t%0,%1,%2" [(set_attr "type" "bitmanip")]) +;; We do not define SHIFT_COUNT_TRUNCATED, so we have to have variants +;; that mask/extend the count if we want to eliminate those ops +;; +;; We could (in theory) use GPR for the various modes, but I haven't +;; seen those cases appear in practice. Without a testcase I've +;; elected to keep the modes X which is easy to reason about. +(define_insn "*bext<mode>_mask_pos" + [(set (match_operand:X 0 "register_operand" "=r") + (zero_extract:X (match_operand:X 1 "register_operand" "r") + (const_int 1) + (and:X + (match_operand:X 2 "register_operand" "r") + (match_operand 3 "const_int_operand"))))] + "(TARGET_ZBS + && INTVAL (operands[3]) + 1 == GET_MODE_BITSIZE (<MODE>mode))" + "bext\t%0,%1,%2" + [(set_attr "type" "bitmanip")]) + ;; This is a bext followed by a seqz. Normally this would be a 3->2 split ;; But the and-not pattern with a constant operand is a define_insn_and_split, ;; so this looks like a 2->2 split, which combine rejects. So implement it @@ -1245,3 +1263,41 @@ expand_crc_using_clmul (<SUBX:MODE>mode, <SUBX1:MODE>mode, operands); DONE; }) + +;; If we have an XOR/IOR with a constant operand (C) and the we can +;; synthesize ~C more efficiently than C, then synthesize ~C and use +;; xnor/orn instead. +;; +;; The same can be done for AND, but mvconst_internal's issues get in +;; the way. That's future work. +(define_split + [(set (match_operand:X 0 "register_operand") + (any_or:X (match_operand:X 1 "register_operand") + (match_operand:X 2 "const_int_operand"))) + (clobber (match_operand:X 3 "register_operand"))] + "TARGET_ZBB + && (riscv_const_insns (operands[2], true) + > riscv_const_insns (GEN_INT (~INTVAL (operands[2])), true))" + [(const_int 0)] +{ + /* Get the inverted constant into the temporary register. */ + riscv_emit_move (operands[3], GEN_INT (~INTVAL (operands[2]))); + + /* For xnor, the NOT operation is in a different position. So + we have to customize the split code we generate a bit. + + It is expected that AND will be handled like IOR in the future. */ + if (<CODE> == XOR) + { + rtx x = gen_rtx_XOR (<X:MODE>mode, operands[1], operands[3]); + x = gen_rtx_NOT (<X:MODE>mode, x); + emit_insn (gen_rtx_SET (operands[0], x)); + } + else + { + rtx x = gen_rtx_NOT (<X:MODE>mode, operands[3]); + x = gen_rtx_IOR (<X:MODE>mode, x, operands[1]); + emit_insn (gen_rtx_SET (operands[0], x)); + } + DONE; +}) diff --git a/gcc/config/riscv/gnu.h b/gcc/config/riscv/gnu.h new file mode 100644 index 0000000..047399b --- /dev/null +++ b/gcc/config/riscv/gnu.h @@ -0,0 +1,59 @@ +/* Definitions for RISC-V GNU/Hurd systems with ELF format. + Copyright (C) 1998-2025 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 +<http://www.gnu.org/licenses/>. */ + +#define TARGET_OS_CPP_BUILTINS() \ + do { \ + GNU_USER_TARGET_OS_CPP_BUILTINS(); \ + } while (0) + +#define GNU_USER_DYNAMIC_LINKER "/lib/ld-riscv" XLEN_SPEC "-" ABI_SPEC ".so.1" + +#define ICACHE_FLUSH_FUNC "__riscv_flush_icache" + +#define CPP_SPEC "%{pthread:-D_REENTRANT}" + +#define LD_EMUL_SUFFIX \ + "%{mabi=lp64d:}" \ + "%{mabi=lp64f:_lp64f}" \ + "%{mabi=lp64:_lp64}" \ + "%{mabi=ilp32d:}" \ + "%{mabi=ilp32f:_ilp32f}" \ + "%{mabi=ilp32:_ilp32}" + +#define LINK_SPEC "\ +-melf" XLEN_SPEC DEFAULT_ENDIAN_SPEC "riscv" LD_EMUL_SUFFIX " \ +%{mno-relax:--no-relax} \ +-X \ +%{mbig-endian:-EB} \ +%{mlittle-endian:-EL} \ +%{shared} \ + %{!shared: \ + %{!static: \ + %{!static-pie: \ + %{rdynamic:-export-dynamic} \ + -dynamic-linker " GNU_USER_DYNAMIC_LINKER "}} \ + %{static:-static} %{static-pie:-static -pie --no-dynamic-linker -z text}}" + +#define STARTFILE_PREFIX_SPEC \ + "/lib" XLEN_SPEC "/" ABI_SPEC "/ " \ + "/usr/lib" XLEN_SPEC "/" ABI_SPEC "/ " \ + "/lib/ " \ + "/usr/lib/ " + +#define RISCV_USE_CUSTOMISED_MULTI_LIB select_by_abi diff --git a/gcc/config/riscv/riscv-target-attr.cc b/gcc/config/riscv/riscv-target-attr.cc index 1d96865..8ad3025 100644 --- a/gcc/config/riscv/riscv-target-attr.cc +++ b/gcc/config/riscv/riscv-target-attr.cc @@ -257,11 +257,7 @@ riscv_target_attr_parser::update_settings (struct gcc_options *opts) const { std::string local_arch = m_subset_list->to_string (true); const char* local_arch_str = local_arch.c_str (); - struct cl_target_option *default_opts - = TREE_TARGET_OPTION (target_option_default_node); - if (opts->x_riscv_arch_string != default_opts->x_riscv_arch_string) - free (CONST_CAST (void *, (const void *) opts->x_riscv_arch_string)); - opts->x_riscv_arch_string = xstrdup (local_arch_str); + opts->x_riscv_arch_string = ggc_strdup (local_arch_str); riscv_set_arch_by_subset_list (m_subset_list, opts); } diff --git a/gcc/config/riscv/riscv-vsetvl.cc b/gcc/config/riscv/riscv-vsetvl.cc index 0ac2538..a8c9256 100644 --- a/gcc/config/riscv/riscv-vsetvl.cc +++ b/gcc/config/riscv/riscv-vsetvl.cc @@ -685,7 +685,7 @@ invalid_opt_bb_p (basic_block cfg_bb) /* We only do LCM optimizations on blocks that are post dominated by EXIT block, that is, we don't do LCM optimizations on infinite loop. */ FOR_EACH_EDGE (e, ei, cfg_bb->succs) - if (e->flags & EDGE_FAKE) + if ((e->flags & EDGE_FAKE) || (e->flags & EDGE_ABNORMAL)) return true; return false; @@ -2698,6 +2698,7 @@ pre_vsetvl::compute_lcm_local_properties () m_avout = sbitmap_vector_alloc (last_basic_block_for_fn (cfun), num_exprs); bitmap_vector_clear (m_avloc, last_basic_block_for_fn (cfun)); + bitmap_vector_clear (m_kill, last_basic_block_for_fn (cfun)); bitmap_vector_clear (m_antloc, last_basic_block_for_fn (cfun)); bitmap_vector_ones (m_transp, last_basic_block_for_fn (cfun)); @@ -2749,6 +2750,10 @@ pre_vsetvl::compute_lcm_local_properties () if (invalid_opt_bb_p (bb->cfg_bb ())) { + if (dump_file && (dump_flags & TDF_DETAILS)) + fprintf (dump_file, "\n --- skipping bb %u due to weird edge", + bb->index ()); + bitmap_clear (m_antloc[bb_index]); bitmap_clear (m_transp[bb_index]); } @@ -3022,6 +3027,18 @@ pre_vsetvl::earliest_fuse_vsetvl_info (int iter) continue; } + /* We cannot lift a vsetvl into the source block if the block is + not transparent WRT to it. + This is too restrictive for blocks where a register's use only + feeds into vsetvls and no regular insns. One example is the + test rvv/vsetvl/avl_single-68.c which is currently XFAILed for + that reason. + In order to support this case we'd need to check the vsetvl's + AVL operand's uses in the source block and make sure they are + only used in other vsetvls. */ + if (!bitmap_bit_p (m_transp[eg->src->index], expr_index)) + continue; + if (dump_file && (dump_flags & TDF_DETAILS)) { fprintf (dump_file, diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc index 38f3ae7..bad59e2 100644 --- a/gcc/config/riscv/riscv.cc +++ b/gcc/config/riscv/riscv.cc @@ -10382,7 +10382,7 @@ riscv_file_end () fprintf (asm_out_file, "1:\n"); /* pr_type. */ - fprintf (asm_out_file, "\t.p2align\t3\n"); + fprintf (asm_out_file, "\t.p2align\t%u\n", p2align); fprintf (asm_out_file, "2:\n"); fprintf (asm_out_file, "\t.long\t0xc0000000\n"); /* pr_datasz. */ @@ -13136,9 +13136,6 @@ parse_features_for_version (tree decl, DECL_SOURCE_LOCATION (decl)); gcc_assert (parse_res); - if (arch_string != default_opts->x_riscv_arch_string) - free (CONST_CAST (void *, (const void *) arch_string)); - cl_target_option_restore (&global_options, &global_options_set, &cur_target); } diff --git a/gcc/config/riscv/riscv.h b/gcc/config/riscv/riscv.h index 2bcabd0..2759a4c 100644 --- a/gcc/config/riscv/riscv.h +++ b/gcc/config/riscv/riscv.h @@ -888,7 +888,7 @@ extern enum riscv_cc get_riscv_cc (const rtx use); #define ASM_OUTPUT_OPCODE(STREAM, PTR) \ (PTR) = riscv_asm_output_opcode(STREAM, PTR) -#define JUMP_TABLES_IN_TEXT_SECTION 0 +#define JUMP_TABLES_IN_TEXT_SECTION (riscv_cmodel == CM_LARGE) #define CASE_VECTOR_MODE SImode #define CASE_VECTOR_PC_RELATIVE (riscv_cmodel != CM_MEDLOW) diff --git a/gcc/config/riscv/riscv.md b/gcc/config/riscv/riscv.md index 26a247c..eec9687 100644 --- a/gcc/config/riscv/riscv.md +++ b/gcc/config/riscv/riscv.md @@ -789,7 +789,7 @@ rtx t5 = gen_reg_rtx (DImode); rtx t6 = gen_reg_rtx (DImode); - riscv_emit_binary (PLUS, operands[0], operands[1], operands[2]); + emit_insn (gen_addsi3_extended (t6, operands[1], operands[2])); if (GET_CODE (operands[1]) != CONST_INT) emit_insn (gen_extend_insn (t4, operands[1], DImode, SImode, 0)); else @@ -799,7 +799,10 @@ else t5 = operands[2]; emit_insn (gen_adddi3 (t3, t4, t5)); - emit_insn (gen_extend_insn (t6, operands[0], DImode, SImode, 0)); + rtx t7 = gen_lowpart (SImode, t6); + SUBREG_PROMOTED_VAR_P (t7) = 1; + SUBREG_PROMOTED_SET (t7, SRP_SIGNED); + emit_move_insn (operands[0], t7); riscv_expand_conditional_branch (operands[3], NE, t6, t3); } @@ -835,8 +838,11 @@ emit_insn (gen_extend_insn (t3, operands[1], DImode, SImode, 0)); else t3 = operands[1]; - riscv_emit_binary (PLUS, operands[0], operands[1], operands[2]); - emit_insn (gen_extend_insn (t4, operands[0], DImode, SImode, 0)); + emit_insn (gen_addsi3_extended (t4, operands[1], operands[2])); + rtx t5 = gen_lowpart (SImode, t4); + SUBREG_PROMOTED_VAR_P (t5) = 1; + SUBREG_PROMOTED_SET (t5, SRP_SIGNED); + emit_move_insn (operands[0], t5); riscv_expand_conditional_branch (operands[3], LTU, t4, t3); } @@ -966,7 +972,7 @@ rtx t5 = gen_reg_rtx (DImode); rtx t6 = gen_reg_rtx (DImode); - riscv_emit_binary (MINUS, operands[0], operands[1], operands[2]); + emit_insn (gen_subsi3_extended (t6, operands[1], operands[2])); if (GET_CODE (operands[1]) != CONST_INT) emit_insn (gen_extend_insn (t4, operands[1], DImode, SImode, 0)); else @@ -976,7 +982,10 @@ else t5 = operands[2]; emit_insn (gen_subdi3 (t3, t4, t5)); - emit_insn (gen_extend_insn (t6, operands[0], DImode, SImode, 0)); + rtx t7 = gen_lowpart (SImode, t6); + SUBREG_PROMOTED_VAR_P (t7) = 1; + SUBREG_PROMOTED_SET (t7, SRP_SIGNED); + emit_move_insn (operands[0], t7); riscv_expand_conditional_branch (operands[3], NE, t6, t3); } @@ -1015,8 +1024,11 @@ emit_insn (gen_extend_insn (t3, operands[1], DImode, SImode, 0)); else t3 = operands[1]; - riscv_emit_binary (MINUS, operands[0], operands[1], operands[2]); - emit_insn (gen_extend_insn (t4, operands[0], DImode, SImode, 0)); + emit_insn (gen_subsi3_extended (t4, operands[1], operands[2])); + rtx t5 = gen_lowpart (SImode, t4); + SUBREG_PROMOTED_VAR_P (t5) = 1; + SUBREG_PROMOTED_SET (t5, SRP_SIGNED); + emit_move_insn (operands[0], t5); riscv_expand_conditional_branch (operands[3], LTU, t3, t4); } diff --git a/gcc/config/riscv/vector.md b/gcc/config/riscv/vector.md index 51eb64f..3ab4d76 100644 --- a/gcc/config/riscv/vector.md +++ b/gcc/config/riscv/vector.md @@ -2136,18 +2136,34 @@ (match_operand 7 "const_int_operand") (reg:SI VL_REGNUM) (reg:SI VTYPE_REGNUM)] UNSPEC_VPREDICATE) - (vec_duplicate:V_VLS - (match_operand:<VEL> 3 "direct_broadcast_operand")) + ;; (vec_duplicate:V_VLS ;; wrapper activated by wrap_vec_dup below. + (match_operand:<VEL> 3 "direct_broadcast_operand") ;; ) (match_operand:V_VLS 2 "vector_merge_operand")))] "TARGET_VECTOR" { /* Transform vmv.v.x/vfmv.v.f (avl = 1) into vmv.s.x since vmv.s.x/vfmv.s.f has better chances to do vsetvl fusion in vsetvl pass. */ + bool wrap_vec_dup = true; + rtx vec_cst = NULL_RTX; if (riscv_vector::splat_to_scalar_move_p (operands)) { operands[1] = riscv_vector::gen_scalar_move_mask (<VM>mode); operands[3] = force_reg (<VEL>mode, operands[3]); } + else if (immediate_operand (operands[3], <VEL>mode) + && (vec_cst = gen_const_vec_duplicate (<MODE>mode, operands[3])) + && (/* -> pred_broadcast<mode>_zero */ + (vector_least_significant_set_mask_operand (operands[1], + <VM>mode) + && vector_const_0_operand (vec_cst, <MODE>mode)) + || (/* pred_broadcast<mode>_imm */ + vector_all_trues_mask_operand (operands[1], <VM>mode) + && vector_const_int_or_double_0_operand (vec_cst, + <MODE>mode)))) + { + operands[3] = vec_cst; + wrap_vec_dup = false; + } /* Handle vmv.s.x instruction (Wb1 mask) which has memory scalar. */ else if (satisfies_constraint_Wdm (operands[3])) { @@ -2191,6 +2207,8 @@ ; else operands[3] = force_reg (<VEL>mode, operands[3]); + if (wrap_vec_dup) + operands[3] = gen_rtx_VEC_DUPLICATE (<MODE>mode, operands[3]); }) (define_insn_and_split "*pred_broadcast<mode>" diff --git a/gcc/config/rx/rx.md b/gcc/config/rx/rx.md index edb2c96..a3d966e 100644 --- a/gcc/config/rx/rx.md +++ b/gcc/config/rx/rx.md @@ -2541,10 +2541,17 @@ (unspec_volatile:SI [(match_operand:BLK 1 "memory_operand") ;; String1 (match_operand:BLK 2 "memory_operand")] ;; String2 UNSPEC_CMPSTRN)) - (use (match_operand:SI 3 "register_operand")) ;; Max Length + (use (match_operand:SI 3 "nonmemory_operand")) ;; Max Length (match_operand:SI 4 "immediate_operand")] ;; Known Align "rx_allow_string_insns" { + bool const_len = CONST_INT_P (operands[3]); + if (const_len && operands[3] == CONST0_RTX (SImode)) + { + emit_move_insn (operands[0], CONST0_RTX (SImode)); + DONE; + } + rtx str1 = gen_rtx_REG (SImode, 1); rtx str2 = gen_rtx_REG (SImode, 2); rtx len = gen_rtx_REG (SImode, 3); @@ -2553,6 +2560,13 @@ emit_move_insn (str2, force_operand (XEXP (operands[2], 0), NULL_RTX)); emit_move_insn (len, operands[3]); + /* Set flags in case len is zero */ + if (!const_len) + { + emit_insn (gen_setpsw (GEN_INT ('C'))); + emit_insn (gen_setpsw (GEN_INT ('Z'))); + } + emit_insn (gen_rx_cmpstrn (operands[0], operands[1], operands[2])); DONE; } @@ -2590,9 +2604,7 @@ (clobber (reg:SI 3)) (clobber (reg:CC CC_REG))] "rx_allow_string_insns" - "setpsw z ; Set flags in case len is zero - setpsw c - scmpu ; Perform the string comparison + "scmpu ; Perform the string comparison mov #-1, %0 ; Set up -1 result (which cannot be created ; by the SC insn) bnc ?+ ; If Carry is not set skip over diff --git a/gcc/config/s390/9175.md b/gcc/config/s390/9175.md new file mode 100644 index 0000000..d0ac0e1 --- /dev/null +++ b/gcc/config/s390/9175.md @@ -0,0 +1,316 @@ +;; Scheduling description for z17. +;; Copyright (C) 2025 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 +;; <http://www.gnu.org/licenses/>. + +(define_attr "z17_unit_fpd" "" + (cond [(eq_attr "mnemonic" "ddb,ddbr,deb,debr,dxbr,sqdb,sqdbr,sqeb,sqebr,\ +sqxbr,vdf,vdg,vdlf,vdlg,vdlq,vdq,vfddb,vfdsb,vfsqdb,vfsqsb,vrf,vrg,vrlf,vrlg,\ +vrlq,vrq,wfddb,wfdsb,wfdxb,wfsqdb,wfsqxb") + (const_int 1)] (const_int 0))) + +(define_attr "z17_unit_fxa" "" + (cond [(eq_attr "mnemonic" "a,afi,ag,agf,agfi,agfr,agh,aghi,aghik,agr,agrk,ah,\ +ahi,ahik,ahy,al,alc,alcg,alcgr,alcr,alfi,alg,algf,algfi,algfr,alghsik,algr,\ +algrk,alhsik,alr,alrk,aly,ar,ark,ay,bdepg,bextg,clzg,ctzg,etnd,flogr,ic,icm,\ +icmh,icmy,icy,iihf,iilf,ipm,la,larl,lay,lb,lbr,lcgfr,lcgr,lcr,lgb,lgbr,lgf,\ +lgfi,lgfr,lgfrl,lgh,lghi,lghr,lghrl,lgr,lh,lhi,lhr,lhrl,lhy,llcr,llgcr,llgfr,\ +llghr,llgtr,llhr,llihf,llihh,llihl,llilf,llilh,llill,llxab,llxaf,llxag,llxah,\ +llxaq,lngfr,lngr,lnr,loc,locg,locghi,locgr,lochi,locr,lpgfr,lpgr,lpr,lr,lrv,\ +lrvg,lrvgr,lrvh,lrvr,lt,ltg,ltgf,ltgfr,ltgr,ltr,lxab,lxaf,lxag,lxah,lxaq,m,mfy,\ +mg,mgh,mghi,mgrk,mh,mhi,mhy,ml,mlg,mlgr,mlr,mr,ms,msc,msfi,msg,msgc,msgf,msgfi,\ +msgfr,msgr,msgrkc,msr,msrkc,msy,n,ncgrk,ncrk,ng,ngr,ngrk,nihf,nihh,nihl,nilf,\ +nilh,nill,nngrk,nnrk,nogrk,nork,nr,nrk,nxgrk,nxrk,ny,o,ocgrk,ocrk,og,ogr,ogrk,\ +oihf,oihh,oihl,oilf,oilh,oill,or,ork,oy,pfpo,popcnt,risbg,risbgn,rll,rllg,\ +rnsbg,rosbg,rxsbg,s,selgr,selr,sg,sgf,sgfr,sgh,sgr,sgrk,sh,shy,sl,slb,slbg,\ +slbgr,slbr,sldl,slfi,slg,slgf,slgfi,slgfr,slgr,slgrk,sll,sllg,sllk,slr,slrk,\ +sly,sr,sra,srag,srak,srda,srdl,srk,srl,srlg,srlk,sy,x,xg,xgr,xgrk,xihf,xilf,xr,\ +xrk,xy") + (const_int 1)] (const_int 0))) + +(define_attr "z17_unit_fxb" "" + (cond [(eq_attr "mnemonic" "agsi,algsi,alsi,asi,b,bc,bcr,bi,br,c,cfi,cg,cgf,\ +cgfi,cgfr,cgfrl,cgh,cghi,cghrl,cghsi,cgit,cgr,cgrl,cgrt,ch,chi,chrl,chsi,chy,\ +cit,cl,clfhsi,clfi,clfit,clg,clgf,clgfi,clgfr,clgfrl,clghrl,clghsi,clgit,clgr,\ +clgrl,clgrt,clgt,clhhsi,clhrl,cli,cliy,clm,clmy,clr,clrl,clrt,clt,cly,cr,crl,\ +crt,cy,laa,laag,lan,lang,lao,laog,lat,lax,laxg,lcdfr,ldgr,ldr,lgat,lgdr,lndfr,\ +lpdfr,lxr,lzdr,lzer,lzxr,mvghi,mvhhi,mvhi,mvi,mviy,ni,niy,nop,nopr,ntstg,oi,\ +oiy,ppa,st,stc,stcy,std,stdy,ste,stey,stg,stgrl,sth,sthrl,sthy,stoc,stocg,strl,\ +strv,strvg,strvh,sty,tend,tm,tmh,tmhh,tmhl,tml,tmlh,tmll,tmy,vlgvb,vlgvf,vlgvg,\ +vlgvh,vlr,vlvgb,vlvgf,vlvgg,vlvgh,vlvgp,vscef,vsceg,vst,vstbrf,vstbrg,vstbrh,\ +vstbrq,vstebrf,vstebrg,vstef,vsteg,vsterf,vsterg,vsterh,vstl,vstrl,vstrlr,xi,\ +xiy") + (const_int 1)] (const_int 0))) + +(define_attr "z17_unit_fxd" "" + (cond [(eq_attr "mnemonic" "dlgr,dlr,dr,dsgfr,dsgr") + (const_int 1)] (const_int 0))) + +(define_attr "z17_unit_lsu" "" + (cond [(eq_attr "mnemonic" "clc,ear,l,lam,lcbb,ld,lde,ldy,lg,lgrl,llc,llgc,\ +llgf,llgfrl,llgh,llghrl,llgt,llh,llhrl,lm,lmg,lmy,lpq,lrl,ly,mvcrl,sar,sfpc,\ +tabort,vl,vlbb,vlbrf,vlbrg,vlbrh,vlbrq,vlbrrepf,vlbrrepg,vlbrreph,vlerf,vlerg,\ +vlerh,vll,vllebrzf,vllebrzg,vllebrzh,vllezb,vllezf,vllezg,vllezh,vllezlf,\ +vlrepb,vlrepf,vlrepg,vlreph,vlrl,vlrlr") + (const_int 1)] (const_int 0))) + +(define_attr "z17_unit_vfu" "" + (cond [(eq_attr "mnemonic" "adb,adbr,adtr,aeb,aebr,axbr,axtr,brcl,cdb,cdbr,\ +cdtr,ceb,cebr,cpsdr,cxbr,cxtr,ddtr,dxtr,fidbr,fidbra,fidtr,fiebr,fiebra,fixbr,\ +fixbra,fixtr,j,jg,kdb,kdbr,kdtr,keb,kebr,kxbr,kxtr,lcdbr,lcebr,lcxbr,ldeb,\ +ldebr,ldetr,le,ledbr,ledtr,ler,ley,lndbr,lnebr,lnxbr,lpdbr,lpebr,lpxbr,ltdbr,\ +ltdtr,ltebr,ltxbr,ltxtr,lxdb,lxdbr,lxdtr,lxeb,lxebr,madb,madbr,maeb,maebr,mdb,\ +mdbr,mdtr,meeb,meebr,msdb,msdbr,mseb,msebr,mxbr,mxtr,sdb,sdbr,sdtr,seb,sebr,\ +sxbr,sxtr,tcdb,tceb,tcxb,tdcdt,tdcet,tdcxt,vab,vaccb,vacccq,vaccf,vaccg,vacch,\ +vaccq,vacq,vaf,vag,vah,vaq,vavgb,vavgf,vavgg,vavgh,vavglb,vavglf,vavglg,vavglh,\ +vavglq,vavgq,vblendb,vblendf,vblendg,vblendh,vblendq,vbperm,vcdgb,vcdlgb,vcefb,\ +vcelfb,vceqb,vceqbs,vceqf,vceqfs,vceqg,vceqgs,vceqh,vceqhs,vceqq,vceqqs,vcfeb,\ +vcfn,vcgdb,vchb,vchbs,vchf,vchfs,vchg,vchgs,vchh,vchhs,vchlb,vchlbs,vchlf,\ +vchlfs,vchlg,vchlgs,vchlh,vchlhs,vchlq,vchlqs,vchq,vchqs,vcksm,vclfeb,vclfnh,\ +vclfnl,vclgdb,vclzb,vclzf,vclzg,vclzh,vclzq,vcnf,vcrnf,vctzb,vctzf,vctzg,vctzh,\ +vctzq,verimb,verimf,verimg,verimh,verllb,verllf,verllg,verllh,verllvb,verllvf,\ +verllvg,verllvh,veslb,veslf,veslg,veslh,veslvb,veslvf,veslvg,veslvh,vesrab,\ +vesraf,vesrag,vesrah,vesravb,vesravf,vesravg,vesravh,vesrlb,vesrlf,vesrlg,\ +vesrlh,vesrlvb,vesrlvf,vesrlvg,vesrlvh,veval,vfadb,vfasb,vfcedb,vfcedbs,vfcesb,\ +vfcesbs,vfchdb,vfchdbs,vfchedb,vfchedbs,vfchesb,vfchesbs,vfchsb,vfchsbs,vfeeb,\ +vfeef,vfeeh,vfeezbs,vfeezfs,vfeezhs,vfeneb,vfenef,vfeneh,vfenezb,vfenezf,\ +vfenezh,vfidb,vfisb,vfkedb,vfkesb,vfkhdb,vfkhedb,vfkhesb,vfkhsb,vflcdb,vflcsb,\ +vflndb,vflnsb,vflpdb,vflpsb,vfmadb,vfmasb,vfmaxdb,vfmaxsb,vfmdb,vfmindb,\ +vfminsb,vfmsb,vfmsdb,vfmssb,vfnmadb,vfnmasb,vfnmsdb,vfnmssb,vfsdb,vfssb,\ +vftcidb,vftcisb,vgbm,vgemb,vgemf,vgemg,vgemh,vgemq,vgfmab,vgfmaf,vgfmag,vgfmah,\ +vgfmb,vgfmf,vgfmg,vgfmh,vgm,vistrb,vistrbs,vistrf,vistrfs,vistrh,vistrhs,vlcb,\ +vlcf,vlcg,vlch,vldeb,vleb,vlebrf,vlebrg,vlebrh,vledb,vlef,vleg,vleh,vleib,\ +vleif,vleig,vleih,vlpb,vlpf,vlpg,vlph,vlpq,vmaeb,vmaef,vmaeg,vmaeh,vmahb,vmahf,\ +vmahg,vmahh,vmahq,vmalb,vmaleb,vmalef,vmaleg,vmaleh,vmalf,vmalg,vmalhb,vmalhf,\ +vmalhg,vmalhh,vmalhq,vmalhw,vmalob,vmalof,vmalog,vmaloh,vmalq,vmaob,vmaof,\ +vmaog,vmaoh,vmeb,vmef,vmeg,vmeh,vmhb,vmhf,vmhg,vmhh,vmhq,vmlb,vmleb,vmlef,\ +vmleg,vmleh,vmlf,vmlg,vmlhb,vmlhf,vmlhg,vmlhh,vmlhq,vmlhw,vmlob,vmlof,vmlog,\ +vmloh,vmlq,vmnb,vmnf,vmng,vmnh,vmnlb,vmnlf,vmnlg,vmnlh,vmnlq,vmnq,vmob,vmof,\ +vmog,vmoh,vmrhb,vmrhf,vmrhg,vmrhh,vmrlb,vmrlf,vmrlg,vmrlh,vmslg,vmxb,vmxf,vmxg,\ +vmxh,vmxlb,vmxlf,vmxlg,vmxlh,vmxlq,vmxq,vn,vnc,vnn,vno,vnot,vnx,vo,voc,vone,\ +vpdi,vperm,vpkf,vpkg,vpkh,vpklsf,vpklsfs,vpklsg,vpklsgs,vpklsh,vpklshs,vpksf,\ +vpksfs,vpksg,vpksgs,vpksh,vpkshs,vpopct,vpopctb,vpopctf,vpopctg,vpopcth,vrepb,\ +vrepf,vrepg,vreph,vrepi,vrepib,vrepif,vrepig,vrepih,vsb,vsbcbiq,vsbiq,vscbib,\ +vscbif,vscbig,vscbih,vscbiq,vsegb,vsegf,vsegh,vsel,vsf,vsg,vsh,vsl,vslb,vsld,\ +vsldb,vsq,vsra,vsrab,vsrd,vsrl,vsrlb,vsumb,vsumgf,vsumgh,vsumh,vsumqf,vsumqg,\ +vtm,vuphb,vuphf,vuphg,vuphh,vuplb,vuplf,vuplg,vuplhb,vuplhf,vuplhg,vuplhh,\ +vuplhw,vupllb,vupllf,vupllg,vupllh,vx,vzero,wcdgb,wcdlgb,wcefb,wcelfb,wcfeb,\ +wcgdb,wclfeb,wclgdb,wfadb,wfasb,wfaxb,wfcdb,wfcedb,wfcesb,wfcexb,wfcexbs,\ +wfchdb,wfchedb,wfchesb,wfchexb,wfchexbs,wfchsb,wfchxb,wfchxbs,wfcsb,wfcxb,\ +wfidb,wfisb,wfixb,wfkdb,wfkedb,wfkesb,wfkexb,wfkhdb,wfkhedb,wfkhesb,wfkhexb,\ +wfkhsb,wfkhxb,wfksb,wfkxb,wflcdb,wflcsb,wflcxb,wflld,wflndb,wflnsb,wflnxb,\ +wflpdb,wflpsb,wflpxb,wflrx,wfmadb,wfmasb,wfmaxb,wfmaxxb,wfmdb,wfminxb,wfmsb,\ +wfmsdb,wfmssb,wfmsxb,wfmxb,wfnmaxb,wfnmsxb,wfsdb,wfssb,wfsxb,wftcixb,wldeb,\ +wledb") + (const_int 1)] (const_int 0))) + +(define_attr "z17_cracked" "" + (cond [(eq_attr "mnemonic" "bas,basr,bras,brasl,cdfbr,cdftr,cdgbr,cdgtr,\ +cdlfbr,cdlftr,cdlgbr,cdlgtr,cefbr,cegbr,celfbr,celgbr,cfdbr,cfebr,cfxbr,cgdbr,\ +cgdtr,cgebr,cgxbr,cgxtr,chhsi,clfdbr,clfdtr,clfebr,clfxbr,clfxtr,clgdbr,clgdtr,\ +clgebr,clgxbr,clgxtr,cs,csg,csy,efpc,ex,exrl,lcgfr,lngfr,lpgfr,lpq,lxr,lzxr,\ +mvc,nc,oc,rnsbg,rosbg,rxsbg,stpq,vgef,vgeg,vscef,vsceg,vsteb,vstebrh,vsteh,xc") + (const_int 1)] (const_int 0))) + +(define_attr "z17_expanded" "" + (cond [(eq_attr "mnemonic" "cds,cdsg,cdsy,cxfbr,cxftr,cxgbr,cxgtr,cxlfbr,\ +cxlftr,cxlgbr,cxlgtr,d,dl,dlg,dsg,dsgf,lam,lm,lmg,lmy,sldl,srda,srdl,stam,stm,\ +stmg,stmy,tbegin,tbeginc") + (const_int 1)] (const_int 0))) + +(define_attr "z17_groupalone" "" + (cond [(eq_attr "mnemonic" "alc,alcg,alcgr,alcr,axbr,axtr,clc,cxbr,cxfbr,\ +cxftr,cxgbr,cxgtr,cxlfbr,cxlftr,cxlgbr,cxlgtr,cxtr,d,dl,dlg,dlgr,dlr,dr,dsg,\ +dsgf,dsgfr,dsgr,dxbr,dxtr,ex,exrl,fixbr,fixbra,fixtr,flogr,kxbr,kxtr,lcxbr,\ +lnxbr,lpxbr,ltxbr,ltxtr,lxdb,lxdbr,lxdtr,lxeb,lxebr,m,madb,maeb,maebr,mfy,mg,\ +mgrk,ml,mlg,mlgr,mlr,mr,msdb,mseb,msebr,mvc,mvcrl,mxbr,mxtr,nc,oc,ppa,sfpc,slb,\ +slbg,slbgr,slbr,sqxbr,sxbr,sxtr,tabort,tbegin,tbeginc,tcxb,tdcxt,tend,xc") + (const_int 1)] (const_int 0))) + +(define_attr "z17_endgroup" "" + (cond [(eq_attr "mnemonic" "bas,basr,bcr,br,bras,brasl,cdsg,clfebr,cs,csg,csy,\ +efpc,ex,exrl,ipm,lam,lpq,lxr,nopr,sldl,srda,srdl,stam,stm,stmg,stmy,tbegin,\ +tbeginc") + (const_int 1)] (const_int 0))) + +(define_attr "z17_groupoftwo" "" + (cond [(eq_attr "mnemonic" "cdfbr,cdftr,cdgbr,cdgtr,cdlfbr,cdlftr,cdlgbr,\ +cdlgtr,cefbr,cegbr,celfbr,celgbr,cfdbr,cfebr,cfxbr,cgdbr,cgdtr,cgebr,cgxbr,\ +cgxtr,chhsi,clfdbr,clfdtr,clfxbr,clfxtr,clgdbr,clgdtr,clgebr,clgxbr,clgxtr,\ +lcgfr,lngfr,lpgfr,lzxr,vacccq,vacq,vblendb,vblendf,vblendg,vblendh,vblendq,\ +veval,vfmadb,vfmasb,vfmsdb,vfmssb,vfnmadb,vfnmasb,vfnmsdb,vfnmssb,vgef,vgeg,\ +vgfmab,vgfmaf,vgfmag,vgfmah,vmaeb,vmaef,vmaeg,vmaeh,vmahb,vmahf,vmahg,vmahh,\ +vmahq,vmalb,vmaleb,vmalef,vmaleg,vmaleh,vmalf,vmalg,vmalhb,vmalhf,vmalhg,\ +vmalhh,vmalhq,vmalhw,vmalob,vmalof,vmalog,vmaloh,vmalq,vmaob,vmaof,vmaog,vmaoh,\ +vmslg,vperm,vsbcbiq,vsbiq,vscef,vsceg,vsel,vsteb,vstebrh,vsteh,wfmadb,wfmasb,\ +wfmaxb,wfmsdb,wfmssb,wfmsxb,wfnmaxb,wfnmsxb") + (const_int 1)] (const_int 0))) + +(define_insn_reservation "z17_0" 0 + (and (eq_attr "cpu" "z17") + (eq_attr "mnemonic" "a,afi,ag,agfi,aghi,aghik,agr,agrk,ahi,ahik,al,alfi,alg,\ +algf,algfi,algfr,alghsik,algr,algrk,alhsik,alr,alrk,aly,ar,ark,ay,b,bc,bcr,bi,\ +br,brcl,c,cfi,cg,cgfi,cghi,cghsi,cgit,cgr,cgrl,cgrt,chi,chsi,cit,cl,clfhsi,\ +clfi,clfit,clg,clgf,clgfi,clgfr,clgfrl,clghrl,clghsi,clgit,clgr,clgrl,clgrt,\ +clgt,clhhsi,clhrl,cli,cliy,clr,clrl,clrt,clt,cly,cr,crl,crt,cy,etnd,ic,icm,\ +icmh,icmy,icy,iihf,iilf,j,jg,la,larl,lat,lay,lb,lbr,lcdfr,lcgr,lcr,ldgr,ldr,\ +lgat,lgb,lgbr,lgf,lgfi,lgfr,lgfrl,lgh,lghi,lghr,lghrl,lgr,lh,lhi,lhr,lhrl,lhy,\ +llcr,llgcr,llgfr,llghr,llgtr,llhr,llihf,llihh,llihl,llilf,llilh,llill,lndfr,\ +lngr,lnr,lpdfr,lpgr,lpr,lr,lrv,lrvg,lrvgr,lrvh,lrvr,lt,ltg,ltgf,ltgfr,ltgr,ltr,\ +lzdr,lzer,n,ncgrk,ncrk,ng,ngr,ngrk,nihf,nihh,nihl,nilf,nilh,nill,nngrk,nnrk,\ +nogrk,nop,nopr,nork,nr,nrk,nxgrk,nxrk,ny,o,ocgrk,ocrk,og,ogr,ogrk,oihf,oihh,\ +oihl,oilf,oilh,oill,or,ork,oy,pfpo,risbg,risbgn,rll,rllg,s,sg,sgr,sgrk,sl,sldl,\ +slfi,slg,slgf,slgfi,slgfr,slgr,slgrk,sll,sllg,sllk,slr,slrk,sly,sr,sra,srag,\ +srak,srda,srdl,srk,srl,srlg,srlk,sy,tm,tmh,tmhh,tmhl,tml,tmlh,tmll,tmy,vlr,\ +vlvgb,vlvgf,vlvgg,vlvgh,x,xg,xgr,xgrk,xihf,xilf,xr,xrk,xy")) "nothing") + +(define_insn_reservation "z17_1" 1 + (and (eq_attr "cpu" "z17") + (eq_attr "mnemonic" "agf,agfr,agh,agsi,ah,ahy,algsi,alsi,asi,cgf,cgfr,cgfrl,\ +cgh,cghrl,ch,chrl,chy,clm,clmy,cpsdr,laa,laag,lan,lang,lao,laog,lax,laxg,le,\ +ler,ley,llxab,llxaf,llxag,llxah,llxaq,loc,locg,locghi,locgr,lochi,locr,lxab,\ +lxaf,lxag,lxah,lxaq,mvghi,mvhhi,mvhi,mvi,mviy,ni,niy,ntstg,oi,oiy,selgr,selr,\ +sgf,sgfr,sgh,sh,shy,st,stc,stcy,stg,stgrl,sth,sthrl,sthy,stoc,stocg,strl,strv,\ +strvg,strvh,sty,vab,vaccb,vacccq,vaccf,vaccg,vacch,vaccq,vacq,vaf,vag,vah,vaq,\ +vavgb,vavgf,vavgg,vavgh,vavglb,vavglf,vavglg,vavglh,vavglq,vavgq,vblendb,\ +vblendf,vblendg,vblendh,vblendq,vbperm,vceqb,vceqbs,vceqf,vceqfs,vceqg,vceqgs,\ +vceqh,vceqhs,vceqq,vceqqs,vcfn,vchb,vchbs,vchf,vchfs,vchg,vchgs,vchh,vchhs,\ +vchlb,vchlbs,vchlf,vchlfs,vchlg,vchlgs,vchlh,vchlhs,vchlq,vchlqs,vchq,vchqs,\ +vclfnh,vclfnl,vclzb,vclzf,vclzg,vclzh,vclzq,vcnf,vcrnf,vctzb,vctzf,vctzg,vctzh,\ +vctzq,verimb,verimf,verimg,verimh,verllb,verllf,verllg,verllh,verllvb,verllvf,\ +verllvg,verllvh,veslb,veslf,veslg,veslh,veslvb,veslvf,veslvg,veslvh,vesrab,\ +vesraf,vesrag,vesrah,vesravb,vesravf,vesravg,vesravh,vesrlb,vesrlf,vesrlg,\ +vesrlh,vesrlvb,vesrlvf,vesrlvg,vesrlvh,veval,vfcedb,vfcedbs,vfcesb,vfcesbs,\ +vfchdb,vfchdbs,vfchedb,vfchedbs,vfchesb,vfchesbs,vfchsb,vfchsbs,vfkedb,vfkesb,\ +vfkhdb,vfkhedb,vfkhesb,vfkhsb,vflcdb,vflcsb,vflndb,vflnsb,vflpdb,vflpsb,\ +vfmaxdb,vfmaxsb,vfmindb,vfminsb,vgbm,vgemb,vgemf,vgemg,vgemh,vgemq,vgm,vlcb,\ +vlcf,vlcg,vlch,vleb,vlebrf,vlebrg,vlebrh,vlef,vleg,vleh,vleib,vleif,vleig,\ +vleih,vlpb,vlpf,vlpg,vlph,vlpq,vmnb,vmnf,vmng,vmnh,vmnlb,vmnlf,vmnlg,vmnlh,\ +vmnlq,vmnq,vmrhb,vmrhf,vmrhg,vmrhh,vmrlb,vmrlf,vmrlg,vmrlh,vmxb,vmxf,vmxg,vmxh,\ +vmxlb,vmxlf,vmxlg,vmxlh,vmxlq,vmxq,vn,vnc,vnn,vno,vnot,vnx,vo,voc,vone,vpdi,\ +vperm,vpkf,vpkg,vpkh,vpklsf,vpklsfs,vpklsg,vpklsgs,vpklsh,vpklshs,vpksf,vpksfs,\ +vpksg,vpksgs,vpksh,vpkshs,vpopct,vpopctb,vpopctf,vpopctg,vpopcth,vrepb,vrepf,\ +vrepg,vreph,vrepi,vrepib,vrepif,vrepig,vrepih,vsb,vsbcbiq,vsbiq,vscbib,vscbif,\ +vscbig,vscbih,vscbiq,vsegb,vsegf,vsegh,vsel,vsf,vsg,vsh,vsl,vslb,vsld,vsldb,\ +vsq,vsra,vsrab,vsrd,vsrl,vsrlb,vuphb,vuphf,vuphg,vuphh,vuplb,vuplf,vuplg,\ +vuplhb,vuplhf,vuplhg,vuplhh,vuplhw,vupllb,vupllf,vupllg,vupllh,vx,vzero,wfcedb,\ +wfcesb,wfcexb,wfcexbs,wfchdb,wfchedb,wfchesb,wfchexb,wfchexbs,wfchsb,wfchxb,\ +wfchxbs,wfkedb,wfkesb,wfkexb,wfkhdb,wfkhedb,wfkhesb,wfkhexb,wfkhsb,wfkhxb,\ +wflcdb,wflcsb,wflcxb,wflndb,wflnsb,wflnxb,wflpdb,wflpsb,wflpxb,wfmaxxb,wfminxb,\ +xi,xiy")) "nothing") + +(define_insn_reservation "z17_2" 2 + (and (eq_attr "cpu" "z17") + (eq_attr "mnemonic" "cdb,cdbr,ceb,cebr,clzg,ctzg,ear,ipm,kdb,kdbr,keb,kebr,l,\ +lcbb,lcdbr,lcebr,ld,lde,ldy,lg,lgdr,lgrl,llc,llgc,llgf,llgfrl,llgh,llghrl,llgt,\ +llh,llhrl,lm,lmg,lmy,lndbr,lnebr,lpdbr,lpebr,lrl,ltdbr,ltebr,ly,popcnt,sar,\ +tcdb,tceb,vfeeb,vfeef,vfeeh,vfeezbs,vfeezfs,vfeezhs,vfeneb,vfenef,vfeneh,\ +vfenezb,vfenezf,vfenezh,vftcidb,vftcisb,vistrb,vistrbs,vistrf,vistrfs,vistrh,\ +vistrhs,vlbrrepf,vlbrrepg,vlbrreph,vlgvb,vlgvf,vlgvg,vlgvh,vllebrzf,vllebrzg,\ +vllebrzh,vllezb,vllezf,vllezg,vllezh,vllezlf,vlrepb,vlrepf,vlrepg,vlreph,vlrl,\ +vlvgp,wfcdb,wfcsb,wfcxb,wfkdb,wfksb,wfkxb,wftcixb")) "nothing") + +(define_insn_reservation "z17_3" 3 + (and (eq_attr "cpu" "z17") + (eq_attr "mnemonic" "bdepg,bextg,cds,cdsy,mgh,mghi,mh,mhi,mhy,ms,msc,msfi,msg,\ +msgc,msgf,msgfi,msgfr,msgr,msgrkc,msr,msrkc,msy,std,stdy,ste,stey,vcksm,vgfmab,\ +vgfmaf,vgfmag,vgfmah,vgfmb,vgfmf,vgfmg,vgfmh,vl,vlbb,vlbrf,vlbrg,vlbrh,vlbrq,\ +vlerf,vlerg,vlerh,vll,vlrlr,vmaeb,vmaef,vmaeg,vmaeh,vmahb,vmahf,vmahg,vmahh,\ +vmahq,vmalb,vmaleb,vmalef,vmaleg,vmaleh,vmalf,vmalg,vmalhb,vmalhf,vmalhg,\ +vmalhh,vmalhq,vmalhw,vmalob,vmalof,vmalog,vmaloh,vmalq,vmaob,vmaof,vmaog,vmaoh,\ +vmeb,vmef,vmeg,vmeh,vmhb,vmhf,vmhg,vmhh,vmhq,vmlb,vmleb,vmlef,vmleg,vmleh,vmlf,\ +vmlg,vmlhb,vmlhf,vmlhg,vmlhh,vmlhq,vmlhw,vmlob,vmlof,vmlog,vmloh,vmlq,vmob,\ +vmof,vmog,vmoh,vsumb,vsumgf,vsumgh,vsumh,vsumqf,vsumqg,vtm")) "nothing") + +(define_insn_reservation "z17_4" 4 + (and (eq_attr "cpu" "z17") + (eq_attr "mnemonic" "bas,basr,bras,brasl,chhsi,clc,ex,exrl,lam,lcgfr,lngfr,\ +lpgfr,lxr,lzxr,mvcrl,ppa,rnsbg,rosbg,rxsbg,tabort,tend,vst,vstbrf,vstbrg,\ +vstbrh,vstbrq,vstebrf,vstebrg,vstef,vsteg,vsterf,vsterg,vsterh,vstl,vstrl,\ +vstrlr")) "nothing") + +(define_insn_reservation "z17_5" 5 + (and (eq_attr "cpu" "z17") + (eq_attr "mnemonic" "adb,adbr,aeb,aebr,alc,alcg,alcgr,alcr,cs,csg,csy,fidbr,\ +fidbra,fiebr,fiebra,ldeb,ldebr,ledbr,madbr,mdb,mdbr,meeb,meebr,msdbr,sdb,sdbr,\ +seb,sebr,slb,slbg,slbgr,slbr,stm,stmg,stmy,vcdgb,vcdlgb,vcefb,vcelfb,vcfeb,\ +vcgdb,vclfeb,vclgdb,vldeb,vledb,vmslg,wcdgb,wcdlgb,wcefb,wcelfb,wcfeb,wcgdb,\ +wclfeb,wclgdb,wflld,wflrx,wldeb,wledb")) "nothing") + +(define_insn_reservation "z17_6" 6 + (and (eq_attr "cpu" "z17") + (eq_attr "mnemonic" "sfpc")) "nothing") + +(define_insn_reservation "z17_7" 7 + (and (eq_attr "cpu" "z17") + (eq_attr "mnemonic" "adtr,cdtr,fidtr,kdtr,ldetr,ltdtr,sdtr,tdcdt,tdcet,vfadb,\ +vfasb,vfidb,vfisb,vfsdb,vfssb,vgef,vgeg,wfadb,wfasb,wfaxb,wfidb,wfisb,wfixb,\ +wfsdb,wfssb,wfsxb")) "nothing") + +(define_insn_reservation "z17_8" 8 + (and (eq_attr "cpu" "z17") + (eq_attr "mnemonic" "cdgtr,cdlgtr,cdsg,cxgtr,cxlgtr,flogr,lpq,m,mfy,mg,mgrk,\ +ml,mlg,mlgr,mlr,mr,stpq,vsteb,vstebrh,vsteh")) "nothing") + +(define_insn_reservation "z17_9" 9 + (and (eq_attr "cpu" "z17") + (eq_attr "mnemonic" "cdfbr,cdgbr,cdlfbr,cdlgbr,cefbr,cegbr,celfbr,celgbr,madb,\ +maeb,maebr,msdb,mseb,msebr,stam")) "nothing") + +(define_insn_reservation "z17_10" 10 + (and (eq_attr "cpu" "z17") + (eq_attr "mnemonic" "cgdtr,cgxtr,clfdtr,clfxtr,clgdtr,clgxtr,d,dl,dlg,dsg,\ +dsgf,efpc,lxdb,lxdbr,lxeb,lxebr,vscef,vsceg")) "nothing") + +(define_insn_reservation "z17_11" 11 + (and (eq_attr "cpu" "z17") + (eq_attr "mnemonic" "cfdbr,cfebr,cgdbr,cgebr,clfdbr,clfebr,clgdbr,clgebr")) "nothing") + +(define_insn_reservation "z17_12" 12 + (and (eq_attr "cpu" "z17") + (eq_attr "mnemonic" "cxbr,cxtr,kxbr,kxtr,tbegin,tbeginc,tcxb,tdcxt")) "nothing") + +(define_insn_reservation "z17_13" 13 + (and (eq_attr "cpu" "z17") + (eq_attr "mnemonic" "axbr,axtr,cxfbr,cxgbr,cxlfbr,cxlgbr,fixbr,fixbra,fixtr,\ +lcxbr,lnxbr,lpxbr,ltxbr,ltxtr,lxdtr,sxbr,sxtr")) "nothing") + +(define_insn_reservation "z17_14" 14 + (and (eq_attr "cpu" "z17") + (eq_attr "mnemonic" "cfxbr,cgxbr,clfxbr,clgxbr,ledtr")) "nothing") + +(define_insn_reservation "z17_15" 15 + (and (eq_attr "cpu" "z17") + (eq_attr "mnemonic" "nc,oc")) "nothing") + +(define_insn_reservation "z17_16" 16 + (and (eq_attr "cpu" "z17") + (eq_attr "mnemonic" "cdftr,cdlftr,cxftr,cxlftr")) "nothing") + +(define_insn_reservation "z17_18" 18 + (and (eq_attr "cpu" "z17") + (eq_attr "mnemonic" "xc")) "nothing") + +(define_insn_reservation "z17_20" 20 + (and (eq_attr "cpu" "z17") + (eq_attr "mnemonic" "ddb,ddbr,ddtr,deb,debr,dlgr,dlr,dr,dsgfr,dsgr,dxbr,dxtr,\ +mdtr,mvc,mxbr,mxtr,sqdb,sqdbr,sqeb,sqebr,sqxbr,vdf,vdg,vdlf,vdlg,vdlq,vdq,\ +vfddb,vfdsb,vfmadb,vfmasb,vfmdb,vfmsb,vfmsdb,vfmssb,vfnmadb,vfnmasb,vfnmsdb,\ +vfnmssb,vfsqdb,vfsqsb,vrf,vrg,vrlf,vrlg,vrlq,vrq,wfddb,wfdsb,wfdxb,wfmadb,\ +wfmasb,wfmaxb,wfmdb,wfmsb,wfmsdb,wfmssb,wfmsxb,wfmxb,wfnmaxb,wfnmsxb,wfsqdb,\ +wfsqxb")) "nothing") + diff --git a/gcc/config/s390/driver-native.cc b/gcc/config/s390/driver-native.cc index 49e8fa0..7a7ceea 100644 --- a/gcc/config/s390/driver-native.cc +++ b/gcc/config/s390/driver-native.cc @@ -127,6 +127,10 @@ s390_host_detect_local_cpu (int argc, const char **argv) case 0x3932: cpu = "arch14"; break; + case 0x9175: + case 0x9176: + cpu = "arch15"; + break; default: cpu = "arch15"; break; diff --git a/gcc/config/s390/s390-builtins.def b/gcc/config/s390/s390-builtins.def index d9af9b1..cee2326 100644 --- a/gcc/config/s390/s390-builtins.def +++ b/gcc/config/s390/s390-builtins.def @@ -300,8 +300,8 @@ #define B_VXE2 (1 << 4) /* Builtins requiring the z15 vector extensions. */ #define B_DEP (1 << 5) /* Builtin has been deprecated and a warning should be issued. */ #define B_NNPA (1 << 6) /* Builtins requiring the NNPA Facility. */ -#define B_VXE3 (1 << 7) /* Builtins requiring the arch15 vector extensions. */ -#define B_ARCH15 (1 << 8) /* Builtins requiring arch15. */ +#define B_VXE3 (1 << 7) /* Builtins requiring the z17 vector extensions. */ +#define B_Z17 (1 << 8) /* Builtins requiring z17. */ /* B_DEF defines a standard (not overloaded) builtin B_DEF (<builtin name>, <RTL expander name>, <function attributes>, <builtin flags>, <operand flags, see above>, <fntype>) @@ -3318,8 +3318,8 @@ B_DEF (s390_vcnf, vcnf_v8hi, 0, /* arch 15 builtins */ -B_DEF (s390_bdepg, bdepg, 0, B_ARCH15, 0, BT_FN_ULONG_ULONG_ULONG) -B_DEF (s390_bextg, bextg, 0, B_ARCH15, 0, BT_FN_ULONG_ULONG_ULONG) +B_DEF (s390_bdepg, bdepg, 0, B_Z17, 0, BT_FN_ULONG_ULONG_ULONG) +B_DEF (s390_bextg, bextg, 0, B_Z17, 0, BT_FN_ULONG_ULONG_ULONG) OB_DEF (s390_vec_blend, s390_vec_blend_s8, s390_vec_blend_dbl, B_VXE3, BT_FN_OV4SI_OV4SI_OV4SI_OV4SI) OB_DEF_VAR (s390_vec_blend_s8, s390_vblendb, 0, 0, BT_OV_V16QI_V16QI_V16QI_V16QI) diff --git a/gcc/config/s390/s390-c.cc b/gcc/config/s390/s390-c.cc index 311d74a..a01c44c 100644 --- a/gcc/config/s390/s390-c.cc +++ b/gcc/config/s390/s390-c.cc @@ -962,7 +962,7 @@ s390_resolve_overloaded_builtin (location_t loc, tree ob_fndecl, if (!TARGET_VXE3 && (ob_flags & B_VXE3)) { - error_at (loc, "%qF requires arch15 or higher", ob_fndecl); + error_at (loc, "%qF requires z17 or higher", ob_fndecl); return error_mark_node; } @@ -1056,7 +1056,7 @@ s390_resolve_overloaded_builtin (location_t loc, tree ob_fndecl, if (!TARGET_VXE3 && bflags_overloaded_builtin_var[last_match_index] & B_VXE3) { - error_at (loc, "%qs matching variant requires arch15 or higher", + error_at (loc, "%qs matching variant requires z17 or higher", IDENTIFIER_POINTER (DECL_NAME (ob_fndecl))); return error_mark_node; } diff --git a/gcc/config/s390/s390-opts.h b/gcc/config/s390/s390-opts.h index 437d3b9..9cacb2c 100644 --- a/gcc/config/s390/s390-opts.h +++ b/gcc/config/s390/s390-opts.h @@ -39,7 +39,7 @@ enum processor_type PROCESSOR_3906_Z14, PROCESSOR_8561_Z15, PROCESSOR_3931_Z16, - PROCESSOR_ARCH15, + PROCESSOR_9175_Z17, PROCESSOR_NATIVE, PROCESSOR_max }; diff --git a/gcc/config/s390/s390.cc b/gcc/config/s390/s390.cc index 0ff3fd5..d82b16e 100644 --- a/gcc/config/s390/s390.cc +++ b/gcc/config/s390/s390.cc @@ -342,7 +342,7 @@ const struct s390_processor processor_table[] = { "z14", "arch12", PROCESSOR_3906_Z14, &zEC12_cost, 12 }, { "z15", "arch13", PROCESSOR_8561_Z15, &zEC12_cost, 13 }, { "z16", "arch14", PROCESSOR_3931_Z16, &zEC12_cost, 14 }, - { "arch15", "arch15", PROCESSOR_ARCH15, &zEC12_cost, 15 }, + { "z17", "arch15", PROCESSOR_9175_Z17, &zEC12_cost, 15 }, { "native", "", PROCESSOR_NATIVE, NULL, 0 } }; @@ -916,7 +916,7 @@ s390_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED, if ((bflags & B_VXE3) && !TARGET_VXE3) { - error ("Builtin %qF requires arch15 or higher", fndecl); + error ("Builtin %qF requires z17 or higher", fndecl); return const0_rtx; } } @@ -9204,7 +9204,7 @@ s390_issue_rate (void) case PROCESSOR_3906_Z14: case PROCESSOR_8561_Z15: case PROCESSOR_3931_Z16: - case PROCESSOR_ARCH15: + case PROCESSOR_9175_Z17: default: return 1; } @@ -15632,7 +15632,6 @@ s390_get_sched_attrmask (rtx_insn *insn) mask |= S390_SCHED_ATTR_MASK_GROUPOFTWO; break; case PROCESSOR_3931_Z16: - case PROCESSOR_ARCH15: if (get_attr_z16_cracked (insn)) mask |= S390_SCHED_ATTR_MASK_CRACKED; if (get_attr_z16_expanded (insn)) @@ -15644,6 +15643,18 @@ s390_get_sched_attrmask (rtx_insn *insn) if (get_attr_z16_groupoftwo (insn)) mask |= S390_SCHED_ATTR_MASK_GROUPOFTWO; break; + case PROCESSOR_9175_Z17: + if (get_attr_z17_cracked (insn)) + mask |= S390_SCHED_ATTR_MASK_CRACKED; + if (get_attr_z17_expanded (insn)) + mask |= S390_SCHED_ATTR_MASK_EXPANDED; + if (get_attr_z17_endgroup (insn)) + mask |= S390_SCHED_ATTR_MASK_ENDGROUP; + if (get_attr_z17_groupalone (insn)) + mask |= S390_SCHED_ATTR_MASK_GROUPALONE; + if (get_attr_z17_groupoftwo (insn)) + mask |= S390_SCHED_ATTR_MASK_GROUPOFTWO; + break; default: gcc_unreachable (); } @@ -15691,7 +15702,6 @@ s390_get_unit_mask (rtx_insn *insn, int *units) mask |= 1 << 3; break; case PROCESSOR_3931_Z16: - case PROCESSOR_ARCH15: *units = 4; if (get_attr_z16_unit_lsu (insn)) mask |= 1 << 0; @@ -15702,6 +15712,17 @@ s390_get_unit_mask (rtx_insn *insn, int *units) if (get_attr_z16_unit_vfu (insn)) mask |= 1 << 3; break; + case PROCESSOR_9175_Z17: + *units = 4; + if (get_attr_z17_unit_lsu (insn)) + mask |= 1 << 0; + if (get_attr_z17_unit_fxa (insn)) + mask |= 1 << 1; + if (get_attr_z17_unit_fxb (insn)) + mask |= 1 << 2; + if (get_attr_z17_unit_vfu (insn)) + mask |= 1 << 3; + break; default: gcc_unreachable (); } @@ -15715,7 +15736,8 @@ s390_is_fpd (rtx_insn *insn) return false; return get_attr_z13_unit_fpd (insn) || get_attr_z14_unit_fpd (insn) - || get_attr_z15_unit_fpd (insn) || get_attr_z16_unit_fpd (insn); + || get_attr_z15_unit_fpd (insn) || get_attr_z16_unit_fpd (insn) + || get_attr_z17_unit_fpd (insn); } static bool @@ -15725,7 +15747,8 @@ s390_is_fxd (rtx_insn *insn) return false; return get_attr_z13_unit_fxd (insn) || get_attr_z14_unit_fxd (insn) - || get_attr_z15_unit_fxd (insn) || get_attr_z16_unit_fxd (insn); + || get_attr_z15_unit_fxd (insn) || get_attr_z16_unit_fxd (insn) + || get_attr_z17_unit_fxd (insn); } /* Returns TRUE if INSN is a long-running instruction. */ diff --git a/gcc/config/s390/s390.h b/gcc/config/s390/s390.h index 6f7195d..8b04bc9 100644 --- a/gcc/config/s390/s390.h +++ b/gcc/config/s390/s390.h @@ -45,12 +45,12 @@ enum processor_flags PF_NNPA = 32768, PF_Z16 = 65536, PF_VXE3 = 131072, - PF_ARCH15 = 262144 + PF_Z17 = 262144 }; /* This is necessary to avoid a warning about comparing different enum types. */ -#define s390_tune_attr ((enum attr_cpu)(s390_tune > PROCESSOR_3931_Z16 ? PROCESSOR_3931_Z16 : s390_tune )) +#define s390_tune_attr ((enum attr_cpu)(s390_tune > PROCESSOR_9175_Z17 ? PROCESSOR_9175_Z17 : s390_tune )) /* These flags indicate that the generated code should run on a cpu providing the respective hardware facility regardless of the @@ -124,10 +124,10 @@ enum processor_flags (s390_arch_flags & PF_VXE3) #define TARGET_CPU_VXE3_P(opts) \ (opts->x_s390_arch_flags & PF_VXE3) -#define TARGET_CPU_ARCH15 \ - (s390_arch_flags & PF_ARCH15) -#define TARGET_CPU_ARCH15_P(opts) \ - (opts->x_s390_arch_flags & PF_ARCH15) +#define TARGET_CPU_Z17 \ + (s390_arch_flags & PF_Z17) +#define TARGET_CPU_Z17_P(opts) \ + (opts->x_s390_arch_flags & PF_Z17) #define TARGET_HARD_FLOAT_P(opts) (!TARGET_SOFT_FLOAT_P(opts)) @@ -198,9 +198,9 @@ enum processor_flags (TARGET_VX && TARGET_CPU_VXE3) #define TARGET_VXE3_P(opts) \ (TARGET_VX_P (opts) && TARGET_CPU_VXE3_P (opts)) -#define TARGET_ARCH15 (TARGET_ZARCH && TARGET_CPU_ARCH15) -#define TARGET_ARCH15_P(opts) \ - (TARGET_ZARCH_P (opts->x_target_flags) && TARGET_CPU_ARCH15_P (opts)) +#define TARGET_Z17 (TARGET_ZARCH && TARGET_CPU_Z17) +#define TARGET_Z17_P(opts) \ + (TARGET_ZARCH_P (opts->x_target_flags) && TARGET_CPU_Z17_P (opts)) #if defined(HAVE_AS_VECTOR_LOADSTORE_ALIGNMENT_HINTS_ON_Z13) #define TARGET_VECTOR_LOADSTORE_ALIGNMENT_HINTS TARGET_Z13 diff --git a/gcc/config/s390/s390.md b/gcc/config/s390/s390.md index 9d49580..05b9da6 100644 --- a/gcc/config/s390/s390.md +++ b/gcc/config/s390/s390.md @@ -599,11 +599,11 @@ ;; Processor type. This attribute must exactly match the processor_type ;; enumeration in s390.h. -(define_attr "cpu" "z900,z990,z9_109,z9_ec,z10,z196,zEC12,z13,z14,z15,z16" +(define_attr "cpu" "z900,z990,z9_109,z9_ec,z10,z196,zEC12,z13,z14,z15,z16,z17" (const (symbol_ref "s390_tune_attr"))) (define_attr "cpu_facility" - "standard,ieee,zarch,cpu_zarch,longdisp,extimm,dfp,z10,z196,zEC12,vx,z13,z14,vxe,z15,vxe2,z16,nnpa,vxe3,arch15" + "standard,ieee,zarch,cpu_zarch,longdisp,extimm,dfp,z10,z196,zEC12,vx,z13,z14,vxe,z15,vxe2,z16,nnpa,vxe3,z17" (const_string "standard")) (define_attr "enabled" "" @@ -681,8 +681,8 @@ (match_test "TARGET_VXE3")) (const_int 1) - (and (eq_attr "cpu_facility" "arch15") - (match_test "TARGET_ARCH15")) + (and (eq_attr "cpu_facility" "z17") + (match_test "TARGET_Z17")) (const_int 1) ] (const_int 0))) @@ -725,6 +725,9 @@ ;; Pipeline description for z16 (include "3931.md") +;; Pipeline description for z17 +(include "9175.md") + ;; Predicates (include "predicates.md") @@ -2056,7 +2059,7 @@ [(set (match_operand:DI 0 "register_operand" "=d") (ashift:DI (sign_extend:DI (match_operand:SI 1 "register_operand" "a")) (const_int LXAMODEITER)))] - "TARGET_ARCH15 && TARGET_64BIT" + "TARGET_Z17 && TARGET_64BIT" "lxa<lxamode>\t%0,0(%1,0)" [(set_attr "op_type" "RXY")]) @@ -2066,7 +2069,7 @@ (ashift:DI (sign_extend:DI (plus:SI (match_operand:SI 1 "register_operand" "a") (match_operand:SI 2 "const_int_operand"))) (const_int LXAMODEITER)))] - "TARGET_ARCH15 && TARGET_64BIT && INTVAL (operands[2]) >= -0x80000 && INTVAL (operands[2]) <= 0x7FFFF" + "TARGET_Z17 && TARGET_64BIT && INTVAL (operands[2]) >= -0x80000 && INTVAL (operands[2]) <= 0x7FFFF" "lxa<lxamode>\t%0,%2(%1,0)" [(set_attr "op_type" "RXY")]) @@ -2076,7 +2079,7 @@ (plus:DI (ashift:DI (sign_extend:DI (match_operand:SI 1 "register_operand" "a")) (const_int LXAMODEITER)) (match_operand:DI 2 "register_operand" "a")))] - "TARGET_ARCH15 && TARGET_64BIT" + "TARGET_Z17 && TARGET_64BIT" "lxa<lxamode>\t%0,0(%1,%2)" [(set_attr "op_type" "RXY")]) @@ -2087,7 +2090,7 @@ (match_operand:SI 2 "const_int_operand"))) (const_int LXAMODEITER)) (match_operand:DI 3 "register_operand" "a")))] - "TARGET_ARCH15 && TARGET_64BIT && INTVAL (operands[2]) >= -0x80000 && INTVAL (operands[2]) <= 0x7FFFF" + "TARGET_Z17 && TARGET_64BIT && INTVAL (operands[2]) >= -0x80000 && INTVAL (operands[2]) <= 0x7FFFF" "lxa<lxamode>\t%0,%2(%1,%3)" [(set_attr "op_type" "RXY")]) @@ -2096,7 +2099,7 @@ (plus:DI (sign_extend:DI (plus:SI (match_operand:SI 1 "register_operand" "a") (match_operand:SI 2 "const_int_operand"))) (match_operand:DI 3 "register_operand" "a")))] - "TARGET_ARCH15 && TARGET_64BIT && INTVAL (operands[2]) >= -0x80000 && INTVAL (operands[2]) <= 0x7FFFF" + "TARGET_Z17 && TARGET_64BIT && INTVAL (operands[2]) >= -0x80000 && INTVAL (operands[2]) <= 0x7FFFF" "lxab\t%0,%2(%1,%3)" [(set_attr "op_type" "RXY")]) @@ -2113,7 +2116,7 @@ 0) (const_int LXAMODEITER)) (const_int <LLXAMASK>)))] - "TARGET_ARCH15 && TARGET_64BIT && INTVAL (operands[2]) >= -0x80000 && INTVAL (operands[2]) <= 0x7FFFF" + "TARGET_Z17 && TARGET_64BIT && INTVAL (operands[2]) >= -0x80000 && INTVAL (operands[2]) <= 0x7FFFF" "llxa<lxamode>\t%0,%2(%1,0)" [(set_attr "op_type" "RXY")]) @@ -2124,7 +2127,7 @@ (const_int LXAMODEITER)) (const_int <LLXAMASK>)) (match_operand:DI 2 "register_operand" "a")))] - "TARGET_ARCH15 && TARGET_64BIT" + "TARGET_Z17 && TARGET_64BIT" "llxa<lxamode>\t%0,0(%1,%2)" [(set_attr "op_type" "RXY")]) @@ -2137,7 +2140,7 @@ (const_int LXAMODEITER)) (const_int <LLXAMASK>)) (match_operand:DI 3 "register_operand" "a")))] - "TARGET_ARCH15 && TARGET_64BIT && INTVAL (operands[2]) >= -0x80000 && INTVAL (operands[2]) <= 0x7FFFF" + "TARGET_Z17 && TARGET_64BIT && INTVAL (operands[2]) >= -0x80000 && INTVAL (operands[2]) <= 0x7FFFF" "llxa<lxamode>\t%0,%2(%1,%3)" [(set_attr "op_type" "RXY")]) @@ -2146,7 +2149,7 @@ (plus:DI (zero_extend:DI (plus:SI (match_operand:SI 1 "register_operand" "a") (match_operand:SI 2 "const_int_operand"))) (match_operand:DI 3 "register_operand" "a")))] - "TARGET_ARCH15 && TARGET_64BIT && INTVAL (operands[2]) >= -0x80000 && INTVAL (operands[2]) <= 0x7FFFF" + "TARGET_Z17 && TARGET_64BIT && INTVAL (operands[2]) >= -0x80000 && INTVAL (operands[2]) <= 0x7FFFF" "llxab\t%0,%2(%1,%3)" [(set_attr "op_type" "RXY")]) @@ -3594,7 +3597,7 @@ (match_operand:BLK 1 "memory_operand" "")) (use (match_operand 2 "const_int_operand" "")) (use (match_operand 3 "immediate_operand" "")) - (clobber (scratch))] + (clobber (match_scratch 4))] "reload_completed" [(parallel [(set (match_dup 0) (match_dup 1)) @@ -3606,7 +3609,7 @@ (match_operand:BLK 1 "memory_operand" "")) (use (match_operand 2 "register_operand" "")) (use (match_operand 3 "memory_operand" "")) - (clobber (scratch))] + (clobber (match_scratch 4))] "reload_completed" [(parallel [(unspec [(match_dup 2) (match_dup 3) @@ -3620,14 +3623,14 @@ (match_operand:BLK 1 "memory_operand" "")) (use (match_operand 2 "register_operand" "")) (use (const:BLK (unspec:BLK [(const_int 0)] UNSPEC_INSN))) - (clobber (scratch))] + (clobber (match_scratch 3))] "TARGET_Z10 && reload_completed" [(parallel [(unspec [(match_dup 2) (const_int 0) - (label_ref (match_dup 3))] UNSPEC_EXECUTE) + (label_ref (match_dup 4))] UNSPEC_EXECUTE) (set (match_dup 0) (match_dup 1)) (use (const_int 1))])] - "operands[3] = gen_label_rtx ();") + "operands[4] = gen_label_rtx ();") (define_split [(set (match_operand:BLK 0 "memory_operand" "") @@ -3849,7 +3852,7 @@ (const_int 0)) (use (match_operand 1 "const_int_operand" "")) (use (match_operand 2 "immediate_operand" "")) - (clobber (scratch)) + (clobber (match_scratch 3)) (clobber (reg:CC CC_REGNUM))] "reload_completed" [(parallel @@ -3863,7 +3866,7 @@ (const_int 0)) (use (match_operand 1 "register_operand" "")) (use (match_operand 2 "memory_operand" "")) - (clobber (scratch)) + (clobber (match_scratch 3)) (clobber (reg:CC CC_REGNUM))] "reload_completed" [(parallel @@ -3879,7 +3882,7 @@ (const_int 0)) (use (match_operand 1 "register_operand" "")) (use (const:BLK (unspec:BLK [(const_int 0)] UNSPEC_INSN))) - (clobber (scratch)) + (clobber (match_scratch 2)) (clobber (reg:CC CC_REGNUM))] "TARGET_Z10 && reload_completed" [(parallel @@ -4044,7 +4047,7 @@ (match_operand:BLK 1 "memory_operand" ""))) (use (match_operand 2 "const_int_operand" "")) (use (match_operand 3 "immediate_operand" "")) - (clobber (scratch))] + (clobber (match_scratch 4))] "reload_completed" [(parallel [(set (reg:CCU CC_REGNUM) (compare:CCU (match_dup 0) (match_dup 1))) @@ -4057,7 +4060,7 @@ (match_operand:BLK 1 "memory_operand" ""))) (use (match_operand 2 "register_operand" "")) (use (match_operand 3 "memory_operand" "")) - (clobber (scratch))] + (clobber (match_scratch 4))] "reload_completed" [(parallel [(unspec [(match_dup 2) (match_dup 3) @@ -4072,7 +4075,7 @@ (match_operand:BLK 1 "memory_operand" ""))) (use (match_operand 2 "register_operand" "")) (use (const:BLK (unspec:BLK [(const_int 0)] UNSPEC_INSN))) - (clobber (scratch))] + (clobber (match_scratch 3))] "TARGET_Z10 && reload_completed" [(parallel [(unspec [(match_dup 2) (const_int 0) @@ -4940,7 +4943,7 @@ (unspec:DI [(match_operand:DI 1 "register_operand" "d") (match_operand:DI 2 "register_operand" "d")] UNSPEC_BDEPG))] - "TARGET_ARCH15 && TARGET_64BIT" + "TARGET_Z17 && TARGET_64BIT" "bdepg\t%0,%1,%2" [(set_attr "op_type" "RRF")]) @@ -4953,7 +4956,7 @@ (unspec:DI [(match_operand:DI 1 "register_operand" "d") (match_operand:DI 2 "register_operand" "d")] UNSPEC_BEXTG))] - "TARGET_ARCH15 && TARGET_64BIT" + "TARGET_Z17 && TARGET_64BIT" "bextg\t%0,%1,%2" [(set_attr "op_type" "RRF")]) @@ -9580,7 +9583,7 @@ (clz:DI (match_operand:DI 1 "register_operand" "d")))] "TARGET_EXTIMM && TARGET_ZARCH" { - if (!(TARGET_ARCH15 && TARGET_64BIT)) + if (!(TARGET_Z17 && TARGET_64BIT)) { rtx_insn *insn; rtx clz_equal; @@ -9601,7 +9604,7 @@ (define_insn "*clzg" [(set (match_operand:DI 0 "register_operand" "=d") (clz:DI (match_operand:DI 1 "register_operand" "d")))] - "TARGET_ARCH15 && TARGET_64BIT" + "TARGET_Z17 && TARGET_64BIT" "clzg\t%0,%1" [(set_attr "op_type" "RRE")]) @@ -9630,7 +9633,7 @@ (define_insn "ctzdi2" [(set (match_operand:DI 0 "register_operand" "=d") (ctz:DI (match_operand:DI 1 "register_operand" "d")))] - "TARGET_ARCH15 && TARGET_64BIT" + "TARGET_Z17 && TARGET_64BIT" "ctzg\t%0,%1" [(set_attr "op_type" "RRE")]) diff --git a/gcc/config/s390/s390.opt b/gcc/config/s390/s390.opt index f064597..6753a93 100644 --- a/gcc/config/s390/s390.opt +++ b/gcc/config/s390/s390.opt @@ -122,7 +122,10 @@ EnumValue Enum(processor_type) String(z16) Value(PROCESSOR_3931_Z16) EnumValue -Enum(processor_type) String(arch15) Value(PROCESSOR_ARCH15) +Enum(processor_type) String(arch15) Value(PROCESSOR_9175_Z17) + +EnumValue +Enum(processor_type) String(z17) Value(PROCESSOR_9175_Z17) EnumValue Enum(processor_type) String(native) Value(PROCESSOR_NATIVE) DriverOnly diff --git a/gcc/config/sh/sh-modes.def b/gcc/config/sh/sh-modes.def index 80650b4..e31ae69 100644 --- a/gcc/config/sh/sh-modes.def +++ b/gcc/config/sh/sh-modes.def @@ -17,6 +17,12 @@ You should have received a copy of the GNU General Public License along with GCC; see the file COPYING3. If not see <http://www.gnu.org/licenses/>. */ +/* SH has the same reversed quiet bit as MIPS. */ +RESET_FLOAT_FORMAT (SF, mips_single_format); +RESET_FLOAT_FORMAT (DF, mips_double_format); +/* TFmode: IEEE quad floating point (software). */ +FLOAT_MODE (TF, 16, mips_quad_format); + /* Vector modes. */ VECTOR_MODE (INT, QI, 2); /* V2QI */ VECTOR_MODES (INT, 4); /* V4QI V2HI */ diff --git a/gcc/configure b/gcc/configure index ab6bec1..1696595 100755 --- a/gcc/configure +++ b/gcc/configure @@ -3948,7 +3948,7 @@ if test x"${DEFAULT_LINKER+set}" = x"set"; then as_fn_error $? "cannot execute: $DEFAULT_LINKER: check --with-ld or env. var. DEFAULT_LINKER" "$LINENO" 5 elif $DEFAULT_LINKER -v < /dev/null 2>&1 | grep GNU > /dev/null; then gnu_ld_flag=yes - elif $DEFAULT_LINKER -v < /dev/null 2>&1 | grep ld64- > /dev/null; then + elif $DEFAULT_LINKER -v < /dev/null 2>&1 | grep 'PROJECT:ld\(64\)*-' > /dev/null; then ld64_flag=yes fi @@ -12694,6 +12694,42 @@ $as_echo "#define HOST_HAS_O_NONBLOCK 1" >>confdefs.h fi +# Check if personality and ADDR_NO_RANDOMIZE are declared +# in sys/personality.h +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for personality ADDR_NO_RANDOMIZE" >&5 +$as_echo_n "checking for personality ADDR_NO_RANDOMIZE... " >&6; } +if ${ac_cv_personality_addr_no_randomize+:} false; then : + $as_echo_n "(cached) " >&6 +else + +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include <sys/personality.h> +int +main () +{ + +personality (personality (0xffffffffU) | ADDR_NO_RANDOMIZE); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + ac_cv_personality_addr_no_randomize=yes +else + ac_cv_personality_addr_no_randomize=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_personality_addr_no_randomize" >&5 +$as_echo "$ac_cv_personality_addr_no_randomize" >&6; } +if test $ac_cv_personality_addr_no_randomize = yes; then + +$as_echo "#define HOST_HAS_PERSONALITY_ADDR_NO_RANDOMIZE 1" >>confdefs.h + +fi + # C++ Modules would like some networking features to provide the mapping # server. You can still use modules without them though. @@ -21484,7 +21520,7 @@ else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF -#line 21487 "configure" +#line 21523 "configure" #include "confdefs.h" #if HAVE_DLFCN_H @@ -21590,7 +21626,7 @@ else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF -#line 21593 "configure" +#line 21629 "configure" #include "confdefs.h" #if HAVE_DLFCN_H @@ -32694,8 +32730,9 @@ $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 | $EGREP 'ld64|dyld' \ - | sed -e 's/.*ld64-//' -e 's/.*dyld-//'| awk '{print $1}'` + gcc_cv_ld64_version=`$gcc_cv_ld -v 2>&1 | $EGREP 'ld64|dyld|PROJECT:ld' \ + | sed -e 's/.*ld64-//' -e 's/.*dyld-//' -e 's/.*PROJECT:ld-//' \ + | awk '{print $1}'` fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $gcc_cv_ld64_version" >&5 $as_echo "$gcc_cv_ld64_version" >&6; } diff --git a/gcc/configure.ac b/gcc/configure.ac index fca0579..9f67e62 100644 --- a/gcc/configure.ac +++ b/gcc/configure.ac @@ -358,7 +358,7 @@ if test x"${DEFAULT_LINKER+set}" = x"set"; then AC_MSG_ERROR([cannot execute: $DEFAULT_LINKER: check --with-ld or env. var. DEFAULT_LINKER]) elif $DEFAULT_LINKER -v < /dev/null 2>&1 | grep GNU > /dev/null; then gnu_ld_flag=yes - elif $DEFAULT_LINKER -v < /dev/null 2>&1 | grep ld64- > /dev/null; then + elif $DEFAULT_LINKER -v < /dev/null 2>&1 | grep 'PROJECT:ld\(64\)*-' > /dev/null; then ld64_flag=yes fi AC_DEFINE_UNQUOTED(DEFAULT_LINKER,"$DEFAULT_LINKER", @@ -1781,6 +1781,21 @@ if test $ac_cv_have_decl_O_NONBLOCK = yes; then [Define if O_NONBLOCK supported by fcntl.]) fi +# Check if personality and ADDR_NO_RANDOMIZE are declared +# in sys/personality.h +AC_CACHE_CHECK(for personality ADDR_NO_RANDOMIZE, + ac_cv_personality_addr_no_randomize, [ +AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ +#include <sys/personality.h>]], [[ +personality (personality (0xffffffffU) | ADDR_NO_RANDOMIZE);]])], +[ac_cv_personality_addr_no_randomize=yes], +[ac_cv_personality_addr_no_randomize=no])]) +if test $ac_cv_personality_addr_no_randomize = yes; then + AC_DEFINE(HOST_HAS_PERSONALITY_ADDR_NO_RANDOMIZE, 1, + [Define if personality and ADDR_NO_RANDOMIZE are declared in +sys/personality.h.]) +fi + # C++ Modules would like some networking features to provide the mapping # server. You can still use modules without them though. @@ -6403,8 +6418,9 @@ 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 | $EGREP 'ld64|dyld' \ - | sed -e 's/.*ld64-//' -e 's/.*dyld-//'| awk '{print $1}'` + gcc_cv_ld64_version=`$gcc_cv_ld -v 2>&1 | $EGREP 'ld64|dyld|PROJECT:ld' \ + | sed -e 's/.*ld64-//' -e 's/.*dyld-//' -e 's/.*PROJECT:ld-//' \ + | awk '{print $1}'` fi AC_MSG_RESULT($gcc_cv_ld64_version) diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index ed52463..e85a710 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,151 @@ +2025-04-21 Jason Merrill <jason@redhat.com> + + * constexpr.cc (cxx_eval_outermost_constant_expr): Move + verify_constant later. + +2025-04-21 Jason Merrill <jason@redhat.com> + + PR c++/118775 + * constexpr.cc (cxx_eval_call_expression): Add assert. + (fold_to_constant): Handle processing_template_decl. + * init.cc (build_new_1): Use fold_to_constant. + +2025-04-21 Jason Merrill <jason@redhat.com> + + PR c++/99456 + * constexpr.cc (cxx_eval_constant_expression): Check strict + instead of manifestly_const_eval. + (maybe_constant_init_1): Be strict for static constexpr vars. + +2025-04-19 Jason Merrill <jason@redhat.com> + + * coroutines.cc (coro_build_expr_stmt) + (coro_build_cvt_void_expr_stmt): Remove. + (build_actor_fn): Use finish_expr_stmt. + * semantics.cc (finish_expr_stmt): Avoid wrapping statement in + EXPR_STMT. + (finish_stmt_expr_expr): Add comment. + +2025-04-17 Jason Merrill <jason@redhat.com> + + * constexpr.cc (is_valid_constexpr_fn): Improve diagnostic. + +2025-04-17 Jason Merrill <jason@redhat.com> + + * constexpr.cc (cxx_eval_outermost_constant_expr): Give both + expression and allocation location in allocated storage diagnostics. + +2025-04-17 Jason Merrill <jason@redhat.com> + + * name-lookup.cc (name_lookup::preserve_state): Fix reserve call. + * rtti.cc (get_tinfo_desc): Use vec_safe_grow_cleared. + +2025-04-17 Jason Merrill <jason@redhat.com> + + * semantics.cc (finish_type_pack_element): Add more info + to diagnostics. + +2025-04-17 Jason Merrill <jason@redhat.com> + + * decl.cc (cp_make_fname_decl): Prevent silent failure. + +2025-04-17 Jason Merrill <jason@redhat.com> + + * lex.cc (unqualified_name_lookup_error): Handle 'requires' better. + +2025-04-17 Jason Merrill <jason@redhat.com> + + PR c++/113360 + * cp-tree.h (struct language_function): Add erroneous bit. + * constexpr.cc (explain_invalid_constexpr_fn): Return if set. + (cxx_eval_call_expression): Quiet if set. + * parser.cc (cp_parser_function_definition_after_declarator) + * pt.cc (instantiate_body): Set it. + +2025-04-16 Jason Merrill <jason@redhat.com> + + PR c++/114772 + PR c++/101180 + * pt.cc (apply_late_template_attributes): Also override + target_option_current_node. + +2025-04-16 Jason Merrill <jason@redhat.com> + + PR c++/116954 + * contracts.cc (remove_contract_attributes): Preserve flags + on the attribute list. + +2025-04-15 Nathaniel Shead <nathanieloshead@gmail.com> + + PR c++/119755 + * lambda.cc (prune_lambda_captures): Remove pruned capture from + function's BLOCK_VARS and BIND_EXPR_VARS. + +2025-04-15 Jason Merrill <jason@redhat.com> + + PR c++/111075 + * constexpr.cc (cxx_eval_call_expression): Allow trivial + call from a thunk. + +2025-04-15 Patrick Palka <ppalka@redhat.com> + + PR c++/119807 + PR c++/112288 + * pt.cc (tsubst_friend_function): Skip remapping an + existing specialization if it doesn't match the shape of + the new friend definition. + +2025-04-15 Jason Merrill <jason@redhat.com> + + PR c++/113835 + * constexpr.cc (cxx_eval_outermost_constant_expr): Bail out early + for std::vector(N). + +2025-04-14 Patrick Palka <ppalka@redhat.com> + + PR c++/99214 + * constraint.cc (satisfy_declaration_constraints): Pass the + original ARGS to push_tinst_level. + +2025-04-13 Patrick Palka <ppalka@redhat.com> + + PR c++/115639 + * constexpr.cc (struct constexpr_call): Add NSDMIs to each + field. Replace 'result' data member with 3-element 'results' + array and a 'result' accessor function. Remove + 'manifestly_const_eval' data member. + (constexpr_call_hasher::equal): Adjust after constexpr_call + layout change. + (cxx_eval_call_expression): Likewise. Define some local + variables closer to their first use. Use unknown_type_node + instead of NULL_TREE as the "in progress" result. After + successully evaluating a call with mce_unknown, also cache the + result in the corresponding mce_true and mce_false slots. + +2025-04-13 Nathaniel Shead <nathanieloshead@gmail.com> + + * module.cc (trees_in::is_matching_decl): Don't check for + mismatches when importing a DECL_MAYBE_DELETED function over one + that's already finished. + +2025-04-13 Nathaniel Shead <nathanieloshead@gmail.com> + + * module.cc (trees_in::is_matching_decl): Add custom errors for + different kinds of mismatches. + +2025-04-12 Patrick Palka <ppalka@redhat.com> + + PR c++/116416 + * constexpr.cc (maybe_constant_init_1): Generalize type of + of manifestly_const_eval parameter from bool to mce_value. + (maybe_constant_init): Define 3-parameter version taking a + manifestly_const_eval instead of bool parameter. + (cxx_constant_init): Adjust. + * cp-gimplify.cc (cp_fold_r) <case TARGET_EXPR>: Pass mce_false + to maybe_constant_init during prvalue folding if ff_mce_false is + set. + * cp-tree.h (maybe_constant_init): Declare new overload. + 2025-04-11 Jason Merrill <jason@redhat.com> PR c++/114970 diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc index 0242425..8a11e62 100644 --- a/gcc/cp/constexpr.cc +++ b/gcc/cp/constexpr.cc @@ -307,7 +307,14 @@ is_valid_constexpr_fn (tree fun, bool complain) { ret = false; if (complain) - error ("%q#T has virtual base classes", DECL_CONTEXT (fun)); + { + if (DECL_CONSTRUCTOR_P (fun)) + error ("%<constexpr%> constructor in %q#T that has " + "virtual base classes", DECL_CONTEXT (fun)); + else + error ("%<constexpr%> destructor in %q#T that has " + "virtual base classes", DECL_CONTEXT (fun)); + } } return ret; @@ -1048,6 +1055,12 @@ explain_invalid_constexpr_fn (tree fun) { static hash_set<tree> *diagnosed; tree body; + + /* Don't try to explain a function we already complained about. */ + if (function *f = DECL_STRUCT_FUNCTION (fun)) + if (f->language->erroneous) + return; + /* In C++23, a function marked 'constexpr' may not actually be a constant expression. We haven't diagnosed the problem yet: -Winvalid-constexpr wasn't enabled. The function was called, so diagnose why it cannot be @@ -1119,20 +1132,22 @@ explain_invalid_constexpr_fn (tree fun) struct GTY((for_user)) constexpr_call { /* Description of the constexpr function definition. */ - constexpr_fundef *fundef; + constexpr_fundef *fundef = nullptr; /* Parameter bindings environment. A TREE_VEC of arguments. */ - tree bindings; - /* Result of the call. - NULL means the call is being evaluated. + tree bindings = NULL_TREE; + /* Result of the call, indexed by the value of + constexpr_ctx::manifestly_const_eval. + unknown_type_node means the call is being evaluated. error_mark_node means that the evaluation was erroneous or otherwise uncacheable (e.g. because it depends on the caller). Otherwise, the actual value of the call. */ - tree result; + tree results[3] = { NULL_TREE, NULL_TREE, NULL_TREE }; /* The hash of this call; we remember it here to avoid having to recalculate it when expanding the hash table. */ - hashval_t hash; - /* The value of constexpr_ctx::manifestly_const_eval. */ - enum mce_value manifestly_const_eval; + hashval_t hash = 0; + + /* The result slot corresponding to the given mce_value. */ + tree& result (mce_value mce) { return results[1 + int(mce)]; } }; struct constexpr_call_hasher : ggc_ptr_hash<constexpr_call> @@ -1427,8 +1442,6 @@ constexpr_call_hasher::equal (constexpr_call *lhs, constexpr_call *rhs) return true; if (lhs->hash != rhs->hash) return false; - if (lhs->manifestly_const_eval != rhs->manifestly_const_eval) - return false; if (!constexpr_fundef_hasher::equal (lhs->fundef, rhs->fundef)) return false; return cp_tree_equal (lhs->bindings, rhs->bindings); @@ -2855,9 +2868,6 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t, { location_t loc = cp_expr_loc_or_input_loc (t); tree fun = get_function_named_in_call (t); - constexpr_call new_call - = { NULL, NULL, NULL, 0, ctx->manifestly_const_eval }; - int depth_ok; if (fun == NULL_TREE) return cxx_eval_internal_function (ctx, t, lval, @@ -2946,12 +2956,11 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t, gcc_assert (arg0); if (new_op_p) { - /* FIXME: We should not get here; the VERIFY_CONSTANT above - should have already caught it. But currently a conversion - from pointer type to arithmetic type is only considered - non-constant for CONVERT_EXPRs, not NOP_EXPRs. */ if (!tree_fits_uhwi_p (arg0)) { + /* We should not get here; the VERIFY_CONSTANT above + should have already caught it. */ + gcc_checking_assert (false); if (!ctx->quiet) error_at (loc, "cannot allocate array: size not constant"); *non_constant_p = true; @@ -3082,6 +3091,7 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t, } constexpr_ctx new_ctx = *ctx; + ctx = &new_ctx; if (DECL_CONSTRUCTOR_P (fun) && !ctx->object && TREE_CODE (t) == AGGR_INIT_EXPR) { @@ -3091,27 +3101,26 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t, tree ctor = new_ctx.ctor = build_constructor (DECL_CONTEXT (fun), NULL); CONSTRUCTOR_NO_CLEARING (ctor) = true; ctx->global->put_value (new_ctx.object, ctor); - ctx = &new_ctx; } /* An immediate invocation is manifestly constant evaluated including the arguments of the call, so use mce_true even for the argument evaluation. */ if (DECL_IMMEDIATE_FUNCTION_P (fun)) - { - new_ctx.manifestly_const_eval = mce_true; - new_call.manifestly_const_eval = mce_true; - ctx = &new_ctx; - } + new_ctx.manifestly_const_eval = mce_true; /* We used to shortcut trivial constructor/op= here, but nowadays we can only get a trivial function here with -fno-elide-constructors. */ gcc_checking_assert (!trivial_fn_p (fun) || !flag_elide_constructors + /* Or it's a call from maybe_thunk_body (111075). */ + || (TREE_CODE (t) == CALL_EXPR ? CALL_FROM_THUNK_P (t) + : AGGR_INIT_FROM_THUNK_P (t)) /* We don't elide constructors when processing a noexcept-expression. */ || cp_noexcept_operand); bool non_constant_args = false; + constexpr_call new_call; new_call.bindings = cxx_bind_parameters_in_call (ctx, t, fun, non_constant_p, overflow_p, &non_constant_args); @@ -3185,7 +3194,12 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t, } } - depth_ok = push_cx_call_context (t); + /* Don't complain about problems evaluating an ill-formed function. */ + if (function *f = DECL_STRUCT_FUNCTION (fun)) + if (f->language->erroneous) + new_ctx.quiet = true; + + int depth_ok = push_cx_call_context (t); /* Remember the object we are constructing or destructing. */ tree new_obj = NULL_TREE; @@ -3227,8 +3241,6 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t, new_call.hash = constexpr_fundef_hasher::hash (new_call.fundef); new_call.hash = iterative_hash_template_arg (new_call.bindings, new_call.hash); - new_call.hash - = iterative_hash_object (ctx->manifestly_const_eval, new_call.hash); /* If we have seen this call before, we are done. */ maybe_initialize_constexpr_call_table (); @@ -3246,22 +3258,23 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t, the slot can move during evaluation of the body. */ *slot = entry = ggc_alloc<constexpr_call> (); *entry = new_call; + entry->result (ctx->manifestly_const_eval) = unknown_type_node; fb.preserve (); } } - /* Calls that are in progress have their result set to NULL, so that we - can detect circular dependencies. Now that we only cache up to - constexpr_cache_depth this won't catch circular dependencies that + /* Calls that are in progress have their result set to unknown_type_node, + so that we can detect circular dependencies. Now that we only cache + up to constexpr_cache_depth this won't catch circular dependencies that start deeper, but they'll hit the recursion or ops limit. */ - else if (entry->result == NULL) + else if (entry->result (ctx->manifestly_const_eval) == unknown_type_node) { if (!ctx->quiet) error ("call has circular dependency"); *non_constant_p = true; - entry->result = result = error_mark_node; + entry->result (ctx->manifestly_const_eval) = result = error_mark_node; } else - result = entry->result; + result = entry->result (ctx->manifestly_const_eval); } if (!depth_ok) @@ -3482,7 +3495,22 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t, else if (!result) result = void_node; if (entry) - entry->result = cacheable ? result : error_mark_node; + { + entry->result (ctx->manifestly_const_eval) + = cacheable ? result : error_mark_node; + + if (result != error_mark_node + && ctx->manifestly_const_eval == mce_unknown) + { + /* Evaluation succeeded and was independent of whether we're in a + manifestly constant-evaluated context, so we can also reuse + this result when evaluating this call with a fixed context. */ + if (!entry->result (mce_true)) + entry->result (mce_true) = entry->result (mce_unknown); + if (!entry->result (mce_false)) + entry->result (mce_false) = entry->result (mce_unknown); + } + } } /* The result of a constexpr function must be completely initialized. @@ -8450,7 +8478,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, if (TREE_CODE (t) == CONVERT_EXPR && ARITHMETIC_TYPE_P (type) && INDIRECT_TYPE_P (TREE_TYPE (op)) - && ctx->manifestly_const_eval == mce_true) + && ctx->strict) { if (!ctx->quiet) error_at (loc, @@ -9116,6 +9144,15 @@ cxx_eval_outermost_constant_expr (tree t, bool allow_non_constant, tree fndecl = cp_get_callee_fndecl_nofold (x); if (fndecl && DECL_IMMEDIATE_FUNCTION_P (fndecl)) is_consteval = true; + /* Don't try to evaluate a std::vector constructor taking an integer, it + will fail in the 'if (heap_var)' block below after doing all the work + (c++/113835). This will need adjustment if P3554 is accepted. Note + that evaluation of e.g. the vector default constructor can succeed, so + we don't shortcut all vector constructors. */ + if (fndecl && DECL_CONSTRUCTOR_P (fndecl) && allow_non_constant + && is_std_class (type, "vector") && call_expr_nargs (x) > 1 + && TREE_CODE (TREE_TYPE (get_nth_callarg (x, 1))) == INTEGER_TYPE) + return t; } if (AGGREGATE_TYPE_P (type) || VECTOR_TYPE_P (type)) { @@ -9190,11 +9227,6 @@ cxx_eval_outermost_constant_expr (tree t, bool allow_non_constant, if (r == void_node && !constexpr_dtor && ctx.ctor) r = ctx.ctor; - if (!constexpr_dtor) - verify_constant (r, allow_non_constant, &non_constant_p, &overflow_p); - else - DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (object) = true; - unsigned int i; tree cleanup; /* Evaluate the cleanups. */ @@ -9213,15 +9245,6 @@ cxx_eval_outermost_constant_expr (tree t, bool allow_non_constant, non_constant_p = true; } - if (TREE_CODE (r) == CONSTRUCTOR && CONSTRUCTOR_NO_CLEARING (r)) - { - if (!allow_non_constant) - error ("%qE is not a constant expression because it refers to " - "an incompletely initialized variable", t); - TREE_CONSTANT (r) = false; - non_constant_p = true; - } - if (!non_constant_p && cxx_dialect >= cxx20 && !global_ctx.heap_vars.is_empty ()) { @@ -9231,9 +9254,11 @@ cxx_eval_outermost_constant_expr (tree t, bool allow_non_constant, if (heap_var) { if (!allow_non_constant && !non_constant_p) - error_at (DECL_SOURCE_LOCATION (heap_var), - "%qE is not a constant expression because it refers to " - "a result of %<operator new%>", t); + { + error ("%qE is not a constant expression because it refers to " + "a result of %<operator new%>", t); + inform (DECL_SOURCE_LOCATION (heap_var), "allocated here"); + } r = t; non_constant_p = true; } @@ -9242,9 +9267,11 @@ cxx_eval_outermost_constant_expr (tree t, bool allow_non_constant, if (DECL_NAME (heap_var) != heap_deleted_identifier) { if (!allow_non_constant && !non_constant_p) - error_at (DECL_SOURCE_LOCATION (heap_var), - "%qE is not a constant expression because allocated " - "storage has not been deallocated", t); + { + error ("%qE is not a constant expression because allocated " + "storage has not been deallocated", t); + inform (DECL_SOURCE_LOCATION (heap_var), "allocated here"); + } r = t; non_constant_p = true; } @@ -9274,6 +9301,21 @@ cxx_eval_outermost_constant_expr (tree t, bool allow_non_constant, non_constant_p = true; } + if (!non_constant_p && !constexpr_dtor) + verify_constant (r, allow_non_constant, &non_constant_p, &overflow_p); + + /* After verify_constant because reduced_constant_expression_p can unset + CONSTRUCTOR_NO_CLEARING. */ + if (!non_constant_p + && TREE_CODE (r) == CONSTRUCTOR && CONSTRUCTOR_NO_CLEARING (r)) + { + if (!allow_non_constant) + error ("%qE is not a constant expression because it refers to " + "an incompletely initialized variable", t); + TREE_CONSTANT (r) = false; + non_constant_p = true; + } + if (non_constant_p) /* If we saw something bad, go back to our argument. The wrapping below is only for the cases of TREE_CONSTANT argument or overflow. */ @@ -9290,13 +9332,17 @@ cxx_eval_outermost_constant_expr (tree t, bool allow_non_constant, if (non_constant_p && !allow_non_constant) return error_mark_node; - else if (constexpr_dtor) - return r; else if (non_constant_p && TREE_CONSTANT (r)) r = mark_non_constant (r); else if (non_constant_p) return t; + if (constexpr_dtor) + { + DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (object) = true; + return r; + } + /* Check we are not trying to return the wrong type. */ if (!same_type_ignoring_top_level_qualifiers_p (type, TREE_TYPE (r))) { @@ -9448,6 +9494,9 @@ fold_simple (tree t) tree fold_to_constant (tree t) { + if (processing_template_decl) + return t; + tree r = fold (t); if (CONSTANT_CLASS_P (r) && !TREE_OVERFLOW (r)) return r; @@ -9705,16 +9754,26 @@ maybe_constant_init_1 (tree t, tree decl, bool allow_non_constant, { /* [basic.start.static] allows constant-initialization of variables with static or thread storage duration even if it isn't required, but we - shouldn't bend the rules the same way for automatic variables. */ + shouldn't bend the rules the same way for automatic variables. + + But still enforce the requirements of constexpr/constinit. + [dcl.constinit] "If a variable declared with the constinit specifier + has dynamic initialization, the program is ill-formed, even if the + implementation would perform that initialization as a static + initialization." */ bool is_static = (decl && DECL_P (decl) && (TREE_STATIC (decl) || DECL_EXTERNAL (decl))); + bool strict = (!is_static + || (decl && DECL_P (decl) + && (DECL_DECLARED_CONSTEXPR_P (decl) + || DECL_DECLARED_CONSTINIT_P (decl)))); if (is_static) manifestly_const_eval = mce_true; if (cp_unevaluated_operand && manifestly_const_eval != mce_true) return fold_to_constant (t); - t = cxx_eval_outermost_constant_expr (t, allow_non_constant, !is_static, + t = cxx_eval_outermost_constant_expr (t, allow_non_constant, strict, manifestly_const_eval, false, decl); } diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc index 2f1678c..44fb086 100644 --- a/gcc/cp/constraint.cc +++ b/gcc/cp/constraint.cc @@ -2704,6 +2704,8 @@ satisfy_declaration_constraints (tree t, sat_info info) static tree satisfy_declaration_constraints (tree t, tree args, sat_info info) { + tree orig_args = args; + /* Update the declaration for diagnostics. */ info.in_decl = t; @@ -2732,7 +2734,7 @@ satisfy_declaration_constraints (tree t, tree args, sat_info info) tree result = boolean_true_node; if (tree norm = get_normalized_constraints_from_decl (t, info.noisy ())) { - if (!push_tinst_level (t, args)) + if (!push_tinst_level (t, orig_args)) return result; tree pattern = DECL_TEMPLATE_RESULT (t); push_to_top_level (); diff --git a/gcc/cp/contracts.cc b/gcc/cp/contracts.cc index f2b126c..3ca2102 100644 --- a/gcc/cp/contracts.cc +++ b/gcc/cp/contracts.cc @@ -863,7 +863,11 @@ remove_contract_attributes (tree fndecl) tree list = NULL_TREE; for (tree p = DECL_ATTRIBUTES (fndecl); p; p = TREE_CHAIN (p)) if (!cxx_contract_attribute_p (p)) - list = tree_cons (TREE_PURPOSE (p), TREE_VALUE (p), list); + { + tree nl = copy_node (p); + TREE_CHAIN (nl) = list; + list = nl; + } DECL_ATTRIBUTES (fndecl) = nreverse (list); } diff --git a/gcc/cp/coroutines.cc b/gcc/cp/coroutines.cc index b92d09f..743da06 100644 --- a/gcc/cp/coroutines.cc +++ b/gcc/cp/coroutines.cc @@ -1852,21 +1852,6 @@ coro_build_frame_access_expr (tree coro_ref, tree member_id, bool preserve_ref, return expr; } -/* Helpers to build EXPR_STMT and void-cast EXPR_STMT, common ops. */ - -static tree -coro_build_expr_stmt (tree expr, location_t loc) -{ - return maybe_cleanup_point_expr_void (build_stmt (loc, EXPR_STMT, expr)); -} - -static tree -coro_build_cvt_void_expr_stmt (tree expr, location_t loc) -{ - tree t = build1 (CONVERT_EXPR, void_type_node, expr); - return coro_build_expr_stmt (t, loc); -} - /* Helpers to build an artificial var, with location LOC, NAME and TYPE, in CTX, and with initializer INIT. */ @@ -2582,8 +2567,7 @@ build_actor_fn (location_t loc, tree coro_frame_type, tree actor, tree fnbody, tree hfa = build_new_method_call (ash, hfa_m, &args, NULL_TREE, LOOKUP_NORMAL, NULL, tf_warning_or_error); r = cp_build_init_expr (ash, hfa); - r = coro_build_cvt_void_expr_stmt (r, loc); - add_stmt (r); + finish_expr_stmt (r); release_tree_vector (args); /* Now we know the real promise, and enough about the frame layout to @@ -2678,8 +2662,7 @@ build_actor_fn (location_t loc, tree coro_frame_type, tree actor, tree fnbody, we must tail call them. However, some targets do not support indirect tail calls to arbitrary callees. See PR94359. */ CALL_EXPR_TAILCALL (resume) = true; - resume = coro_build_cvt_void_expr_stmt (resume, loc); - add_stmt (resume); + finish_expr_stmt (resume); r = build_stmt (loc, RETURN_EXPR, NULL); gcc_checking_assert (maybe_cleanup_point_expr_void (r) == r); diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 55f986e..7798efb 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -2206,6 +2206,8 @@ struct GTY(()) language_function { BOOL_BITFIELD invalid_constexpr : 1; BOOL_BITFIELD throwing_cleanup : 1; + /* True if we gave any errors in this function. */ + BOOL_BITFIELD erroneous : 1; hash_table<named_label_hash> *x_named_labels; diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc index 4e97093..84398e5 100644 --- a/gcc/cp/decl.cc +++ b/gcc/cp/decl.cc @@ -5339,6 +5339,8 @@ cp_make_fname_decl (location_t loc, tree id, int type_dep) decl = pushdecl_outermost_localscope (decl); if (decl != error_mark_node) add_decl_expr (decl); + else + gcc_assert (seen_error ()); } else { diff --git a/gcc/cp/init.cc b/gcc/cp/init.cc index e589e45..062a493 100644 --- a/gcc/cp/init.cc +++ b/gcc/cp/init.cc @@ -3405,7 +3405,7 @@ build_new_1 (vec<tree, va_gc> **placement, tree type, tree nelts, errval = throw_bad_array_new_length (); if (outer_nelts_check != NULL_TREE) size = build3 (COND_EXPR, sizetype, outer_nelts_check, size, errval); - size = cp_fully_fold (size); + size = fold_to_constant (size); /* Create the argument list. */ vec_safe_insert (*placement, 0, size); /* Do name-lookup to find the appropriate operator. */ @@ -3462,7 +3462,7 @@ build_new_1 (vec<tree, va_gc> **placement, tree type, tree nelts, outer_nelts_check = NULL_TREE; } - size = cp_fully_fold (size); + size = fold_to_constant (size); /* If size is zero e.g. due to type having zero size, try to preserve outer_nelts for constant expression evaluation purposes. */ diff --git a/gcc/cp/lambda.cc b/gcc/cp/lambda.cc index f0a54b6..b2e0ecd 100644 --- a/gcc/cp/lambda.cc +++ b/gcc/cp/lambda.cc @@ -1858,6 +1858,13 @@ prune_lambda_captures (tree body) cp_walk_tree_without_duplicates (&body, mark_const_cap_r, &const_vars); + tree bind_expr = expr_single (DECL_SAVED_TREE (lambda_function (lam))); + if (bind_expr && TREE_CODE (bind_expr) == MUST_NOT_THROW_EXPR) + bind_expr = expr_single (TREE_OPERAND (bind_expr, 0)); + /* FIXME: We don't currently handle noexcept lambda captures correctly, + so bind_expr may not be set; see PR c++/119764. */ + gcc_assert (!bind_expr || TREE_CODE (bind_expr) == BIND_EXPR); + tree *fieldp = &TYPE_FIELDS (LAMBDA_EXPR_CLOSURE (lam)); for (tree *capp = &LAMBDA_EXPR_CAPTURE_LIST (lam); *capp; ) { @@ -1879,6 +1886,23 @@ prune_lambda_captures (tree body) fieldp = &DECL_CHAIN (*fieldp); *fieldp = DECL_CHAIN (*fieldp); + /* And out of the bindings for the function. */ + tree *blockp = &BLOCK_VARS (current_binding_level->blocks); + while (*blockp != DECL_EXPR_DECL (**use)) + blockp = &DECL_CHAIN (*blockp); + *blockp = DECL_CHAIN (*blockp); + + /* And maybe out of the vars declared in the containing + BIND_EXPR, if it's listed there. */ + if (bind_expr) + { + tree *bindp = &BIND_EXPR_VARS (bind_expr); + while (*bindp && *bindp != DECL_EXPR_DECL (**use)) + bindp = &DECL_CHAIN (*bindp); + if (*bindp) + *bindp = DECL_CHAIN (*bindp); + } + /* And remove the capture proxy declaration. */ **use = void_node; continue; diff --git a/gcc/cp/lex.cc b/gcc/cp/lex.cc index c12b084..12af81e 100644 --- a/gcc/cp/lex.cc +++ b/gcc/cp/lex.cc @@ -749,6 +749,9 @@ unqualified_name_lookup_error (tree name, location_t loc) if (IDENTIFIER_ANY_OP_P (name)) error_at (loc, "%qD not defined", name); + else if (!flag_concepts && name == ridpointers[(int)RID_REQUIRES]) + error_at (loc, "%<requires%> only available with %<-std=c++20%> or " + "%<-fconcepts%>"); else { if (!objc_diagnose_private_ivar (name)) diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc index 37fab5b..5ff5c46 100644 --- a/gcc/cp/module.cc +++ b/gcc/cp/module.cc @@ -12090,6 +12090,8 @@ trees_in::is_matching_decl (tree existing, tree decl, bool is_typedef) gcc_checking_assert (TREE_CODE (e_inner) == TREE_CODE (d_inner)); } + // FIXME: do more precise errors at point of mismatch + const char *mismatch_msg = nullptr; if (TREE_CODE (d_inner) == FUNCTION_DECL) { tree e_ret = fndecl_declared_return_type (existing); @@ -12099,13 +12101,20 @@ trees_in::is_matching_decl (tree existing, tree decl, bool is_typedef) && LAMBDA_TYPE_P (DECL_CONTEXT (d_inner))) /* This has a recursive type that will compare different. */; else if (!same_type_p (d_ret, e_ret)) - goto mismatch; + { + mismatch_msg = G_("conflicting type for imported declaration %#qD"); + goto mismatch; + } tree e_type = TREE_TYPE (e_inner); tree d_type = TREE_TYPE (d_inner); if (DECL_EXTERN_C_P (d_inner) != DECL_EXTERN_C_P (e_inner)) - goto mismatch; + { + mismatch_msg = G_("conflicting language linkage for imported " + "declaration %#qD"); + goto mismatch; + } for (tree e_args = TYPE_ARG_TYPES (e_type), d_args = TYPE_ARG_TYPES (d_type); @@ -12113,10 +12122,18 @@ trees_in::is_matching_decl (tree existing, tree decl, bool is_typedef) e_args = TREE_CHAIN (e_args), d_args = TREE_CHAIN (d_args)) { if (!(e_args && d_args)) - goto mismatch; + { + mismatch_msg = G_("conflicting argument list for imported " + "declaration %#qD"); + goto mismatch; + } if (!same_type_p (TREE_VALUE (d_args), TREE_VALUE (e_args))) - goto mismatch; + { + mismatch_msg = G_("conflicting argument types for imported " + "declaration %#qD"); + goto mismatch; + } } /* If EXISTING has an undeduced or uninstantiated exception @@ -12147,9 +12164,14 @@ trees_in::is_matching_decl (tree existing, tree decl, bool is_typedef) } } } - else if (!DEFERRED_NOEXCEPT_SPEC_P (d_spec) + else if (!DECL_MAYBE_DELETED (d_inner) + && !DEFERRED_NOEXCEPT_SPEC_P (d_spec) && !comp_except_specs (d_spec, e_spec, ce_type)) - goto mismatch; + { + mismatch_msg = G_("conflicting %<noexcept%> specifier for " + "imported declaration %#qD"); + goto mismatch; + } /* Similarly if EXISTING has an undeduced return type, but DECL's is already deduced. */ @@ -12163,16 +12185,26 @@ trees_in::is_matching_decl (tree existing, tree decl, bool is_typedef) } else if (type_uses_auto (d_ret) && !same_type_p (TREE_TYPE (d_type), TREE_TYPE (e_type))) - goto mismatch; + { + mismatch_msg = G_("conflicting deduced return type for " + "imported declaration %#qD"); + goto mismatch; + } /* Similarly if EXISTING has undeduced constexpr, but DECL's is already deduced. */ if (DECL_MAYBE_DELETED (e_inner) && !DECL_MAYBE_DELETED (d_inner) && DECL_DECLARED_CONSTEXPR_P (d_inner)) DECL_DECLARED_CONSTEXPR_P (e_inner) = true; + else if (!DECL_MAYBE_DELETED (e_inner) && DECL_MAYBE_DELETED (d_inner)) + /* Nothing to do. */; else if (DECL_DECLARED_CONSTEXPR_P (e_inner) != DECL_DECLARED_CONSTEXPR_P (d_inner)) - goto mismatch; + { + mismatch_msg = G_("conflicting %<constexpr%> for imported " + "declaration %#qD"); + goto mismatch; + } /* Don't synthesize a defaulted function if we're importing one we've already determined. */ @@ -12184,13 +12216,17 @@ trees_in::is_matching_decl (tree existing, tree decl, bool is_typedef) if (!DECL_ORIGINAL_TYPE (e_inner) || !same_type_p (DECL_ORIGINAL_TYPE (d_inner), DECL_ORIGINAL_TYPE (e_inner))) - goto mismatch; + { + mismatch_msg = G_("conflicting imported declaration %q#D"); + goto mismatch; + } } /* Using cp_tree_equal because we can meet TYPE_ARGUMENT_PACKs here. I suspect the entities that directly do that are things that shouldn't go to duplicate_decls (FIELD_DECLs etc). */ else if (!cp_tree_equal (TREE_TYPE (decl), TREE_TYPE (existing))) { + mismatch_msg = G_("conflicting type for imported declaration %#qD"); mismatch: if (DECL_IS_UNDECLARED_BUILTIN (existing)) /* Just like duplicate_decls, presum the user knows what @@ -12203,11 +12239,9 @@ trees_in::is_matching_decl (tree existing, tree decl, bool is_typedef) equality isn't feasible in general for local entities. */; else { - // FIXME:QOI Might be template specialization from a module, - // not necessarily global module + gcc_checking_assert (mismatch_msg); auto_diagnostic_group d; - error_at (DECL_SOURCE_LOCATION (decl), - "conflicting global module declaration %#qD", decl); + error_at (DECL_SOURCE_LOCATION (decl), mismatch_msg, decl); inform (DECL_SOURCE_LOCATION (existing), "existing declaration %#qD", existing); return false; diff --git a/gcc/cp/name-lookup.cc b/gcc/cp/name-lookup.cc index 1cd982e..498126a 100644 --- a/gcc/cp/name-lookup.cc +++ b/gcc/cp/name-lookup.cc @@ -583,7 +583,7 @@ name_lookup::preserve_state () if (previous) { unsigned length = vec_safe_length (previous->scopes); - vec_safe_reserve (previous->scopes, length * 2); + vec_safe_reserve (previous->scopes, length); for (unsigned ix = length; ix--;) { tree decl = (*previous->scopes)[ix]; diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc index 812a7c5..3628cfe 100644 --- a/gcc/cp/parser.cc +++ b/gcc/cp/parser.cc @@ -33634,6 +33634,8 @@ cp_parser_function_definition_after_declarator (cp_parser* parser, = parser->num_template_parameter_lists; parser->num_template_parameter_lists = 0; + int errs = errorcount + sorrycount; + /* If the next token is `try', `__transaction_atomic', or `__transaction_relaxed`, then we are looking at either function-try-block or function-transaction-block. Note that all of these include the @@ -33653,6 +33655,9 @@ cp_parser_function_definition_after_declarator (cp_parser* parser, fn = finish_function (inline_p); check_module_decl_linkage (fn); + if ((errorcount + sorrycount) > errs) + DECL_STRUCT_FUNCTION (fn)->language->erroneous = true; + if (modules_p () && !inline_p && TYPE_P (DECL_CONTEXT (fn)) diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc index b7060b4..a71705f 100644 --- a/gcc/cp/pt.cc +++ b/gcc/cp/pt.cc @@ -11772,6 +11772,10 @@ tsubst_friend_function (tree decl, tree args) elt.args = DECL_TI_ARGS (spec); elt.spec = NULL_TREE; + if (TMPL_ARGS_HAVE_MULTIPLE_LEVELS (DECL_TI_ARGS (spec)) + && !is_specialization_of_friend (spec, new_template)) + continue; + decl_specializations->remove_elt (&elt); tree& spec_args = DECL_TI_ARGS (spec); @@ -12425,6 +12429,8 @@ apply_late_template_attributes (tree *decl_p, tree attributes, int attr_flags, auto o4 = make_temp_override (scope_chain->omp_declare_target_attribute, NULL); auto o5 = make_temp_override (scope_chain->omp_begin_assumes, NULL); + auto o6 = make_temp_override (target_option_current_node, + target_option_default_node); cplus_decl_attributes (decl_p, late_attrs, attr_flags); @@ -27752,6 +27758,11 @@ instantiate_body (tree pattern, tree args, tree d, bool nested_p) if (DECL_OMP_DECLARE_REDUCTION_P (code_pattern)) cp_check_omp_declare_reduction (d); + + if (int errs = errorcount + sorrycount) + if (errs > current_tinst_level->errors) + if (function *f = DECL_STRUCT_FUNCTION (d)) + f->language->erroneous = true; } /* We're not deferring instantiation any more. */ diff --git a/gcc/cp/rtti.cc b/gcc/cp/rtti.cc index 3539962..18bc479 100644 --- a/gcc/cp/rtti.cc +++ b/gcc/cp/rtti.cc @@ -1318,18 +1318,9 @@ get_pseudo_ti_index (tree type) static tinfo_s * get_tinfo_desc (unsigned ix) { - unsigned len = tinfo_descs->length (); - - if (len <= ix) - { - /* too short, extend. */ - len = ix + 1 - len; - vec_safe_reserve (tinfo_descs, len); - tinfo_s elt; - elt.type = elt.vtable = elt.name = NULL_TREE; - while (len--) - tinfo_descs->quick_push (elt); - } + if (tinfo_descs->length () <= ix) + /* too short, extend. */ + vec_safe_grow_cleared (tinfo_descs, ix + 1); tinfo_s *res = &(*tinfo_descs)[ix]; diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc index a10ef34..1aa35d3 100644 --- a/gcc/cp/semantics.cc +++ b/gcc/cp/semantics.cc @@ -1180,10 +1180,13 @@ finish_expr_stmt (tree expr) expr = error_mark_node; /* Simplification of inner statement expressions, compound exprs, - etc can result in us already having an EXPR_STMT. */ + etc can result in us already having an EXPR_STMT or other statement + tree. Don't wrap them in EXPR_STMT. */ if (TREE_CODE (expr) != CLEANUP_POINT_EXPR) { - if (TREE_CODE (expr) != EXPR_STMT) + if (TREE_CODE (expr) != EXPR_STMT + && !STATEMENT_CLASS_P (expr) + && TREE_CODE (expr) != STATEMENT_LIST) expr = build_stmt (loc, EXPR_STMT, expr); expr = maybe_cleanup_point_expr_void (expr); } @@ -3082,6 +3085,7 @@ finish_stmt_expr_expr (tree expr, tree stmt_expr) } else if (processing_template_decl) { + /* Not finish_expr_stmt because we don't want convert_to_void. */ expr = build_stmt (input_location, EXPR_STMT, expr); expr = add_stmt (expr); /* Mark the last statement so that we can recognize it as such at @@ -5088,22 +5092,32 @@ static tree finish_type_pack_element (tree idx, tree types, tsubst_flags_t complain) { idx = maybe_constant_value (idx, NULL_TREE, mce_true); - if (TREE_CODE (idx) != INTEGER_CST || !INTEGRAL_TYPE_P (TREE_TYPE (idx))) + if (!INTEGRAL_TYPE_P (TREE_TYPE (idx))) { if (complain & tf_error) - error ("pack index is not an integral constant"); + error ("pack index has non-integral type %qT", TREE_TYPE (idx)); + return error_mark_node; + } + if (TREE_CODE (idx) != INTEGER_CST) + { + if (complain & tf_error) + { + error ("pack index is not an integral constant"); + cxx_constant_value (idx); + } return error_mark_node; } if (tree_int_cst_sgn (idx) < 0) { if (complain & tf_error) - error ("pack index is negative"); + error ("pack index %qE is negative", idx); return error_mark_node; } if (wi::to_widest (idx) >= TREE_VEC_LENGTH (types)) { if (complain & tf_error) - error ("pack index is out of range"); + error ("pack index %qE is out of range for pack of length %qd", + idx, TREE_VEC_LENGTH (types)); return error_mark_node; } return TREE_VEC_ELT (types, tree_to_shwi (idx)); diff --git a/gcc/d/ChangeLog b/gcc/d/ChangeLog index ca31897..f816c70 100644 --- a/gcc/d/ChangeLog +++ b/gcc/d/ChangeLog @@ -1,3 +1,44 @@ +2025-04-17 Iain Buclaw <ibuclaw@gdcproject.org> + + * dmd/MERGE: Merge upstream dmd 956e73d64e. + +2025-04-15 Iain Buclaw <ibuclaw@gdcproject.org> + + PR d/119826 + * types.cc (TypeVisitor::visit (TypeEnum *)): Propagate flags of main + enum types to all forward-referenced variants. + +2025-04-15 Iain Buclaw <ibuclaw@gdcproject.org> + + PR d/119799 + * decl.cc (DeclVisitor::visit (VarDeclaration *)): Check front-end + type size before building the VAR_DECL. Allow C symbols to have a + size of `0'. + +2025-04-15 Iain Buclaw <ibuclaw@gdcproject.org> + + PR d/119817 + * imports.cc (ImportVisitor::visit (OverloadSet *)): Don't push + NULL_TREE to vector of import symbols. + +2025-04-12 Iain Buclaw <ibuclaw@gdcproject.org> + + PR d/109023 + * d-compiler.cc: Include dmd/errors.h. + (Compiler::onImport): Implement. + * d-lang.cc (d_handle_option): Handle -finclude-imports. + (d_parse_file): Run semantic on included imports. + * gdc.texi: Document -finclude-imports. + * lang.opt: Add finclude-imports. + * lang.opt.urls: Regenerate. + +2025-04-12 Iain Buclaw <ibuclaw@gdcproject.org> + + PR d/119758 + * d-lang.cc (d_parse_file): Use endswith in test for -fonly= argument. + * d-spec.cc (lang_specific_driver): Rework -fonly= and pass all input + files to the front-end compiler when the option is seen. + 2025-04-11 Iain Buclaw <ibuclaw@gdcproject.org> * dmd/MERGE: Merge upstream dmd 1b34fea478. diff --git a/gcc/d/d-compiler.cc b/gcc/d/d-compiler.cc index 160539d..e18f5d3 100644 --- a/gcc/d/d-compiler.cc +++ b/gcc/d/d-compiler.cc @@ -20,6 +20,7 @@ along with GCC; see the file COPYING3. If not see #include "coretypes.h" #include "dmd/compiler.h" +#include "dmd/errors.h" #include "dmd/expression.h" #include "dmd/identifier.h" #include "dmd/module.h" @@ -164,7 +165,39 @@ Compiler::onParseModule (Module *m) driver intends on compiling the import. */ bool -Compiler::onImport (Module *) +Compiler::onImport (Module *m) { - return false; + if (!includeImports) + return false; + + if (m->filetype != FileType::d && m->filetype != FileType::c) + return false; + + /* All imports modules are included except those in the runtime library. */ + ModuleDeclaration *md = m->md; + if (md && md->id) + { + if (md->packages.length >= 1) + { + if (!strcmp (md->packages.ptr[0]->toChars (), "core") + || !strcmp (md->packages.ptr[0]->toChars (), "std") + || !strcmp (md->packages.ptr[0]->toChars (), "gcc") + || !strcmp (md->packages.ptr[0]->toChars (), "etc")) + return false; + } + else if (!strcmp (md->id->toChars (), "object")) + return false; + } + else if (m->ident) + { + if (!strcmp (m->ident->toChars (), "object")) + return false; + } + + /* This import will be compiled. */ + if (global.params.v.verbose) + message ("compileimport (%s)", m->srcfile.toChars ()); + + compiledImports.push (m); + return true; } diff --git a/gcc/d/d-lang.cc b/gcc/d/d-lang.cc index 0dab76b..ec2ea59 100644 --- a/gcc/d/d-lang.cc +++ b/gcc/d/d-lang.cc @@ -523,6 +523,10 @@ d_handle_option (size_t scode, const char *arg, HOST_WIDE_INT value, global.params.ignoreUnsupportedPragmas = value; break; + case OPT_finclude_imports: + includeImports = true; + break; + case OPT_finvariants: global.params.useInvariants = value ? CHECKENABLEon : CHECKENABLEoff; break; @@ -1309,6 +1313,21 @@ d_parse_file (void) dmd::semantic3 (m, NULL); } + if (includeImports) + { + for (size_t i = 0; i < compiledImports.length; i++) + { + Module *m = compiledImports[i]; + gcc_assert (m->isRoot ()); + + if (global.params.v.verbose) + message ("semantic3 %s", m->toChars ()); + + dmd::semantic3 (m, NULL); + modules.push (m); + } + } + Module::runDeferredSemantic3 (); /* Check again, incase semantic3 pass loaded any more modules. */ diff --git a/gcc/d/decl.cc b/gcc/d/decl.cc index 136f78b..9ddf7cf 100644 --- a/gcc/d/decl.cc +++ b/gcc/d/decl.cc @@ -791,6 +791,12 @@ public: } else if (d->isDataseg ()) { + /* When the front-end type size is invalid, an error has already been + given for the declaration or type. */ + dinteger_t size = dmd::size (d->type, d->loc); + if (size == SIZE_INVALID) + return; + tree decl = get_symbol_decl (d); /* Only need to build the VAR_DECL for extern declarations. */ @@ -804,9 +810,7 @@ public: return; /* How big a symbol can be should depend on back-end. */ - tree size = build_integer_cst (dmd::size (d->type, d->loc), - build_ctype (Type::tsize_t)); - if (!valid_constant_size_p (size)) + if (!valid_constant_size_p (build_integer_cst (size, size_type_node))) { error_at (make_location_t (d->loc), "size is too large"); return; @@ -835,8 +839,9 @@ public: } /* Frontend should have already caught this. */ - gcc_assert (!integer_zerop (size) - || d->type->toBasetype ()->isTypeSArray ()); + gcc_assert ((size != 0 && size != SIZE_INVALID) + || d->type->toBasetype ()->isTypeSArray () + || d->isCsymbol ()); d_finish_decl (decl); diff --git a/gcc/d/dmd/MERGE b/gcc/d/dmd/MERGE index ee5eb85..58d19b4 100644 --- a/gcc/d/dmd/MERGE +++ b/gcc/d/dmd/MERGE @@ -1,4 +1,4 @@ -1b34fea4788136b54ec77c6ed9678754d109fc79 +956e73d64e532a68213970316c2590c572ec03f3 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/expressionsem.d b/gcc/d/dmd/expressionsem.d index 19111e3..b02f6ea 100644 --- a/gcc/d/dmd/expressionsem.d +++ b/gcc/d/dmd/expressionsem.d @@ -6978,10 +6978,10 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor while (1) { AttribDeclaration ad = s.isAttribDeclaration(); - if (!ad) - break; - if (ad.decl && ad.decl.length == 1) + if (ad && ad.decl && ad.decl.length == 1) s = (*ad.decl)[0]; + else + break; } //printf("inserting '%s' %p into sc = %p\n", s.toChars(), s, sc); diff --git a/gcc/d/gdc.texi b/gcc/d/gdc.texi index 2cb0c4a62..3a8bea0 100644 --- a/gcc/d/gdc.texi +++ b/gcc/d/gdc.texi @@ -277,6 +277,12 @@ Sets @code{__traits(getTargetInfo, "cppStd")} to @code{202002}. Sets @code{__traits(getTargetInfo, "cppStd")} to @code{202302}. @end table +@opindex finclude-imports +@item -finclude-imports +Include imported modules in the compilation, as if they were given on the +command line. When this option is enabled, all imported modules are compiled +except those that are part of libphobos. + @opindex finvariants @opindex fno-invariants @item -fno-invariants diff --git a/gcc/d/imports.cc b/gcc/d/imports.cc index 776caaf..16e4df6 100644 --- a/gcc/d/imports.cc +++ b/gcc/d/imports.cc @@ -182,7 +182,11 @@ public: vec_alloc (tset, d->a.length); for (size_t i = 0; i < d->a.length; i++) - vec_safe_push (tset, build_import_decl (d->a[i])); + { + tree overload = build_import_decl (d->a[i]); + if (overload != NULL_TREE) + vec_safe_push (tset, overload); + } this->result_ = build_tree_list_vec (tset); tset->truncate (0); diff --git a/gcc/d/lang.opt b/gcc/d/lang.opt index 50c6f2f..298ff58 100644 --- a/gcc/d/lang.opt +++ b/gcc/d/lang.opt @@ -327,6 +327,10 @@ fignore-unknown-pragmas D Ignore unsupported pragmas. +finclude-imports +D RejectNegative +Include imported modules in the compilation. + finvariants D Var(flag_invariants) Generate code for class invariant contracts. diff --git a/gcc/d/lang.opt.urls b/gcc/d/lang.opt.urls index fa311d4..b4886bf 100644 --- a/gcc/d/lang.opt.urls +++ b/gcc/d/lang.opt.urls @@ -155,6 +155,9 @@ LangUrlSuffix_D(gdc/Runtime-Options.html#index-fextern-std) fignore-unknown-pragmas LangUrlSuffix_D(gdc/Warnings.html#index-fignore-unknown-pragmas) +finclude-imports +LangUrlSuffix_D(gdc/Runtime-Options.html#index-finclude-imports) + finvariants LangUrlSuffix_D(gdc/Runtime-Options.html#index-finvariants) diff --git a/gcc/d/types.cc b/gcc/d/types.cc index e43fa88..1c74840 100644 --- a/gcc/d/types.cc +++ b/gcc/d/types.cc @@ -1179,6 +1179,26 @@ public: layout_type (t->ctype); + /* Fix up all forward-referenced variants of this enum type. */ + for (tree v = TYPE_MAIN_VARIANT (t->ctype); v; + v = TYPE_NEXT_VARIANT (v)) + { + if (v == t->ctype) + continue; + + TYPE_VALUES (v) = TYPE_VALUES (t->ctype); + TYPE_LANG_SPECIFIC (v) = TYPE_LANG_SPECIFIC (t->ctype); + TYPE_MIN_VALUE (v) = TYPE_MIN_VALUE (t->ctype); + TYPE_MAX_VALUE (v) = TYPE_MAX_VALUE (t->ctype); + TYPE_UNSIGNED (v) = TYPE_UNSIGNED (t->ctype); + TYPE_SIZE (v) = TYPE_SIZE (t->ctype); + TYPE_SIZE_UNIT (v) = TYPE_SIZE_UNIT (t->ctype); + SET_TYPE_MODE (v, TYPE_MODE (t->ctype)); + TYPE_PRECISION (v) = TYPE_PRECISION (t->ctype); + SET_TYPE_ALIGN (v, TYPE_ALIGN (t->ctype)); + TYPE_USER_ALIGN (v) = TYPE_USER_ALIGN (t->ctype); + } + /* Complete forward-referenced fields of this enum type. */ finish_incomplete_fields (t->ctype); } diff --git a/gcc/doc/cfg.texi b/gcc/doc/cfg.texi index b8c6427..bbd6694 100644 --- a/gcc/doc/cfg.texi +++ b/gcc/doc/cfg.texi @@ -297,10 +297,12 @@ edge. The opposite conversion is difficult, but should not happen anyway. The edges can be eliminated via @code{purge_dead_edges} call. @findex REG_EH_REGION, EDGE_ABNORMAL_CALL -In the RTL representation, the destination of an exception edge is -specified by @code{REG_EH_REGION} note attached to the insn. -In case of a trapping call the @code{EDGE_ABNORMAL_CALL} flag is set -too. In the @code{GIMPLE} representation, this extra flag is not set. +In the RTL representation, a @code{REG_EH_REGION} note is attached to +an instruction that can throw an exception. The destination of the +exception edge originating at such an instruction is specified by the +value of the @code{REG_EH_REGION} note. In case of a trapping call +the @code{EDGE_ABNORMAL_CALL} flag is set too. In the @code{GIMPLE} +representation, this extra flag is not set. @findex may_trap_p, tree_could_trap_p In the RTL representation, the predicate @code{may_trap_p} may be used diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi index ae3357f..0978c4c 100644 --- a/gcc/doc/extend.texi +++ b/gcc/doc/extend.texi @@ -1933,6 +1933,13 @@ Note that if such a function is called indirectly the compiler may or may not inline it depending on optimization level and a failure to inline an indirect call may or may not be diagnosed. +If you need to use the inlined function in multiple translation units, +you should put the @code{always_inline} attribute on a function +definition in a header file that is included in all translation units +where the function is used. Link-time optimization can inline +functions across translation units, but only if an optimization level +that normally enables inlining is additionally specified. + @cindex @code{artificial} function attribute @item artificial This attribute is useful for small inline wrappers that if possible @@ -12299,15 +12306,6 @@ for the @samp{att} and @samp{intel} dialects of assembler: @item @code{%3} @tab @code{$.L3} @tab @code{OFFSET FLAT:.L3} -@item @code{%4} -@tab @code{$8} -@tab @code{8} -@item @code{%5} -@tab @code{%xmm0} -@tab @code{xmm0} -@item @code{%7} -@tab @code{$0} -@tab @code{0} @end multitable The table below shows the list of supported modifiers and their effects. @@ -12324,32 +12322,17 @@ The table below shows the list of supported modifiers and their effects. @tab @code{%b0} @tab @code{%al} @tab @code{al} -@item @code{B} -@tab print the opcode suffix of b. -@tab @code{%B0} -@tab @code{b} -@tab @item @code{c} @tab Require a constant operand and print the constant expression with no punctuation. @tab @code{%c1} @tab @code{2} @tab @code{2} -@item @code{d} -@tab print duplicated register operand for AVX instruction. -@tab @code{%d5} -@tab @code{%xmm0, %xmm0} -@tab @code{xmm0, xmm0} @item @code{E} @tab Print the address in Double Integer (DImode) mode (8 bytes) when the target is 64-bit. Otherwise mode is unspecified (VOIDmode). @tab @code{%E1} @tab @code{%(rax)} @tab @code{[rax]} -@item @code{g} -@tab Print the V16SFmode name of the register. -@tab @code{%g0} -@tab @code{%zmm0} -@tab @code{zmm0} @item @code{h} @tab Print the QImode name for a ``high'' register. @tab @code{%h0} @@ -12371,16 +12354,6 @@ high 8 bytes of SSE values. For a memref in (%rax), it generates @tab @code{%l3} @tab @code{.L3} @tab @code{.L3} -@item @code{L} -@tab print the opcode suffix of l. -@tab @code{%L0} -@tab @code{l} -@tab -@item @code{N} -@tab print maskz. -@tab @code{%N7} -@tab @code{@{z@}} -@tab @code{@{z@}} @item @code{p} @tab Print raw symbol name (without syntax-specific prefixes). @tab @code{%p2} @@ -12396,76 +12369,20 @@ issue the bare constant. See @code{p} above. @tab @code{%q0} @tab @code{%rax} @tab @code{rax} -@item @code{Q} -@tab print the opcode suffix of q. -@tab @code{%Q0} -@tab @code{q} -@tab -@item @code{R} -@tab print embedded rounding and sae. -@tab @code{%R4} -@tab @code{@{rn-sae@}, } -@tab @code{, @{rn-sae@}} -@item @code{r} -@tab print only sae. -@tab @code{%r4} -@tab @code{@{sae@}, } -@tab @code{, @{sae@}} -@item @code{s} -@tab print a shift double count, followed by the assemblers argument -delimiterprint the opcode suffix of s. -@tab @code{%s1} -@tab @code{$2, } -@tab @code{2, } -@item @code{S} -@tab print the opcode suffix of s. -@tab @code{%S0} -@tab @code{s} -@tab -@item @code{t} -@tab print the V8SFmode name of the register. -@tab @code{%t5} -@tab @code{%ymm0} -@tab @code{ymm0} -@item @code{T} -@tab print the opcode suffix of t. -@tab @code{%T0} -@tab @code{t} -@tab -@item @code{V} -@tab print naked full integer register name without %. -@tab @code{%V0} -@tab @code{eax} -@tab @code{eax} @item @code{w} @tab Print the HImode name of the register. @tab @code{%w0} @tab @code{%ax} @tab @code{ax} -@item @code{W} -@tab print the opcode suffix of w. -@tab @code{%W0} -@tab @code{w} -@tab -@item @code{x} -@tab print the V4SFmode name of the register. -@tab @code{%x5} -@tab @code{%xmm0} -@tab @code{xmm0} -@item @code{y} -@tab print "st(0)" instead of "st" as a register. -@tab @code{%y6} -@tab @code{%st(0)} -@tab @code{st(0)} @item @code{z} @tab Print the opcode suffix for the size of the current integer operand (one of @code{b}/@code{w}/@code{l}/@code{q}). @tab @code{%z0} @tab @code{l} @tab -@item @code{Z} -@tab Like @code{z}, with special suffixes for x87 instructions. @end multitable +@code{V} is a special modifier which prints the name of the full integer +register without @code{%}. @anchor{x86floatingpointasmoperands} @subsubsection x86 Floating-Point @code{asm} Operands @@ -13061,6 +12978,7 @@ C and/or C++ standards, while others remain specific to GNU C. * Binary constants:: Binary constants using the @samp{0b} prefix. * Dollar Signs:: Dollar sign is allowed in identifiers. * Character Escapes:: @samp{\e} stands for the character @key{ESC}. +* Raw String Literals:: C++ raw string literals are supported in C. * Alternate Keywords:: @code{__const__}, @code{__asm__}, etc., for header files. * Function Names:: Printable strings which are the name of the current function. @@ -14082,6 +14000,25 @@ machines, typically because the target assembler does not allow them. You can use the sequence @samp{\e} in a string or character constant to stand for the ASCII character @key{ESC}. +@node Raw String Literals +@subsection Raw String Literals +@cindex raw string literals +@cindex string literals, raw + +The C++11 standard added syntax for raw string literals prefixed +with @samp{R}. This syntax allows you to use an arbitrary delimiter +sequence instead of escaping special characters within the string. +For example, these string constants are all equivalent: + +@smallexample +const char *s1 = "\\"; +const char *s2 = R"(\)"; +const char *s3 = R"foo(\)foo"; +@end smallexample + +As an extension, GCC also accepts raw string literals in C with +@option{-std=gnu99} or later. + @node Alternate Keywords @subsection Alternate Keywords @cindex alternate keywords diff --git a/gcc/doc/gm2.texi b/gcc/doc/gm2.texi index 8baee24..cb52e8c 100644 --- a/gcc/doc/gm2.texi +++ b/gcc/doc/gm2.texi @@ -2699,10 +2699,10 @@ PROCEDURE Example (foo, bar: CARDINAL) : CARDINAL ; VAR myout: CARDINAL ; BEGIN - ASM VOLATILE ("movq %1,%%rax; addq %2,%%rax; movq %%rax,%0" + ASM VOLATILE ("movl %1,%%eax; addl %2,%%eax; movl %%eax,%0" : "=rm" (myout) (* outputs *) : "rm" (foo), "rm" (bar) (* inputs *) - : "rax") ; (* we trash *) + : "eax") ; (* we trash *) RETURN( myout ) END Example ; @end example @@ -2720,10 +2720,10 @@ VAR myout: CARDINAL ; BEGIN ASM VOLATILE ( - "movq %[left],%%rax; addq %[right],%%rax; movq %%rax,%[output]" + "movl %[left],%%eax; addl %[right],%%eax; movl %%eax,%[output]" : [output] "=rm" (myout) (* outputs *) : [left] "rm" (foo), [right] "rm" (bar) (* inputs *) - : "rax") ; (* we trash *) + : "eax") ; (* we trash *) RETURN( myout ) END Example ; @end example diff --git a/gcc/doc/install.texi b/gcc/doc/install.texi index b5509ff..1af0082 100644 --- a/gcc/doc/install.texi +++ b/gcc/doc/install.texi @@ -350,6 +350,12 @@ documentation including the target @code{SYSTEM} definition module. If Python3 is unavailable Modula-2 documentation will include a target independent version of the SYSTEM modules. +@item @anchor{gccrs-prerequisite}gccrs + +The official Rust compiler and Rust build system (cargo) are required for +building various parts of the gccrs frontend, until gccrs can compile them +by itself. The minimum supported Rust version is 1.49. + @item A ``working'' POSIX compatible shell, or GNU bash Necessary when running @command{configure} because some diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index fbaa29f..020442a 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -593,7 +593,7 @@ Objective-C and Objective-C++ Dialects}. -finline-functions -finline-functions-called-once -finline-limit=@var{n} -finline-small-functions -fipa-modref -fipa-cp -fipa-cp-clone -fipa-bit-cp -fipa-vrp -fipa-pta -fipa-profile -fipa-pure-const --fipa-reference -fipa-reference-addressable +-fipa-reference -fipa-reference-addressable -fipa-reorder-for-locality -fipa-stack-alignment -fipa-icf -fira-algorithm=@var{algorithm} -flate-combine-instructions -flifetime-dse -flive-patching=@var{level} -fira-region=@var{region} -fira-hoist-pressure @@ -2199,6 +2199,7 @@ those that have already been displayed. If @option{--help} is also specified anywhere on the command line then this takes precedence over any @option{--help=} option. +@opindex Q If the @option{-Q} option appears on the command line before the @option{--help=} option, then the descriptive text displayed by @option{--help=} is changed. Instead of describing the displayed @@ -12746,6 +12747,7 @@ complexity than at @option{-O}. -fipa-pure-const -fipa-reference -fipa-reference-addressable +-fivopts -fmerge-constants -fmove-loop-invariants -fmove-loop-stores @@ -12854,6 +12856,13 @@ by @option{-O2} and also turns on the following optimization flags: Reduce compilation time and make debugging produce the expected results. This is the default. +At @option{-O0}, GCC completely disables most optimization passes; +they are not run even if you explicitly enable them on the command +line, or are listed by @option{-Q --help=optimizers} as being enabled by +default. Many optimizations performed by GCC depend on code analysis +or canonicalization passes that are enabled by @option{-O}, and it would +not be useful to run individual optimization passes in isolation. + @opindex Os @item -Os Optimize for size. @option{-Os} enables all @option{-O2} optimizations @@ -13871,6 +13880,21 @@ Enabled by default at @option{-O1} and higher. Discover read-only, write-only and non-addressable static variables. Enabled by default at @option{-O1} and higher. +@opindex fipa-reorder-for-locality +@item -fipa-reorder-for-locality +Group call chains close together in the binary layout to improve code +locality and minimize jump distances between frequently called functions. +Unlike @option{-freorder-functions} this pass considers the call +chains between functions and groups them together, rather than grouping all +hot/normal/cold/never-executed functions into separate sections. +Unlike @option{-fprofile-reorder-functions} it aims to improve code locality +throughout the runtime of the program rather than focusing on program startup. +This option is incompatible with an explicit +@option{-flto-partition=} option since it enforces a custom partitioning +scheme. +If using this option it is recommended to also use profile feedback, but this +option is not enabled by default otherwise. + @opindex fipa-stack-alignment @item -fipa-stack-alignment Reduce stack alignment on call sites if possible. @@ -14291,6 +14315,7 @@ Enabled by default at @option{-O1} and higher. @item -fivopts Perform induction variable optimizations (strength reduction, induction variable merging and induction variable elimination) on trees. +Enabled by default at @option{-O1} and higher. @opindex ftree-parallelize-loops @item -ftree-parallelize-loops=n @@ -14606,11 +14631,13 @@ Enabled for x86 at levels @option{-O2}, @option{-O3}, @option{-Os}. @opindex freorder-functions @item -freorder-functions Reorder functions in the object file in order to -improve code locality. This is implemented by using special -subsections @code{.text.hot} for most frequently executed functions and -@code{.text.unlikely} for unlikely executed functions. Reordering is done by -the linker so object file format must support named sections and linker must -place them in a reasonable way. +improve code locality. Unlike @option{-fipa-reorder-for-locality} this option +prioritises grouping all functions within a category +(hot/normal/cold/never-executed) together. +This is implemented by using special subsections @code{.text.hot} for most +frequently executed functions and @code{.text.unlikely} for unlikely executed +functions. Reordering is done by the linker so object file format must support +named sections and linker must place them in a reasonable way. This option isn't effective unless you either provide profile feedback (see @option{-fprofile-arcs} for details) or manually annotate functions with @@ -14622,12 +14649,14 @@ Enabled at levels @option{-O2}, @option{-O3}, @option{-Os}. @item -fstrict-aliasing Allow the compiler to assume the strictest aliasing rules applicable to the language being compiled. For C (and C++), this activates -optimizations based on the type of expressions. In particular, an -object of one type is assumed never to reside at the same address as an -object of a different type, unless the types are almost the same. For -example, an @code{unsigned int} can alias an @code{int}, but not a -@code{void*} or a @code{double}. A character type may alias any other -type. +optimizations based on the type of expressions. In particular, accessing +an object of one type via an expression of a different type is not allowed, +unless the types are @dfn{compatible types}, differ only in signedness or +qualifiers, or the expression has a character type. Accessing scalar +objects via a corresponding vector type is also allowed. + +For example, an @code{unsigned int} can alias an @code{int}, but not a +@code{void*} or a @code{double}. A character type may alias any other type. @anchor{Type-punning}Pay special attention to code like this: @smallexample @@ -15635,7 +15664,8 @@ Enabled by @option{-fprofile-generate}, @option{-fprofile-use}, and @item -fprofile-reorder-functions Function reordering based on profile instrumentation collects first time of execution of a function and orders these functions -in ascending order. +in ascending order, aiming to optimize program startup through more +efficient loading of text segments. Enabled with @option{-fprofile-use}. @@ -21284,8 +21314,13 @@ Toggle @option{-fvar-tracking-assignments}, in the same way that @opindex Q @item -Q -Makes the compiler print out each function name as it is compiled, and -print some statistics about each pass when it finishes. +When used on the command line prior to @option{--help=}, @option{-Q} +acts as a modifier to the help output. @xref{Overall Options}, +for details about @option{--help=}. + +Otherwise, this option makes the compiler print out each function name +as it is compiled, and print some statistics about each pass when it +finishes. @opindex ftime-report @item -ftime-report @@ -33344,7 +33379,7 @@ system representing a certain processor type. Possible values for @samp{z9-109}, @samp{z9-ec}/@samp{arch7}, @samp{z10}/@samp{arch8}, @samp{z196}/@samp{arch9}, @samp{zEC12}, @samp{z13}/@samp{arch11}, @samp{z14}/@samp{arch12}, @samp{z15}/@samp{arch13}, -@samp{z16}/@samp{arch14}, and @samp{native}. +@samp{z16}/@samp{arch14}, @samp{z17}/@samp{arch15}, and @samp{native}. The default is @option{-march=z900}. @@ -34872,7 +34907,7 @@ Intel Lakemont MCU, based on Intel Pentium CPU. Intel Pentium MMX CPU, based on Pentium core with MMX instruction set support. @item pentiumpro -Intel Pentium Pro CPU@. +Intel Pentium Pro CPU with no MMX support. @item i686 When used with @option{-march}, the Pentium Pro diff --git a/gcc/except.cc b/gcc/except.cc index d5eb927..0fe1e09 100644 --- a/gcc/except.cc +++ b/gcc/except.cc @@ -970,12 +970,26 @@ expand_dw2_landing_pad_for_region (eh_region region) { /* Nothing */ } if (region->exc_ptr_reg) - emit_move_insn (region->exc_ptr_reg, - gen_rtx_REG (ptr_mode, EH_RETURN_DATA_REGNO (0))); + { + rtx exc_ptr_reg; + if (EH_RETURN_DATA_REGNO (0) != INVALID_REGNUM) + exc_ptr_reg = gen_rtx_REG (ptr_mode, EH_RETURN_DATA_REGNO (0)); + else + /* The target must be doing something special. Submit a dummy. */ + exc_ptr_reg = constm1_rtx; + emit_move_insn (region->exc_ptr_reg, exc_ptr_reg); + } if (region->filter_reg) - emit_move_insn (region->filter_reg, - gen_rtx_REG (targetm.eh_return_filter_mode (), - EH_RETURN_DATA_REGNO (1))); + { + rtx filter_reg; + if (EH_RETURN_DATA_REGNO (1) != INVALID_REGNUM) + filter_reg = gen_rtx_REG (targetm.eh_return_filter_mode (), + EH_RETURN_DATA_REGNO (1)); + else + /* The target must be doing something special. Submit a dummy. */ + filter_reg = constm1_rtx; + emit_move_insn (region->filter_reg, filter_reg); + } } /* Expand the extra code needed at landing pads for dwarf2 unwinding. */ @@ -2935,7 +2949,14 @@ switch_to_exception_section (const char * ARG_UNUSED (fnname)) { section *s; - if (exception_section) + if (exception_section + /* Don't use the cached section for comdat if it will be different. */ +#ifdef HAVE_LD_EH_GC_SECTIONS + && !(targetm_common.have_named_sections + && DECL_COMDAT_GROUP (current_function_decl) + && HAVE_COMDAT_GROUP) +#endif + ) s = exception_section; else { diff --git a/gcc/expmed.cc b/gcc/expmed.cc index df09cbc..8cf10d9 100644 --- a/gcc/expmed.cc +++ b/gcc/expmed.cc @@ -285,7 +285,7 @@ init_expmed (void) for (speed = 0; speed < 2; speed++) { crtl->maybe_hot_insn_p = speed; - set_zero_cost (speed, set_src_cost (const0_rtx, mode, speed)); + set_zero_cost (speed, set_src_cost (const0_rtx, QImode, speed)); for (mode = MIN_MODE_INT; mode <= MAX_MODE_INT; mode = (machine_mode)(mode + 1)) diff --git a/gcc/flag-types.h b/gcc/flag-types.h index 0127698..db57376 100644 --- a/gcc/flag-types.h +++ b/gcc/flag-types.h @@ -404,7 +404,15 @@ enum lto_partition_model { LTO_PARTITION_BALANCED = 2, LTO_PARTITION_1TO1 = 3, LTO_PARTITION_MAX = 4, - LTO_PARTITION_CACHE = 5 + LTO_PARTITION_CACHE = 5, + LTO_PARTITION_DEFAULT= 6 +}; + +/* flag_lto_locality_cloning initialization values. */ +enum lto_locality_cloning_model { + LTO_LOCALITY_NO_CLONING = 0, + LTO_LOCALITY_NON_INTERPOSABLE_CLONING = 1, + LTO_LOCALITY_MAXIMAL_CLONING = 2, }; /* flag_lto_linker_output initialization values. */ diff --git a/gcc/fold-const.cc b/gcc/fold-const.cc index 1275ef7..c9471ea 100644 --- a/gcc/fold-const.cc +++ b/gcc/fold-const.cc @@ -7246,6 +7246,12 @@ tree_swap_operands_p (const_tree arg0, const_tree arg1) if (TREE_CONSTANT (arg0)) return true; + /* Put invariant address in arg1. */ + if (is_gimple_invariant_address (arg1)) + return false; + if (is_gimple_invariant_address (arg0)) + return true; + /* It is preferable to swap two SSA_NAME to ensure a canonical form for commutative and comparison operators. Ensuring a canonical form allows the optimizers to find additional redundancies without diff --git a/gcc/fortran/ChangeLog b/gcc/fortran/ChangeLog index 19a26ba..56325a9 100644 --- a/gcc/fortran/ChangeLog +++ b/gcc/fortran/ChangeLog @@ -1,3 +1,59 @@ +2025-04-19 Steven G. Kargl <kargl@gcc.gnu.org> + + PR fortran/119836 + * resolve.cc (check_pure_function): Fix checking for + an impure subprogram within a DO CONCURRENT construct. + (pure_subroutine): Ditto. + +2025-04-16 Harald Anlauf <anlauf@gmx.de> + + PR fortran/106948 + * resolve.cc (gfc_pure_function): If a function has been resolved, + but esym is not yet set, look at its attributes to see whether it + is pure or elemental. + +2025-04-15 Tobias Burnus <tburnus@baylibre.com> + + * f95-lang.cc (LANG_HOOKS_OMP_DEEP_MAPPING, + LANG_HOOKS_OMP_DEEP_MAPPING_P, LANG_HOOKS_OMP_DEEP_MAPPING_CNT): + Define. + * openmp.cc (gfc_match_omp_clause_reduction): Fix location setting. + (resolve_omp_clauses): Permit allocatable components, reject + them and polymorphic variables in PRIVATE/FIRSTPRIVATE. + * trans-decl.cc (add_clause): Set clause location. + * trans-openmp.cc (gfc_has_alloc_comps): Add ptr_ok and + shallow_alloc_only Boolean arguments. + (gfc_omp_replace_alloc_by_to_mapping): New. + (gfc_omp_private_outer_ref, gfc_walk_alloc_comps, + gfc_omp_clause_default_ctor, gfc_omp_clause_copy_ctor, + gfc_omp_clause_assign_op, gfc_omp_clause_dtor): Update call to it. + (gfc_omp_finish_clause): Minor cleanups, improve location data, + handle allocatable components. + (gfc_omp_deep_mapping_map, gfc_omp_deep_mapping_item, + gfc_omp_deep_mapping_comps, gfc_omp_gen_simple_loop, + gfc_omp_get_array_size, gfc_omp_elmental_loop, + gfc_omp_deep_map_kind_p, gfc_omp_deep_mapping_int_p, + gfc_omp_deep_mapping_p, gfc_omp_deep_mapping_do, + gfc_omp_deep_mapping_cnt, gfc_omp_deep_mapping): New. + (gfc_trans_omp_array_section): Save array descriptor in case + deep-mapping lang hook will need it. + (gfc_trans_omp_clauses): Likewise; use better clause location data. + * trans.h (gfc_omp_deep_mapping_p, gfc_omp_deep_mapping_cnt, + gfc_omp_deep_mapping): Add function prototypes. + +2025-04-13 Thomas Koenig <tkoenig@gcc.gnu.org> + + PR fortran/119669 + * interface.cc (compare_parameter): Error when mismatch between + formal argument as subroutine and function. If the dummy + argument is a known function, set its typespec. + +2025-04-12 Thomas Schwinge <tschwinge@baylibre.com> + + PR fortran/101602 + * trans-stmt.cc (gfc_trans_concurrent_locality_spec): Fix + 'static_assert'. + 2025-04-09 Harald Anlauf <anlauf@gmx.de> PR fortran/119656 diff --git a/gcc/fortran/f95-lang.cc b/gcc/fortran/f95-lang.cc index 124d62f..1f09553 100644 --- a/gcc/fortran/f95-lang.cc +++ b/gcc/fortran/f95-lang.cc @@ -148,6 +148,9 @@ gfc_get_sarif_source_language (const char *) #undef LANG_HOOKS_OMP_CLAUSE_LINEAR_CTOR #undef LANG_HOOKS_OMP_CLAUSE_DTOR #undef LANG_HOOKS_OMP_FINISH_CLAUSE +#undef LANG_HOOKS_OMP_DEEP_MAPPING +#undef LANG_HOOKS_OMP_DEEP_MAPPING_P +#undef LANG_HOOKS_OMP_DEEP_MAPPING_CNT #undef LANG_HOOKS_OMP_ALLOCATABLE_P #undef LANG_HOOKS_OMP_SCALAR_TARGET_P #undef LANG_HOOKS_OMP_SCALAR_P @@ -188,6 +191,9 @@ gfc_get_sarif_source_language (const char *) #define LANG_HOOKS_OMP_CLAUSE_LINEAR_CTOR gfc_omp_clause_linear_ctor #define LANG_HOOKS_OMP_CLAUSE_DTOR gfc_omp_clause_dtor #define LANG_HOOKS_OMP_FINISH_CLAUSE gfc_omp_finish_clause +#define LANG_HOOKS_OMP_DEEP_MAPPING gfc_omp_deep_mapping +#define LANG_HOOKS_OMP_DEEP_MAPPING_P gfc_omp_deep_mapping_p +#define LANG_HOOKS_OMP_DEEP_MAPPING_CNT gfc_omp_deep_mapping_cnt #define LANG_HOOKS_OMP_ALLOCATABLE_P gfc_omp_allocatable_p #define LANG_HOOKS_OMP_SCALAR_P gfc_omp_scalar_p #define LANG_HOOKS_OMP_SCALAR_TARGET_P gfc_omp_scalar_target_p diff --git a/gcc/fortran/interface.cc b/gcc/fortran/interface.cc index c702239..1e552a3 100644 --- a/gcc/fortran/interface.cc +++ b/gcc/fortran/interface.cc @@ -2534,16 +2534,33 @@ compare_parameter (gfc_symbol *formal, gfc_expr *actual, gfc_find_symbol (actual_name, gsym->ns, 0, &global_asym); if (global_asym != NULL) { - gcc_assert (formal->attr.function); - if (!gfc_compare_types (&global_asym->ts, &formal->ts)) + if (formal->attr.subroutine) { - gfc_error ("Type mismatch at %L passing global " - "function %qs declared at %L (%s/%s)", - &actual->where, actual_name, &gsym->where, - gfc_typename (&global_asym->ts), - gfc_dummy_typename (&formal->ts)); + gfc_error ("Mismatch between subroutine and " + "function at %L", &actual->where); return false; } + else if (formal->attr.function) + { + if (!gfc_compare_types (&global_asym->ts, + &formal->ts)) + { + gfc_error ("Type mismatch at %L passing global " + "function %qs declared at %L (%s/%s)", + &actual->where, actual_name, + &gsym->where, + gfc_typename (&global_asym->ts), + gfc_dummy_typename (&formal->ts)); + return false; + } + } + else + { + /* The global symbol is a function. Set the formal + argument acordingly. */ + formal->attr.function = 1; + formal->ts = global_asym->ts; + } } } } diff --git a/gcc/fortran/openmp.cc b/gcc/fortran/openmp.cc index ded80b7..df82940 100644 --- a/gcc/fortran/openmp.cc +++ b/gcc/fortran/openmp.cc @@ -1588,7 +1588,7 @@ gfc_match_omp_clause_reduction (char pc, gfc_omp_clauses *c, bool openacc, { gfc_omp_namelist *p = gfc_get_omp_namelist (), **tl; p->sym = n->sym; - p->where = p->where; + p->where = n->where; p->u.map.op = OMP_MAP_ALWAYS_TOFROM; tl = &c->lists[OMP_LIST_MAP]; @@ -9681,22 +9681,6 @@ resolve_omp_clauses (gfc_code *code, gfc_omp_clauses *omp_clauses, && n->sym->as->type == AS_ASSUMED_SIZE) gfc_error ("Assumed size array %qs in %s clause at %L", n->sym->name, name, &n->where); - if (!openacc - && list == OMP_LIST_MAP - && n->sym->ts.type == BT_DERIVED - && n->sym->ts.u.derived->attr.alloc_comp) - gfc_error ("List item %qs with allocatable components is not " - "permitted in map clause at %L", n->sym->name, - &n->where); - if (!openacc - && (list == OMP_LIST_MAP - || list == OMP_LIST_FROM - || list == OMP_LIST_TO) - && ((n->expr && n->expr->ts.type == BT_CLASS) - || (!n->expr && n->sym->ts.type == BT_CLASS))) - gfc_warning (OPT_Wopenmp, - "Mapping polymorphic list item at %L is " - "unspecified behavior", &n->where); if (list == OMP_LIST_MAP && !openacc) switch (code->op) { @@ -10008,9 +9992,11 @@ resolve_omp_clauses (gfc_code *code, gfc_omp_clauses *omp_clauses, n->sym->name, name, &n->where); if (!openacc - && list == OMP_LIST_FIRSTPRIVATE - && ((n->expr && n->expr->ts.type == BT_CLASS) - || (!n->expr && n->sym->ts.type == BT_CLASS))) + && (list == OMP_LIST_PRIVATE + || list == OMP_LIST_FIRSTPRIVATE) + && ((n->sym->ts.type == BT_DERIVED + && n->sym->ts.u.derived->attr.alloc_comp) + || n->sym->ts.type == BT_CLASS)) switch (code->op) { case EXEC_OMP_TARGET: @@ -10025,9 +10011,19 @@ resolve_omp_clauses (gfc_code *code, gfc_omp_clauses *omp_clauses, case EXEC_OMP_TARGET_TEAMS_DISTRIBUTE_PARALLEL_DO_SIMD: case EXEC_OMP_TARGET_TEAMS_DISTRIBUTE_SIMD: case EXEC_OMP_TARGET_TEAMS_LOOP: - gfc_warning (OPT_Wopenmp, - "FIRSTPRIVATE with polymorphic list item at " - "%L is unspecified behavior", &n->where); + if (n->sym->ts.type == BT_DERIVED + && n->sym->ts.u.derived->attr.alloc_comp) + gfc_error ("Sorry, list item %qs at %L with allocatable" + " components is not yet supported in %s " + "clause", n->sym->name, &n->where, + list == OMP_LIST_PRIVATE ? "PRIVATE" + : "FIRSTPRIVATE"); + else + gfc_error ("Polymorphic list item %qs at %L in %s " + "clause has unspecified behavior and " + "unsupported", n->sym->name, &n->where, + list == OMP_LIST_PRIVATE ? "PRIVATE" + : "FIRSTPRIVATE"); break; default: break; diff --git a/gcc/fortran/resolve.cc b/gcc/fortran/resolve.cc index cdf043b..f03708e 100644 --- a/gcc/fortran/resolve.cc +++ b/gcc/fortran/resolve.cc @@ -3190,6 +3190,13 @@ gfc_pure_function (gfc_expr *e, const char **name) || e->value.function.isym->elemental; *name = e->value.function.isym->name; } + else if (e->symtree && e->symtree->n.sym && e->symtree->n.sym->attr.dummy) + { + /* The function has been resolved, but esym is not yet set. + This can happen with functions as dummy argument. */ + pure = e->symtree->n.sym->attr.pure; + *name = e->symtree->n.sym->name; + } else { /* Implicit functions are not pure. */ @@ -3253,14 +3260,30 @@ static bool check_pure_function (gfc_expr *e) gfc_do_concurrent_flag = 0 when the check for an impure function occurs. Check the stack to see if the source code has a nested BLOCK construct. */ + for (stack = cs_base; stack; stack = stack->prev) { - if (stack->current->op == EXEC_BLOCK) saw_block = true; + if (!saw_block && stack->current->op == EXEC_BLOCK) + { + saw_block = true; + continue; + } + if (saw_block && stack->current->op == EXEC_DO_CONCURRENT) { - gfc_error ("Reference to impure function at %L inside a " - "DO CONCURRENT", &e->where); - return false; + bool is_pure; + is_pure = (e->value.function.isym + && (e->value.function.isym->pure + || e->value.function.isym->elemental)) + || (e->value.function.esym + && (e->value.function.esym->attr.pure + || e->value.function.esym->attr.elemental)); + if (!is_pure) + { + gfc_error ("Reference to impure function at %L inside a " + "DO CONCURRENT", &e->where); + return false; + } } } @@ -3656,16 +3679,29 @@ pure_subroutine (gfc_symbol *sym, const char *name, locus *loc) /* A BLOCK construct within a DO CONCURRENT construct leads to gfc_do_concurrent_flag = 0 when the check for an impure subroutine - occurs. Check the stack to see if the source code has a nested - BLOCK construct. */ + occurs. Walk up the stack to see if the source code has a nested + construct. */ + for (stack = cs_base; stack; stack = stack->prev) { - if (stack->current->op == EXEC_BLOCK) saw_block = true; + if (stack->current->op == EXEC_BLOCK) + { + saw_block = true; + continue; + } + if (saw_block && stack->current->op == EXEC_DO_CONCURRENT) { - gfc_error ("Subroutine call at %L in a DO CONCURRENT block " - "is not PURE", loc); - return false; + + bool is_pure = true; + is_pure = sym->attr.pure || sym->attr.elemental; + + if (!is_pure) + { + gfc_error ("Subroutine call at %L in a DO CONCURRENT block " + "is not PURE", loc); + return false; + } } } diff --git a/gcc/fortran/trans-decl.cc b/gcc/fortran/trans-decl.cc index aea132d..ddc4960 100644 --- a/gcc/fortran/trans-decl.cc +++ b/gcc/fortran/trans-decl.cc @@ -6920,6 +6920,7 @@ add_clause (gfc_symbol *sym, gfc_omp_map_op map_op) n = gfc_get_omp_namelist (); n->sym = sym; + n->where = sym->declared_at; n->u.map.op = map_op; if (!module_oacc_clauses) diff --git a/gcc/fortran/trans-openmp.cc b/gcc/fortran/trans-openmp.cc index 03d9432..0b8150f 100644 --- a/gcc/fortran/trans-openmp.cc +++ b/gcc/fortran/trans-openmp.cc @@ -25,6 +25,10 @@ along with GCC; see the file COPYING3. If not see #include "options.h" #include "tree.h" #include "gfortran.h" +#include "basic-block.h" +#include "tree-ssa.h" +#include "function.h" +#include "gimple.h" #include "gimple-expr.h" #include "trans.h" #include "stringpool.h" @@ -41,6 +45,8 @@ along with GCC; see the file COPYING3. If not see #include "omp-low.h" #include "memmodel.h" /* For MEMMODEL_ enums. */ #include "dependency.h" +#include "gimple-iterator.h" /* For gsi_iterator_update. */ +#include "gimplify-me.h" /* For force_gimple_operand. */ #undef GCC_DIAG_STYLE #define GCC_DIAG_STYLE __gcc_tdiag__ @@ -375,22 +381,28 @@ gfc_omp_report_decl (tree decl) return decl; } -/* Return true if TYPE has any allocatable components. */ +/* Return true if TYPE has any allocatable components; + if ptr_ok, the decl itself is permitted to have the POINTER attribute. + if shallow_alloc_only, returns only true if any of the fields is an + allocatable; called with true by gfc_omp_replace_alloc_by_to_mapping. */ static bool -gfc_has_alloc_comps (tree type, tree decl) +gfc_has_alloc_comps (tree type, tree decl, bool ptr_ok, + bool shallow_alloc_only=false) { tree field, ftype; if (POINTER_TYPE_P (type)) { - if (GFC_DECL_GET_SCALAR_ALLOCATABLE (decl)) + if (GFC_DECL_GET_SCALAR_ALLOCATABLE (decl) + || (ptr_ok && GFC_DECL_GET_SCALAR_POINTER (decl))) type = TREE_TYPE (type); else if (GFC_DECL_GET_SCALAR_POINTER (decl)) return false; } - if (GFC_DESCRIPTOR_TYPE_P (type) + if (!ptr_ok + && GFC_DESCRIPTOR_TYPE_P (type) && (GFC_TYPE_ARRAY_AKIND (type) == GFC_ARRAY_POINTER || GFC_TYPE_ARRAY_AKIND (type) == GFC_ARRAY_POINTER_CONT)) return false; @@ -409,12 +421,51 @@ gfc_has_alloc_comps (tree type, tree decl) if (GFC_DESCRIPTOR_TYPE_P (ftype) && GFC_TYPE_ARRAY_AKIND (ftype) == GFC_ARRAY_ALLOCATABLE) return true; - if (gfc_has_alloc_comps (ftype, field)) + if (!shallow_alloc_only + && gfc_has_alloc_comps (ftype, field, false)) return true; } return false; } +/* gfc_omp_replace_alloc_by_to_mapping is used with gfc_omp_deep_mapping... to + handle the following: + + For map(alloc: dt), the array descriptors of allocatable components should + be mapped as 'to'; this could be done by (A) adding 'map(to: dt%alloc_comp)' + for each component (and avoiding to increment the reference count). + Or (B) by just mapping all of 'dt' as 'to'. + + If 'dt' contains several allocatable components and not much other data, + (A) is more efficient. If 'dt' contains a large const-size array, (A) will + copy it to the device instead of only 'alloc'ating it. + + IMPLEMENTATION CHOICE: We do (A). It avoids the ref-count issue and it is + expected that, for real-world code, derived types with allocatable + components only have few other components and either no const-size arrays. + This copying is done irrespectively whether the allocatables are allocated. + + If users wanted to save memory, they have to use 'map(alloc:dt%comp)' as + also with 'map(alloc:dt)' all components get copied. + + For the copy to the device, only allocatable arrays are relevant as their + the bounds are required; the pointer is set separately (GOMP_MAP_ATTACH) + and the only setting required for scalars. However, when later copying out + of the device, an unallocated allocatable must remain unallocated/NULL on + the host; to achieve this we also must have it set to NULL on the device + to avoid issues with uninitialized memory being copied back for the pointer + address. If we could set the pointer to NULL, gfc_has_alloc_comps's + shallow_alloc_only could be restricted to return true only for arrays. + + We only need to return true if there are allocatable-array components. */ + +static bool +gfc_omp_replace_alloc_by_to_mapping (tree type, tree decl, bool ptr_ok) +{ + return gfc_has_alloc_comps (type, decl, ptr_ok, true); +} + + /* Return true if TYPE is polymorphic but not with pointer attribute. */ static bool @@ -487,7 +538,7 @@ gfc_omp_private_outer_ref (tree decl) if (GFC_DECL_GET_SCALAR_ALLOCATABLE (decl)) return true; - if (gfc_has_alloc_comps (type, decl)) + if (gfc_has_alloc_comps (type, decl, false)) return true; return false; @@ -627,7 +678,7 @@ gfc_walk_alloc_comps (tree decl, tree dest, tree var, { tree ftype = TREE_TYPE (field); tree declf, destf = NULL_TREE; - bool has_alloc_comps = gfc_has_alloc_comps (ftype, field); + bool has_alloc_comps = gfc_has_alloc_comps (ftype, field, false); if ((!GFC_DESCRIPTOR_TYPE_P (ftype) || GFC_TYPE_ARRAY_AKIND (ftype) != GFC_ARRAY_ALLOCATABLE) && !GFC_DECL_GET_SCALAR_ALLOCATABLE (field) @@ -751,7 +802,7 @@ gfc_omp_clause_default_ctor (tree clause, tree decl, tree outer) && (!GFC_DECL_GET_SCALAR_ALLOCATABLE (OMP_CLAUSE_DECL (clause)) || !POINTER_TYPE_P (type))) { - if (gfc_has_alloc_comps (type, OMP_CLAUSE_DECL (clause))) + if (gfc_has_alloc_comps (type, OMP_CLAUSE_DECL (clause), false)) { gcc_assert (outer); gfc_start_block (&block); @@ -804,7 +855,7 @@ gfc_omp_clause_default_ctor (tree clause, tree decl, tree outer) else gfc_add_modify (&cond_block, unshare_expr (decl), fold_convert (TREE_TYPE (decl), ptr)); - if (gfc_has_alloc_comps (type, OMP_CLAUSE_DECL (clause))) + if (gfc_has_alloc_comps (type, OMP_CLAUSE_DECL (clause), false)) { tree tem = gfc_walk_alloc_comps (outer, decl, OMP_CLAUSE_DECL (clause), @@ -945,7 +996,7 @@ gfc_omp_clause_copy_ctor (tree clause, tree dest, tree src) && (!GFC_DECL_GET_SCALAR_ALLOCATABLE (OMP_CLAUSE_DECL (clause)) || !POINTER_TYPE_P (type))) { - if (gfc_has_alloc_comps (type, OMP_CLAUSE_DECL (clause))) + if (gfc_has_alloc_comps (type, OMP_CLAUSE_DECL (clause), false)) { gfc_start_block (&block); gfc_add_modify (&block, dest, src); @@ -1004,7 +1055,7 @@ gfc_omp_clause_copy_ctor (tree clause, tree dest, tree src) builtin_decl_explicit (BUILT_IN_MEMCPY), 3, ptr, srcptr, size); gfc_add_expr_to_block (&cond_block, fold_convert (void_type_node, call)); - if (gfc_has_alloc_comps (type, OMP_CLAUSE_DECL (clause))) + if (gfc_has_alloc_comps (type, OMP_CLAUSE_DECL (clause), false)) { tree tem = gfc_walk_alloc_comps (src, dest, OMP_CLAUSE_DECL (clause), @@ -1049,7 +1100,7 @@ gfc_omp_clause_assign_op (tree clause, tree dest, tree src) && (!GFC_DECL_GET_SCALAR_ALLOCATABLE (OMP_CLAUSE_DECL (clause)) || !POINTER_TYPE_P (type))) { - if (gfc_has_alloc_comps (type, OMP_CLAUSE_DECL (clause))) + if (gfc_has_alloc_comps (type, OMP_CLAUSE_DECL (clause), false)) { gfc_start_block (&block); /* First dealloc any allocatable components in DEST. */ @@ -1071,7 +1122,7 @@ gfc_omp_clause_assign_op (tree clause, tree dest, tree src) gfc_start_block (&block); - if (gfc_has_alloc_comps (type, OMP_CLAUSE_DECL (clause))) + if (gfc_has_alloc_comps (type, OMP_CLAUSE_DECL (clause), false)) { then_b = gfc_walk_alloc_comps (dest, NULL_TREE, OMP_CLAUSE_DECL (clause), WALK_ALLOC_COMPS_DTOR); @@ -1186,7 +1237,7 @@ gfc_omp_clause_assign_op (tree clause, tree dest, tree src) builtin_decl_explicit (BUILT_IN_MEMCPY), 3, ptr, srcptr, size); gfc_add_expr_to_block (&cond_block, fold_convert (void_type_node, call)); - if (gfc_has_alloc_comps (type, OMP_CLAUSE_DECL (clause))) + if (gfc_has_alloc_comps (type, OMP_CLAUSE_DECL (clause), false)) { tree tem = gfc_walk_alloc_comps (src, dest, OMP_CLAUSE_DECL (clause), @@ -1438,7 +1489,7 @@ gfc_omp_clause_dtor (tree clause, tree decl) && (!GFC_DECL_GET_SCALAR_ALLOCATABLE (OMP_CLAUSE_DECL (clause)) || !POINTER_TYPE_P (type))) { - if (gfc_has_alloc_comps (type, OMP_CLAUSE_DECL (clause))) + if (gfc_has_alloc_comps (type, OMP_CLAUSE_DECL (clause), false)) return gfc_walk_alloc_comps (decl, NULL_TREE, OMP_CLAUSE_DECL (clause), WALK_ALLOC_COMPS_DTOR); @@ -1458,7 +1509,7 @@ gfc_omp_clause_dtor (tree clause, tree decl) tem = gfc_call_free (decl); tem = gfc_omp_unshare_expr (tem); - if (gfc_has_alloc_comps (type, OMP_CLAUSE_DECL (clause))) + if (gfc_has_alloc_comps (type, OMP_CLAUSE_DECL (clause), false)) { stmtblock_t block; tree then_b; @@ -1538,6 +1589,7 @@ gfc_omp_finish_clause (tree c, gimple_seq *pre_p, bool openacc) return; tree decl = OMP_CLAUSE_DECL (c); + location_t loc = OMP_CLAUSE_LOCATION (c); /* Assumed-size arrays can't be mapped implicitly, they have to be mapped explicitly using array sections. */ @@ -1553,13 +1605,9 @@ gfc_omp_finish_clause (tree c, gimple_seq *pre_p, bool openacc) return; } - if (!openacc && GFC_CLASS_TYPE_P (TREE_TYPE (decl))) - warning_at (OMP_CLAUSE_LOCATION (c), OPT_Wopenmp, - "Implicit mapping of polymorphic variable %qD is " - "unspecified behavior", decl); - tree c2 = NULL_TREE, c3 = NULL_TREE, c4 = NULL_TREE; tree present = gfc_omp_check_optional_argument (decl, true); + tree orig_decl = NULL_TREE; if (POINTER_TYPE_P (TREE_TYPE (decl))) { if (!gfc_omp_privatize_by_reference (decl) @@ -1568,7 +1616,7 @@ gfc_omp_finish_clause (tree c, gimple_seq *pre_p, bool openacc) && !GFC_DECL_CRAY_POINTEE (decl) && !GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (TREE_TYPE (decl)))) return; - tree orig_decl = decl; + orig_decl = decl; c4 = build_omp_clause (OMP_CLAUSE_LOCATION (c), OMP_CLAUSE_MAP); OMP_CLAUSE_SET_MAP_KIND (c4, GOMP_MAP_POINTER); @@ -1579,16 +1627,16 @@ gfc_omp_finish_clause (tree c, gimple_seq *pre_p, bool openacc) && (GFC_DECL_GET_SCALAR_POINTER (orig_decl) || GFC_DECL_GET_SCALAR_ALLOCATABLE (orig_decl))) { - c2 = build_omp_clause (input_location, OMP_CLAUSE_MAP); + c2 = build_omp_clause (loc, OMP_CLAUSE_MAP); OMP_CLAUSE_SET_MAP_KIND (c2, GOMP_MAP_POINTER); - OMP_CLAUSE_DECL (c2) = decl; + OMP_CLAUSE_DECL (c2) = unshare_expr (decl); OMP_CLAUSE_SIZE (c2) = size_int (0); stmtblock_t block; gfc_start_block (&block); - tree ptr = decl; - ptr = gfc_build_cond_assign_expr (&block, present, decl, - null_pointer_node); + tree ptr = gfc_build_cond_assign_expr (&block, present, + unshare_expr (decl), + null_pointer_node); gimplify_and_add (gfc_finish_block (&block), pre_p); ptr = build_fold_indirect_ref (ptr); OMP_CLAUSE_DECL (c) = ptr; @@ -1605,10 +1653,10 @@ gfc_omp_finish_clause (tree c, gimple_seq *pre_p, bool openacc) { c3 = build_omp_clause (OMP_CLAUSE_LOCATION (c), OMP_CLAUSE_MAP); OMP_CLAUSE_SET_MAP_KIND (c3, GOMP_MAP_POINTER); - OMP_CLAUSE_DECL (c3) = unshare_expr (decl); + OMP_CLAUSE_DECL (c3) = decl; OMP_CLAUSE_SIZE (c3) = size_int (0); decl = build_fold_indirect_ref (decl); - OMP_CLAUSE_DECL (c) = decl; + OMP_CLAUSE_DECL (c) = unshare_expr (decl); } } if (GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (decl))) @@ -1634,7 +1682,7 @@ gfc_omp_finish_clause (tree c, gimple_seq *pre_p, bool openacc) gcc_assert (POINTER_TYPE_P (TREE_TYPE (ptr))); ptr = build_fold_indirect_ref (ptr); OMP_CLAUSE_DECL (c) = ptr; - c2 = build_omp_clause (input_location, OMP_CLAUSE_MAP); + c2 = build_omp_clause (loc, OMP_CLAUSE_MAP); OMP_CLAUSE_SET_MAP_KIND (c2, GOMP_MAP_TO_PSET); if (present) { @@ -1651,7 +1699,7 @@ gfc_omp_finish_clause (tree c, gimple_seq *pre_p, bool openacc) : GOMP_MAP_POINTER); if (present) { - ptr = gfc_conv_descriptor_data_get (decl); + ptr = gfc_conv_descriptor_data_get (unshare_expr (decl)); ptr = gfc_build_addr_expr (NULL, ptr); ptr = gfc_build_cond_assign_expr (&block, present, ptr, null_pointer_node); @@ -1664,6 +1712,17 @@ gfc_omp_finish_clause (tree c, gimple_seq *pre_p, bool openacc) tree size = create_tmp_var (gfc_array_index_type); tree elemsz = TYPE_SIZE_UNIT (gfc_get_element_type (type)); elemsz = fold_convert (gfc_array_index_type, elemsz); + + if (orig_decl == NULL_TREE) + orig_decl = decl; + if (!openacc + && gfc_has_alloc_comps (type, orig_decl, true)) + { + /* Save array descriptor for use in gfc_omp_deep_mapping{,_p,_cnt}; + force evaluate to ensure that it is not gimplified + is a decl. */ + gfc_allocate_lang_decl (size); + GFC_DECL_SAVED_DESCRIPTOR (size) = orig_decl; + } enum gfc_array_kind akind = GFC_TYPE_ARRAY_AKIND (type); if (akind == GFC_ARRAY_ALLOCATABLE || akind == GFC_ARRAY_POINTER @@ -1692,14 +1751,14 @@ gfc_omp_finish_clause (tree c, gimple_seq *pre_p, bool openacc) else_b = gfc_finish_block (&cond_block); tem = gfc_conv_descriptor_data_get (unshare_expr (decl)); tem = fold_convert (pvoid_type_node, tem); - cond = fold_build2_loc (input_location, NE_EXPR, + cond = fold_build2_loc (loc, NE_EXPR, boolean_type_node, tem, null_pointer_node); if (present) { - cond = fold_build2_loc (input_location, TRUTH_ANDIF_EXPR, + cond = fold_build2_loc (loc, TRUTH_ANDIF_EXPR, boolean_type_node, present, cond); } - gfc_add_expr_to_block (&block, build3_loc (input_location, COND_EXPR, + gfc_add_expr_to_block (&block, build3_loc (loc, COND_EXPR, void_type_node, cond, then_b, else_b)); } @@ -1739,11 +1798,30 @@ gfc_omp_finish_clause (tree c, gimple_seq *pre_p, bool openacc) tree stmt = gfc_finish_block (&block); gimplify_and_add (stmt, pre_p); } + else + { + if (OMP_CLAUSE_SIZE (c) == NULL_TREE) + OMP_CLAUSE_SIZE (c) + = DECL_P (decl) ? DECL_SIZE_UNIT (decl) + : TYPE_SIZE_UNIT (TREE_TYPE (decl)); + + tree type = TREE_TYPE (decl); + if (POINTER_TYPE_P (type) && POINTER_TYPE_P (TREE_TYPE (type))) + type = TREE_TYPE (type); + if (!openacc + && orig_decl != NULL_TREE + && gfc_has_alloc_comps (type, orig_decl, true)) + { + /* Save array descriptor for use in gfc_omp_deep_mapping{,_p,_cnt}; + force evaluate to ensure that it is not gimplified + is a decl. */ + tree size = create_tmp_var (TREE_TYPE (OMP_CLAUSE_SIZE (c))); + gfc_allocate_lang_decl (size); + GFC_DECL_SAVED_DESCRIPTOR (size) = orig_decl; + gimplify_assign (size, OMP_CLAUSE_SIZE (c), pre_p); + OMP_CLAUSE_SIZE (c) = size; + } + } tree last = c; - if (OMP_CLAUSE_SIZE (c) == NULL_TREE) - OMP_CLAUSE_SIZE (c) - = DECL_P (decl) ? DECL_SIZE_UNIT (decl) - : TYPE_SIZE_UNIT (TREE_TYPE (decl)); if (gimplify_expr (&OMP_CLAUSE_SIZE (c), pre_p, NULL, is_gimple_val, fb_rvalue) == GS_ERROR) OMP_CLAUSE_SIZE (c) = size_int (0); @@ -1767,6 +1845,715 @@ gfc_omp_finish_clause (tree c, gimple_seq *pre_p, bool openacc) } +/* map(<flag>: data [len: <size>]) + map(attach: &data [bias: <bias>]) + offset += 2; offset_data += 2 */ +static void +gfc_omp_deep_mapping_map (tree data, tree size, unsigned HOST_WIDE_INT tkind, + location_t loc, tree data_array, tree sizes_array, + tree kinds_array, tree offset_data, tree offset, + gimple_seq *seq, const gimple *ctx) +{ + tree one = build_int_cst (size_type_node, 1); + + STRIP_NOPS (data); + if (!POINTER_TYPE_P (TREE_TYPE (data))) + { + gcc_assert (TREE_CODE (data) == INDIRECT_REF); + data = TREE_OPERAND (data, 0); + } + + /* data_array[offset_data] = data; */ + tree tmp = build4 (ARRAY_REF, TREE_TYPE (TREE_TYPE (data_array)), + unshare_expr (data_array), offset_data, + NULL_TREE, NULL_TREE); + gimplify_assign (tmp, data, seq); + + /* offset_data++ */ + tmp = build2_loc (loc, PLUS_EXPR, size_type_node, offset_data, one); + gimplify_assign (offset_data, tmp, seq); + + /* data_array[offset_data] = &data; */ + tmp = build4 (ARRAY_REF, TREE_TYPE (TREE_TYPE (data_array)), + unshare_expr (data_array), + offset_data, NULL_TREE, NULL_TREE); + gimplify_assign (tmp, build_fold_addr_expr (data), seq); + + /* offset_data++ */ + tmp = build2_loc (loc, PLUS_EXPR, size_type_node, offset_data, one); + gimplify_assign (offset_data, tmp, seq); + + /* sizes_array[offset] = size */ + tmp = build2_loc (loc, MULT_EXPR, size_type_node, + TYPE_SIZE_UNIT (size_type_node), offset); + tmp = build2_loc (loc, POINTER_PLUS_EXPR, TREE_TYPE (sizes_array), + sizes_array, tmp); + gimple_seq seq2 = NULL; + tmp = force_gimple_operand (tmp, &seq2, true, NULL_TREE); + gimple_seq_add_seq (seq, seq2); + tmp = build_fold_indirect_ref_loc (loc, tmp); + gimplify_assign (tmp, size, seq); + + /* FIXME: tkind |= talign << talign_shift; */ + /* kinds_array[offset] = tkind. */ + tmp = build2_loc (loc, MULT_EXPR, size_type_node, + TYPE_SIZE_UNIT (short_unsigned_type_node), offset); + tmp = build2_loc (loc, POINTER_PLUS_EXPR, TREE_TYPE (kinds_array), + kinds_array, tmp); + seq2 = NULL; + tmp = force_gimple_operand (tmp, &seq2, true, NULL_TREE); + gimple_seq_add_seq (seq, seq2); + tmp = build_fold_indirect_ref_loc (loc, tmp); + gimplify_assign (tmp, build_int_cst (short_unsigned_type_node, tkind), seq); + + /* offset++ */ + tmp = build2_loc (loc, PLUS_EXPR, size_type_node, offset, one); + gimplify_assign (offset, tmp, seq); + + /* sizes_array[offset] = bias (= 0). */ + tmp = build2_loc (loc, MULT_EXPR, size_type_node, + TYPE_SIZE_UNIT (size_type_node), offset); + tmp = build2_loc (loc, POINTER_PLUS_EXPR, TREE_TYPE (sizes_array), + sizes_array, tmp); + seq2 = NULL; + tmp = force_gimple_operand (tmp, &seq2, true, NULL_TREE); + gimple_seq_add_seq (seq, seq2); + tmp = build_fold_indirect_ref_loc (loc, tmp); + gimplify_assign (tmp, build_zero_cst (size_type_node), seq); + + gcc_assert (gimple_code (ctx) == GIMPLE_OMP_TARGET); + tkind = (gimple_omp_target_kind (ctx) == GF_OMP_TARGET_KIND_EXIT_DATA + ? GOMP_MAP_DETACH : GOMP_MAP_ATTACH); + + /* kinds_array[offset] = tkind. */ + tmp = build2_loc (loc, MULT_EXPR, size_type_node, + TYPE_SIZE_UNIT (short_unsigned_type_node), offset); + tmp = build2_loc (loc, POINTER_PLUS_EXPR, TREE_TYPE (kinds_array), + kinds_array, tmp); + seq2 = NULL; + tmp = force_gimple_operand (tmp, &seq2, true, NULL_TREE); + gimple_seq_add_seq (seq, seq2); + tmp = build_fold_indirect_ref_loc (loc, tmp); + gimplify_assign (tmp, build_int_cst (short_unsigned_type_node, tkind), seq); + + /* offset++ */ + tmp = build2_loc (loc, PLUS_EXPR, size_type_node, offset, one); + gimplify_assign (offset, tmp, seq); +} + +static void gfc_omp_deep_mapping_item (bool, bool, bool, location_t, tree, + tree *, unsigned HOST_WIDE_INT, tree, + tree, tree, tree, tree, tree, + gimple_seq *, const gimple *, bool *); + +/* Map allocatable components. */ +static void +gfc_omp_deep_mapping_comps (bool is_cnt, location_t loc, tree decl, + tree *token, unsigned HOST_WIDE_INT tkind, + tree data_array, tree sizes_array, tree kinds_array, + tree offset_data, tree offset, tree num, + gimple_seq *seq, const gimple *ctx, + bool *poly_warned) +{ + tree type = TREE_TYPE (decl); + if (TREE_CODE (type) != RECORD_TYPE) + return; + for (tree field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field)) + { + type = TREE_TYPE (field); + if (gfc_is_polymorphic_nonptr (type) + || GFC_DECL_GET_SCALAR_ALLOCATABLE (field) + || (GFC_DESCRIPTOR_TYPE_P (type) + && GFC_TYPE_ARRAY_AKIND (type) == GFC_ARRAY_ALLOCATABLE)) + { + tree tmp = fold_build3_loc (loc, COMPONENT_REF, TREE_TYPE (field), + decl, field, NULL_TREE); + gfc_omp_deep_mapping_item (is_cnt, true, true, loc, tmp, token, + tkind, data_array, sizes_array, + kinds_array, offset_data, offset, num, + seq, ctx, poly_warned); + } + else if (GFC_DECL_GET_SCALAR_POINTER (field) + || GFC_DESCRIPTOR_TYPE_P (type)) + continue; + else if (gfc_has_alloc_comps (TREE_TYPE (field), field, false)) + { + tree tmp = fold_build3_loc (loc, COMPONENT_REF, TREE_TYPE (field), + decl, field, NULL_TREE); + if (TREE_CODE (TREE_TYPE (tmp)) == ARRAY_TYPE) + gfc_omp_deep_mapping_item (is_cnt, false, false, loc, tmp, + token, tkind, data_array, sizes_array, + kinds_array, offset_data, offset, num, + seq, ctx, poly_warned); + else + gfc_omp_deep_mapping_comps (is_cnt, loc, tmp, token, tkind, + data_array, sizes_array, kinds_array, + offset_data, offset, num, seq, ctx, + poly_warned); + } + } +} + +static void +gfc_omp_gen_simple_loop (tree var, tree begin, tree end, enum tree_code cond, + tree step, location_t loc, gimple_seq *seq1, + gimple_seq *seq2) +{ + tree tmp; + + /* var = begin. */ + gimplify_assign (var, begin, seq1); + + /* Loop: for (var = begin; var <cond> end; var += step). */ + tree label_loop = create_artificial_label (loc); + tree label_cond = create_artificial_label (loc); + + gimplify_and_add (fold_build1_loc (loc, GOTO_EXPR, void_type_node, + label_cond), seq1); + gimple_seq_add_stmt (seq1, gimple_build_label (label_loop)); + + /* Everything above is seq1; place loop body here. */ + + /* End of loop body -> put into seq2. */ + tmp = fold_build2_loc (loc, PLUS_EXPR, TREE_TYPE (var), var, step); + gimplify_assign (var, tmp, seq2); + gimple_seq_add_stmt (seq2, gimple_build_label (label_cond)); + tmp = fold_build2_loc (loc, cond, boolean_type_node, var, end); + tmp = build3_v (COND_EXPR, tmp, build1_v (GOTO_EXPR, label_loop), + build_empty_stmt (loc)); + gimplify_and_add (tmp, seq2); +} + +/* Return size variable with the size of an array. */ +static tree +gfc_omp_get_array_size (location_t loc, tree desc, gimple_seq *seq) +{ + tree tmp; + gimple_seq seq1 = NULL, seq2 = NULL; + tree size = build_decl (loc, VAR_DECL, create_tmp_var_name ("size"), + size_type_node); + tree extent = build_decl (loc, VAR_DECL, create_tmp_var_name ("extent"), + gfc_array_index_type); + tree idx = build_decl (loc, VAR_DECL, create_tmp_var_name ("idx"), + signed_char_type_node); + + tree begin = build_zero_cst (signed_char_type_node); + tree end; + if (GFC_TYPE_ARRAY_AKIND (TREE_TYPE (desc)) == GFC_ARRAY_ASSUMED_SHAPE_CONT + || GFC_TYPE_ARRAY_AKIND (TREE_TYPE (desc)) == GFC_ARRAY_ASSUMED_SHAPE) + end = gfc_conv_descriptor_rank (desc); + else + end = build_int_cst (signed_char_type_node, + GFC_TYPE_ARRAY_RANK (TREE_TYPE (desc))); + tree step = build_int_cst (signed_char_type_node, 1); + + /* size = 0 + for (idx = 0; idx < rank; idx++) + extent = gfc->dim[i].ubound - gfc->dim[i].lbound + 1 + if (extent < 0) extent = 0 + size *= extent. */ + gimplify_assign (size, build_int_cst (size_type_node, 1), seq); + + gfc_omp_gen_simple_loop (idx, begin, end, LT_EXPR, step, loc, &seq1, &seq2); + gimple_seq_add_seq (seq, seq1); + + tmp = fold_build2_loc (loc, MINUS_EXPR, gfc_array_index_type, + gfc_conv_descriptor_ubound_get (desc, idx), + gfc_conv_descriptor_lbound_get (desc, idx)); + tmp = fold_build2_loc (loc, PLUS_EXPR, gfc_array_index_type, + tmp, gfc_index_one_node); + gimplify_assign (extent, tmp, seq); + tmp = fold_build2_loc (loc, LT_EXPR, boolean_type_node, + extent, gfc_index_zero_node); + tmp = build3_v (COND_EXPR, tmp, + fold_build2_loc (loc, MODIFY_EXPR, + gfc_array_index_type, + extent, gfc_index_zero_node), + build_empty_stmt (loc)); + gimplify_and_add (tmp, seq); + /* size *= extent. */ + gimplify_assign (size, fold_build2_loc (loc, MULT_EXPR, size_type_node, size, + fold_convert (size_type_node, + extent)), seq); + gimple_seq_add_seq (seq, seq2); + return size; +} + +/* Generate loop to access every array element; takes addr of first element + (decl's data comp); returns loop code in seq1 + seq2 + and the pointer to the element as return value. */ +static tree +gfc_omp_elmental_loop (location_t loc, tree decl, tree size, tree elem_len, + gimple_seq *seq1, gimple_seq *seq2) +{ + tree idx = build_decl (loc, VAR_DECL, create_tmp_var_name ("idx"), + size_type_node); + tree begin = build_zero_cst (size_type_node); + tree end = size; + tree step = build_int_cst (size_type_node, 1); + tree ptr; + + gfc_omp_gen_simple_loop (idx, begin, end, LT_EXPR, step, loc, seq1, seq2); + + tree type = TREE_TYPE (decl); + if (POINTER_TYPE_P (type)) + { + type = TREE_TYPE (type); + gcc_assert (TREE_CODE (type) == ARRAY_TYPE); + decl = fold_convert (build_pointer_type (TREE_TYPE (type)), decl); + } + else + { + gcc_assert (TREE_CODE (type) == ARRAY_TYPE); + decl = build_fold_addr_expr_loc (loc, decl); + } + decl = fold_convert (build_pointer_type (TREE_TYPE (type)), decl); + tree tmp = build2_loc (loc, MULT_EXPR, size_type_node, idx, + fold_convert (size_type_node, elem_len)); + ptr = build2_loc (loc, POINTER_PLUS_EXPR, TREE_TYPE (decl), decl, tmp); + gimple_seq seq3 = NULL; + ptr = force_gimple_operand (ptr, &seq3, true, NULL_TREE); + gimple_seq_add_seq (seq1, seq3); + + return ptr; +} + + +/* If do_copy, copy data pointer and vptr (if applicable) as well. + Otherwise, only handle allocatable components. + do_copy == false can happen only with nonpolymorphic arguments + to a copy clause. + if (is_cnt) token ... offset is ignored and num is used, otherwise + num is NULL_TREE and unused. */ + +static void +gfc_omp_deep_mapping_item (bool is_cnt, bool do_copy, bool do_alloc_check, + location_t loc, tree decl, tree *token, + unsigned HOST_WIDE_INT tkind, tree data_array, + tree sizes_array, tree kinds_array, tree offset_data, + tree offset, tree num, gimple_seq *seq, + const gimple *ctx, bool *poly_warned) +{ + tree tmp; + tree type = TREE_TYPE (decl); + if (POINTER_TYPE_P (type)) + type = TREE_TYPE (type); + tree end_label = NULL_TREE; + tree size = NULL_TREE, elem_len = NULL_TREE; + + bool poly = gfc_is_polymorphic_nonptr (type); + if (poly && is_cnt && !*poly_warned) + { + if (gfc_is_unlimited_polymorphic_nonptr (type)) + error_at (loc, + "Mapping of unlimited polymorphic list item %qD is " + "unspecified behavior and unsupported", decl); + + else + warning_at (loc, OPT_Wopenmp, + "Mapping of polymorphic list item %qD is " + "unspecified behavior", decl); + *poly_warned = true; + } + if (do_alloc_check) + { + tree then_label = create_artificial_label (loc); + end_label = create_artificial_label (loc); + tmp = decl; + if (TREE_CODE (TREE_TYPE (tmp)) == REFERENCE_TYPE + || (POINTER_TYPE_P (TREE_TYPE (tmp)) + && (POINTER_TYPE_P (TREE_TYPE (TREE_TYPE (tmp))) + || GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (TREE_TYPE (tmp)))))) + tmp = build_fold_indirect_ref_loc (loc, tmp); + if (poly) + tmp = gfc_class_data_get (tmp); + if (GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (tmp))) + tmp = gfc_conv_descriptor_data_get (tmp); + gimple_seq seq2 = NULL; + tmp = force_gimple_operand (tmp, &seq2, true, NULL_TREE); + gimple_seq_add_seq (seq, seq2); + + gimple_seq_add_stmt (seq, + gimple_build_cond (NE_EXPR, tmp, null_pointer_node, + then_label, end_label)); + gimple_seq_add_stmt (seq, gimple_build_label (then_label)); + } + tree class_decl = decl; + if (poly) + { + decl = gfc_class_data_get (decl); + type = TREE_TYPE (decl); + } + if (POINTER_TYPE_P (TREE_TYPE (decl))) + { + decl = build_fold_indirect_ref (decl); + type = TREE_TYPE (decl); + } + + if (is_cnt && do_copy) + { + tree tmp = fold_build2_loc (loc, PLUS_EXPR, size_type_node, + num, build_int_cst (size_type_node, 1)); + gimplify_assign (num, tmp, seq); + } + else if (do_copy) + { + /* copy data pointer */ + tree bytesize; + if (GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (decl))) + { + /* TODO: Optimization: Shouldn't this be an expr. const, except for + deferred-length strings. (Cf. also below). */ + elem_len = (poly ? gfc_class_vtab_size_get (class_decl) + : gfc_conv_descriptor_elem_len (decl)); + tmp = (POINTER_TYPE_P (TREE_TYPE (decl)) + ? build_fold_indirect_ref (decl) : decl); + size = gfc_omp_get_array_size (loc, tmp, seq); + bytesize = fold_build2_loc (loc, MULT_EXPR, size_type_node, + fold_convert (size_type_node, size), + fold_convert (size_type_node, elem_len)); + tmp = gfc_conv_descriptor_data_get (decl); + } + else if (poly) + { + tmp = decl; + bytesize = fold_convert (size_type_node, + gfc_class_vtab_size_get (class_decl)); + } + else + { + tmp = decl; + bytesize = TYPE_SIZE_UNIT (TREE_TYPE (decl)); + } + unsigned HOST_WIDE_INT tkind2 = tkind; + if (!is_cnt + && (tkind == GOMP_MAP_ALLOC + || (tkind == GOMP_MAP_FROM + && (gimple_omp_target_kind (ctx) + != GF_OMP_TARGET_KIND_EXIT_DATA))) + && gfc_omp_replace_alloc_by_to_mapping (TREE_TYPE (decl), decl, true)) + tkind2 = tkind == GOMP_MAP_ALLOC ? GOMP_MAP_TO : GOMP_MAP_TOFROM; + + gfc_omp_deep_mapping_map (tmp, bytesize, tkind2, loc, data_array, + sizes_array, kinds_array, offset_data, + offset, seq, ctx); + } + + tmp = decl; + if (POINTER_TYPE_P (TREE_TYPE (decl))) + while (TREE_CODE (tmp) == COMPONENT_REF || TREE_CODE (tmp) == ARRAY_REF) + tmp = TREE_OPERAND (tmp, TREE_CODE (tmp) == COMPONENT_REF ? 1 : 0); + if (poly || gfc_has_alloc_comps (type, tmp, true)) + { + gimple_seq seq2 = NULL; + if (GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (decl))) + { + if (elem_len == NULL_TREE) + { + elem_len = gfc_conv_descriptor_elem_len (decl); + size = fold_convert (size_type_node, + gfc_omp_get_array_size (loc, decl, seq)); + } + decl = gfc_conv_descriptor_data_get (decl); + decl = gfc_omp_elmental_loop (loc, decl, size, elem_len, seq, &seq2); + decl = build_fold_indirect_ref_loc (loc, decl); + } + else if (TREE_CODE (TREE_TYPE (tmp)) == ARRAY_TYPE) + { + type = TREE_TYPE (tmp); + /* FIXME: PR95868 - for var%str of deferred length, elem_len == 0; + len is stored as var%_str_length, but not in GFC_DECL_STRING_LEN + nor in TYPE_SIZE_UNIT as expression. */ + elem_len = TYPE_SIZE_UNIT (TREE_TYPE (type)); + size = fold_convert (size_type_node, GFC_TYPE_ARRAY_SIZE (type)); + decl = gfc_omp_elmental_loop (loc, decl, size, elem_len, seq, &seq2); + decl = build_fold_indirect_ref_loc (loc, decl); + } + else if (POINTER_TYPE_P (TREE_TYPE (decl))) + decl = build_fold_indirect_ref (decl); + + gfc_omp_deep_mapping_comps (is_cnt, loc, decl, token, tkind, + data_array, sizes_array, kinds_array, + offset_data, offset, num, seq, ctx, + poly_warned); + gimple_seq_add_seq (seq, seq2); + } + if (end_label) + gimple_seq_add_stmt (seq, gimple_build_label (end_label)); +} + + +/* Which map types to check/handle for deep mapping. */ +static bool +gfc_omp_deep_map_kind_p (tree clause) +{ + switch (OMP_CLAUSE_CODE (clause)) + { + case OMP_CLAUSE_MAP: + break; + case OMP_CLAUSE_FIRSTPRIVATE: + case OMP_CLAUSE_TO: + case OMP_CLAUSE_FROM: + return true; + default: + gcc_unreachable (); + } + + switch (OMP_CLAUSE_MAP_KIND (clause)) + { + case GOMP_MAP_TO: + case GOMP_MAP_FROM: + case GOMP_MAP_TOFROM: + case GOMP_MAP_ALWAYS_TO: + case GOMP_MAP_ALWAYS_FROM: + case GOMP_MAP_ALWAYS_TOFROM: + case GOMP_MAP_ALWAYS_PRESENT_FROM: + case GOMP_MAP_ALWAYS_PRESENT_TO: + case GOMP_MAP_ALWAYS_PRESENT_TOFROM: + case GOMP_MAP_FIRSTPRIVATE: + case GOMP_MAP_ALLOC: + return true; + case GOMP_MAP_POINTER: + case GOMP_MAP_TO_PSET: + case GOMP_MAP_FORCE_PRESENT: + case GOMP_MAP_DELETE: + case GOMP_MAP_FORCE_DEVICEPTR: + case GOMP_MAP_DEVICE_RESIDENT: + case GOMP_MAP_LINK: + case GOMP_MAP_IF_PRESENT: + case GOMP_MAP_PRESENT_ALLOC: + case GOMP_MAP_PRESENT_FROM: + case GOMP_MAP_PRESENT_TO: + case GOMP_MAP_PRESENT_TOFROM: + case GOMP_MAP_FIRSTPRIVATE_INT: + case GOMP_MAP_USE_DEVICE_PTR: + case GOMP_MAP_ZERO_LEN_ARRAY_SECTION: + case GOMP_MAP_FORCE_ALLOC: + case GOMP_MAP_FORCE_TO: + case GOMP_MAP_FORCE_FROM: + case GOMP_MAP_FORCE_TOFROM: + case GOMP_MAP_USE_DEVICE_PTR_IF_PRESENT: + case GOMP_MAP_STRUCT: + case GOMP_MAP_STRUCT_UNORD: + case GOMP_MAP_ALWAYS_POINTER: + case GOMP_MAP_POINTER_TO_ZERO_LENGTH_ARRAY_SECTION: + case GOMP_MAP_DELETE_ZERO_LEN_ARRAY_SECTION: + case GOMP_MAP_RELEASE: + case GOMP_MAP_ATTACH: + case GOMP_MAP_DETACH: + case GOMP_MAP_FORCE_DETACH: + case GOMP_MAP_ATTACH_ZERO_LENGTH_ARRAY_SECTION: + case GOMP_MAP_FIRSTPRIVATE_POINTER: + case GOMP_MAP_FIRSTPRIVATE_REFERENCE: + case GOMP_MAP_ATTACH_DETACH: + break; + default: + gcc_unreachable (); + } + return false; +} + +/* Three OpenMP deep-mapping lang hooks: gfc_omp_deep_mapping{_p,_cnt,}. */ + +/* Common check for gfc_omp_deep_mapping_p and gfc_omp_deep_mapping_do. */ + +static tree +gfc_omp_deep_mapping_int_p (const gimple *ctx, tree clause) +{ + if (is_gimple_omp_oacc (ctx) || !gfc_omp_deep_map_kind_p (clause)) + return NULL_TREE; + tree decl = OMP_CLAUSE_DECL (clause); + if (OMP_CLAUSE_SIZE (clause) != NULL_TREE + && DECL_P (OMP_CLAUSE_SIZE (clause)) + && DECL_LANG_SPECIFIC (OMP_CLAUSE_SIZE (clause)) + && GFC_DECL_SAVED_DESCRIPTOR (OMP_CLAUSE_SIZE (clause))) + /* Saved decl. */ + decl = GFC_DECL_SAVED_DESCRIPTOR (OMP_CLAUSE_SIZE (clause)); + else if (TREE_CODE (decl) == MEM_REF || TREE_CODE (decl) == INDIRECT_REF) + /* The following can happen for, e.g., class(t) :: var(..) */ + decl = TREE_OPERAND (decl, 0); + if (TREE_CODE (decl) == INDIRECT_REF) + /* The following can happen for, e.g., class(t) :: var(..) */ + decl = TREE_OPERAND (decl, 0); + if (DECL_P (decl) + && DECL_LANG_SPECIFIC (decl) + && GFC_DECL_SAVED_DESCRIPTOR (decl)) + decl = GFC_DECL_SAVED_DESCRIPTOR (decl); + /* Handle map(to: var.desc) map([to/from/tofrom:] var.desc.data) + to get proper map kind by skipping to the next item. */ + tree tmp = OMP_CLAUSE_CHAIN (clause); + if (tmp != NULL_TREE + && OMP_CLAUSE_CODE (tmp) == OMP_CLAUSE_CODE (clause) + && OMP_CLAUSE_SIZE (tmp) != NULL_TREE + && DECL_P (OMP_CLAUSE_SIZE (tmp)) + && DECL_LANG_SPECIFIC (OMP_CLAUSE_SIZE (tmp)) + && GFC_DECL_SAVED_DESCRIPTOR (OMP_CLAUSE_SIZE (tmp)) == decl) + return NULL_TREE; + if (DECL_P (decl) + && DECL_LANG_SPECIFIC (decl) + && GFC_DECL_SAVED_DESCRIPTOR (decl)) + decl = GFC_DECL_SAVED_DESCRIPTOR (decl); + tree type = TREE_TYPE (decl); + if (POINTER_TYPE_P (type)) + type = TREE_TYPE (type); + if (POINTER_TYPE_P (type)) + type = TREE_TYPE (type); + tmp = decl; + while (TREE_CODE (tmp) == COMPONENT_REF || TREE_CODE (tmp) == ARRAY_REF) + tmp = TREE_OPERAND (tmp, TREE_CODE (tmp) == COMPONENT_REF ? 1 : 0); + if (!gfc_is_polymorphic_nonptr (type) + && !gfc_has_alloc_comps (type, tmp, true)) + return NULL_TREE; + return decl; +} + +/* Return true if there is deep mapping, even if the number of mapping is known + at compile time. */ +bool +gfc_omp_deep_mapping_p (const gimple *ctx, tree clause) +{ + tree decl = gfc_omp_deep_mapping_int_p (ctx, clause); + if (decl == NULL_TREE) + return false; + return true; +} + +/* Handle gfc_omp_deep_mapping{,_cnt} */ +static tree +gfc_omp_deep_mapping_do (bool is_cnt, const gimple *ctx, tree clause, + unsigned HOST_WIDE_INT tkind, tree data, tree sizes, + tree kinds, tree offset_data, tree offset, + gimple_seq *seq) +{ + tree num = NULL_TREE; + location_t loc = OMP_CLAUSE_LOCATION (clause); + tree decl = gfc_omp_deep_mapping_int_p (ctx, clause); + bool poly_warned = false; + if (decl == NULL_TREE) + return NULL_TREE; + /* Handle: map(alloc:dt%cmp [len: ptr_size]) map(tofrom: D.0123...), + where GFC_DECL_SAVED_DESCRIPTOR(D.0123) is the same (here: dt%cmp). */ + if (OMP_CLAUSE_CODE (clause) == OMP_CLAUSE_MAP + && (OMP_CLAUSE_MAP_KIND (clause) == GOMP_MAP_ALLOC + || OMP_CLAUSE_MAP_KIND (clause) == GOMP_MAP_PRESENT_ALLOC)) + { + tree c = clause; + while ((c = OMP_CLAUSE_CHAIN (c)) != NULL_TREE) + { + if (!gfc_omp_deep_map_kind_p (c)) + continue; + tree d = gfc_omp_deep_mapping_int_p (ctx, c); + if (d != NULL_TREE && operand_equal_p (decl, d, 0)) + return NULL_TREE; + } + } + tree type = TREE_TYPE (decl); + if (POINTER_TYPE_P (type)) + type = TREE_TYPE (type); + if (POINTER_TYPE_P (type)) + type = TREE_TYPE (type); + bool poly = gfc_is_polymorphic_nonptr (type); + + if (is_cnt) + { + num = build_decl (loc, VAR_DECL, + create_tmp_var_name ("n_deepmap"), size_type_node); + tree tmp = fold_build2_loc (loc, MODIFY_EXPR, size_type_node, num, + build_int_cst (size_type_node, 0)); + gimple_add_tmp_var (num); + gimplify_and_add (tmp, seq); + } + else + gcc_assert (short_unsigned_type_node == TREE_TYPE (TREE_TYPE (kinds))); + + bool do_copy = poly; + bool do_alloc_check = false; + tree token = NULL_TREE; + tree tmp = decl; + if (poly) + { + tmp = TYPE_FIELDS (type); + type = TREE_TYPE (tmp); + } + else + while (TREE_CODE (tmp) == COMPONENT_REF || TREE_CODE (tmp) == ARRAY_REF) + tmp = TREE_OPERAND (tmp, TREE_CODE (tmp) == COMPONENT_REF ? 1 : 0); + /* If the clause argument is nonallocatable, skip is-allocate check. */ + if (GFC_DECL_GET_SCALAR_ALLOCATABLE (tmp) + || GFC_DECL_GET_SCALAR_POINTER (tmp) + || (GFC_DESCRIPTOR_TYPE_P (type) + && (GFC_TYPE_ARRAY_AKIND (type) == GFC_ARRAY_ALLOCATABLE + || GFC_TYPE_ARRAY_AKIND (type) == GFC_ARRAY_POINTER + || GFC_TYPE_ARRAY_AKIND (type) == GFC_ARRAY_POINTER_CONT))) + do_alloc_check = true; + + if (!is_cnt + && OMP_CLAUSE_CODE (clause) == OMP_CLAUSE_MAP + && (tkind == GOMP_MAP_ALLOC + || (tkind == GOMP_MAP_FROM + && (gimple_omp_target_kind (ctx) + != GF_OMP_TARGET_KIND_EXIT_DATA))) + && (poly || gfc_omp_replace_alloc_by_to_mapping (type, tmp, true))) + OMP_CLAUSE_SET_MAP_KIND (clause, tkind == GOMP_MAP_ALLOC ? GOMP_MAP_TO + : GOMP_MAP_TOFROM); + + /* TODO: For map(a(:)), we know it is present & allocated. */ + + tree present = (DECL_P (decl) ? gfc_omp_check_optional_argument (decl, true) + : NULL_TREE); + if (POINTER_TYPE_P (TREE_TYPE (decl)) + && POINTER_TYPE_P (TREE_TYPE (TREE_TYPE (decl)))) + decl = build_fold_indirect_ref (decl); + if (present) + { + tree then_label = create_artificial_label (loc); + tree end_label = create_artificial_label (loc); + gimple_seq seq2 = NULL; + tmp = force_gimple_operand (present, &seq2, true, NULL_TREE); + gimple_seq_add_seq (seq, seq2); + gimple_seq_add_stmt (seq, + gimple_build_cond_from_tree (present, + then_label, end_label)); + gimple_seq_add_stmt (seq, gimple_build_label (then_label)); + gfc_omp_deep_mapping_item (is_cnt, do_copy, do_alloc_check, loc, decl, + &token, tkind, data, sizes, kinds, + offset_data, offset, num, seq, ctx, + &poly_warned); + gimple_seq_add_stmt (seq, gimple_build_label (end_label)); + } + else + gfc_omp_deep_mapping_item (is_cnt, do_copy, do_alloc_check, loc, decl, + &token, tkind, data, sizes, kinds, offset_data, + offset, num, seq, ctx, &poly_warned); + /* Multiply by 2 as there are two mappings: data + pointer assign. */ + if (is_cnt) + gimplify_assign (num, + fold_build2_loc (loc, MULT_EXPR, + size_type_node, num, + build_int_cst (size_type_node, 2)), seq); + return num; +} + +/* Return tree with a variable which contains the count of deep-mappyings + (value depends, e.g., on allocation status) */ +tree +gfc_omp_deep_mapping_cnt (const gimple *ctx, tree clause, gimple_seq *seq) +{ + return gfc_omp_deep_mapping_do (true, ctx, clause, 0, NULL_TREE, NULL_TREE, + NULL_TREE, NULL_TREE, NULL_TREE, seq); +} + +/* Does the actual deep mapping. */ +void +gfc_omp_deep_mapping (const gimple *ctx, tree clause, + unsigned HOST_WIDE_INT tkind, tree data, + tree sizes, tree kinds, tree offset_data, tree offset, + gimple_seq *seq) +{ + (void) gfc_omp_deep_mapping_do (false, ctx, clause, tkind, data, sizes, kinds, + offset_data, offset, seq); +} + /* Return true if DECL is a scalar variable (for the purpose of implicit firstprivatization/mapping). Only if 'ptr_alloc_ok.' is true, allocatables and pointers are permitted. */ @@ -2478,6 +3265,18 @@ gfc_trans_omp_array_section (stmtblock_t *block, gfc_exec_op op, elemsz = fold_convert (gfc_array_index_type, elemsz); OMP_CLAUSE_SIZE (node) = fold_build2 (MULT_EXPR, gfc_array_index_type, OMP_CLAUSE_SIZE (node), elemsz); + if (n->expr->ts.type == BT_DERIVED + && n->expr->ts.u.derived->attr.alloc_comp) + { + /* Save array descriptor for use in gfc_omp_deep_mapping{,_p,_cnt}; + force evaluate to ensure that it is not gimplified + is a decl. */ + tree tmp = OMP_CLAUSE_SIZE (node); + tree var = gfc_create_var (TREE_TYPE (tmp), NULL); + gfc_add_modify_loc (input_location, block, var, tmp); + OMP_CLAUSE_SIZE (node) = var; + gfc_allocate_lang_decl (var); + GFC_DECL_SAVED_DESCRIPTOR (var) = se.expr; + } } gcc_assert (se.post.head == NULL_TREE); gcc_assert (POINTER_TYPE_P (TREE_TYPE (ptr))); @@ -3213,8 +4012,9 @@ gfc_trans_omp_clauses (stmtblock_t *block, gfc_omp_clauses *clauses, if (!n->sym->attr.referenced) continue; + location_t map_loc = gfc_get_location (&n->where); bool always_modifier = false; - tree node = build_omp_clause (input_location, OMP_CLAUSE_MAP); + tree node = build_omp_clause (map_loc, OMP_CLAUSE_MAP); tree node2 = NULL_TREE; tree node3 = NULL_TREE; tree node4 = NULL_TREE; @@ -3361,7 +4161,7 @@ gfc_trans_omp_clauses (stmtblock_t *block, gfc_omp_clauses *clauses, && n->u.map.op != OMP_MAP_RELEASE) { gcc_assert (n->sym->ts.u.cl->backend_decl); - node5 = build_omp_clause (input_location, OMP_CLAUSE_MAP); + node5 = build_omp_clause (map_loc, OMP_CLAUSE_MAP); OMP_CLAUSE_SET_MAP_KIND (node5, GOMP_MAP_ALWAYS_TO); OMP_CLAUSE_DECL (node5) = n->sym->ts.u.cl->backend_decl; OMP_CLAUSE_SIZE (node5) @@ -3378,7 +4178,7 @@ gfc_trans_omp_clauses (stmtblock_t *block, gfc_omp_clauses *clauses, ptr = build_fold_indirect_ref (ptr); OMP_CLAUSE_DECL (node) = ptr; OMP_CLAUSE_SIZE (node) = gfc_class_vtab_size_get (decl); - node2 = build_omp_clause (input_location, OMP_CLAUSE_MAP); + node2 = build_omp_clause (map_loc, OMP_CLAUSE_MAP); OMP_CLAUSE_SET_MAP_KIND (node2, GOMP_MAP_ATTACH_DETACH); OMP_CLAUSE_DECL (node2) = gfc_class_data_get (decl); OMP_CLAUSE_SIZE (node2) = size_int (0); @@ -3434,8 +4234,7 @@ gfc_trans_omp_clauses (stmtblock_t *block, gfc_omp_clauses *clauses, size = TYPE_SIZE_UNIT (TREE_TYPE (decl)); else size = size_int (0); - node4 = build_omp_clause (input_location, - OMP_CLAUSE_MAP); + node4 = build_omp_clause (map_loc, OMP_CLAUSE_MAP); OMP_CLAUSE_SET_MAP_KIND (node4, gmk); OMP_CLAUSE_DECL (node4) = decl; OMP_CLAUSE_SIZE (node4) = size; @@ -3459,8 +4258,7 @@ gfc_trans_omp_clauses (stmtblock_t *block, gfc_omp_clauses *clauses, size = TYPE_SIZE_UNIT (TREE_TYPE (decl)); else size = size_int (0); - node3 = build_omp_clause (input_location, - OMP_CLAUSE_MAP); + node3 = build_omp_clause (map_loc, OMP_CLAUSE_MAP); OMP_CLAUSE_SET_MAP_KIND (node3, gmk); OMP_CLAUSE_DECL (node3) = decl; OMP_CLAUSE_SIZE (node3) = size; @@ -3477,7 +4275,7 @@ gfc_trans_omp_clauses (stmtblock_t *block, gfc_omp_clauses *clauses, gcc_assert (POINTER_TYPE_P (TREE_TYPE (ptr))); ptr = build_fold_indirect_ref (ptr); OMP_CLAUSE_DECL (node) = ptr; - node2 = build_omp_clause (input_location, OMP_CLAUSE_MAP); + node2 = build_omp_clause (map_loc, OMP_CLAUSE_MAP); OMP_CLAUSE_DECL (node2) = decl; OMP_CLAUSE_SIZE (node2) = TYPE_SIZE_UNIT (type); if (n->u.map.op == OMP_MAP_DELETE) @@ -3493,8 +4291,7 @@ gfc_trans_omp_clauses (stmtblock_t *block, gfc_omp_clauses *clauses, && n->u.map.op != OMP_MAP_DELETE && n->u.map.op != OMP_MAP_RELEASE) { - node3 = build_omp_clause (input_location, - OMP_CLAUSE_MAP); + node3 = build_omp_clause (map_loc, OMP_CLAUSE_MAP); if (present) { ptr = gfc_conv_descriptor_data_get (decl); @@ -3634,10 +4431,10 @@ gfc_trans_omp_clauses (stmtblock_t *block, gfc_omp_clauses *clauses, { /* A single indirectref is handled by the middle end. */ gcc_assert (!POINTER_TYPE_P (TREE_TYPE (decl))); - decl = TREE_OPERAND (decl, 0); - decl = gfc_build_cond_assign_expr (block, present, decl, + tree tmp = TREE_OPERAND (decl, 0); + tmp = gfc_build_cond_assign_expr (block, present, tmp, null_pointer_node); - OMP_CLAUSE_DECL (node) = build_fold_indirect_ref (decl); + OMP_CLAUSE_DECL (node) = build_fold_indirect_ref (tmp); } else OMP_CLAUSE_DECL (node) = decl; @@ -3672,6 +4469,33 @@ gfc_trans_omp_clauses (stmtblock_t *block, gfc_omp_clauses *clauses, size = gfc_evaluate_now (size, block); OMP_CLAUSE_SIZE (node) = size; } + if ((TREE_CODE (decl) != PARM_DECL + || DECL_ARTIFICIAL (OMP_CLAUSE_DECL (node))) + && n->sym->ts.type == BT_DERIVED + && n->sym->ts.u.derived->attr.alloc_comp) + { + /* Save array descriptor for use in + gfc_omp_deep_mapping{,_p,_cnt}; force evaluate + to ensure that it is not gimplified + is a decl. */ + tree tmp = OMP_CLAUSE_SIZE (node); + if (tmp == NULL_TREE) + tmp = DECL_P (decl) ? DECL_SIZE_UNIT (decl) + : TYPE_SIZE_UNIT (TREE_TYPE (decl)); + tree var = gfc_create_var (TREE_TYPE (tmp), NULL); + gfc_add_modify_loc (input_location, block, var, tmp); + OMP_CLAUSE_SIZE (node) = var; + gfc_allocate_lang_decl (var); + if (TREE_CODE (decl) == INDIRECT_REF) + decl = TREE_OPERAND (decl, 0); + if (TREE_CODE (decl) == INDIRECT_REF) + decl = TREE_OPERAND (decl, 0); + if (DECL_LANG_SPECIFIC (decl) + && GFC_DECL_SAVED_DESCRIPTOR (decl)) + GFC_DECL_SAVED_DESCRIPTOR (var) + = GFC_DECL_SAVED_DESCRIPTOR (decl); + else + GFC_DECL_SAVED_DESCRIPTOR (var) = decl; + } } else if (n->expr && n->expr->expr_type == EXPR_VARIABLE @@ -3727,8 +4551,7 @@ gfc_trans_omp_clauses (stmtblock_t *block, gfc_omp_clauses *clauses, goto finalize_map_clause; } - node2 = build_omp_clause (input_location, - OMP_CLAUSE_MAP); + node2 = build_omp_clause (map_loc, OMP_CLAUSE_MAP); OMP_CLAUSE_SET_MAP_KIND (node2, GOMP_MAP_ATTACH_DETACH); OMP_CLAUSE_DECL (node2) = POINTER_TYPE_P (TREE_TYPE (se.expr)) @@ -3754,13 +4577,37 @@ gfc_trans_omp_clauses (stmtblock_t *block, gfc_omp_clauses *clauses, kind = GOMP_MAP_RELEASE; else kind = GOMP_MAP_TO; - node3 = build_omp_clause (input_location, - OMP_CLAUSE_MAP); + node3 = build_omp_clause (map_loc, OMP_CLAUSE_MAP); OMP_CLAUSE_SET_MAP_KIND (node3, kind); OMP_CLAUSE_DECL (node3) = se.string_length; OMP_CLAUSE_SIZE (node3) = TYPE_SIZE_UNIT (gfc_charlen_type_node); } + if (!openacc + && n->expr->ts.type == BT_DERIVED + && n->expr->ts.u.derived->attr.alloc_comp) + { + /* Save array descriptor for use in + gfc_omp_deep_mapping{,_p,_cnt}; force evaluate + to ensure that it is not gimplified + is a decl. */ + tree tmp = OMP_CLAUSE_SIZE (node); + if (tmp == NULL_TREE) + tmp = (DECL_P (se.expr) + ? DECL_SIZE_UNIT (se.expr) + : TYPE_SIZE_UNIT (TREE_TYPE (se.expr))); + tree var = gfc_create_var (TREE_TYPE (tmp), NULL); + gfc_add_modify_loc (input_location, block, var, tmp); + OMP_CLAUSE_SIZE (node) = var; + gfc_allocate_lang_decl (var); + if (TREE_CODE (se.expr) == INDIRECT_REF) + se.expr = TREE_OPERAND (se.expr, 0); + if (DECL_LANG_SPECIFIC (se.expr) + && GFC_DECL_SAVED_DESCRIPTOR (se.expr)) + GFC_DECL_SAVED_DESCRIPTOR (var) + = GFC_DECL_SAVED_DESCRIPTOR (se.expr); + else + GFC_DECL_SAVED_DESCRIPTOR (var) = se.expr; + } } } else if (n->expr @@ -3800,7 +4647,7 @@ gfc_trans_omp_clauses (stmtblock_t *block, gfc_omp_clauses *clauses, && (lastref->u.c.component->ts.type == BT_DERIVED || lastref->u.c.component->ts.type == BT_CLASS)) { - if (pointer || (openacc && allocatable)) + if (pointer || allocatable) { /* If it's a bare attach/detach clause, we just want to perform a single attach/detach operation, of the @@ -3880,8 +4727,7 @@ gfc_trans_omp_clauses (stmtblock_t *block, gfc_omp_clauses *clauses, OMP_CLAUSE_DECL (node) = data; OMP_CLAUSE_SIZE (node) = size; - node2 = build_omp_clause (input_location, - OMP_CLAUSE_MAP); + node2 = build_omp_clause (map_loc, OMP_CLAUSE_MAP); OMP_CLAUSE_SET_MAP_KIND (node2, GOMP_MAP_ATTACH_DETACH); OMP_CLAUSE_DECL (node2) = build_fold_addr_expr (data); @@ -3893,6 +4739,22 @@ gfc_trans_omp_clauses (stmtblock_t *block, gfc_omp_clauses *clauses, OMP_CLAUSE_SIZE (node) = TYPE_SIZE_UNIT (TREE_TYPE (inner)); } + if (!openacc + && n->expr->ts.type == BT_DERIVED + && n->expr->ts.u.derived->attr.alloc_comp) + { + /* Save array descriptor for use in + gfc_omp_deep_mapping{,_p,_cnt}; force evaluate + to ensure that it is not gimplified + is a decl. */ + tree tmp = OMP_CLAUSE_SIZE (node); + tree var = gfc_create_var (TREE_TYPE (tmp), NULL); + gfc_add_modify_loc (input_location, block, var, tmp); + OMP_CLAUSE_SIZE (node) = var; + gfc_allocate_lang_decl (var); + if (TREE_CODE (inner) == INDIRECT_REF) + inner = TREE_OPERAND (inner, 0); + GFC_DECL_SAVED_DESCRIPTOR (var) = inner; + } } else if (lastref->type == REF_ARRAY && lastref->u.ar.type == AR_FULL) @@ -3952,8 +4814,7 @@ gfc_trans_omp_clauses (stmtblock_t *block, gfc_omp_clauses *clauses, elemsz = TYPE_SIZE_UNIT (elemsz); elemsz = fold_build2 (MULT_EXPR, size_type_node, len, elemsz); - node4 = build_omp_clause (input_location, - OMP_CLAUSE_MAP); + node4 = build_omp_clause (map_loc, OMP_CLAUSE_MAP); OMP_CLAUSE_SET_MAP_KIND (node4, map_kind); OMP_CLAUSE_DECL (node4) = se.string_length; OMP_CLAUSE_SIZE (node4) @@ -3963,8 +4824,7 @@ gfc_trans_omp_clauses (stmtblock_t *block, gfc_omp_clauses *clauses, OMP_CLAUSE_SIZE (node) = fold_build2 (MULT_EXPR, gfc_array_index_type, OMP_CLAUSE_SIZE (node), elemsz); - node2 = build_omp_clause (input_location, - OMP_CLAUSE_MAP); + node2 = build_omp_clause (map_loc, OMP_CLAUSE_MAP); if (map_kind == GOMP_MAP_RELEASE || map_kind == GOMP_MAP_DELETE) { @@ -3978,6 +4838,23 @@ gfc_trans_omp_clauses (stmtblock_t *block, gfc_omp_clauses *clauses, OMP_CLAUSE_SIZE (node2) = TYPE_SIZE_UNIT (type); if (!openacc) { + if (n->expr->ts.type == BT_DERIVED + && n->expr->ts.u.derived->attr.alloc_comp) + { + /* Save array descriptor for use + in gfc_omp_deep_mapping{,_p,_cnt}; force + evaluate to ensure that it is + not gimplified + is a decl. */ + tree tmp = OMP_CLAUSE_SIZE (node); + tree var = gfc_create_var (TREE_TYPE (tmp), + NULL); + gfc_add_modify_loc (map_loc, block, + var, tmp); + OMP_CLAUSE_SIZE (node) = var; + gfc_allocate_lang_decl (var); + GFC_DECL_SAVED_DESCRIPTOR (var) = inner; + } + gfc_omp_namelist *n2 = clauses->lists[OMP_LIST_MAP]; @@ -4035,8 +4912,7 @@ gfc_trans_omp_clauses (stmtblock_t *block, gfc_omp_clauses *clauses, if (drop_mapping) continue; } - node3 = build_omp_clause (input_location, - OMP_CLAUSE_MAP); + node3 = build_omp_clause (map_loc, OMP_CLAUSE_MAP); OMP_CLAUSE_SET_MAP_KIND (node3, GOMP_MAP_ATTACH_DETACH); OMP_CLAUSE_DECL (node3) @@ -4107,7 +4983,8 @@ gfc_trans_omp_clauses (stmtblock_t *block, gfc_omp_clauses *clauses, default: gcc_unreachable (); } - tree node = build_omp_clause (input_location, clause_code); + tree node = build_omp_clause (gfc_get_location (&n->where), + clause_code); if (n->expr == NULL || (n->expr->ref->type == REF_ARRAY && n->expr->ref->u.ar.type == AR_FULL diff --git a/gcc/fortran/trans.h b/gcc/fortran/trans.h index 63a566a..ae7be9f 100644 --- a/gcc/fortran/trans.h +++ b/gcc/fortran/trans.h @@ -839,6 +839,10 @@ tree gfc_omp_clause_assign_op (tree, tree, tree); tree gfc_omp_clause_linear_ctor (tree, tree, tree, tree); tree gfc_omp_clause_dtor (tree, tree); void gfc_omp_finish_clause (tree, gimple_seq *, bool); +bool gfc_omp_deep_mapping_p (const gimple *, tree); +tree gfc_omp_deep_mapping_cnt (const gimple *, tree, gimple_seq *); +void gfc_omp_deep_mapping (const gimple *, tree, unsigned HOST_WIDE_INT, tree, + tree, tree, tree, tree, gimple_seq *); bool gfc_omp_allocatable_p (tree); bool gfc_omp_scalar_p (tree, bool); bool gfc_omp_scalar_target_p (tree); @@ -30,6 +30,9 @@ compilation is specified by a string called a "spec". */ #define INCLUDE_STRING #include "config.h" #include "system.h" +#ifdef HOST_HAS_PERSONALITY_ADDR_NO_RANDOMIZE +#include <sys/personality.h> +#endif #include "coretypes.h" #include "multilib.h" /* before tm.h */ #include "tm.h" @@ -8003,6 +8006,10 @@ try_generate_repro (const char **argv) else new_argv[out_arg] = "-o-"; +#ifdef HOST_HAS_PERSONALITY_ADDR_NO_RANDOMIZE + personality (personality (0xffffffffU) | ADDR_NO_RANDOMIZE); +#endif + int status; for (attempt = 0; attempt < RETRY_ICE_ATTEMPTS; ++attempt) { diff --git a/gcc/gimple-fold.cc b/gcc/gimple-fold.cc index b645613..94d5a1e 100644 --- a/gcc/gimple-fold.cc +++ b/gcc/gimple-fold.cc @@ -906,20 +906,60 @@ size_must_be_zero_p (tree size) static bool optimize_memcpy_to_memset (gimple_stmt_iterator *gsip, tree dest, tree src, tree len) { + ao_ref read; gimple *stmt = gsi_stmt (*gsip); if (gimple_has_volatile_ops (stmt)) return false; - tree vuse = gimple_vuse (stmt); - if (vuse == NULL || TREE_CODE (vuse) != SSA_NAME) - return false; - gimple *defstmt = SSA_NAME_DEF_STMT (vuse); tree src2 = NULL_TREE, len2 = NULL_TREE; poly_int64 offset, offset2; tree val = integer_zero_node; + bool len_was_null = len == NULL_TREE; + if (len == NULL_TREE) + len = (TREE_CODE (src) == COMPONENT_REF + ? DECL_SIZE_UNIT (TREE_OPERAND (src, 1)) + : TYPE_SIZE_UNIT (TREE_TYPE (src))); + if (len == NULL_TREE + || !poly_int_tree_p (len)) + return false; + + ao_ref_init (&read, src); + tree vuse = gimple_vuse (stmt); + gimple *defstmt; + do { + if (vuse == NULL || TREE_CODE (vuse) != SSA_NAME) + return false; + defstmt = SSA_NAME_DEF_STMT (vuse); + if (is_a <gphi*>(defstmt)) + return false; + + /* If the len was null, then we can use TBBA. */ + if (stmt_may_clobber_ref_p_1 (defstmt, &read, + /* tbaa_p = */ len_was_null)) + break; + vuse = gimple_vuse (defstmt); + } while (true); + if (gimple_store_p (defstmt) && gimple_assign_single_p (defstmt) + && TREE_CODE (gimple_assign_rhs1 (defstmt)) == STRING_CST + && !gimple_clobber_p (defstmt)) + { + tree str = gimple_assign_rhs1 (defstmt); + src2 = gimple_assign_lhs (defstmt); + /* The string must contain all null char's for now. */ + for (int i = 0; i < TREE_STRING_LENGTH (str); i++) + { + if (TREE_STRING_POINTER (str)[i] != 0) + { + src2 = NULL_TREE; + break; + } + } + } + else if (gimple_store_p (defstmt) + && gimple_assign_single_p (defstmt) && TREE_CODE (gimple_assign_rhs1 (defstmt)) == CONSTRUCTOR && !gimple_clobber_p (defstmt)) src2 = gimple_assign_lhs (defstmt); @@ -939,17 +979,11 @@ optimize_memcpy_to_memset (gimple_stmt_iterator *gsip, tree dest, tree src, tree if (src2 == NULL_TREE) return false; - if (len == NULL_TREE) - len = (TREE_CODE (src) == COMPONENT_REF - ? DECL_SIZE_UNIT (TREE_OPERAND (src, 1)) - : TYPE_SIZE_UNIT (TREE_TYPE (src))); if (len2 == NULL_TREE) len2 = (TREE_CODE (src2) == COMPONENT_REF ? DECL_SIZE_UNIT (TREE_OPERAND (src2, 1)) : TYPE_SIZE_UNIT (TREE_TYPE (src2))); - if (len == NULL_TREE - || !poly_int_tree_p (len) - || len2 == NULL_TREE + if (len2 == NULL_TREE || !poly_int_tree_p (len2)) return false; diff --git a/gcc/gimple-lower-bitint.cc b/gcc/gimple-lower-bitint.cc index c52a657..6fefc83 100644 --- a/gcc/gimple-lower-bitint.cc +++ b/gcc/gimple-lower-bitint.cc @@ -6647,10 +6647,28 @@ gimple_lower_bitint (void) bitmap_set_bit (large_huge.m_names, SSA_NAME_VERSION (s)); if (has_single_use (s)) { - if (!large_huge.m_single_use_names) - large_huge.m_single_use_names = BITMAP_ALLOC (NULL); - bitmap_set_bit (large_huge.m_single_use_names, - SSA_NAME_VERSION (s)); + tree s2 = s; + /* The coalescing hook special cases SSA_NAME copies. + Make sure not to mark in m_single_use_names single + use SSA_NAMEs copied from non-single use SSA_NAMEs. */ + while (gimple_assign_copy_p (SSA_NAME_DEF_STMT (s2))) + { + s2 = gimple_assign_rhs1 (SSA_NAME_DEF_STMT (s2)); + if (TREE_CODE (s2) != SSA_NAME) + break; + if (!has_single_use (s2)) + { + s2 = NULL_TREE; + break; + } + } + if (s2) + { + if (!large_huge.m_single_use_names) + large_huge.m_single_use_names = BITMAP_ALLOC (NULL); + bitmap_set_bit (large_huge.m_single_use_names, + SSA_NAME_VERSION (s)); + } } if (SSA_NAME_VAR (s) && ((TREE_CODE (SSA_NAME_VAR (s)) == PARM_DECL diff --git a/gcc/ginclude/stddef.h b/gcc/ginclude/stddef.h index 0d53103..bacf24d 100644 --- a/gcc/ginclude/stddef.h +++ b/gcc/ginclude/stddef.h @@ -89,6 +89,21 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see #undef _PTRDIFF_T_ #endif +/* When modular code is enabled with macOS SDKs from version 15, the + include guards are set in the includers of this code, rather than as + part of it. This means the we must unset them or the intended code + here will be bypassed (resulting in undefined values). */ +#if defined (__APPLE__) +# if defined(__has_feature) && __has_feature(modules) +# if defined (__need_ptrdiff_t) +# undef __PTRDIFF_T +# endif +# if defined (__need_size_t) +# undef __SIZE_T +# endif +# endif +#endif + /* On VxWorks, <type/vxTypesBase.h> may have defined macros like _TYPE_size_t which will typedef size_t. fixincludes patched the vxTypesBase.h so that this macro is only defined if _GCC_SIZE_T is diff --git a/gcc/ipa-cp.cc b/gcc/ipa-cp.cc index 2645689..806c2bd 100644 --- a/gcc/ipa-cp.cc +++ b/gcc/ipa-cp.cc @@ -307,14 +307,31 @@ ipcp_lattice<valtype>::print (FILE * f, bool dump_sources, bool dump_benefits) fprintf (f, "\n"); } -/* If VALUE has all bits set to one, print "-1" to F, otherwise simply print it - hexadecimally to F. */ +/* Print VALUE to F in a form which in usual cases does not take thousands of + characters. */ static void ipcp_print_widest_int (FILE *f, const widest_int &value) { - if (wi::eq_p (wi::bit_not (value), 0)) + if (value == -1) fprintf (f, "-1"); + else if (wi::arshift (value, 128) == -1) + { + char buf[35], *p = buf + 2; + widest_int v = wi::zext (value, 128); + size_t len; + print_hex (v, buf); + len = strlen (p); + if (len == 32) + { + fprintf (f, "0xf..f"); + while (*p == 'f') + ++p; + } + else + fprintf (f, "0xf..f%0*d", (int) (32 - len), 0); + fputs (p, f); + } else print_hex (value, f); } @@ -331,7 +348,7 @@ ipcp_bits_lattice::print (FILE *f) fprintf (f, " Bits: value = "); ipcp_print_widest_int (f, get_value ()); fprintf (f, ", mask = "); - print_hex (get_mask (), f); + ipcp_print_widest_int (f, get_mask ()); fprintf (f, "\n"); } } @@ -916,11 +933,13 @@ ipcp_bits_lattice::meet_with_1 (widest_int value, widest_int mask, m_mask = (m_mask | mask) | (m_value ^ value); if (drop_all_ones) m_mask |= m_value; - m_value &= ~m_mask; + widest_int cap_mask = wi::shifted_mask <widest_int> (0, precision, true); + m_mask |= cap_mask; if (wi::sext (m_mask, precision) == -1) return set_to_bottom (); + m_value &= ~m_mask; return m_mask != old_mask; } @@ -996,6 +1015,8 @@ ipcp_bits_lattice::meet_with (ipcp_bits_lattice& other, unsigned precision, adjusted_mask |= adjusted_value; adjusted_value &= ~adjusted_mask; } + widest_int cap_mask = wi::shifted_mask <widest_int> (0, precision, true); + adjusted_mask |= cap_mask; if (wi::sext (adjusted_mask, precision) == -1) return set_to_bottom (); return set_to_constant (adjusted_value, adjusted_mask); @@ -1467,10 +1488,12 @@ ipacp_value_safe_for_type (tree param_type, tree value) return NULL_TREE; } -/* Return the result of a (possibly arithmetic) operation on the constant value - INPUT. OPERAND is 2nd operand for binary operation. RES_TYPE is the type - in which any operation is to be performed. Return NULL_TREE if that cannot - be determined or be considered an interprocedural invariant. */ +/* Return the result of a (possibly arithmetic) operation determined by OPCODE + on the constant value INPUT. OPERAND is 2nd operand for binary operation + and is required for binary operations. RES_TYPE, required when opcode is + not NOP_EXPR, is the type in which any operation is to be performed. Return + NULL_TREE if that cannot be determined or be considered an interprocedural + invariant. */ static tree ipa_get_jf_arith_result (enum tree_code opcode, tree input, tree operand, @@ -1491,16 +1514,6 @@ ipa_get_jf_arith_result (enum tree_code opcode, tree input, tree operand, return NULL_TREE; } - if (!res_type) - { - if (TREE_CODE_CLASS (opcode) == tcc_comparison) - res_type = boolean_type_node; - else if (expr_type_first_operand_type_p (opcode)) - res_type = TREE_TYPE (input); - else - return NULL_TREE; - } - if (TREE_CODE_CLASS (opcode) == tcc_unary) res = fold_unary (opcode, res_type, input); else @@ -1584,7 +1597,10 @@ ipa_value_from_jfunc (class ipa_node_params *info, struct ipa_jump_func *jfunc, return NULL_TREE; enum tree_code opcode = ipa_get_jf_pass_through_operation (jfunc); tree op2 = ipa_get_jf_pass_through_operand (jfunc); - tree cstval = ipa_get_jf_arith_result (opcode, input, op2, NULL_TREE); + tree op_type + = (opcode == NOP_EXPR) ? NULL_TREE + : ipa_get_jf_pass_through_op_type (jfunc); + tree cstval = ipa_get_jf_arith_result (opcode, input, op2, op_type); return ipacp_value_safe_for_type (parm_type, cstval); } else @@ -1724,24 +1740,7 @@ ipa_vr_intersect_with_arith_jfunc (vrange &vr, const value_range *inter_vr; if (operation != NOP_EXPR) { - /* Since we construct arithmetic jump functions even when there is a - type conversion in between the operation encoded in the jump - function and when it is passed in a call argument, the IPA - propagation phase must also perform the operation and conversion - in two separate steps. - - TODO: In order to remove the use of expr_type_first_operand_type_p - predicate we would need to stream the operation type, ideally - encoding the whole jump function as a series of expr_eval_op - structures. */ - - tree operation_type; - if (expr_type_first_operand_type_p (operation)) - operation_type = src_type; - else if (operation == ABSU_EXPR) - operation_type = unsigned_type_for (src_type); - else - return; + tree operation_type = ipa_get_jf_pass_through_op_type (jfunc); op_res.set_varying (operation_type); if (!ipa_vr_operation_and_type_effects (op_res, src_vr, operation, operation_type, src_type)) @@ -1771,14 +1770,7 @@ ipa_vr_intersect_with_arith_jfunc (vrange &vr, value_range op_vr (TREE_TYPE (operand)); ipa_get_range_from_ip_invariant (op_vr, operand, context_node); - tree operation_type; - if (TREE_CODE_CLASS (operation) == tcc_comparison) - operation_type = boolean_type_node; - else if (expr_type_first_operand_type_p (operation)) - operation_type = src_type; - else - return; - + tree operation_type = ipa_get_jf_pass_through_op_type (jfunc); value_range op_res (operation_type); if (!ipa_vr_supported_type_p (operation_type) || !handler.operand_check_p (operation_type, src_type, op_vr.type ()) @@ -1918,10 +1910,11 @@ ipa_agg_value_from_jfunc (ipa_node_params *info, cgraph_node *node, return NULL_TREE; } - return ipa_get_jf_arith_result (item->value.pass_through.operation, - value, - item->value.pass_through.operand, - item->type); + tree cstval = ipa_get_jf_arith_result (item->value.pass_through.operation, + value, + item->value.pass_through.operand, + item->value.pass_through.op_type); + return ipacp_value_safe_for_type (item->type, cstval); } /* Process all items in AGG_JFUNC relative to caller (or the node the original @@ -2150,13 +2143,15 @@ ipcp_lattice<valtype>::add_value (valtype newval, cgraph_edge *cs, /* A helper function that returns result of operation specified by OPCODE on the value of SRC_VAL. If non-NULL, OPND1_TYPE is expected type for the value of SRC_VAL. If the operation is binary, OPND2 is a constant value - acting as its second operand. */ + acting as its second operand. OP_TYPE is the type in which the operation is + performed. */ static tree get_val_across_arith_op (enum tree_code opcode, tree opnd1_type, tree opnd2, - ipcp_value<tree> *src_val) + ipcp_value<tree> *src_val, + tree op_type) { tree opnd1 = src_val->value; @@ -2165,17 +2160,19 @@ get_val_across_arith_op (enum tree_code opcode, && !useless_type_conversion_p (opnd1_type, TREE_TYPE (opnd1))) return NULL_TREE; - return ipa_get_jf_arith_result (opcode, opnd1, opnd2, NULL_TREE); + return ipa_get_jf_arith_result (opcode, opnd1, opnd2, op_type); } /* Propagate values through an arithmetic transformation described by a jump function associated with edge CS, taking values from SRC_LAT and putting - them into DEST_LAT. OPND1_TYPE is expected type for the values in SRC_LAT. - OPND2 is a constant value if transformation is a binary operation. - SRC_OFFSET specifies offset in an aggregate if SRC_LAT describes lattice of - a part of the aggregate. SRC_IDX is the index of the source parameter. - RES_TYPE is the value type of result being propagated into. Return true if - DEST_LAT changed. */ + them into DEST_LAT. OPND1_TYPE, if non-NULL, is the expected type for the + values in SRC_LAT. OPND2 is a constant value if transformation is a binary + operation. SRC_OFFSET specifies offset in an aggregate if SRC_LAT describes + lattice of a part of an aggregate, otherwise it should be -1. SRC_IDX is + the index of the source parameter. OP_TYPE is the type in which the + operation is performed and can be NULL when OPCODE is NOP_EXPR. RES_TYPE is + the value type of result being propagated into. Return true if DEST_LAT + changed. */ static bool propagate_vals_across_arith_jfunc (cgraph_edge *cs, @@ -2186,6 +2183,7 @@ propagate_vals_across_arith_jfunc (cgraph_edge *cs, ipcp_lattice<tree> *dest_lat, HOST_WIDE_INT src_offset, int src_idx, + tree op_type, tree res_type) { ipcp_value<tree> *src_val; @@ -2241,7 +2239,7 @@ propagate_vals_across_arith_jfunc (cgraph_edge *cs, for (int j = 1; j < max_recursive_depth; j++) { tree cstval = get_val_across_arith_op (opcode, opnd1_type, opnd2, - src_val); + src_val, op_type); cstval = ipacp_value_safe_for_type (res_type, cstval); if (!cstval) break; @@ -2266,7 +2264,7 @@ propagate_vals_across_arith_jfunc (cgraph_edge *cs, } tree cstval = get_val_across_arith_op (opcode, opnd1_type, opnd2, - src_val); + src_val, op_type); cstval = ipacp_value_safe_for_type (res_type, cstval); if (cstval) ret |= dest_lat->add_value (cstval, cs, src_val, src_idx, @@ -2290,11 +2288,13 @@ propagate_vals_across_pass_through (cgraph_edge *cs, ipa_jump_func *jfunc, tree parm_type) { gcc_checking_assert (parm_type); - return propagate_vals_across_arith_jfunc (cs, - ipa_get_jf_pass_through_operation (jfunc), - NULL_TREE, + enum tree_code opcode = ipa_get_jf_pass_through_operation (jfunc); + tree op_type = (opcode == NOP_EXPR) ? NULL_TREE + : ipa_get_jf_pass_through_op_type (jfunc); + return propagate_vals_across_arith_jfunc (cs, opcode, NULL_TREE, ipa_get_jf_pass_through_operand (jfunc), - src_lat, dest_lat, -1, src_idx, parm_type); + src_lat, dest_lat, -1, src_idx, op_type, + parm_type); } /* Propagate values through an ancestor jump function JFUNC associated with @@ -2507,14 +2507,12 @@ propagate_bits_across_jump_function (cgraph_edge *cs, int idx, return dest_lattice->set_to_bottom (); } - unsigned precision = TYPE_PRECISION (parm_type); - signop sgn = TYPE_SIGN (parm_type); - if (jfunc->type == IPA_JF_PASS_THROUGH || jfunc->type == IPA_JF_ANCESTOR) { ipa_node_params *caller_info = ipa_node_params_sum->get (cs->caller); tree operand = NULL_TREE; + tree op_type = NULL_TREE; enum tree_code code; unsigned src_idx; bool keep_null = false; @@ -2524,7 +2522,10 @@ propagate_bits_across_jump_function (cgraph_edge *cs, int idx, code = ipa_get_jf_pass_through_operation (jfunc); src_idx = ipa_get_jf_pass_through_formal_id (jfunc); if (code != NOP_EXPR) - operand = ipa_get_jf_pass_through_operand (jfunc); + { + operand = ipa_get_jf_pass_through_operand (jfunc); + op_type = ipa_get_jf_pass_through_op_type (jfunc); + } } else { @@ -2551,6 +2552,11 @@ propagate_bits_across_jump_function (cgraph_edge *cs, int idx, if (!src_lats->bits_lattice.bottom_p ()) { + if (!op_type) + op_type = ipa_get_type (caller_info, src_idx); + + unsigned precision = TYPE_PRECISION (op_type); + signop sgn = TYPE_SIGN (op_type); bool drop_all_ones = keep_null && !src_lats->bits_lattice.known_nonzero_p (); @@ -2570,7 +2576,8 @@ propagate_bits_across_jump_function (cgraph_edge *cs, int idx, = widest_int::from (bm.mask (), TYPE_SIGN (parm_type)); widest_int value = widest_int::from (bm.value (), TYPE_SIGN (parm_type)); - return dest_lattice->meet_with (value, mask, precision); + return dest_lattice->meet_with (value, mask, + TYPE_PRECISION (parm_type)); } } return dest_lattice->set_to_bottom (); @@ -2869,6 +2876,7 @@ propagate_aggregate_lattice (struct cgraph_edge *cs, src_lat, aglat, src_offset, src_idx, + item->value.pass_through.op_type, item->type); if (src_lat->contains_variable) @@ -5394,11 +5402,14 @@ find_more_scalar_values_for_callers_subset (struct cgraph_node *node, if (self_recursive_pass_through_p (cs, jump_func, i, false)) { gcc_assert (newval); - t = ipa_get_jf_arith_result ( - ipa_get_jf_pass_through_operation (jump_func), - newval, + enum tree_code opcode + = ipa_get_jf_pass_through_operation (jump_func); + tree op_type = (opcode == NOP_EXPR) ? NULL_TREE + : ipa_get_jf_pass_through_op_type (jump_func); + t = ipa_get_jf_arith_result (opcode, newval, ipa_get_jf_pass_through_operand (jump_func), - type); + op_type); + t = ipacp_value_safe_for_type (type, t); } else t = ipa_value_from_jfunc (ipa_node_params_sum->get (cs->caller), @@ -5603,10 +5614,13 @@ push_agg_values_for_index_from_edge (struct cgraph_edge *cs, int index, && self_recursive_agg_pass_through_p (cs, &agg_jf, index, false) && (srcvalue = interim->get_value(index, agg_jf.offset / BITS_PER_UNIT))) - value = ipa_get_jf_arith_result (agg_jf.value.pass_through.operation, - srcvalue, - agg_jf.value.pass_through.operand, - agg_jf.type); + { + value = ipa_get_jf_arith_result (agg_jf.value.pass_through.operation, + srcvalue, + agg_jf.value.pass_through.operand, + agg_jf.value.pass_through.op_type); + value = ipacp_value_safe_for_type (agg_jf.type, value); + } else value = ipa_agg_value_from_jfunc (caller_info, cs->caller, &agg_jf); @@ -6426,7 +6440,7 @@ ipcp_store_vr_results (void) fprintf (dump_file, " param %i: value = ", i); ipcp_print_widest_int (dump_file, bits->get_value ()); fprintf (dump_file, ", mask = "); - print_hex (bits->get_mask (), dump_file); + ipcp_print_widest_int (dump_file, bits->get_mask ()); fprintf (dump_file, "\n"); } } diff --git a/gcc/ipa-locality-cloning.cc b/gcc/ipa-locality-cloning.cc new file mode 100644 index 0000000..2684046 --- /dev/null +++ b/gcc/ipa-locality-cloning.cc @@ -0,0 +1,1137 @@ +/* Code locality based function cloning. + Copyright The GNU Toolchain Authors + +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 +<http://www.gnu.org/licenses/>. */ + +/* This file implements cloning required to improve partitioning of the + callgraph for locality considerations. + + Partitioning for improving code locality. + This pass aims to place frequently executed callchains closer together in + memory to improve performance through improved locality. If any frequent + callchains cannot be placed together because they are already placed + elsewhere, local function clones are created and all callers near to the + clones are redirected to use this copy. + + Locality code placement is done in 2 parts. + 1. IPA pass to be executed after ipa-inline and before ipa-pure-const. + Execute stage prepares the plan to place all nodes into partitions. + 2. WPA Partition stage actually implements the plan. + + Brief overview of the IPA pass: + 1. Create and sort callchains. If PGO is available, use real profile + counts. Otherwise, use a set of heuristics to sort the callchains. + 2. Create a partition plan for the callchains, processing them in the sorted + order. + 1. If a function is unpartitioned, place it in the current partition. + 2. If a function is already placed in a partition away from current + partition as part of another callchain: + Create a local clone in current partition, if cloning criteria is + satisfied. + 3. Redirect any new caller to a local clone if one exists. + Partition size is param controlled to fine tune per program behavior. */ + +#include "config.h" +#define INCLUDE_ALGORITHM +#include "system.h" +#include "coretypes.h" +#include "target.h" +#include "function.h" +#include "tree.h" +#include "alloc-pool.h" +#include "tree-pass.h" +#include "cgraph.h" +#include "symbol-summary.h" +#include "tree-vrp.h" +#include "symtab-thunks.h" +#include "sreal.h" +#include "ipa-cp.h" +#include "ipa-prop.h" +#include "ipa-fnsummary.h" +#include "ipa-modref-tree.h" +#include "ipa-modref.h" +#include "symtab-clones.h" +#include "ipa-locality-cloning.h" + +/* Locality partitions, assigns nodes to partitions. These are used later in + WPA partitioning. */ +vec<locality_partition> locality_partitions; + +/* Map from original node to its latest clone. Gets overwritten whenever a new + clone is created from the same node. */ +hash_map<cgraph_node *, cgraph_node *> node_to_clone; +/* Map from clone to its original node. */ +hash_map<cgraph_node *, cgraph_node *> clone_to_node; + +/* Data structure to hold static heuristics and orders for cgraph_nodes. */ +struct locality_order +{ + cgraph_node *node; + sreal order; + locality_order (cgraph_node *node, sreal order) : node (node), order (order) + {} +}; + +/* Return true if NODE is already in some partition. */ +static inline bool +node_partitioned_p (cgraph_node *node) +{ + return node->aux; +} + +/* Add symbol NODE to partition PART. */ +static void +add_node_to_partition (locality_partition part, cgraph_node *node) +{ + struct cgraph_edge *e; + if (node_partitioned_p (node)) + return; + + part->nodes.safe_push (node); + node->aux = (void *) (uintptr_t) (part->part_id); + + if (!node->alias && node->get_partitioning_class () == SYMBOL_PARTITION) + part->insns += ipa_size_summaries->get (node)->size; + + /* Add all inline clones and callees that are duplicated. */ + for (e = node->callees; e; e = e->next_callee) + if (!e->inline_failed) + add_node_to_partition (part, e->callee); + /* omp declare_variant_alt or transparent_alias with definition or linker + discardable (non-local comdat but not forced and not + used by non-LTO). */ + else if (e->callee->get_partitioning_class () == SYMBOL_DUPLICATE) + add_node_to_partition (part, e->callee); + + /* Add all thunks associated with the function. */ + for (e = node->callers; e; e = e->next_caller) + if (e->caller->thunk && !e->caller->inlined_to) + add_node_to_partition (part, e->caller); + + /* Add all aliases associated with the symbol. */ + struct ipa_ref *ref; + FOR_EACH_ALIAS (node, ref) + if (!ref->referring->transparent_alias) + { + cgraph_node *referring = dyn_cast<cgraph_node *> (ref->referring); + /* Only add function aliases. + Varpool refs are added later in LTO partitioning pass. */ + if (referring) + add_node_to_partition (part, referring); + } + else + { + struct ipa_ref *ref2; + /* We do not need to add transparent aliases if they are not used. + However we must add aliases of transparent aliases if they exist. */ + FOR_EACH_ALIAS (ref->referring, ref2) + { + /* Nested transparent aliases are not permitted. */ + gcc_checking_assert (!ref2->referring->transparent_alias); + cgraph_node *referring = dyn_cast<cgraph_node *> (ref2->referring); + if (referring) + add_node_to_partition (part, referring); + } + } +} + +/* Return TRUE if NODE is in PARTITION. */ +static bool +node_in_partition_p (locality_partition partition, cgraph_node *node) +{ + return ((uintptr_t) (partition->part_id) == (uintptr_t) (node->aux)); +} + +/* Helper function for qsort; to break ties. */ +static int +compare_node_uids (cgraph_node *n1, cgraph_node *n2) +{ + int res = n1->get_uid () - n2->get_uid (); + gcc_assert (res != 0); + return res > 0 ? 1 : -1; +} + +/* Helper function for qsort; sort nodes by order. */ +static int +static_profile_cmp (const void *pa, const void *pb) +{ + const locality_order *a = *static_cast<const locality_order *const *> (pa); + const locality_order *b = *static_cast<const locality_order *const *> (pb); + /* Ascending order. */ + if (b->order < a->order) + return 1; + if (b->order > a->order) + return -1; + return compare_node_uids (a->node, b->node); +} + +/* Helper function for qsort; sort nodes by profile count. */ +static int +compare_edge_profile_counts (const void *pa, const void *pb) +{ + const locality_order *a = *static_cast<const locality_order *const *> (pa); + const locality_order *b = *static_cast<const locality_order *const *> (pb); + + profile_count cnt1 = a->node->count.ipa (); + profile_count cnt2 = b->node->count.ipa (); + if (!cnt1.compatible_p (cnt2)) + return static_profile_cmp (pa, pb); + + if (cnt1 < cnt2) + return 1; + if (cnt1 > cnt2) + return -1; + return static_profile_cmp (pa, pb); +} + +/* Create and return a new partition and increment NPARTITIONS. */ + +static locality_partition +create_partition (int &npartitions) +{ + locality_partition part = XCNEW (struct locality_partition_def); + npartitions++; + part->part_id = npartitions; + part->nodes.create (1); + part->insns = 0; + locality_partitions.safe_push (part); + return part; +} + +/* Structure for holding profile count information of callers of a node. */ +struct profile_stats +{ + /* Sum of non-recursive call counts. */ + profile_count nonrec_count; + + /* Sum of recursive call counts. */ + profile_count rec_count; + + /* If non-NULL, this node is the target of alias or thunk and calls from this + should be count in rec_count. */ + cgraph_node *target; +}; + +/* Initialize fields of STATS. */ +static inline void +init_profile_stats (profile_stats *stats, cgraph_node *target = NULL) +{ + stats->nonrec_count = profile_count::zero (); + stats->rec_count = profile_count::zero (); + stats->target = target; +} + +/* Helper function of to accumulate call counts. */ +static bool +accumulate_profile_counts_after_cloning (cgraph_node *node, void *data) +{ + struct profile_stats *stats = (struct profile_stats *) data; + for (cgraph_edge *e = node->callers; e; e = e->next_caller) + { + if (!e->count.initialized_p ()) + continue; + + if (e->caller == stats->target) + stats->rec_count += e->count.ipa (); + else + stats->nonrec_count += e->count.ipa (); + } + return false; +} + +/* NEW_NODE is a previously created clone of ORIG_NODE already present in + current partition. EDGES contains newly redirected edges to NEW_NODE. + Adjust profile information for both nodes and the edge. */ + +static void +adjust_profile_info_for_non_self_rec_edges (auto_vec<cgraph_edge *> &edges, + cgraph_node *new_node, + cgraph_node *orig_node) +{ + profile_count orig_node_count = orig_node->count.ipa (); + profile_count edge_count = profile_count::zero (); + profile_count final_new_count = profile_count::zero (); + profile_count final_orig_count = profile_count::zero (); + + for (unsigned i = 0; i < edges.length (); ++i) + if (edges[i]->count.initialized_p ()) + edge_count += edges[i]->count.ipa (); + + final_orig_count = orig_node_count - edge_count; + + /* NEW_NODE->count was adjusted for other callers when the clone was + first created. Just add the new edge count. */ + final_new_count = new_node->count + edge_count; + + final_new_count = orig_node_count.combine_with_ipa_count (final_new_count); + orig_node->count = final_orig_count; + new_node->count = final_new_count; + + if (dump_file) + { + fprintf (dump_file, "Adjusting profile information for %s\n", + new_node->dump_asm_name ()); + fprintf (dump_file, "\tOriginal node %s\n", orig_node->dump_asm_name ()); + fprintf (dump_file, "\tOriginal count: "); + orig_node_count.dump (dump_file); + fprintf (dump_file, "\n\tAdjusted original count to: "); + final_orig_count.dump (dump_file); + fprintf (dump_file, "\n\tAdjusted clone count to: "); + final_new_count.dump (dump_file); + fprintf (dump_file, "\n"); + } + + /* Scale all callee edges according to adjusted counts. */ + profile_count orig_node_count_copy = orig_node_count; + profile_count::adjust_for_ipa_scaling (&final_new_count, + &orig_node_count_copy); + for (cgraph_edge *cs = new_node->callees; cs; cs = cs->next_callee) + cs->count = cs->count.apply_scale (final_new_count, orig_node_count_copy); + for (cgraph_edge *cs = new_node->indirect_calls; cs; cs = cs->next_callee) + cs->count = cs->count.apply_scale (final_new_count, orig_node_count_copy); + + profile_count::adjust_for_ipa_scaling (&final_orig_count, &orig_node_count); + for (cgraph_edge *cs = orig_node->callees; cs; cs = cs->next_callee) + cs->count = cs->count.apply_scale (final_orig_count, orig_node_count); + for (cgraph_edge *cs = orig_node->indirect_calls; cs; cs = cs->next_callee) + cs->count = cs->count.apply_scale (final_orig_count, orig_node_count); +} + +/* Adjust profile counts of NEW_NODE and ORIG_NODE, where NEW_NODE is a clone + of OLD_NODE. + Assumes that all eligible edges from current partition so far are redirected + to NEW_NODE and recursive edges are adjusted. */ + +static void +adjust_profile_info (cgraph_node *new_node, cgraph_node *orig_node) +{ + /* If all calls to NEW_NODE are non-recursive, subtract corresponding count + from ORIG_NODE and assign to NEW_NODE, any unexpected remainder stays with + ORIG_NODE. + Recursive calls if present, likely contribute to majority of count; + scale according to redirected callers' count. */ + + profile_count orig_node_count = orig_node->count.ipa (); + profile_stats new_stats, orig_stats; + + init_profile_stats (&new_stats); + init_profile_stats (&orig_stats); + + new_node->call_for_symbol_thunks_and_aliases + (accumulate_profile_counts_after_cloning, &new_stats, false); + orig_node->call_for_symbol_thunks_and_aliases + (accumulate_profile_counts_after_cloning, &orig_stats, false); + + profile_count orig_nonrec_count = orig_stats.nonrec_count; + profile_count orig_rec_count = orig_stats.rec_count; + profile_count new_nonrec_count = new_stats.nonrec_count; + profile_count new_rec_count = new_stats.rec_count; + + profile_count final_new_count = new_nonrec_count; + profile_count final_orig_count = profile_count::zero (); + + /* All calls to NEW_NODE are non-recursive or recursive calls have + zero count. */ + if (!new_rec_count.nonzero_p ()) + final_orig_count = orig_node_count - new_nonrec_count; + else + { + /* If ORIG_NODE is externally visible, indirect calls or calls from + another part of the code may contribute to the count. + update_profiling_info () from ipa-cp.cc pretends to have an extra + caller to represent the extra counts. */ + if (!orig_node->local) + { + profile_count pretend_count = (orig_node_count - new_nonrec_count - + orig_nonrec_count - orig_rec_count); + orig_nonrec_count += pretend_count; + } + + /* Remaining rec_count is assigned in proportion to clone's non-recursive + count. */ + profile_count rec_count = orig_node_count - new_nonrec_count + - orig_nonrec_count; + profile_count new_rec_scaled + = rec_count.apply_scale (new_nonrec_count, + new_nonrec_count + orig_nonrec_count); + final_new_count += new_rec_scaled; + final_orig_count = orig_node_count - final_new_count; + } + + final_new_count = orig_node_count.combine_with_ipa_count (final_new_count); + new_node->count = final_new_count; + orig_node->count = final_orig_count; + + if (dump_file) + { + fprintf (dump_file, "Adjusting profile information for %s\n", + new_node->dump_asm_name ()); + fprintf (dump_file, "\tOriginal node %s\n", orig_node->dump_asm_name ()); + fprintf (dump_file, "\tOriginal count: "); + orig_node_count.dump (dump_file); + fprintf (dump_file, "\n\tAdjusted original count to: "); + final_orig_count.dump (dump_file); + fprintf (dump_file, "\n\tAdjusted clone count to: "); + final_new_count.dump (dump_file); + fprintf (dump_file, "\n"); + } + + /* Scale all callee edges according to adjusted counts. */ + profile_count orig_node_count_copy = orig_node_count; + profile_count::adjust_for_ipa_scaling (&final_new_count, + &orig_node_count_copy); + for (cgraph_edge *cs = new_node->callees; cs; cs = cs->next_callee) + cs->count = cs->count.apply_scale (final_new_count, orig_node_count_copy); + for (cgraph_edge *cs = new_node->indirect_calls; cs; cs = cs->next_callee) + cs->count = cs->count.apply_scale (final_new_count, orig_node_count_copy); + + profile_count::adjust_for_ipa_scaling (&final_orig_count, &orig_node_count); + for (cgraph_edge *cs = orig_node->callees; cs; cs = cs->next_callee) + cs->count = cs->count.apply_scale (final_orig_count, orig_node_count); + for (cgraph_edge *cs = orig_node->indirect_calls; cs; cs = cs->next_callee) + cs->count = cs->count.apply_scale (final_orig_count, orig_node_count); +} + +/* Return true if EDGE can be safely redirected to another callee. */ +static inline bool +edge_redirectable_p (cgraph_edge *edge, lto_locality_cloning_model cm) +{ + if (cm == LTO_LOCALITY_NON_INTERPOSABLE_CLONING) + { + /* Interposability may change on edge basis. */ + enum availability avail; + avail = edge->callee->get_availability (edge->caller); + if (avail <= AVAIL_INTERPOSABLE) + return false; + } + return true; +} + +/* Create a locality clone of CNODE and redirect all callers present in + PARTITION. + Create a clone dpending on whether CNODE itself is a clone or not. */ + +static cgraph_node * +create_locality_clone (cgraph_node *cnode, + locality_partition partition, int &cl_num, + lto_locality_cloning_model cm) +{ + cgraph_node *cl_node = NULL; + vec<cgraph_edge *> redirect_callers = vNULL; + /* All callers of cnode in current partition are redirected. */ + struct cgraph_edge *edge; + for (edge = cnode->callers; edge; edge = edge->next_caller) + { + struct cgraph_node *caller = edge->caller; + if (node_in_partition_p (partition, caller) && caller->definition + && caller != cnode && edge_redirectable_p (edge, cm)) + redirect_callers.safe_push (edge); + } + + const char *suffix = "locality_clone"; + + tree old_decl = cnode->decl; + tree new_decl = copy_node (old_decl); + + /* Generate a new name for the new version. */ + const char *name = IDENTIFIER_POINTER (DECL_NAME (old_decl)); + DECL_NAME (new_decl) = clone_function_name (name, suffix, cl_num); + SET_DECL_ASSEMBLER_NAME (new_decl, + clone_function_name (old_decl, suffix, cl_num)); + cl_num++; + if (dump_file) + fprintf (dump_file, "\tNew name %s\n", + IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (new_decl))); + + cl_node = cnode->create_clone (new_decl, cnode->count /*profile_count*/, + false /*update_original*/, redirect_callers, + false /*call_duplication_hook*/, + NULL /*new_inlined_to*/, + NULL /*param_adjustments*/, suffix); + + set_new_clone_decl_and_node_flags (cl_node); + + if (cnode->ipa_transforms_to_apply.exists ()) + cl_node->ipa_transforms_to_apply + = cnode->ipa_transforms_to_apply.copy (); + + if (dump_file) + { + fprintf (dump_file, "Cloned Node: %s %s\n", cnode->dump_asm_name (), + cl_node->dump_asm_name ()); + + for (edge = cl_node->callers; edge; edge = edge->next_caller) + fprintf (dump_file, "Redirected callers: %s\n", + edge->caller->dump_asm_name ()); + + for (edge = cl_node->callees; edge; edge = edge->next_callee) + fprintf (dump_file, "Callees of clone: %s %d\n", + edge->callee->dump_asm_name (), edge->frequency ()); + } + return cl_node; +} + +/* Redirect recursive edges of CLONE to correctly point to CLONE. As part of + cloning process, all callee edges of a node are just duplicated but not + redirected. Therefore, these edges still call to original of CLONE. + + For non-inlined CLONEs, NEW_CALLEE == CLONE and ORIG_CALLEE is CLONE's + original node. + + For inlined node, self recursion to CLONE's original same as non-inlined, + additionally, calls to CLONE->inlined_to are also recursive: + NEW_CALLEE == CLONE->inlined_into and + ORIG_CALLEE == original node of CLONE->inlined_into. */ + +static void +adjust_recursive_callees (cgraph_node *clone, cgraph_node *new_callee, + cgraph_node *orig_callee) +{ + cgraph_node *alias = NULL; + for (cgraph_edge *e = clone->callees; e; e = e->next_callee) + { + if (!e->inline_failed) + continue; + + /* Only self-cycle or local alias are handled. */ + cgraph_node *callee = e->callee; + if (callee == orig_callee) + { + cgraph_node **cl = node_to_clone.get (orig_callee); + gcc_assert (cl && *cl == new_callee); + e->redirect_callee_duplicating_thunks (new_callee); + if (dump_file) + fprintf (dump_file, "recursive call from %s to %s orig %s\n", + e->caller->dump_asm_name (), e->callee->dump_asm_name (), + callee->dump_asm_name ()); + } + else if (callee->alias + && e->callee->ultimate_alias_target () == orig_callee) + { + if (!alias) + { + alias = dyn_cast<cgraph_node *> ( + new_callee->noninterposable_alias ()); + } + e->redirect_callee_duplicating_thunks (alias); + if (dump_file) + fprintf (dump_file, "recursive call from %s to %s orig %s\n", + e->caller->dump_asm_name (), e->callee->dump_asm_name (), + callee->dump_asm_name ()); + } + } + new_callee->expand_all_artificial_thunks (); + if (alias) + alias->expand_all_artificial_thunks (); +} + +/* Create clones for CALLER's inlined callees, ORIG_INLINED_TO is the original + node from clone_as_needed () such that new_inlined_to is a clone of it. */ + +static void +inline_clones (cgraph_node *caller, cgraph_node *orig_inlined_to) +{ + struct cgraph_edge *edge; + for (edge = caller->callees; edge; edge = edge->next_callee) + { + struct cgraph_node *callee = edge->callee; + if (edge->inline_failed) + continue; + + if (callee->inlined_to != orig_inlined_to) + continue; + + struct cgraph_node *new_inlined_to, *cl; + if (caller->inlined_to) + new_inlined_to = caller->inlined_to; + else + new_inlined_to = caller; + + cl = callee->create_clone (callee->decl, + edge->count /*profile_count*/, + true /*update_original*/, + vNULL /*redirect_callers*/, + false /*call_duplication_hook*/, + new_inlined_to /*new_inlined_to*/, + NULL /*param_adjustments*/, + "locality_clone" /*suffix*/); + edge->redirect_callee (cl); + + node_to_clone.put (callee, cl); + clone_to_node.put (cl, callee); + + if (callee->thunk) + { + thunk_info *info = thunk_info::get (callee); + *thunk_info::get_create (cl) = *info; + } + + adjust_recursive_callees (cl, new_inlined_to, orig_inlined_to); + adjust_recursive_callees (cl, cl, callee); + if (dump_file) + { + fprintf (dump_file, "Inline cloned\n"); + cl->dump (dump_file); + } + + /* Recursively inline till end of this callchain. */ + inline_clones (cl, orig_inlined_to); + } +} + +/* Clone EDGE->CALLEE if it or a clone of it is not already in PARTITION. + Redirect all callers of EDGE->CALLEE that are in PARTITION, not just the + EDGE. If a clone is already present in PARTITION, redirect all edges from + EDGE->CALLER to EDGE->CALLEE. This is because we only visit one edge per + caller to callee and redirect for all others from there. + + If cloning, also recursively clone inlined functions till the end of the + callchain because inlined clones have 1-1 exclusive copy and edge from + caller to inlined node. + + There are 2 flows possible: + 1. Only redirect + 1.1. cnode is already in current partition - cnode mustn't be a + locality_clone -> nothing to do + 1.2. A clone of cnode is in current partition - find out if it's the + correct clone for edge - must be a locality_clone but the exact same + kind as callee i.e. orig or cp/sra clone, if yes, redirect, else go to #2 + 1.3. Cnode/a clone of cnode is in current partition but caller is inlined + 2. Clone and redirect + 2.1. cnode is original node + 2.2. cnode itself is a clone + Clone inlines + Flavors of edges: + 1. Normal -> orig nodes, locality clones or cp/sra clones + 2. Recursive -> direct recursion + 3. Alias -> recursion via aliasing or as a result of IPA code duplication + 4. Inline -> shouldn't be included in callchain. */ + +static cgraph_node * +clone_node_as_needed (cgraph_edge *edge, locality_partition partition, + int &cl_num, lto_locality_cloning_model cm) +{ + /* suitable_for_locality_cloning_p () currently prohibits cloning aliases due + to potential versioning and materialization issues. Could be enabled in + the future. suitable_for_locality_cloning_p () also checks for + interposability for CNODE but not for edge redirection. */ + struct cgraph_node *cnode = edge->callee; + struct cgraph_node *caller = edge->caller; + + /* If clone of cnode is already in the partition + Get latest clone of cnode. If current partition has cloned cnode, that + clone should be returned. Otherwise, clone from previous partition is + returned + Original node and its clone shouldn't co-exist in current partition + + This is required if callee is partitioned via another edge before caller + was, and we are now visiting caller->callee edge + + 1) a -> b ==> a -> bc1; b was cloned say via d -> bc1, a is orig + 2) ac1 -> b ==> ac1 -> bc1; b was cloned and a was just cloned + 3) a -> bc1 and bc2 present, mustn't happen, b was cloned and a was + redirected without being partitioned first. + Why will we do this again - multiple edges and something's wrong in + partition_callchain () + 4) ac1 -> bc1 ==> ac1 -> bc2; a was cloned and we already got (1) in some + other partition + 5) ac1 -> bc1 but no clone present in this PARTITION. Create from b, not + from bc1? + 6) a -> b; a -> bc0; create new clone, no clone present + 7) ac0 -> b; ac0 -> bc0 same as (6) + 8) a -> bc0 and no clone present, mustn't happen, same as (3) + + Redirect when bc1 is present and: + a -> b or ac -> b or ac -> bc0 */ + + cgraph_node *orig_cnode = cnode; + cgraph_node **o_cnode = clone_to_node.get (cnode); + if (o_cnode) + orig_cnode = *o_cnode; + + cgraph_node **cnode_cl = node_to_clone.get (orig_cnode); + + if (cnode_cl && node_in_partition_p (partition, *cnode_cl)) + { + if (node_in_partition_p (partition, caller)) + { + bool clone_p = false; + auto_vec<cgraph_edge *> redirected_edges; + for (cgraph_edge *ec = caller->callees; ec; ec = ec->next_callee) + if (ec->callee == cnode && edge_redirectable_p (ec, cm)) + { + ec->redirect_callee_duplicating_thunks (*cnode_cl); + clone_p = true; + redirected_edges.safe_push (ec); + if (dump_file) + { + fprintf (dump_file, "clone present %s %s redirecting %s\n", + cnode->dump_asm_name (), + (*cnode_cl)->dump_asm_name (), + caller->dump_asm_name ()); + } + } + if (clone_p) + { + (*cnode_cl)->expand_all_artificial_thunks (); + adjust_profile_info_for_non_self_rec_edges (redirected_edges, + *cnode_cl, cnode); + return NULL; + } + } + } + + /* Create a new clone for a -> b, ac -> b. + For ac -> bc, should be done on bc or b? + bc could be from b_cp/b_sra or b. */ + + if (orig_cnode != cnode) + { + if (dump_file) + fprintf (dump_file, "Clone of clone %s %s\n", cnode->dump_asm_name (), + orig_cnode->dump_asm_name ()); + return NULL; + } + + struct cgraph_node *cloned_node + = create_locality_clone (cnode, partition, cl_num, cm); + + gcc_assert (cloned_node); + if (!cloned_node) + return NULL; + + node_to_clone.put (cnode, cloned_node); + clone_to_node.put (cloned_node, cnode); + + adjust_recursive_callees (cloned_node, cloned_node, cnode); + symtab->call_cgraph_duplication_hooks (cnode, cloned_node); + + adjust_profile_info (cloned_node, cnode); + /* Inline clones are created iff their inlined_to == CNODE. */ + inline_clones (cloned_node, cnode); + + return cloned_node; +} + +/* Accumulate frequency of all edges from EDGE->caller to EDGE->callee. */ + +static sreal +accumulate_incoming_edge_frequency (cgraph_edge *edge) +{ + sreal count = 0; + struct cgraph_edge *e; + for (e = edge->callee->callers; e; e = e->next_caller) + { + /* Make a local decision about all edges for EDGE->caller but not the + other nodes already in the partition. Their edges will be visited + later or may have been visited before and not fit the + cut-off criteria. */ + if (e->caller == edge->caller) + count += e->sreal_frequency (); + } + return count; +} + +/* Determine if EDGE->CALLEE is suitable for cloning. It is assummed that the + callee is not an inlined node. */ + +static bool +suitable_for_locality_cloning_p (cgraph_edge *edge, + lto_locality_cloning_model cm) +{ + cgraph_node *node = edge->callee; + if (!node->versionable) + return false; + + /* Out-of-line locality clones of ipcp or sra clones will be created in this + pass after IPA inline is run. A locality clone has the same function + body and the same updated signature as the ipcp/sra clone. + This fails or asserts based on how the clone is created: + 1. If param_adjustments and tree_map are not recorded for locality clone: + clone materialization (tree_function_versioning ()) fails when + updating signature and remapping calls because clone_of (ipcp/sra + clone) and locality clone differ in param information. + 2. If param_adjustments and tree_map are provided: asserts are triggered + in fnsummary duplication because IPA inline resets some summaries. + + One inelegant solution is to provide param_adjustments and tree_map, and + then set clone_of to ipcp/sra clone's clone_of. However, this sometimes + results in segmentation fault when the compiled program is run. + Disabling clone of clones altogether for now with an aim to resolve this + is future. */ + if (node->clone_of) + return false; + + if (node->alias) + return false; + + if (edge->recursive_p ()) + return false; + + if (!node->definition) + return false; + + /* Don't clone NODE if IPA count of NODE or EDGE is zero. */ + if (!node->count.ipa ().nonzero_p () || !edge->count.ipa ().nonzero_p ()) + return false; + + if (cm == LTO_LOCALITY_NON_INTERPOSABLE_CLONING) + { + /* Interposability may change on edge basis. */ + enum availability avail; + edge->callee->ultimate_alias_target (&avail, edge->caller); + if (avail <= AVAIL_INTERPOSABLE) + return false; + } + + return true; +} + +/* Map from caller to all callees already visited for partitioning. */ +hash_map<cgraph_node *, auto_vec<cgraph_node *> > caller_to_callees; + +/* Partition EDGE->CALLEE into PARTITION or clone if already partitioned and + satisfies cloning criteria such as CLONING_MODEL, REAL_FREQ and SIZE + cut-offs and CLONE_FURTHER_P set by previous caller. */ + +/* callgraph can have multiple caller to callee edges for multiple callsites + For the first such edge, we make decisions about cutoffs and cloning because + we redirect ALL callsites to cloned callee, not just one of them. */ + +static void +partition_callchain (cgraph_edge *edge, locality_partition partition, + bool clone_further_p, + lto_locality_cloning_model cloning_model, + double freq_cutoff, int size, int &cl_num) +{ + /* Aliases are added in the same partition as their targets. + Aliases are not cloned and their callees are not processed separately. */ + cgraph_node *node = edge->callee->ultimate_alias_target (); + cgraph_node *caller = edge->caller; + cgraph_node *caller_node = node, *cl_node = NULL; + + /* Already visited the caller to callee edges. */ + auto_vec<cgraph_node *> &callees = caller_to_callees.get_or_insert (caller); + if (std::find (callees.begin (), callees.end (), node) != callees.end ()) + return; + + callees.safe_push (node); + + if (node->get_partitioning_class () == SYMBOL_PARTITION) + { + if (!node_partitioned_p (node)) + { + add_node_to_partition (partition, node); + if (dump_file) + fprintf (dump_file, "Partitioned node: %s\n", + node->dump_asm_name ()); + } + else if (cloning_model >= LTO_LOCALITY_NON_INTERPOSABLE_CLONING + && !node_in_partition_p (partition, node)) + { + /* Non-inlined node, or alias, already partitioned + If cut-off, don't clone callees but partition unpartitioned + callees. + size is node + inlined nodes. */ + if (clone_further_p) + { + if (!node->alias) + if (ipa_size_summaries->get (node)->size >= size) + clone_further_p = false; + + if (freq_cutoff != 0.0) + { + sreal acc_freq = accumulate_incoming_edge_frequency (edge); + if (acc_freq.to_double () < freq_cutoff) + clone_further_p = false; + } + } + + if (!suitable_for_locality_cloning_p (edge, cloning_model)) + clone_further_p = false; + + if (clone_further_p) + { + /* Try to clone NODE and its inline chain. */ + if (dump_file) + fprintf (dump_file, "Cloning node: %s\n", + node->dump_asm_name ()); + cl_node = clone_node_as_needed (edge, partition, cl_num, + cloning_model); + if (cl_node) + { + add_node_to_partition (partition, cl_node); + caller_node = cl_node; + } + else + caller_node = NULL; + } + } + } + else if (!node->inlined_to) + return; + + if (caller_node) + for (cgraph_edge *e = caller_node->callees; e; e = e->next_callee) + partition_callchain (e, partition, clone_further_p, cloning_model, + freq_cutoff, size, cl_num); +} + +/* Determine whether NODE is an entrypoint to a callchain. */ + +static bool +is_entry_node_p (cgraph_node *node) +{ + /* node->inlined_to is returned as SYMBOL_DUPLICATE. */ + if (node->get_partitioning_class () != SYMBOL_PARTITION) + return false; + + if (!node->callers) + return true; + + for (cgraph_edge *e = node->callers; e; e = e->next_caller) + { + if (! e->recursive_p ()) + return false; + } + if (node->alias + && !is_entry_node_p (node->ultimate_alias_target ())) + return false; + return true; +} + +/* Determine order of all external nodes if PGO profile is available. + Store the order in ORDER. */ + +static bool +locality_determine_ipa_order (auto_vec<locality_order *> *order) +{ + struct cgraph_node *node; + auto_vec<locality_order *> non_comparable_nodes; + FOR_EACH_DEFINED_FUNCTION (node) + if (node->get_partitioning_class () == SYMBOL_PARTITION) + { + if (node->no_reorder) + { + if (dump_file) + fprintf (dump_file, "no reorder %s\n", node->dump_asm_name ()); + return false; + } + else if (is_entry_node_p (node)) + { + profile_count pcnt = node->count.ipa (); + if (!pcnt.initialized_p () || !pcnt.ipa_p ()) + { + sreal cnt = 0; + locality_order *lo = new locality_order (node, cnt); + non_comparable_nodes.safe_push (lo); + continue; + } + sreal count = 0; + struct cgraph_edge *edge; + for (edge = node->callees; edge; edge = edge->next_callee) + { + /* For PGO, frequency is not used in + compare_edge_profile_counts (), it's used only as part of + static profile order. */ + sreal freq = edge->sreal_frequency (); + count += freq; + } + locality_order *cl = new locality_order (node, count); + order->safe_push (cl); + } + } + order->qsort (compare_edge_profile_counts); + for (auto el : non_comparable_nodes) + order->safe_push (el); + return true; +} + +/* Determine order of all external nodes if only static profile is available. + Store the order in ORDER. */ + +static bool +locality_determine_static_order (auto_vec<locality_order *> *order) +{ + struct cgraph_node *node; + FOR_EACH_DEFINED_FUNCTION (node) + if (node->get_partitioning_class () == SYMBOL_PARTITION) + { + if (node->no_reorder) + { + if (dump_file) + fprintf (dump_file, "no reorder %s\n", node->dump_asm_name ()); + return false; + } + else if (is_entry_node_p (node)) + { + sreal count = 0; + struct cgraph_edge *edge; + for (edge = node->callees; edge; edge = edge->next_callee) + { + sreal freq = edge->sreal_frequency (); + count += freq; + } + locality_order *cl = new locality_order (node, count); + order->safe_push (cl); + } + } + order->qsort (static_profile_cmp); + return true; +} + +/* Partitioning for code locality. + 1. Create and sort callchains. If PGO is available, use real profile + counts. Otherwise, use a set of heuristics to sort the callchains. + 2. Partition the external nodes and their callchains in the determined order + 2.1. If !partition, partition, else try and clone if it satisfies cloning + criteria. + 3. Partition all other unpartitioned nodes. */ + +static void +locality_partition_and_clone (int max_locality_partition_size, + lto_locality_cloning_model cloning_model, + int freq_denominator, int size) +{ + locality_partition partition; + int npartitions = 0; + + auto_vec<locality_order *> order; + auto_vec<varpool_node *> varpool_order; + struct cgraph_node *node; + bool order_p; + + int cl_num = 0; + + double real_freq = 0.0; + if (freq_denominator > 0) + real_freq = 1.0 / (double) freq_denominator; + + cgraph_node *n = symtab->first_defined_function (); + if (n && n->count.ipa_p ()) + order_p = locality_determine_ipa_order (&order); + else + order_p = locality_determine_static_order (&order); + if (!order_p) + { + if (dump_file) + { + fprintf (dump_file, "Locality partition: falling back to balanced" + "model\n"); + } + + return; + } + + int64_t partition_size + = max_locality_partition_size + ? max_locality_partition_size : param_max_partition_size; + partition = create_partition (npartitions); + + for (unsigned i = 0; i < order.length (); i++) + { + node = order[i]->node; + if (node_partitioned_p (node)) + continue; + + if (partition->insns > partition_size) + partition = create_partition (npartitions); + if (dump_file) + fprintf (dump_file, "Partition id: %d\n", partition->part_id); + + add_node_to_partition (partition, node); + if (dump_file) + fprintf (dump_file, "Ordered Node: %s\n", node->dump_asm_name ()); + + for (cgraph_edge *edge = node->callees; edge; edge = edge->next_callee) + { + /* Recursively partition the callchain of edge->callee. */ + partition_callchain (edge, partition, true, cloning_model, real_freq, + size, cl_num); + } + } + + for (unsigned i = 0; i < order.length (); i++) + delete order[i]; + order = vNULL; +} + +/* Entry point to locality-clone pass. */ +static int +lc_execute (void) +{ + symtab_node *node; + FOR_EACH_SYMBOL (node) + node->aux = NULL; + + locality_partition_and_clone (param_max_locality_partition_size, + flag_lto_locality_cloning, + param_lto_locality_frequency, + param_lto_locality_size); + + FOR_EACH_SYMBOL (node) + node->aux = NULL; + return 0; +} + +namespace { + +const pass_data pass_data_ipa_locality_clone = { + IPA_PASS, /* type */ + "locality-clone", /* name */ + OPTGROUP_NONE, /* optinfo_flags */ + TV_IPA_LC, /* tv_id */ + 0, /* properties_required */ + 0, /* properties_provided */ + 0, /* properties_destroyed */ + 0, /* todo_flags_start */ + (TODO_dump_symtab | TODO_remove_functions), /* todo_flags_finish */ +}; + +class pass_ipa_locality_cloning : public ipa_opt_pass_d +{ +public: + pass_ipa_locality_cloning (gcc::context *ctxt) + : ipa_opt_pass_d (pass_data_ipa_locality_clone, ctxt, + NULL, /* generate_summary */ + NULL, /* write_summary */ + NULL, /* read_summary */ + NULL, /* write_optimization_summary */ + NULL, /* read_optimization_summary */ + NULL, /* stmt_fixup */ + 0, /* function_transform_todo_flags_start */ + NULL, /* function_transform */ + NULL) /* variable_transform */ + {} + + /* opt_pass methods: */ + virtual bool gate (function *) + { + return (flag_wpa && flag_ipa_reorder_for_locality); + } + + virtual unsigned int execute (function *) { return lc_execute (); } + +}; // class pass_ipa_locality_cloning + +} // namespace + +ipa_opt_pass_d * +make_pass_ipa_locality_cloning (gcc::context *ctxt) +{ + return new pass_ipa_locality_cloning (ctxt); +} diff --git a/gcc/ipa-locality-cloning.h b/gcc/ipa-locality-cloning.h new file mode 100644 index 0000000..591ce57 --- /dev/null +++ b/gcc/ipa-locality-cloning.h @@ -0,0 +1,35 @@ +/* LTO partitioning logic routines. + Copyright The GNU Toolchain Authors + +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 +<http://www.gnu.org/licenses/>. */ + +#ifndef IPA_LOCALITY_CLONING_H +#define IPA_LOCALITY_CLONING_H + +/* Structure describing locality partitions. */ +struct locality_partition_def +{ + int part_id; + vec<cgraph_node *> nodes; + int insns; +}; + +typedef struct locality_partition_def *locality_partition; + +extern vec<locality_partition> locality_partitions; + +#endif /* IPA_LOCALITY_CLONING_H */ diff --git a/gcc/ipa-prop.cc b/gcc/ipa-prop.cc index a120f94..0398d69 100644 --- a/gcc/ipa-prop.cc +++ b/gcc/ipa-prop.cc @@ -60,6 +60,7 @@ along with GCC; see the file COPYING3. If not see #include "gimple-range.h" #include "value-range-storage.h" #include "vr-values.h" +#include "lto-streamer.h" /* Function summary where the parameter infos are actually stored. */ ipa_node_params_t *ipa_node_params_sum = NULL; @@ -454,7 +455,11 @@ ipa_dump_jump_function (FILE *f, ipa_jump_func *jump_func, if (jump_func->value.pass_through.operation != NOP_EXPR) { fprintf (f, " "); - print_generic_expr (f, jump_func->value.pass_through.operand); + if (jump_func->value.pass_through.operand) + print_generic_expr (f, jump_func->value.pass_through.operand); + fprintf (f, " (in type "); + print_generic_expr (f, jump_func->value.pass_through.op_type); + fprintf (f, ")"); } if (jump_func->value.pass_through.agg_preserved) fprintf (f, ", agg_preserved"); @@ -510,7 +515,11 @@ ipa_dump_jump_function (FILE *f, ipa_jump_func *jump_func, if (item->value.pass_through.operation != NOP_EXPR) { fprintf (f, " "); - print_generic_expr (f, item->value.pass_through.operand); + if (item->value.pass_through.operand) + print_generic_expr (f, item->value.pass_through.operand); + fprintf (f, " (in type "); + print_generic_expr (f, jump_func->value.pass_through.op_type); + fprintf (f, ")"); } } else if (item->jftype == IPA_JF_CONST) @@ -682,6 +691,7 @@ ipa_set_jf_simple_pass_through (struct ipa_jump_func *jfunc, int formal_id, { jfunc->type = IPA_JF_PASS_THROUGH; jfunc->value.pass_through.operand = NULL_TREE; + jfunc->value.pass_through.op_type = NULL_TREE; jfunc->value.pass_through.formal_id = formal_id; jfunc->value.pass_through.operation = NOP_EXPR; jfunc->value.pass_through.agg_preserved = agg_preserved; @@ -692,10 +702,11 @@ ipa_set_jf_simple_pass_through (struct ipa_jump_func *jfunc, int formal_id, static void ipa_set_jf_unary_pass_through (struct ipa_jump_func *jfunc, int formal_id, - enum tree_code operation) + enum tree_code operation, tree op_type) { jfunc->type = IPA_JF_PASS_THROUGH; jfunc->value.pass_through.operand = NULL_TREE; + jfunc->value.pass_through.op_type = op_type; jfunc->value.pass_through.formal_id = formal_id; jfunc->value.pass_through.operation = operation; jfunc->value.pass_through.agg_preserved = false; @@ -705,10 +716,12 @@ ipa_set_jf_unary_pass_through (struct ipa_jump_func *jfunc, int formal_id, static void ipa_set_jf_arith_pass_through (struct ipa_jump_func *jfunc, int formal_id, - tree operand, enum tree_code operation) + tree operand, enum tree_code operation, + tree op_type) { jfunc->type = IPA_JF_PASS_THROUGH; jfunc->value.pass_through.operand = unshare_expr_without_location (operand); + jfunc->value.pass_through.op_type = op_type; jfunc->value.pass_through.formal_id = formal_id; jfunc->value.pass_through.operation = operation; jfunc->value.pass_through.agg_preserved = false; @@ -1513,6 +1526,9 @@ compute_complex_assign_jump_func (struct ipa_func_body_info *fbi, if (index >= 0) { + if (lto_variably_modified_type_p (TREE_TYPE (name))) + return; + switch (gimple_assign_rhs_class (stmt)) { case GIMPLE_BINARY_RHS: @@ -1526,7 +1542,8 @@ compute_complex_assign_jump_func (struct ipa_func_body_info *fbi, return; ipa_set_jf_arith_pass_through (jfunc, index, op2, - gimple_assign_rhs_code (stmt)); + gimple_assign_rhs_code (stmt), + TREE_TYPE (name)); break; } case GIMPLE_SINGLE_RHS: @@ -1539,7 +1556,8 @@ compute_complex_assign_jump_func (struct ipa_func_body_info *fbi, case GIMPLE_UNARY_RHS: if (!CONVERT_EXPR_CODE_P (gimple_assign_rhs_code (stmt))) ipa_set_jf_unary_pass_through (jfunc, index, - gimple_assign_rhs_code (stmt)); + gimple_assign_rhs_code (stmt), + TREE_TYPE (name)); default:; } return; @@ -1912,6 +1930,7 @@ analyze_agg_content_value (struct ipa_func_body_info *fbi, if (!is_gimple_assign (stmt)) break; + lhs = gimple_assign_lhs (stmt); rhs1 = gimple_assign_rhs1 (stmt); } @@ -1931,7 +1950,8 @@ analyze_agg_content_value (struct ipa_func_body_info *fbi, PASS-THROUGH jump function with ASSERT_EXPR operation whith operand 1 (the constant from the PHI node). */ - if (gimple_phi_num_args (phi) != 2) + if (gimple_phi_num_args (phi) != 2 + || lto_variably_modified_type_p (TREE_TYPE (lhs))) return; tree arg0 = gimple_phi_arg_def (phi, 0); tree arg1 = gimple_phi_arg_def (phi, 1); @@ -1956,6 +1976,7 @@ analyze_agg_content_value (struct ipa_func_body_info *fbi, code = ASSERT_EXPR; agg_value->pass_through.operand = operand; + agg_value->pass_through.op_type = TREE_TYPE (lhs); } else if (is_gimple_assign (stmt)) { @@ -1980,10 +2001,12 @@ analyze_agg_content_value (struct ipa_func_body_info *fbi, with one operand, here we only allow tc_unary operation to avoid possible problem. Then we can use (opclass == tc_unary) or not to distinguish unary and binary. */ - if (TREE_CODE_CLASS (code) != tcc_unary || CONVERT_EXPR_CODE_P (code)) + if (TREE_CODE_CLASS (code) != tcc_unary || CONVERT_EXPR_CODE_P (code) + || lto_variably_modified_type_p (TREE_TYPE (lhs))) return; rhs1 = get_ssa_def_if_simple_copy (rhs1, &stmt); + agg_value->pass_through.op_type = TREE_TYPE (lhs); break; case GIMPLE_BINARY_RHS: @@ -1992,12 +2015,16 @@ analyze_agg_content_value (struct ipa_func_body_info *fbi, gimple *rhs2_stmt = stmt; tree rhs2 = gimple_assign_rhs2 (stmt); + if (lto_variably_modified_type_p (TREE_TYPE (lhs))) + return; + rhs1 = get_ssa_def_if_simple_copy (rhs1, &rhs1_stmt); rhs2 = get_ssa_def_if_simple_copy (rhs2, &rhs2_stmt); if (is_gimple_ip_invariant (rhs2)) { agg_value->pass_through.operand = rhs2; + agg_value->pass_through.op_type = TREE_TYPE (lhs); stmt = rhs1_stmt; } else if (is_gimple_ip_invariant (rhs1)) @@ -2008,6 +2035,7 @@ analyze_agg_content_value (struct ipa_func_body_info *fbi, return; agg_value->pass_through.operand = rhs1; + agg_value->pass_through.op_type = TREE_TYPE (lhs); stmt = rhs2_stmt; rhs1 = rhs2; } @@ -3520,12 +3548,17 @@ update_jump_functions_after_inlining (struct cgraph_edge *cs, ipa_set_jf_simple_pass_through (dst, formal_id, agg_p); } else if (TREE_CODE_CLASS (operation) == tcc_unary) - ipa_set_jf_unary_pass_through (dst, formal_id, operation); + { + tree op_t = ipa_get_jf_pass_through_op_type (src); + ipa_set_jf_unary_pass_through (dst, formal_id, operation, + op_t); + } else { tree operand = ipa_get_jf_pass_through_operand (src); + tree op_t = ipa_get_jf_pass_through_op_type (src); ipa_set_jf_arith_pass_through (dst, formal_id, operand, - operation); + operation, op_t); } break; } @@ -4935,9 +4968,13 @@ ipa_write_jump_function (struct output_block *ob, } else if (TREE_CODE_CLASS (jump_func->value.pass_through.operation) == tcc_unary) - streamer_write_uhwi (ob, jump_func->value.pass_through.formal_id); + { + stream_write_tree (ob, jump_func->value.pass_through.op_type, true); + streamer_write_uhwi (ob, jump_func->value.pass_through.formal_id); + } else { + stream_write_tree (ob, jump_func->value.pass_through.op_type, true); stream_write_tree (ob, jump_func->value.pass_through.operand, true); streamer_write_uhwi (ob, jump_func->value.pass_through.formal_id); } @@ -4979,6 +5016,8 @@ ipa_write_jump_function (struct output_block *ob, case IPA_JF_LOAD_AGG: streamer_write_uhwi (ob, item->value.pass_through.operation); streamer_write_uhwi (ob, item->value.pass_through.formal_id); + if (item->value.pass_through.operation != NOP_EXPR) + stream_write_tree (ob, item->value.pass_through.op_type, true); if (TREE_CODE_CLASS (item->value.pass_through.operation) != tcc_unary) stream_write_tree (ob, item->value.pass_through.operand, true); @@ -5047,15 +5086,18 @@ ipa_read_jump_function (class lto_input_block *ib, } else if (TREE_CODE_CLASS (operation) == tcc_unary) { + tree op_type = stream_read_tree (ib, data_in); int formal_id = streamer_read_uhwi (ib); - ipa_set_jf_unary_pass_through (jump_func, formal_id, operation); + ipa_set_jf_unary_pass_through (jump_func, formal_id, operation, + op_type); } else { + tree op_type = stream_read_tree (ib, data_in); tree operand = stream_read_tree (ib, data_in); int formal_id = streamer_read_uhwi (ib); ipa_set_jf_arith_pass_through (jump_func, formal_id, operand, - operation); + operation, op_type); } break; case IPA_JF_ANCESTOR: @@ -5103,6 +5145,10 @@ ipa_read_jump_function (class lto_input_block *ib, operation = (enum tree_code) streamer_read_uhwi (ib); item.value.pass_through.operation = operation; item.value.pass_through.formal_id = streamer_read_uhwi (ib); + if (operation != NOP_EXPR) + item.value.pass_through.op_type = stream_read_tree (ib, data_in); + else + item.value.pass_through.op_type = NULL_TREE; if (TREE_CODE_CLASS (operation) == tcc_unary) item.value.pass_through.operand = NULL_TREE; else @@ -5393,6 +5439,49 @@ ipa_read_node_info (class lto_input_block *ib, struct cgraph_node *node, } } +/* Stream out ipa_return_summary. */ +static void +ipa_write_return_summaries (output_block *ob) +{ + if (!ipa_return_value_sum) + { + streamer_write_uhwi (ob, 0); + return; + } + + lto_symtab_encoder_t encoder = ob->decl_state->symtab_node_encoder; + unsigned int count = 0; + for (int i = 0; i < lto_symtab_encoder_size (encoder); i++) + { + symtab_node *snode = lto_symtab_encoder_deref (encoder, i); + cgraph_node *cnode = dyn_cast <cgraph_node *> (snode); + ipa_return_value_summary *v; + + if (cnode && cnode->definition && !cnode->alias + && (v = ipa_return_value_sum->get (cnode)) + && v->vr) + count++; + } + streamer_write_uhwi (ob, count); + + for (int i = 0; i < lto_symtab_encoder_size (encoder); i++) + { + symtab_node *snode = lto_symtab_encoder_deref (encoder, i); + cgraph_node *cnode = dyn_cast <cgraph_node *> (snode); + ipa_return_value_summary *v; + + if (cnode && cnode->definition && !cnode->alias + && (v = ipa_return_value_sum->get (cnode)) + && v->vr) + { + streamer_write_uhwi + (ob, + lto_symtab_encoder_encode (encoder, cnode)); + v->vr->streamer_write (ob); + } + } +} + /* Write jump functions for nodes in SET. */ void @@ -5429,11 +5518,58 @@ ipa_prop_write_jump_functions (void) && ipa_node_params_sum->get (node) != NULL) ipa_write_node_info (ob, node); } - streamer_write_char_stream (ob->main_stream, 0); + ipa_write_return_summaries (ob); produce_asm (ob); destroy_output_block (ob); } +/* Record that return value range of N is VAL. */ + +static void +ipa_record_return_value_range_1 (cgraph_node *n, value_range val) +{ + if (!ipa_return_value_sum) + { + if (!ipa_vr_hash_table) + ipa_vr_hash_table = hash_table<ipa_vr_ggc_hash_traits>::create_ggc (37); + ipa_return_value_sum = new (ggc_alloc_no_dtor <ipa_return_value_sum_t> ()) + ipa_return_value_sum_t (symtab, true); + ipa_return_value_sum->disable_insertion_hook (); + } + ipa_return_value_sum->get_create (n)->vr = ipa_get_value_range (val); + if (dump_file && (dump_flags & TDF_DETAILS)) + { + fprintf (dump_file, "Recording return range of %s:", n->dump_name ()); + val.dump (dump_file); + fprintf (dump_file, "\n"); + } +} + +/* Stream out ipa_return_summary. */ +static void +ipa_read_return_summaries (lto_input_block *ib, + struct lto_file_decl_data *file_data, + class data_in *data_in) +{ + unsigned int f_count = streamer_read_uhwi (ib); + for (unsigned int i = 0; i < f_count; i++) + { + unsigned int index = streamer_read_uhwi (ib); + lto_symtab_encoder_t encoder = file_data->symtab_node_encoder; + struct cgraph_node *node + = dyn_cast <cgraph_node *> + (lto_symtab_encoder_deref (encoder, index)); + ipa_vr rvr; + rvr.streamer_read (ib, data_in); + if (node->prevailing_p ()) + { + value_range tmp; + rvr.get_vrange (tmp); + ipa_record_return_value_range_1 (node, tmp); + } + } +} + /* Read section in file FILE_DATA of length LEN with data DATA. */ static void @@ -5470,6 +5606,7 @@ ipa_prop_read_section (struct lto_file_decl_data *file_data, const char *data, gcc_assert (node->definition); ipa_read_node_info (&ib_main, node, data_in); } + ipa_read_return_summaries (&ib_main, file_data, data_in); lto_free_section_data (file_data, LTO_section_jump_functions, NULL, data, len); lto_data_in_delete (data_in); @@ -5589,6 +5726,7 @@ read_ipcp_transformation_info (lto_input_block *ib, cgraph_node *node, } } + /* Write all aggregate replacement for nodes in set. */ void @@ -5627,7 +5765,7 @@ ipcp_write_transformation_summaries (void) && lto_symtab_encoder_encode_body_p (encoder, cnode)) write_ipcp_transformation_info (ob, cnode, ts); } - streamer_write_char_stream (ob->main_stream, 0); + ipa_write_return_summaries (ob); produce_asm (ob); destroy_output_block (ob); } @@ -5668,6 +5806,7 @@ read_replacements_section (struct lto_file_decl_data *file_data, index)); read_ipcp_transformation_info (&ib_main, node, data_in); } + ipa_read_return_summaries (&ib_main, file_data, data_in); lto_free_section_data (file_data, LTO_section_jump_functions, NULL, data, len); lto_data_in_delete (data_in); @@ -6148,22 +6287,8 @@ ipcp_transform_function (struct cgraph_node *node) void ipa_record_return_value_range (value_range val) { - cgraph_node *n = cgraph_node::get (current_function_decl); - if (!ipa_return_value_sum) - { - if (!ipa_vr_hash_table) - ipa_vr_hash_table = hash_table<ipa_vr_ggc_hash_traits>::create_ggc (37); - ipa_return_value_sum = new (ggc_alloc_no_dtor <ipa_return_value_sum_t> ()) - ipa_return_value_sum_t (symtab, true); - ipa_return_value_sum->disable_insertion_hook (); - } - ipa_return_value_sum->get_create (n)->vr = ipa_get_value_range (val); - if (dump_file && (dump_flags & TDF_DETAILS)) - { - fprintf (dump_file, "Recording return range "); - val.dump (dump_file); - fprintf (dump_file, "\n"); - } + ipa_record_return_value_range_1 + (cgraph_node::get (current_function_decl), val); } /* Return true if value range of DECL is known and if so initialize RANGE. */ @@ -6224,6 +6349,10 @@ ipa_agg_pass_through_jf_equivalent_p (ipa_pass_through_data *ipt1, || ipt1->formal_id != ipt2->formal_id || (!agg_jf && (ipt1->agg_preserved != ipt2->agg_preserved))) return false; + if (ipt1->operation != NOP_EXPR + && (TYPE_MAIN_VARIANT (ipt1->op_type) + != TYPE_MAIN_VARIANT (ipt2->op_type))) + return false; if (((ipt1->operand != NULL_TREE) != (ipt2->operand != NULL_TREE)) || (ipt1->operand && !values_equal_for_ipcp_p (ipt1->operand, ipt2->operand))) diff --git a/gcc/ipa-prop.h b/gcc/ipa-prop.h index 7735b57..3bd442f 100644 --- a/gcc/ipa-prop.h +++ b/gcc/ipa-prop.h @@ -96,6 +96,9 @@ struct GTY(()) ipa_pass_through_data /* If an operation is to be performed on the original parameter, this is the second (constant) operand. */ tree operand; + /* The result type of the operation. In case of no operation (represented by + NOP_EXPR) it should be NULL_TREE. */ + tree op_type; /* Number of the caller's formal parameter being passed. */ int formal_id; /* Operation that is performed on the argument before it is passed on. @@ -387,6 +390,18 @@ ipa_get_jf_pass_through_operand (struct ipa_jump_func *jfunc) return jfunc->value.pass_through.operand; } +/* Return the type of the operation in a non-NOP pass through jmp function + JFUNC. */ + +inline tree +ipa_get_jf_pass_through_op_type (struct ipa_jump_func *jfunc) +{ + gcc_checking_assert (jfunc->type == IPA_JF_PASS_THROUGH + && jfunc->value.pass_through.operation != NOP_EXPR); + + return jfunc->value.pass_through.op_type; +} + /* Return the number of the caller's formal parameter that a pass through jump function JFUNC refers to. */ diff --git a/gcc/lto-cgraph.cc b/gcc/lto-cgraph.cc index ac835a4..8439c51 100644 --- a/gcc/lto-cgraph.cc +++ b/gcc/lto-cgraph.cc @@ -229,6 +229,8 @@ lto_set_symtab_encoder_in_partition (lto_symtab_encoder_t encoder, symtab_node *node) { int index = lto_symtab_encoder_encode (encoder, node); + if (dump_file) + fprintf(dump_file, "Node %s, index %d\n", node->asm_name(), index); encoder->nodes[index].in_partition = true; } diff --git a/gcc/lto-streamer-out.cc b/gcc/lto-streamer-out.cc index d5b6ee7..a055d12d 100644 --- a/gcc/lto-streamer-out.cc +++ b/gcc/lto-streamer-out.cc @@ -130,7 +130,7 @@ destroy_output_block (struct output_block *ob) /* Wrapper around variably_modified_type_p avoiding type modification during WPA streaming. */ -static bool +bool lto_variably_modified_type_p (tree type) { return (in_lto_p diff --git a/gcc/lto-streamer.h b/gcc/lto-streamer.h index ff33bf0..4b7209e3 100644 --- a/gcc/lto-streamer.h +++ b/gcc/lto-streamer.h @@ -906,6 +906,7 @@ void lto_output_decl_state_streams (struct output_block *, void lto_output_decl_state_refs (struct output_block *, struct lto_output_stream *, struct lto_out_decl_state *); +bool lto_variably_modified_type_p (tree); void lto_output_location (struct output_block *, struct bitpack_d *, location_t); void lto_output_location_and_block (struct output_block *, struct bitpack_d *, diff --git a/gcc/lto/ChangeLog b/gcc/lto/ChangeLog index ee53915..4da9ca3 100644 --- a/gcc/lto/ChangeLog +++ b/gcc/lto/ChangeLog @@ -1,3 +1,13 @@ +2025-04-15 Kyrylo Tkachov <ktkachov@nvidia.com> + + * lto-partition.cc (add_node_references_to_partition): Define. + (create_partition): Likewise. + (lto_locality_map): Likewise. + (lto_promote_cross_file_statics): Add extra dumping. + * lto-partition.h (lto_locality_map): Declare prototype. + * lto.cc (do_whole_program_analysis): Handle + flag_ipa_reorder_for_locality. + 2025-02-28 Richard Biener <rguenther@suse.de> PR lto/91299 diff --git a/gcc/lto/lto-partition.cc b/gcc/lto/lto-partition.cc index 3046951..c7e69ee 100644 --- a/gcc/lto/lto-partition.cc +++ b/gcc/lto/lto-partition.cc @@ -37,6 +37,7 @@ along with GCC; see the file COPYING3. If not see #include "ipa-prop.h" #include "ipa-fnsummary.h" #include "lto-partition.h" +#include "ipa-locality-cloning.h" #include <limits> @@ -1418,6 +1419,126 @@ lto_balanced_map (int n_lto_partitions, int max_partition_size) } } +/* Add all references of NODE into PARTITION. */ + +static void +add_node_references_to_partition (ltrans_partition partition, symtab_node *node) +{ + struct ipa_ref *ref = NULL; + varpool_node *vnode; + for (int j = 0; node->iterate_reference (j, ref); j++) + if (is_a <varpool_node *> (ref->referred)) + { + vnode = dyn_cast <varpool_node *> (ref->referred); + if (!symbol_partitioned_p (vnode) + && !vnode->no_reorder + && vnode->get_partitioning_class () == SYMBOL_PARTITION) + { + add_symbol_to_partition (partition, vnode); + if (dump_file) + fprintf (dump_file, "Varpool Node: %s\n", vnode->dump_asm_name ()); + add_node_references_to_partition (partition, vnode); + } + } + + for (int j = 0; node->iterate_referring (j, ref); j++) + if (is_a <varpool_node *> (ref->referring)) + { + vnode = dyn_cast <varpool_node *> (ref->referring); + gcc_assert (vnode->definition); + if (!symbol_partitioned_p (vnode) + && !vnode->no_reorder + && !vnode->can_remove_if_no_refs_p () + && vnode->get_partitioning_class () == SYMBOL_PARTITION) + { + add_symbol_to_partition (partition, vnode); + if (dump_file) + fprintf (dump_file, "Varpool Node: %s\n", vnode->dump_asm_name ()); + add_node_references_to_partition (partition, vnode); + } + } + if (cgraph_node *cnode = dyn_cast <cgraph_node *> (node)) + { + struct cgraph_edge *e; + + /* Add all inline clones and callees that are duplicated. */ + for (e = cnode->callees; e; e = e->next_callee) + if (e->callee->get_partitioning_class () == SYMBOL_DUPLICATE) + add_node_references_to_partition (partition, e->callee); + + /* Add all thunks associated with the function. */ + for (e = cnode->callers; e; e = e->next_caller) + if (e->caller->thunk && !e->caller->inlined_to) + add_node_references_to_partition (partition, e->caller); + } + +} + +/* Create and return the created partition of name NAME. */ + +static ltrans_partition +create_partition (int &npartitions, const char *name) +{ + npartitions++; + return new_partition (name); +} + +/* Partitioning for code locality. + The partitioning plan (and prerequisite cloning) will have been done by the + IPA locality cloning pass. This function just implements that plan by + assigning those partitions to ltrans_parititions. */ + +void +lto_locality_map (int max_partition_size) +{ + symtab_node *snode; + int npartitions = 0; + + auto_vec<varpool_node *> varpool_order; + struct cgraph_node *node; + + if (locality_partitions.length () == 0) + { + if (dump_file) + { + fprintf (dump_file, "Locality partition: falling back to balanced " + "model\n"); + } + lto_balanced_map (param_lto_partitions, param_max_partition_size); + return; + } + ltrans_partition partition = nullptr; + for (auto part : locality_partitions) + { + partition = create_partition (npartitions, ""); + for (unsigned j = 0; j < part->nodes.length (); j++) + { + node = part->nodes[j]; + if (symbol_partitioned_p (node)) + continue; + + add_symbol_to_partition (partition, node); + add_node_references_to_partition (partition, node); + } + } + + int64_t partition_size = max_partition_size; + /* All other unpartitioned symbols. */ + FOR_EACH_SYMBOL (snode) + { + if (snode->get_partitioning_class () == SYMBOL_PARTITION + && !symbol_partitioned_p (snode)) + { + if (partition->insns > partition_size) + partition = create_partition (npartitions, ""); + + add_symbol_to_partition (partition, snode); + if (dump_file) + fprintf (dump_file, "Un-ordered Node: %s\n", snode->dump_asm_name ()); + } + } +} + /* Return true if we must not change the name of the NODE. The name as extracted from the corresponding decl should be passed in NAME. */ @@ -1732,7 +1853,12 @@ lto_promote_cross_file_statics (void) { ltrans_partition part = ltrans_partitions[i]; + if (dump_file) + fprintf (dump_file, "lto_promote_cross_file_statics for part %s %p\n", + part->name, (void *)part->encoder); part->encoder = compute_ltrans_boundary (part->encoder); + if (dump_file) + fprintf (dump_file, "new encoder %p\n", (void *)part->encoder); } lto_clone_numbers = new hash_map<const char *, unsigned>; diff --git a/gcc/lto/lto-partition.h b/gcc/lto/lto-partition.h index 38b3f1e..a6a4195 100644 --- a/gcc/lto/lto-partition.h +++ b/gcc/lto/lto-partition.h @@ -37,6 +37,7 @@ void lto_1_to_1_map (void); void lto_max_map (void); void lto_cache_map (int, int); void lto_balanced_map (int, int); +void lto_locality_map (int); void lto_promote_cross_file_statics (void); void free_ltrans_partitions (void); void lto_promote_statics_nonwpa (void); diff --git a/gcc/lto/lto.cc b/gcc/lto/lto.cc index 18ca475..183634f 100644 --- a/gcc/lto/lto.cc +++ b/gcc/lto/lto.cc @@ -547,7 +547,9 @@ do_whole_program_analysis (void) symtab_node::checking_verify_symtab_nodes (); bitmap_obstack_release (NULL); - if (flag_lto_partition == LTO_PARTITION_1TO1) + if (flag_ipa_reorder_for_locality) + lto_locality_map (param_max_locality_partition_size); + else if (flag_lto_partition == LTO_PARTITION_1TO1) lto_1_to_1_map (); else if (flag_lto_partition == LTO_PARTITION_MAX) lto_max_map (); diff --git a/gcc/opts.cc b/gcc/opts.cc index 80c7a97..5e7b77d 100644 --- a/gcc/opts.cc +++ b/gcc/opts.cc @@ -1037,6 +1037,25 @@ report_conflicting_sanitizer_options (struct gcc_options *opts, location_t loc, } } +/* Validate from OPTS and OPTS_SET that when -fipa-reorder-for-locality is + enabled no explicit -flto-partition is also passed as the locality cloning + pass uses its own partitioning scheme. */ + +static void +validate_ipa_reorder_locality_lto_partition (struct gcc_options *opts, + struct gcc_options *opts_set) +{ + static bool validated_p = false; + + if (opts->x_flag_lto_partition != LTO_PARTITION_DEFAULT) + { + if (opts_set->x_flag_ipa_reorder_for_locality && !validated_p) + error ("%<-fipa-reorder-for-locality%> is incompatible with" + " an explicit %qs option", "-flto-partition"); + } + validated_p = true; +} + /* After all options at LOC have been read into OPTS and OPTS_SET, finalize settings of those options and diagnose incompatible combinations. */ @@ -1249,6 +1268,10 @@ finish_options (struct gcc_options *opts, struct gcc_options *opts_set, if (opts->x_flag_reorder_blocks_and_partition) SET_OPTION_IF_UNSET (opts, opts_set, flag_reorder_functions, 1); + validate_ipa_reorder_locality_lto_partition (opts, opts_set); + if (opts_set->x_flag_lto_partition != LTO_PARTITION_DEFAULT) + opts_set->x_flag_lto_partition = opts->x_flag_lto_partition = LTO_PARTITION_BALANCED; + /* The -gsplit-dwarf option requires -ggnu-pubnames. */ if (opts->x_dwarf_split_debug_info) opts->x_debug_generate_pub_sections = 2; diff --git a/gcc/params.opt b/gcc/params.opt index 422d082..a2b606f 100644 --- a/gcc/params.opt +++ b/gcc/params.opt @@ -469,6 +469,33 @@ Minimal size of a partition for LTO (in estimated instructions). Common Joined UInteger Var(param_lto_partitions) Init(128) IntegerRange(1, 65536) Param Number of partitions the program should be split to. +Enum +Name(lto_locality_cloning_model) Type(enum lto_locality_cloning_model) UnknownError(unknown LTO partitioning model %qs) + +EnumValue +Enum(lto_locality_cloning_model) String(no) Value(LTO_LOCALITY_NO_CLONING) + +EnumValue +Enum(lto_locality_cloning_model) String(non_interposable) Value(LTO_LOCALITY_NON_INTERPOSABLE_CLONING) + +EnumValue +Enum(lto_locality_cloning_model) String(maximal) Value(LTO_LOCALITY_MAXIMAL_CLONING) + +-param=lto-partition-locality-cloning= +Common Joined RejectNegative Enum(lto_locality_cloning_model) Var(flag_lto_locality_cloning) Init(LTO_LOCALITY_MAXIMAL_CLONING) Optimization + +-param=lto-partition-locality-frequency-cutoff= +Common Joined UInteger Var(param_lto_locality_frequency) Init(1) IntegerRange(0, 65536) Param Optimization +The denominator n of fraction 1/n of the execution frequency of callee to be cloned for a particular caller. Special value of 0 dictates to always clone without a cut-off. + +-param=lto-partition-locality-size-cutoff= +Common Joined UInteger Var(param_lto_locality_size) Init(1000) IntegerRange(1, 65536) Param Optimization +Size cut-off for callee including inlined calls to be cloned for a particular caller. + +-param=lto-max-locality-partition= +Common Joined UInteger Var(param_max_locality_partition_size) Init(1000000) Param +Maximal size of a locality partition for LTO (in estimated instructions). Value of 0 results in default value being used. + -param=max-average-unrolled-insns= Common Joined UInteger Var(param_max_average_unrolled_insns) Init(80) Param Optimization The maximum number of instructions to consider to unroll in a loop on average. diff --git a/gcc/passes.def b/gcc/passes.def index 9fd85a3..3b25105 100644 --- a/gcc/passes.def +++ b/gcc/passes.def @@ -162,6 +162,7 @@ along with GCC; see the file COPYING3. If not see NEXT_PASS (pass_ipa_sra); NEXT_PASS (pass_ipa_fn_summary); NEXT_PASS (pass_ipa_inline); + NEXT_PASS (pass_ipa_locality_cloning); NEXT_PASS (pass_ipa_pure_const); NEXT_PASS (pass_ipa_modref); NEXT_PASS (pass_ipa_free_fn_summary, false /* small_p */); diff --git a/gcc/rust/ChangeLog b/gcc/rust/ChangeLog index 64053d4..453b9f7 100644 --- a/gcc/rust/ChangeLog +++ b/gcc/rust/ChangeLog @@ -1,3 +1,162 @@ +2025-04-14 Arthur Cohen <arthur.cohen@embecosm.com> + + * util/rust-lang-item.h: Add new manually_drop lang item. + * util/rust-lang-item.cc: Likewise. + +2025-04-14 Arthur Cohen <arthur.cohen@embecosm.com> + + * util/rust-attribute-values.h: Add RUSTFMT value. + * util/rust-attributes.cc: Define the attribute. + * util/rust-attributes.h (enum CompilerPass): Add EXTERNAL variant. + * expand/rust-macro-builtins.cc: Fix formatting. + +2025-04-14 Arthur Cohen <arthur.cohen@embecosm.com> + + * resolve/rust-early-name-resolver-2.0.cc (Early::visit_attributes): Remove assertion. + +2025-04-14 Arthur Cohen <arthur.cohen@embecosm.com> + + * util/rust-attribute-values.h: Add missing attributes. + * util/rust-attributes.cc: Likewise. + * util/rust-attributes.h (enum CompilerPass): Mention adding something for const + functions. + +2025-04-14 beamandala <mandalapubhavesh@gmail.com> + + * expand/rust-macro-builtins.cc (MacroBuiltin::builtin_transcribers): + Add entry for track_caller. + * util/rust-attribute-values.h: add `TRACK_CALLER` attribute. + * util/rust-attributes.cc: add `track_caller` attribute definition. + +2025-04-14 Owen Avery <powerboat9.gamer@gmail.com> + + * checks/errors/rust-const-checker.cc + (ConstChecker::visit): Visit the enum items of enums. + * resolve/rust-ast-resolve-item.cc + (ResolveItem::visit): Resolve enum discriminants during nr1.0. + +2025-04-14 Arthur Cohen <arthur.cohen@embecosm.com> + + * expand/rust-macro-builtins-format-args.cc (format_args_parse_arguments): Improve safety, + allow extra commas after end of argument list. + +2025-04-14 Arthur Cohen <arthur.cohen@embecosm.com> + + * expand/rust-macro-expand.cc (MacroExpander::expand_decl_macro): Call into + TokenTreeDesugar. + * expand/rust-token-tree-desugar.cc: New file. + * expand/rust-token-tree-desugar.h: New file. + * Make-lang.in: Compile them. + +2025-04-14 Arthur Cohen <arthur.cohen@embecosm.com> + + * expand/rust-macro-expand.cc (MacroExpander::match_n_matches): Do not + insert fragments and substack fragments if the matcher failed. + +2025-04-14 Arthur Cohen <arthur.cohen@embecosm.com> + + * rust-session-manager.cc (Session::compile_crate): Call the visitor later in the pipeline. + +2025-04-14 Arthur Cohen <arthur.cohen@embecosm.com> + + * ast/rust-ast.h (DelimTokenTree::get_locus): New function. + +2025-04-14 Arthur Cohen <arthur.cohen@embecosm.com> + + * ast/rust-expr.h (class RangeExpr): Add empty outer attributes and allow getting them + and setting them. + +2025-04-14 Arthur Cohen <arthur.cohen@embecosm.com> + + * resolve/rust-toplevel-name-resolver-2.0.cc (TopLevel::visit): Return if module + is unloaded. + +2025-04-14 Arthur Cohen <arthur.cohen@embecosm.com> + + * typecheck/rust-hir-type-check-expr.cc (is_default_fn): New. + (emit_ambiguous_resolution_error): New. + (handle_multiple_candidates): Properly handle multiple candidates in + the case of specialization. + (TypeCheckExpr::visit): Call `handle_multiple_candidates`. + +2025-04-14 Andrew Pinski <quic_apinski@quicinc.com> + + PR rust/119342 + * rust-gcc.cc (block): Add comment on why chaining + the variables of the scope toether. + +2025-04-14 Andrew Pinski <quic_apinski@quicinc.com> + + PR rust/119341 + * rust-gcc.cc (function_type): Use range fors. + (function_type_variadic): Likewise. + (fill_in_fields): Likewise. + (statement_list): Likewise. + (block): Likewise. + (block_add_statements): Likewise. + (function_set_parameters): Likewise. + (write_global_definitions): Likewise. + +2025-04-14 Andrew Pinski <quic_apinski@quicinc.com> + + * rust-gcc.cc (Bvariable::get_tree): Use error_operand_p. + (pointer_type): Likewise. + (reference_type): Likewise. + (immutable_type): Likewise. + (function_type): Likewise. + (function_type_variadic): Likewise. + Cleanup the check for receiver.type first. + (function_ptr_type): Use error_operand_p. + (fill_in_fields): Likewise. + (fill_in_array): Likewise. + (named_type): Likewise. + (type_size): Likewise. + (type_alignment): Likewise. + (type_field_alignment): Likewise. + (type_field_offset): Likewise. + (zero_expression): Likewise. + (float_constant_expression): Likewise. + (convert_expression): Likewise. + (struct_field_expression): Likewise. + (compound_expression): Likewise. + (conditional_expression): Likewise. + (negation_expression): Likewise. + (arithmetic_or_logical_expression): Likewise. + (arithmetic_or_logical_expression_checked): Likewise. + (comparison_expression): Likewise. + (lazy_boolean_expression): Likewise. + (constructor_expression): Likewise. + (array_constructor_expression): Likewise. + (array_index_expression): Likewise. + (call_expression): Likewise. + (init_statement): Likewise. + (assignment_statement): Likewise. + (return_statement): Likewise. + (exception_handler_statement): Likewise. + (if_statement): Likewise. + (compound_statement): Likewise. + Tighten up the code, removing t variable. + (statement_list): Use error_operand_p. + (block): Likewise. + (block_add_statements): Likewise. + (convert_tree): Likewise. + (global_variable): Likewise. + (global_variable_set_init): Likewise. + (local_variable): Likewise. + (parameter_variable): Likewise. + (static_chain_variable): Likewise. + (temporary_variable): Likewise. + (function): Likewise. Tighten up the code. + (function_defer_statement): Use error_operand_p. + (function_set_parameters): Use error_operand_p. + (write_global_definitions): Use error_operand_p. + Tighten up the code around the loop. + +2025-04-14 Andrew Pinski <quic_apinski@quicinc.com> + + * rust-gcc.cc (is_floating_point): Use FLOAT_TYPE_P + instead of manually checking the type. + 2025-04-08 Matty Kuhn <matty.kuhn.1@gmail.com> * ast/rust-ast.h: (AST::Attribute): add empty_input function diff --git a/gcc/rust/Make-lang.in b/gcc/rust/Make-lang.in index 4028b47..835e113 100644 --- a/gcc/rust/Make-lang.in +++ b/gcc/rust/Make-lang.in @@ -115,6 +115,7 @@ GRS_OBJS = \ rust/rust-macro-builtins-format-args.o \ rust/rust-macro-builtins-location.o \ rust/rust-macro-builtins-include.o \ + rust/rust-token-tree-desugar.o \ rust/rust-fmt.o \ rust/rust-hir.o \ rust/rust-hir-map.o \ diff --git a/gcc/rust/ast/rust-ast.h b/gcc/rust/ast/rust-ast.h index 09e0fce..91611ec 100644 --- a/gcc/rust/ast/rust-ast.h +++ b/gcc/rust/ast/rust-ast.h @@ -1018,6 +1018,7 @@ public: } DelimType get_delim_type () const { return delim_type; } + location_t get_locus () const { return locus; } }; /* Forward decl - definition moved to rust-expr.h as it requires LiteralExpr diff --git a/gcc/rust/ast/rust-expr.h b/gcc/rust/ast/rust-expr.h index 84cdfdb..69538df 100644 --- a/gcc/rust/ast/rust-expr.h +++ b/gcc/rust/ast/rust-expr.h @@ -3004,6 +3004,10 @@ class RangeExpr : public ExprWithoutBlock { location_t locus; + // Some visitors still check for attributes on RangeExprs, and they will need + // to be supported in the future - so keep that for now + std::vector<Attribute> empty_attributes = {}; + protected: // outer attributes not allowed before range expressions RangeExpr (location_t locus) : locus (locus) {} @@ -3013,15 +3017,11 @@ public: std::vector<Attribute> &get_outer_attrs () override final { - // RangeExpr cannot have any outer attributes - rust_assert (false); + return empty_attributes; } // should never be called - error if called - void set_outer_attrs (std::vector<Attribute> /* new_attrs */) override - { - rust_assert (false); - } + void set_outer_attrs (std::vector<Attribute> /* new_attrs */) override {} Expr::Kind get_expr_kind () const override { return Expr::Kind::Range; } }; diff --git a/gcc/rust/checks/errors/rust-const-checker.cc b/gcc/rust/checks/errors/rust-const-checker.cc index 4904322..4c2257a 100644 --- a/gcc/rust/checks/errors/rust-const-checker.cc +++ b/gcc/rust/checks/errors/rust-const-checker.cc @@ -646,6 +646,9 @@ ConstChecker::visit (Enum &enum_item) { check_default_const_generics (enum_item.get_generic_params (), ConstGenericCtx::Enum); + + for (auto &item : enum_item.get_variants ()) + item->accept_vis (*this); } void diff --git a/gcc/rust/expand/rust-macro-builtins-format-args.cc b/gcc/rust/expand/rust-macro-builtins-format-args.cc index 8eb32d5..3e1249d 100644 --- a/gcc/rust/expand/rust-macro-builtins-format-args.cc +++ b/gcc/rust/expand/rust-macro-builtins-format-args.cc @@ -55,6 +55,8 @@ format_args_parse_arguments (AST::MacroInvocData &invoc) if (parser.peek_current_token ()->get_id () == STRING_LITERAL) format_expr = parser.parse_literal_expr (); + rust_assert (format_expr); + // TODO(Arthur): Clean this up - if we haven't parsed a string literal but a // macro invocation, what do we do here? return a tl::unexpected? auto format_str = static_cast<AST::LiteralExpr &> (*format_expr) @@ -81,6 +83,11 @@ format_args_parse_arguments (AST::MacroInvocData &invoc) { parser.skip_token (COMMA); + // Check in case of an extraneous comma in the args list, which is + // allowed - format_args!("fmt", arg, arg2,) + if (parser.peek_current_token ()->get_id () == last_token_id) + break; + if (parser.peek_current_token ()->get_id () == IDENTIFIER && parser.peek (1)->get_id () == EQUAL) { diff --git a/gcc/rust/expand/rust-macro-builtins.cc b/gcc/rust/expand/rust-macro-builtins.cc index 39c4c46..8b406ff 100644 --- a/gcc/rust/expand/rust-macro-builtins.cc +++ b/gcc/rust/expand/rust-macro-builtins.cc @@ -83,7 +83,6 @@ const BiMap<std::string, BuiltinMacro> MacroBuiltin::builtins = {{ {"Ord", BuiltinMacro::Ord}, {"PartialOrd", BuiltinMacro::PartialOrd}, {"Hash", BuiltinMacro::Hash}, - }}; AST::MacroTranscriberFunc @@ -137,6 +136,7 @@ std::unordered_map<std::string, AST::MacroTranscriberFunc> {"cfg_accessible", MacroBuiltin::sorry}, {"rustc_const_stable", MacroBuiltin::sorry}, {"rustc_const_unstable", MacroBuiltin::sorry}, + {"track_caller", MacroBuiltin::sorry}, /* Derive builtins do not need a real transcriber, but still need one. It should however never be called since builtin derive macros get expanded differently, and benefit from knowing on what kind of items they are diff --git a/gcc/rust/expand/rust-macro-expand.cc b/gcc/rust/expand/rust-macro-expand.cc index cd17a3f..673b8fb 100644 --- a/gcc/rust/expand/rust-macro-expand.cc +++ b/gcc/rust/expand/rust-macro-expand.cc @@ -28,6 +28,7 @@ #include "rust-cfg-strip.h" #include "rust-early-name-resolver.h" #include "rust-proc-macro.h" +#include "rust-token-tree-desugar.h" namespace Rust { @@ -78,7 +79,10 @@ MacroExpander::expand_decl_macro (location_t invoc_locus, * trees. */ - AST::DelimTokenTree &invoc_token_tree = invoc.get_delim_tok_tree (); + AST::DelimTokenTree &invoc_token_tree_sugar = invoc.get_delim_tok_tree (); + + // We must first desugar doc comments into proper attributes + auto invoc_token_tree = AST::TokenTreeDesugar ().go (invoc_token_tree_sugar); // find matching arm AST::MacroRule *matched_rule = nullptr; @@ -621,9 +625,10 @@ MacroExpander::match_n_matches (Parser<MacroInvocLexer> &parser, // matched fragment get the offset in the token stream size_t offs_end = source.get_offs (); - sub_stack.insert_metavar ( - MatchedFragment (fragment->get_ident ().as_string (), - offs_begin, offs_end)); + if (valid_current_match) + sub_stack.insert_metavar ( + MatchedFragment (fragment->get_ident ().as_string (), + offs_begin, offs_end)); } break; @@ -650,15 +655,15 @@ MacroExpander::match_n_matches (Parser<MacroInvocLexer> &parser, } auto old_stack = sub_stack.pop (); - // nest metavars into repetitions - for (auto &ent : old_stack) - sub_stack.append_fragment (ent.first, std::move (ent.second)); - // If we've encountered an error once, stop trying to match more // repetitions if (!valid_current_match) break; + // nest metavars into repetitions + for (auto &ent : old_stack) + sub_stack.append_fragment (ent.first, std::move (ent.second)); + match_amount++; // Break early if we notice there's too many expressions already diff --git a/gcc/rust/expand/rust-token-tree-desugar.cc b/gcc/rust/expand/rust-token-tree-desugar.cc new file mode 100644 index 0000000..3b47180 --- /dev/null +++ b/gcc/rust/expand/rust-token-tree-desugar.cc @@ -0,0 +1,72 @@ +// Copyright (C) 2025 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 +// <http://www.gnu.org/licenses/>. + +#include "rust-token-tree-desugar.h" +#include "rust-ast.h" +#include "rust-token.h" + +namespace Rust { +namespace AST { + +DelimTokenTree +TokenTreeDesugar::go (DelimTokenTree &tts) +{ + tts.accept_vis (*this); + + return DelimTokenTree (tts.get_delim_type (), std::move (desugared), + tts.get_locus ()); +} + +void +TokenTreeDesugar::append (TokenPtr &&new_token) +{ + desugared.emplace_back (std::make_unique<Token> (std::move (new_token))); +} + +void +TokenTreeDesugar::append (std::unique_ptr<TokenTree> &&new_token) +{ + desugared.emplace_back (std::move (new_token)); +} + +void +TokenTreeDesugar::visit (Token &tts) +{ + if (tts.get_id () == TokenId::OUTER_DOC_COMMENT + || tts.get_id () == TokenId::INNER_DOC_COMMENT) + { + append (Rust::Token::make (TokenId::HASH, tts.get_locus ())); + + if (tts.get_id () == TokenId::INNER_DOC_COMMENT) + append (Rust::Token::make (EXCLAM, tts.get_locus ())); + + append (Rust::Token::make (TokenId::LEFT_SQUARE, tts.get_locus ())); + append (Rust::Token::make_identifier (tts.get_locus (), "doc")); + append (Rust::Token::make (TokenId::EQUAL, tts.get_locus ())); + append (Rust::Token::make_string (tts.get_locus (), + std::string (tts.get_str ()))); + append (Rust::Token::make (TokenId::RIGHT_SQUARE, tts.get_locus ())); + } + else + { + append (tts.clone_token ()); + } +} + +}; // namespace AST +}; // namespace Rust diff --git a/gcc/rust/expand/rust-token-tree-desugar.h b/gcc/rust/expand/rust-token-tree-desugar.h new file mode 100644 index 0000000..ccba53b --- /dev/null +++ b/gcc/rust/expand/rust-token-tree-desugar.h @@ -0,0 +1,55 @@ +// Copyright (C) 2025 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 +// <http://www.gnu.org/licenses/>. + +#ifndef RUST_TOKEN_TREE_DESUGAR_H +#define RUST_TOKEN_TREE_DESUGAR_H + +#include "rust-ast-visitor.h" +#include "rust-system.h" +#include "rust-ast.h" + +namespace Rust { +namespace AST { + +/** + * Desugar a given token-tree before parsing it for a macro invocation. At the + * moment, the sole purpose of this desugar is to transform doc-comments into + * their attribute form (/// comment -> #[doc = "comment"]) + */ +class TokenTreeDesugar : public DefaultASTVisitor +{ +public: + TokenTreeDesugar () : desugared (std::vector<std::unique_ptr<TokenTree>> ()) + {} + + DelimTokenTree go (DelimTokenTree &tts); + +private: + std::vector<std::unique_ptr<TokenTree>> desugared; + void append (TokenPtr &&new_token); + void append (std::unique_ptr<TokenTree> &&new_token); + + using DefaultASTVisitor::visit; + + virtual void visit (Token &tts) override; +}; + +}; // namespace AST +}; // namespace Rust + +#endif //! RUST_TOKEN_TREE_DESUGAR_H diff --git a/gcc/rust/resolve/rust-ast-resolve-item.cc b/gcc/rust/resolve/rust-ast-resolve-item.cc index d584961..30f6d43 100644 --- a/gcc/rust/resolve/rust-ast-resolve-item.cc +++ b/gcc/rust/resolve/rust-ast-resolve-item.cc @@ -356,6 +356,8 @@ ResolveItem::visit (AST::EnumItemDiscriminant &item) auto cpath = canonical_prefix.append (decl); mappings.insert_canonical_path (item.get_node_id (), cpath); + + ResolveExpr::go (item.get_expr (), path, cpath); } void diff --git a/gcc/rust/resolve/rust-early-name-resolver-2.0.cc b/gcc/rust/resolve/rust-early-name-resolver-2.0.cc index afaca1f..36456e1 100644 --- a/gcc/rust/resolve/rust-early-name-resolver-2.0.cc +++ b/gcc/rust/resolve/rust-early-name-resolver-2.0.cc @@ -325,10 +325,9 @@ Early::visit_attributes (std::vector<AST::Attribute> &attrs) auto pm_def = mappings.lookup_derive_proc_macro_def ( definition->get_node_id ()); - rust_assert (pm_def.has_value ()); - - mappings.insert_derive_proc_macro_invocation (trait, - pm_def.value ()); + if (pm_def.has_value ()) + mappings.insert_derive_proc_macro_invocation (trait, + pm_def.value ()); } } else if (Analysis::BuiltinAttributeMappings::get () diff --git a/gcc/rust/resolve/rust-toplevel-name-resolver-2.0.cc b/gcc/rust/resolve/rust-toplevel-name-resolver-2.0.cc index 8863be7..ba37dee 100644 --- a/gcc/rust/resolve/rust-toplevel-name-resolver-2.0.cc +++ b/gcc/rust/resolve/rust-toplevel-name-resolver-2.0.cc @@ -113,7 +113,17 @@ TopLevel::visit (AST::Module &module) // This was copied from the old early resolver method // 'accumulate_escaped_macros' if (module.get_kind () == AST::Module::UNLOADED) - module.load_items (); + { + module.load_items (); + + // If the module was previously unloaded, then we don't want to visit it + // this time around as the CfgStrip hasn't run on its inner items yet. + // Skip it for now, mark the visitor as dirty and try again + + dirty = true; + + return; + } DefaultResolver::visit (module); diff --git a/gcc/rust/rust-gcc.cc b/gcc/rust/rust-gcc.cc index 72aef08..234721c 100644 --- a/gcc/rust/rust-gcc.cc +++ b/gcc/rust/rust-gcc.cc @@ -61,7 +61,7 @@ tree Bvariable::get_tree (location_t location) const { - if (this->t_ == error_mark_node) + if (error_operand_p (this->t_)) return error_mark_node; TREE_USED (this->t_) = 1; @@ -431,7 +431,7 @@ float_type (int bits) tree pointer_type (tree to_type) { - if (to_type == error_mark_node) + if (error_operand_p (to_type)) return error_mark_node; tree type = build_pointer_type (to_type); return type; @@ -442,7 +442,7 @@ pointer_type (tree to_type) tree reference_type (tree to_type) { - if (to_type == error_mark_node) + if (error_operand_p (to_type)) return error_mark_node; tree type = build_reference_type (to_type); return type; @@ -453,7 +453,7 @@ reference_type (tree to_type) tree immutable_type (tree base) { - if (base == error_mark_node) + if (error_operand_p (base)) return error_mark_node; tree constified = build_qualified_type (base, TYPE_QUAL_CONST); return constified; @@ -472,17 +472,16 @@ function_type (const typed_identifier &receiver, if (receiver.type != NULL_TREE) { tree t = receiver.type; - if (t == error_mark_node) + if (error_operand_p (t)) return error_mark_node; *pp = tree_cons (NULL_TREE, t, NULL_TREE); pp = &TREE_CHAIN (*pp); } - for (std::vector<typed_identifier>::const_iterator p = parameters.begin (); - p != parameters.end (); ++p) + for (const auto &p : parameters) { - tree t = p->type; - if (t == error_mark_node) + tree t = p.type; + if (error_operand_p (t)) return error_mark_node; *pp = tree_cons (NULL_TREE, t, NULL_TREE); pp = &TREE_CHAIN (*pp); @@ -502,11 +501,11 @@ function_type (const typed_identifier &receiver, gcc_assert (result_struct != NULL); result = result_struct; } - if (result == error_mark_node) + if (error_operand_p (result)) return error_mark_node; tree fntype = build_function_type (result, args); - if (fntype == error_mark_node) + if (error_operand_p (fntype)) return error_mark_node; return build_pointer_type (fntype); @@ -521,21 +520,16 @@ function_type_variadic (const typed_identifier &receiver, size_t n = parameters.size () + (receiver.type != NULL_TREE ? 1 : 0); tree *args = XALLOCAVEC (tree, n); size_t offs = 0; + if (error_operand_p (receiver.type)) + return error_mark_node; if (receiver.type != NULL_TREE) - { - tree t = receiver.type; - if (t == error_mark_node) - return error_mark_node; - - args[offs++] = t; - } + args[offs++] = receiver.type; - for (std::vector<typed_identifier>::const_iterator p = parameters.begin (); - p != parameters.end (); ++p) + for (const auto &p : parameters) { - tree t = p->type; - if (t == error_mark_node) + tree t = p.type; + if (error_operand_p (t)) return error_mark_node; args[offs++] = t; } @@ -550,11 +544,11 @@ function_type_variadic (const typed_identifier &receiver, gcc_assert (result_struct != NULL_TREE); result = result_struct; } - if (result == error_mark_node) + if (error_operand_p (result)) return error_mark_node; tree fntype = build_varargs_function_type_array (result, n, args); - if (fntype == error_mark_node) + if (error_operand_p (fntype)) return error_mark_node; return build_pointer_type (fntype); @@ -569,7 +563,7 @@ function_ptr_type (tree result_type, const std::vector<tree> ¶meters, for (auto ¶m : parameters) { - if (param == error_mark_node) + if (error_operand_p (param)) return error_mark_node; *pp = tree_cons (NULL_TREE, param, NULL_TREE); @@ -583,7 +577,7 @@ function_ptr_type (tree result_type, const std::vector<tree> ¶meters, result = void_type_node; tree fntype = build_function_type (result, args); - if (fntype == error_mark_node) + if (error_operand_p (fntype)) return error_mark_node; return build_pointer_type (fntype); @@ -613,14 +607,13 @@ fill_in_fields (tree fill, const std::vector<typed_identifier> &fields, { tree field_trees = NULL_TREE; tree *pp = &field_trees; - for (std::vector<typed_identifier>::const_iterator p = fields.begin (); - p != fields.end (); ++p) + for (const auto &p : fields) { - tree name_tree = get_identifier_from_string (p->name); - tree type_tree = p->type; - if (type_tree == error_mark_node) + tree name_tree = get_identifier_from_string (p.name); + tree type_tree = p.type; + if (error_operand_p (type_tree)) return error_mark_node; - tree field = build_decl (p->location, FIELD_DECL, name_tree, type_tree); + tree field = build_decl (p.location, FIELD_DECL, name_tree, type_tree); DECL_CONTEXT (field) = fill; *pp = field; pp = &DECL_CHAIN (field); @@ -652,7 +645,7 @@ array_type (tree element_type, tree length) tree fill_in_array (tree fill, tree element_type, tree length_tree) { - if (element_type == error_mark_node || length_tree == error_mark_node) + if (error_operand_p (element_type) || error_operand_p (length_tree)) return error_mark_node; gcc_assert (TYPE_SIZE (element_type) != NULL_TREE); @@ -684,7 +677,7 @@ fill_in_array (tree fill, tree element_type, tree length_tree) tree named_type (const std::string &name, tree type, location_t location) { - if (type == error_mark_node) + if (error_operand_p (type)) return error_mark_node; // The middle-end expects a basic type to have a name. In Rust every @@ -714,7 +707,7 @@ named_type (const std::string &name, tree type, location_t location) int64_t type_size (tree t) { - if (t == error_mark_node) + if (error_operand_p (t)) return 1; if (t == void_type_node) return 0; @@ -732,7 +725,7 @@ type_size (tree t) int64_t type_alignment (tree t) { - if (t == error_mark_node) + if (error_operand_p (t)) return 1; return TYPE_ALIGN_UNIT (t); } @@ -742,7 +735,7 @@ type_alignment (tree t) int64_t type_field_alignment (tree t) { - if (t == error_mark_node) + if (error_operand_p (t)) return 1; return rust_field_alignment (t); } @@ -752,7 +745,7 @@ type_field_alignment (tree t) int64_t type_field_offset (tree struct_tree, size_t index) { - if (struct_tree == error_mark_node) + if (error_operand_p (struct_tree)) return 0; gcc_assert (TREE_CODE (struct_tree) == RECORD_TYPE); tree field = TYPE_FIELDS (struct_tree); @@ -773,7 +766,7 @@ tree zero_expression (tree t) { tree ret; - if (t == error_mark_node) + if (error_operand_p (t)) ret = error_mark_node; else ret = build_zero_cst (t); @@ -794,7 +787,7 @@ tree float_constant_expression (tree t, mpfr_t val) { tree ret; - if (t == error_mark_node) + if (error_operand_p (t)) return error_mark_node; REAL_VALUE_TYPE r1; @@ -845,8 +838,7 @@ boolean_constant_expression (bool val) tree convert_expression (tree type_tree, tree expr_tree, location_t location) { - if (type_tree == error_mark_node || expr_tree == error_mark_node - || TREE_TYPE (expr_tree) == error_mark_node) + if (error_operand_p (type_tree) || error_operand_p (expr_tree)) return error_mark_node; tree ret; @@ -878,8 +870,7 @@ convert_expression (tree type_tree, tree expr_tree, location_t location) tree struct_field_expression (tree struct_tree, size_t index, location_t location) { - if (struct_tree == error_mark_node - || TREE_TYPE (struct_tree) == error_mark_node) + if (error_operand_p (struct_tree)) return error_mark_node; gcc_assert (TREE_CODE (TREE_TYPE (struct_tree)) == RECORD_TYPE || TREE_CODE (TREE_TYPE (struct_tree)) == UNION_TYPE); @@ -895,7 +886,7 @@ struct_field_expression (tree struct_tree, size_t index, location_t location) field = DECL_CHAIN (field); gcc_assert (field != NULL_TREE); } - if (TREE_TYPE (field) == error_mark_node) + if (error_operand_p (TREE_TYPE (field))) return error_mark_node; tree ret = fold_build3_loc (location, COMPONENT_REF, TREE_TYPE (field), struct_tree, field, NULL_TREE); @@ -909,7 +900,7 @@ struct_field_expression (tree struct_tree, size_t index, location_t location) tree compound_expression (tree stat, tree expr, location_t location) { - if (stat == error_mark_node || expr == error_mark_node) + if (error_operand_p (stat) || error_operand_p (expr)) return error_mark_node; tree ret = fold_build2_loc (location, COMPOUND_EXPR, TREE_TYPE (expr), stat, expr); @@ -923,8 +914,8 @@ tree conditional_expression (tree, tree type_tree, tree cond_expr, tree then_expr, tree else_expr, location_t location) { - if (type_tree == error_mark_node || cond_expr == error_mark_node - || then_expr == error_mark_node || else_expr == error_mark_node) + if (error_operand_p (type_tree) || error_operand_p (cond_expr) + || error_operand_p (then_expr) || error_operand_p (else_expr)) return error_mark_node; tree ret = build3_loc (location, COND_EXPR, type_tree, cond_expr, then_expr, else_expr); @@ -1021,12 +1012,12 @@ operator_to_tree_code (LazyBooleanOperator op) } } -/* Helper function for deciding if a tree is a floating point node. */ +/* Returns true if the type of EXP is a floating point type. + False otherwise. */ bool -is_floating_point (tree t) +is_floating_point (tree exp) { - auto tree_type = TREE_CODE (TREE_TYPE (t)); - return tree_type == REAL_TYPE || tree_type == COMPLEX_TYPE; + return FLOAT_TYPE_P (TREE_TYPE (exp)); } // Return an expression for the negation operation OP EXPR. @@ -1035,7 +1026,7 @@ negation_expression (NegationOperator op, tree expr_tree, location_t location) { /* Check if the expression is an error, in which case we return an error expression. */ - if (expr_tree == error_mark_node || TREE_TYPE (expr_tree) == error_mark_node) + if (error_operand_p (expr_tree)) return error_mark_node; /* For negation operators, the resulting type should be the same as its @@ -1071,7 +1062,7 @@ arithmetic_or_logical_expression (ArithmeticOrLogicalOperator op, tree left, { /* Check if either expression is an error, in which case we return an error expression. */ - if (left == error_mark_node || right == error_mark_node) + if (error_operand_p (left) || error_operand_p (right)) return error_mark_node; // unwrap the const decls if set @@ -1182,7 +1173,7 @@ arithmetic_or_logical_expression_checked (ArithmeticOrLogicalOperator op, { /* Check if either expression is an error, in which case we return an error expression. */ - if (left == error_mark_node || right == error_mark_node) + if (error_operand_p (left) || error_operand_p (right)) return error_mark_node; // FIXME: Add `if (!debug_mode)` @@ -1222,7 +1213,7 @@ comparison_expression (ComparisonOperator op, tree left_tree, tree right_tree, { /* Check if either expression is an error, in which case we return an error expression. */ - if (left_tree == error_mark_node || right_tree == error_mark_node) + if (error_operand_p (left_tree) || error_operand_p (right_tree)) return error_mark_node; /* For comparison operators, the resulting type should be boolean. */ @@ -1242,7 +1233,7 @@ lazy_boolean_expression (LazyBooleanOperator op, tree left_tree, { /* Check if either expression is an error, in which case we return an error expression. */ - if (left_tree == error_mark_node || right_tree == error_mark_node) + if (error_operand_p (left_tree) || error_operand_p (right_tree)) return error_mark_node; /* For lazy boolean operators, the resulting type should be the same as the @@ -1263,7 +1254,7 @@ constructor_expression (tree type_tree, bool is_variant, const std::vector<tree> &vals, int union_index, location_t location) { - if (type_tree == error_mark_node) + if (error_operand_p (type_tree)) return error_mark_node; vec<constructor_elt, va_gc> *init; @@ -1305,8 +1296,8 @@ constructor_expression (tree type_tree, bool is_variant, gcc_assert (field != NULL_TREE); field = DECL_CHAIN (field); } - if (TREE_TYPE (field) == error_mark_node || val == error_mark_node - || TREE_TYPE (val) == error_mark_node) + + if (TREE_TYPE (field) == error_mark_node || error_operand_p (val)) return error_mark_node; if (int_size_in_bytes (TREE_TYPE (field)) == 0) @@ -1336,8 +1327,7 @@ constructor_expression (tree type_tree, bool is_variant, { gcc_assert (field != NULL_TREE); tree val = (*p); - if (TREE_TYPE (field) == error_mark_node || val == error_mark_node - || TREE_TYPE (val) == error_mark_node) + if (TREE_TYPE (field) == error_mark_node || error_operand_p (val)) return error_mark_node; if (int_size_in_bytes (TREE_TYPE (field)) == 0) @@ -1376,7 +1366,7 @@ array_constructor_expression (tree type_tree, const std::vector<tree> &vals, location_t location) { - if (type_tree == error_mark_node) + if (error_operand_p (type_tree)) return error_mark_node; gcc_assert (indexes.size () == vals.size ()); @@ -1393,7 +1383,7 @@ array_constructor_expression (tree type_tree, tree index = size_int (indexes[i]); tree val = vals[i]; - if (index == error_mark_node || val == error_mark_node) + if (error_operand_p (index) || error_operand_p (val)) return error_mark_node; if (element_size == 0) @@ -1497,8 +1487,7 @@ array_initializer (tree fndecl, tree block, tree array_type, tree length, tree array_index_expression (tree array_tree, tree index_tree, location_t location) { - if (array_tree == error_mark_node || TREE_TYPE (array_tree) == error_mark_node - || index_tree == error_mark_node) + if (error_operand_p (array_tree) || error_operand_p (index_tree)) return error_mark_node; // A function call that returns a zero sized object will have been @@ -1520,7 +1509,7 @@ tree call_expression (tree fn, const std::vector<tree> &fn_args, tree chain_expr, location_t location) { - if (fn == error_mark_node || TREE_TYPE (fn) == error_mark_node) + if (error_operand_p (fn)) return error_mark_node; gcc_assert (FUNCTION_POINTER_TYPE_P (TREE_TYPE (fn))); @@ -1600,7 +1589,7 @@ tree init_statement (tree, Bvariable *var, tree init_tree) { tree var_tree = var->get_decl (); - if (var_tree == error_mark_node || init_tree == error_mark_node) + if (error_operand_p (var_tree) || error_operand_p (init_tree)) return error_mark_node; gcc_assert (TREE_CODE (var_tree) == VAR_DECL); @@ -1631,7 +1620,7 @@ init_statement (tree, Bvariable *var, tree init_tree) tree assignment_statement (tree lhs, tree rhs, location_t location) { - if (lhs == error_mark_node || rhs == error_mark_node) + if (error_operand_p (lhs) || error_operand_p (rhs)) return error_mark_node; // To avoid problems with GNU ld, we don't make zero-sized @@ -1656,14 +1645,14 @@ assignment_statement (tree lhs, tree rhs, location_t location) tree return_statement (tree fntree, tree val, location_t location) { - if (fntree == error_mark_node) + if (error_operand_p (fntree)) return error_mark_node; tree result = DECL_RESULT (fntree); - if (result == error_mark_node) + if (error_operand_p (result)) return error_mark_node; - if (val == error_mark_node) + if (error_operand_p (val)) return error_mark_node; tree set @@ -1681,8 +1670,8 @@ tree exception_handler_statement (tree try_stmt, tree except_stmt, tree finally_stmt, location_t location) { - if (try_stmt == error_mark_node || except_stmt == error_mark_node - || finally_stmt == error_mark_node) + if (error_operand_p (try_stmt) || error_operand_p (except_stmt) + || error_operand_p (finally_stmt)) return error_mark_node; if (except_stmt != NULL_TREE) @@ -1701,8 +1690,8 @@ tree if_statement (tree, tree cond_tree, tree then_tree, tree else_tree, location_t location) { - if (cond_tree == error_mark_node || then_tree == error_mark_node - || else_tree == error_mark_node) + if (error_operand_p (cond_tree) || error_operand_p (then_tree) + || error_operand_p (else_tree)) return error_mark_node; tree ret = build3_loc (location, COND_EXPR, void_type_node, cond_tree, then_tree, else_tree); @@ -1728,15 +1717,12 @@ exit_expression (tree cond_tree, location_t locus) tree compound_statement (tree s1, tree s2) { - tree stmt_list = NULL_TREE; - tree t = s1; - if (t == error_mark_node) - return error_mark_node; - append_to_statement_list (t, &stmt_list); - t = s2; - if (t == error_mark_node) + if (error_operand_p (s1) || error_operand_p (s2)) return error_mark_node; - append_to_statement_list (t, &stmt_list); + + tree stmt_list = NULL_TREE; + append_to_statement_list (s1, &stmt_list); + append_to_statement_list (s2, &stmt_list); // If neither statement has any side effects, stmt_list can be NULL // at this point. @@ -1752,11 +1738,9 @@ tree statement_list (const std::vector<tree> &statements) { tree stmt_list = NULL_TREE; - for (std::vector<tree>::const_iterator p = statements.begin (); - p != statements.end (); ++p) + for (tree t : statements) { - tree t = (*p); - if (t == error_mark_node) + if (error_operand_p (t)) return error_mark_node; append_to_statement_list (t, &stmt_list); } @@ -1808,12 +1792,13 @@ block (tree fndecl, tree enclosing, const std::vector<Bvariable *> &vars, *pp = block_tree; } + // Chain the variables of the scope together so they are all connected + // to the block. tree *pp = &BLOCK_VARS (block_tree); - for (std::vector<Bvariable *>::const_iterator pv = vars.begin (); - pv != vars.end (); ++pv) + for (Bvariable *bv : vars) { - *pp = (*pv)->get_decl (); - if (*pp != error_mark_node) + *pp = bv->get_decl (); + if (!error_operand_p (*pp)) pp = &DECL_CHAIN (*pp); } *pp = NULL_TREE; @@ -1832,11 +1817,9 @@ void block_add_statements (tree bind_tree, const std::vector<tree> &statements) { tree stmt_list = NULL_TREE; - for (std::vector<tree>::const_iterator p = statements.begin (); - p != statements.end (); ++p) + for (tree s : statements) { - tree s = (*p); - if (s != error_mark_node) + if (!error_operand_p (s)) append_to_statement_list (s, &stmt_list); } @@ -1914,8 +1897,7 @@ convert_tree (tree type_tree, tree expr_tree, location_t location) if (type_tree == TREE_TYPE (expr_tree)) return expr_tree; - if (type_tree == error_mark_node || expr_tree == error_mark_node - || TREE_TYPE (expr_tree) == error_mark_node) + if (error_operand_p (type_tree) || error_operand_p (expr_tree)) return error_mark_node; if (POINTER_TYPE_P (type_tree) || INTEGRAL_TYPE_P (type_tree) @@ -1944,7 +1926,7 @@ global_variable (const std::string &var_name, const std::string &asm_name, tree type_tree, bool is_external, bool is_hidden, bool in_unique_section, location_t location) { - if (type_tree == error_mark_node) + if (error_operand_p (type_tree)) return Bvariable::error_variable (); // The GNU linker does not like dynamic variables with zero size. @@ -1983,11 +1965,11 @@ global_variable (const std::string &var_name, const std::string &asm_name, void global_variable_set_init (Bvariable *var, tree expr_tree) { - if (expr_tree == error_mark_node) + if (error_operand_p (expr_tree)) return; gcc_assert (TREE_CONSTANT (expr_tree)); tree var_decl = var->get_decl (); - if (var_decl == error_mark_node) + if (error_operand_p (var_decl)) return; DECL_INITIAL (var_decl) = expr_tree; @@ -2008,7 +1990,7 @@ Bvariable * local_variable (tree function, const std::string &name, tree type_tree, Bvariable *decl_var, location_t location) { - if (type_tree == error_mark_node) + if (error_operand_p (type_tree)) return Bvariable::error_variable (); tree decl = build_decl (location, VAR_DECL, get_identifier_from_string (name), type_tree); @@ -2029,7 +2011,7 @@ Bvariable * parameter_variable (tree function, const std::string &name, tree type_tree, location_t location) { - if (type_tree == error_mark_node) + if (error_operand_p (type_tree)) return Bvariable::error_variable (); tree decl = build_decl (location, PARM_DECL, get_identifier_from_string (name), type_tree); @@ -2046,7 +2028,7 @@ Bvariable * static_chain_variable (tree fndecl, const std::string &name, tree type_tree, location_t location) { - if (type_tree == error_mark_node) + if (error_operand_p (type_tree)) return Bvariable::error_variable (); tree decl = build_decl (location, PARM_DECL, get_identifier_from_string (name), type_tree); @@ -2080,8 +2062,8 @@ temporary_variable (tree fndecl, tree bind_tree, tree type_tree, tree init_tree, tree *pstatement) { gcc_assert (fndecl != NULL_TREE); - if (type_tree == error_mark_node || init_tree == error_mark_node - || fndecl == error_mark_node) + if (error_operand_p (type_tree) || error_operand_p (init_tree) + || error_operand_p (fndecl)) { *pstatement = error_mark_node; return Bvariable::error_variable (); @@ -2198,13 +2180,13 @@ tree function (tree functype, const std::string &name, const std::string &asm_name, unsigned int flags, location_t location) { - if (functype != error_mark_node) - { - gcc_assert (FUNCTION_POINTER_TYPE_P (functype)); - functype = TREE_TYPE (functype); - } + if (error_operand_p (functype)) + return error_mark_node; + + gcc_assert (FUNCTION_POINTER_TYPE_P (functype)); + functype = TREE_TYPE (functype); tree id = get_identifier_from_string (name); - if (functype == error_mark_node || id == error_mark_node) + if (error_operand_p (id)) return error_mark_node; tree decl = build_decl (location, FUNCTION_DECL, id, functype); @@ -2242,8 +2224,8 @@ tree function_defer_statement (tree function, tree undefer_tree, tree defer_tree, location_t location) { - if (undefer_tree == error_mark_node || defer_tree == error_mark_node - || function == error_mark_node) + if (error_operand_p (undefer_tree) || error_operand_p (defer_tree) + || error_operand_p (function)) return error_mark_node; if (DECL_STRUCT_FUNCTION (function) == NULL) @@ -2275,16 +2257,15 @@ bool function_set_parameters (tree function, const std::vector<Bvariable *> ¶m_vars) { - if (function == error_mark_node) + if (error_operand_p (function)) return false; tree params = NULL_TREE; tree *pp = ¶ms; - for (std::vector<Bvariable *>::const_iterator pv = param_vars.begin (); - pv != param_vars.end (); ++pv) + for (Bvariable *bv : param_vars) { - *pp = (*pv)->get_decl (); - gcc_assert (*pp != error_mark_node); + *pp = bv->get_decl (); + gcc_assert (!error_operand_p (*pp)); pp = &DECL_CHAIN (*pp); } *pp = NULL_TREE; @@ -2309,23 +2290,19 @@ write_global_definitions (const std::vector<tree> &type_decls, // Convert all non-erroneous declarations into Gimple form. size_t i = 0; - for (std::vector<Bvariable *>::const_iterator p = variable_decls.begin (); - p != variable_decls.end (); ++p) + for (Bvariable *bv : variable_decls) { - tree v = (*p)->get_decl (); - if (v != error_mark_node) - { - defs[i] = v; - rust_preserve_from_gc (defs[i]); - ++i; - } + tree v = bv->get_decl (); + if (error_operand_p (v)) + continue; + defs[i] = v; + rust_preserve_from_gc (defs[i]); + ++i; } - for (std::vector<tree>::const_iterator p = type_decls.begin (); - p != type_decls.end (); ++p) + for (tree type_tree : type_decls) { - tree type_tree = (*p); - if (type_tree != error_mark_node && IS_TYPE_OR_DECL_P (type_tree)) + if (!error_operand_p (type_tree) && IS_TYPE_OR_DECL_P (type_tree)) { defs[i] = TYPE_NAME (type_tree); gcc_assert (defs[i] != NULL); @@ -2333,21 +2310,18 @@ write_global_definitions (const std::vector<tree> &type_decls, ++i; } } - for (std::vector<tree>::const_iterator p = constant_decls.begin (); - p != constant_decls.end (); ++p) + for (tree t : constant_decls) { - if ((*p) != error_mark_node) + if (!error_operand_p (t)) { - defs[i] = (*p); + defs[i] = t; rust_preserve_from_gc (defs[i]); ++i; } } - for (std::vector<tree>::const_iterator p = function_decls.begin (); - p != function_decls.end (); ++p) + for (tree decl : function_decls) { - tree decl = (*p); - if (decl != error_mark_node) + if (!error_operand_p (decl)) { rust_preserve_from_gc (decl); if (DECL_STRUCT_FUNCTION (decl) == NULL) diff --git a/gcc/rust/rust-session-manager.cc b/gcc/rust/rust-session-manager.cc index 15f21ef..48acbf34 100644 --- a/gcc/rust/rust-session-manager.cc +++ b/gcc/rust/rust-session-manager.cc @@ -611,7 +611,6 @@ Session::compile_crate (const char *filename) return; AST::CollectLangItems ().go (parsed_crate); - AST::DesugarQuestionMark ().go (parsed_crate); auto name_resolution_ctx = Resolver2_0::NameResolutionContext (); // expansion pipeline stage @@ -619,6 +618,7 @@ Session::compile_crate (const char *filename) expansion (parsed_crate, name_resolution_ctx); AST::DesugarForLoops ().go (parsed_crate); + AST::DesugarQuestionMark ().go (parsed_crate); rust_debug ("\033[0;31mSUCCESSFULLY FINISHED EXPANSION \033[0m"); if (options.dump_option_enabled (CompileOptions::EXPANSION_DUMP)) diff --git a/gcc/rust/typecheck/rust-hir-type-check-expr.cc b/gcc/rust/typecheck/rust-hir-type-check-expr.cc index 791795f..b2bcac0 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-expr.cc +++ b/gcc/rust/typecheck/rust-hir-type-check-expr.cc @@ -16,6 +16,8 @@ // along with GCC; see the file COPYING3. If not see // <http://www.gnu.org/licenses/>. +#include "optional.h" +#include "rust-hir-expr.h" #include "rust-system.h" #include "rust-tyty-call.h" #include "rust-hir-type-check-struct-field.h" @@ -1154,6 +1156,94 @@ TypeCheckExpr::visit (HIR::FieldAccessExpr &expr) infered = lookup->get_field_type (); } +bool +is_default_fn (const MethodCandidate &candidate) +{ + if (candidate.candidate.is_impl_candidate ()) + { + auto *item = candidate.candidate.item.impl.impl_item; + + if (item->get_impl_item_type () == HIR::ImplItem::FUNCTION) + { + auto &fn = static_cast<HIR::Function &> (*item); + + return fn.is_default (); + } + } + + return false; +} + +void +emit_ambiguous_resolution_error (HIR::MethodCallExpr &expr, + std::set<MethodCandidate> &candidates) +{ + rich_location r (line_table, expr.get_method_name ().get_locus ()); + std::string rich_msg = "multiple " + + expr.get_method_name ().get_segment ().as_string () + + " found"; + + // We have to filter out default candidates + for (auto &c : candidates) + if (!is_default_fn (c)) + r.add_range (c.candidate.locus); + + r.add_fixit_replace (rich_msg.c_str ()); + + rust_error_at (r, ErrorCode::E0592, "duplicate definitions with name %qs", + expr.get_method_name ().get_segment ().as_string ().c_str ()); +} + +// We are allowed to have multiple candidates if they are all specializable +// functions or if all of them except one are specializable functions. +// In the later case, we just return a valid candidate without erroring out +// about ambiguity. If there are two or more specialized functions, then we +// error out. +// +// FIXME: The first case is not handled at the moment, so we error out +tl::optional<const MethodCandidate &> +handle_multiple_candidates (HIR::MethodCallExpr &expr, + std::set<MethodCandidate> &candidates) +{ + auto all_default = true; + tl::optional<const MethodCandidate &> found = tl::nullopt; + + for (auto &c : candidates) + { + if (!is_default_fn (c)) + { + all_default = false; + + // We haven't found a final candidate yet, so we can select + // this one. However, if we already have a candidate, then + // that means there are multiple non-default candidates - we + // must error out + if (!found) + { + found = c; + } + else + { + emit_ambiguous_resolution_error (expr, candidates); + return tl::nullopt; + } + } + } + + // None of the candidates were a non-default (specialized) function, so we + // error out + if (all_default) + { + rust_sorry_at (expr.get_locus (), + "cannot resolve method calls to non-specialized methods " + "(all function candidates are %qs)", + "default"); + return tl::nullopt; + } + + return found; +} + void TypeCheckExpr::visit (HIR::MethodCallExpr &expr) { @@ -1181,34 +1271,25 @@ TypeCheckExpr::visit (HIR::MethodCallExpr &expr) return; } - if (candidates.size () > 1) - { - rich_location r (line_table, expr.get_method_name ().get_locus ()); - std::string rich_msg - = "multiple " + expr.get_method_name ().get_segment ().as_string () - + " found"; + tl::optional<const MethodCandidate &> candidate = *candidates.begin (); - for (auto &c : candidates) - r.add_range (c.candidate.locus); + if (candidates.size () > 1) + candidate = handle_multiple_candidates (expr, candidates); - r.add_fixit_replace (rich_msg.c_str ()); + if (!candidate) + return; - rust_error_at ( - r, ErrorCode::E0592, "duplicate definitions with name %qs", - expr.get_method_name ().get_segment ().as_string ().c_str ()); - return; - } + auto found_candidate = *candidate; - auto candidate = *candidates.begin (); rust_debug_loc (expr.get_method_name ().get_locus (), "resolved method to: {%u} {%s} with [%lu] adjustments", - candidate.candidate.ty->get_ref (), - candidate.candidate.ty->debug_str ().c_str (), - (unsigned long) candidate.adjustments.size ()); + found_candidate.candidate.ty->get_ref (), + found_candidate.candidate.ty->debug_str ().c_str (), + (unsigned long) found_candidate.adjustments.size ()); // Get the adjusted self Adjuster adj (receiver_tyty); - TyTy::BaseType *adjusted_self = adj.adjust_type (candidate.adjustments); + TyTy::BaseType *adjusted_self = adj.adjust_type (found_candidate.adjustments); rust_debug ("receiver: %s adjusted self %s", receiver_tyty->debug_str ().c_str (), adjusted_self->debug_str ().c_str ()); @@ -1219,10 +1300,10 @@ TypeCheckExpr::visit (HIR::MethodCallExpr &expr) HirId autoderef_mappings_id = expr.get_receiver ().get_mappings ().get_hirid (); context->insert_autoderef_mappings (autoderef_mappings_id, - std::move (candidate.adjustments)); + std::move (found_candidate.adjustments)); - PathProbeCandidate &resolved_candidate = candidate.candidate; - TyTy::BaseType *lookup_tyty = candidate.candidate.ty; + PathProbeCandidate &resolved_candidate = found_candidate.candidate; + TyTy::BaseType *lookup_tyty = found_candidate.candidate.ty; NodeId resolved_node_id = resolved_candidate.is_impl_candidate () ? resolved_candidate.item.impl.impl_item->get_impl_mappings () @@ -1249,8 +1330,8 @@ TypeCheckExpr::visit (HIR::MethodCallExpr &expr) fn->prepare_higher_ranked_bounds (); rust_debug_loc (expr.get_locus (), "resolved method call to: {%u} {%s}", - candidate.candidate.ty->get_ref (), - candidate.candidate.ty->debug_str ().c_str ()); + found_candidate.candidate.ty->get_ref (), + found_candidate.candidate.ty->debug_str ().c_str ()); if (resolved_candidate.is_impl_candidate ()) { diff --git a/gcc/rust/util/rust-attribute-values.h b/gcc/rust/util/rust-attribute-values.h index 9ef5cc5..47e6a17 100644 --- a/gcc/rust/util/rust-attribute-values.h +++ b/gcc/rust/util/rust-attribute-values.h @@ -40,12 +40,14 @@ public: static constexpr auto &NO_MANGLE = "no_mangle"; static constexpr auto &REPR = "repr"; static constexpr auto &RUSTC_BUILTIN_MACRO = "rustc_builtin_macro"; + static constexpr auto &RUSTC_MACRO_TRANSPARENCY = "rustc_macro_transparency"; static constexpr auto &PATH = "path"; static constexpr auto &MACRO_USE = "macro_use"; static constexpr auto &MACRO_EXPORT = "macro_export"; static constexpr auto &PROC_MACRO = "proc_macro"; static constexpr auto &PROC_MACRO_DERIVE = "proc_macro_derive"; static constexpr auto &PROC_MACRO_ATTRIBUTE = "proc_macro_attribute"; + static constexpr auto &TARGET_FEATURE = "target_feature"; // From now on, these are reserved by the compiler and gated through // #![feature(rustc_attrs)] @@ -54,10 +56,35 @@ public: = "rustc_inherit_overflow_checks"; static constexpr auto &STABLE = "stable"; static constexpr auto &UNSTABLE = "unstable"; + + static constexpr auto &RUSTC_PROMOTABLE = "rustc_promotable"; static constexpr auto &RUSTC_CONST_STABLE = "rustc_const_stable"; static constexpr auto &RUSTC_CONST_UNSTABLE = "rustc_const_unstable"; + + static constexpr auto &RUSTC_SPECIALIZATION_TRAIT + = "rustc_specialization_trait"; + static constexpr auto &RUSTC_UNSAFE_SPECIALIZATION_MARKER + = "rustc_unsafe_specialization_marker"; + static constexpr auto &RUSTC_RESERVATION_IMPL = "rustc_reservation_impl"; + static constexpr auto &RUSTC_PAREN_SUGAR = "rustc_paren_sugar"; + static constexpr auto &RUSTC_NONNULL_OPTIMIZATION_GUARANTEED + = "rustc_nonnull_optimization_guaranteed"; + + static constexpr auto &RUSTC_LAYOUT_SCALAR_VALID_RANGE_START + = "rustc_layout_scalar_valid_range_start"; + static constexpr auto &MAY_DANGLE = "may_dangle"; static constexpr auto &PRELUDE_IMPORT = "prelude_import"; + static constexpr auto &TRACK_CALLER = "track_caller"; + + static constexpr auto &RUSTC_DIAGNOSTIC_ITEM = "rustc_diagnostic_item"; + static constexpr auto &RUSTC_ON_UNIMPLEMENTED = "rustc_on_unimplemented"; + + static constexpr auto &FUNDAMENTAL = "fundamental"; + + static constexpr auto &NON_EXHAUSTIVE = "non_exhaustive"; + + static constexpr auto &RUSTFMT = "rustfmt"; }; } // namespace Values } // namespace Rust diff --git a/gcc/rust/util/rust-attributes.cc b/gcc/rust/util/rust-attributes.cc index 03452c7..c77e99c 100644 --- a/gcc/rust/util/rust-attributes.cc +++ b/gcc/rust/util/rust-attributes.cc @@ -57,6 +57,7 @@ static const BuiltinAttrDefinition __definitions[] {Attrs::NO_MANGLE, CODE_GENERATION}, {Attrs::REPR, CODE_GENERATION}, {Attrs::RUSTC_BUILTIN_MACRO, EXPANSION}, + {Attrs::RUSTC_MACRO_TRANSPARENCY, EXPANSION}, {Attrs::PATH, EXPANSION}, {Attrs::MACRO_USE, NAME_RESOLUTION}, {Attrs::MACRO_EXPORT, NAME_RESOLUTION}, @@ -72,10 +73,29 @@ static const BuiltinAttrDefinition __definitions[] {Attrs::RUSTC_INHERIT_OVERFLOW_CHECKS, CODE_GENERATION}, {Attrs::STABLE, STATIC_ANALYSIS}, {Attrs::UNSTABLE, STATIC_ANALYSIS}, + // assuming we keep these for static analysis + {Attrs::RUSTC_PROMOTABLE, CODE_GENERATION}, {Attrs::RUSTC_CONST_STABLE, STATIC_ANALYSIS}, {Attrs::RUSTC_CONST_UNSTABLE, STATIC_ANALYSIS}, - {Attrs::PRELUDE_IMPORT, NAME_RESOLUTION}}; + {Attrs::PRELUDE_IMPORT, NAME_RESOLUTION}, + {Attrs::TRACK_CALLER, CODE_GENERATION}, + {Attrs::RUSTC_SPECIALIZATION_TRAIT, TYPE_CHECK}, + {Attrs::RUSTC_UNSAFE_SPECIALIZATION_MARKER, TYPE_CHECK}, + {Attrs::RUSTC_RESERVATION_IMPL, TYPE_CHECK}, + {Attrs::RUSTC_PAREN_SUGAR, TYPE_CHECK}, + {Attrs::RUSTC_NONNULL_OPTIMIZATION_GUARANTEED, TYPE_CHECK}, + + {Attrs::RUSTC_LAYOUT_SCALAR_VALID_RANGE_START, CODE_GENERATION}, + + {Attrs::PRELUDE_IMPORT, NAME_RESOLUTION}, + + {Attrs::RUSTC_DIAGNOSTIC_ITEM, STATIC_ANALYSIS}, + {Attrs::RUSTC_ON_UNIMPLEMENTED, STATIC_ANALYSIS}, + + {Attrs::FUNDAMENTAL, TYPE_CHECK}, + {Attrs::NON_EXHAUSTIVE, TYPE_CHECK}, + {Attrs::RUSTFMT, EXTERNAL}}; BuiltinAttributeMappings * BuiltinAttributeMappings::get () diff --git a/gcc/rust/util/rust-attributes.h b/gcc/rust/util/rust-attributes.h index c928c8e..7c7a1fc 100644 --- a/gcc/rust/util/rust-attributes.h +++ b/gcc/rust/util/rust-attributes.h @@ -40,7 +40,12 @@ enum CompilerPass HIR_LOWERING, TYPE_CHECK, STATIC_ANALYSIS, - CODE_GENERATION + CODE_GENERATION, + + // External Rust tooling attributes, like #[rustfmt::skip] + EXTERNAL, + + // Do we need to add something here for const fns? }; struct BuiltinAttrDefinition diff --git a/gcc/rust/util/rust-lang-item.cc b/gcc/rust/util/rust-lang-item.cc index a76cc7f..9aff31b 100644 --- a/gcc/rust/util/rust-lang-item.cc +++ b/gcc/rust/util/rust-lang-item.cc @@ -118,6 +118,7 @@ const BiMap<std::string, LangItem::Kind> Rust::LangItem::lang_items = {{ {"discriminant_kind", Kind::DISCRIMINANT_KIND}, {"discriminant_type", Kind::DISCRIMINANT_TYPE}, + {"manually_drop", Kind::MANUALLY_DROP}, }}; tl::optional<LangItem::Kind> diff --git a/gcc/rust/util/rust-lang-item.h b/gcc/rust/util/rust-lang-item.h index 8f3af36..67a5d9c 100644 --- a/gcc/rust/util/rust-lang-item.h +++ b/gcc/rust/util/rust-lang-item.h @@ -150,6 +150,8 @@ public: DISCRIMINANT_TYPE, DISCRIMINANT_KIND, + + MANUALLY_DROP, }; static const BiMap<std::string, Kind> lang_items; diff --git a/gcc/sanitizer.def b/gcc/sanitizer.def index 4b7c9dc..c5a9c2d 100644 --- a/gcc/sanitizer.def +++ b/gcc/sanitizer.def @@ -247,7 +247,7 @@ DEF_SANITIZER_BUILTIN(BUILT_IN_TSAN_INIT, "__tsan_init", DEF_SANITIZER_BUILTIN(BUILT_IN_TSAN_FUNC_ENTRY, "__tsan_func_entry", BT_FN_VOID_PTR, ATTR_NOTHROW_LEAF_LIST) DEF_SANITIZER_BUILTIN(BUILT_IN_TSAN_FUNC_EXIT, "__tsan_func_exit", - BT_FN_VOID_PTR, ATTR_NOTHROW_LEAF_LIST) + BT_FN_VOID, ATTR_NOTHROW_LEAF_LIST) DEF_SANITIZER_BUILTIN(BUILT_IN_TSAN_VPTR_UPDATE, "__tsan_vptr_update", BT_FN_VOID_PTR_PTR, ATTR_NOTHROW_LEAF_LIST) DEF_SANITIZER_BUILTIN(BUILT_IN_TSAN_READ1, "__tsan_read1", diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 330a283..4c219bd 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,598 @@ +2025-04-21 Jason Merrill <jason@redhat.com> + + PR c++/118775 + * g++.dg/cpp2a/constexpr-new24.C: Adjust diagnostic. + +2025-04-21 Andrew Bennett <andrew.bennett@imgtec.com> + + * gcc.dg/memcpy-4.c: Remove mips specific code. + * gcc.target/mips/memcpy-2.c: New test. + +2025-04-21 Matthew Fortune <matthew.fortune@imgtec.com> + + * gcc.target/mips/clear-cache-1.c: Also allow jrc. + +2025-04-21 Matthew Fortune <matthew.fortune@imgtec.com> + + * gcc.dg/tree-ssa/ssa-dom-cse-2.c: Do not check output for + MIPS lp64 abi. + +2025-04-21 Andrew Pinski <quic_apinski@quicinc.com> + + PR middle-end/119507 + * g++.dg/eh/pr119507.C: New test. + +2025-04-21 hongtao.liu <hongtao.liu@intel.com> + + * gcc.target/i386/recip-vec-divf-fma.c: New test. + +2025-04-20 H.J. Lu <hjl.tools@gmail.com> + + PR target/117863 + * gcc.dg/rtl/i386/vector_eq-2.c: New test. + * gcc.dg/rtl/i386/vector_eq-3.c: Likewise. + +2025-04-19 Thomas Schwinge <tschwinge@baylibre.com> + + PR testsuite/119508 + * rust/compile/nr2/compile.exp: Disable parallel testing. + +2025-04-19 Co-authored-by: Jeff Law <jlaw@ventanamicro.com> + + PR target/118410 + * gcc.target/riscv/pr118410-1.c: New test. + * gcc.target/riscv/pr118410-2.c: Likewise. + +2025-04-19 Andrew Pinski <quic_apinski@quicinc.com> + + * gcc.dg/pr118947-1.c: Use 1025 as the size of the buf. + * gcc.dg/pr78408-3.c: Likewise. + +2025-04-19 Andrew Pinski <quic_apinski@quicinc.com> + + PR rtl-optimization/111949 + * gcc.target/aarch64/bic-1.c: New test. + +2025-04-19 Jiaxun Yang <jiaxun.yang@flygoat.com> + + PR target/111814 + * gcc.target/sh/pr111814.c: New test. + +2025-04-19 Maciej W. Rozycki <macro@orcam.me.uk> + + * gcc.target/alpha/memcpy-nested-offset-long.c: New file. + * gcc.target/alpha/memcpy-nested-offset-quad.c: New file. + +2025-04-19 Steven G. Kargl <kargl@gcc.gnu.org> + + PR fortran/119836 + * gfortran.dg/do_concurrent_all_clauses.f90: Remove invalid + dg-error test. + * gfortran.dg/pr119836_1.f90: New test. + * gfortran.dg/pr119836_2.f90: New test. + * gfortran.dg/pr119836_3.f90: New test. + * gfortran.dg/pr119836_4.f90: New test. + +2025-04-18 Thomas Schwinge <tschwinge@baylibre.com> + + PR cobol/119818 + * cobol.dg/group2/FUNCTION_DATE___TIME_OMNIBUS.cob: + 'dg-set-target-env-var TZ UTC0'. + +2025-04-18 Jeff Law <jlaw@ventanamicro.com> + + * gcc.target/riscv/bext-ext-2.c: New test + +2025-04-18 Jonathan Yong <10walls@gmail.com> + + * g++.dg/abi/ref-temp1.C: Replicate some test based on + PE expectations. + * lib/target-supports.exp: New check_effective_target_pe. + +2025-04-18 Andrew Pinski <quic_apinski@quicinc.com> + + PR tree-optimization/87901 + * gcc.dg/tree-ssa/ssa-dse-53.c: New test. + * gcc.dg/tree-ssa/ssa-dse-54.c: New test. + +2025-04-18 Andrew Pinski <quic_apinski@quicinc.com> + + PR tree-optimization/87901 + * gcc.dg/tree-ssa/ssa-dse-52.c: New test. + +2025-04-18 Andrew Pinski <quic_apinski@quicinc.com> + + PR tree-optimization/118902 + * gcc.dg/tree-ssa/pr118902-1.c: New test. + +2025-04-18 Andrew Pinski <quic_apinski@quicinc.com> + + PR tree-optimization/118947 + * gcc.dg/pr118947-1.c: New test. + +2025-04-18 Andrew Pinski <quic_apinski@quicinc.com> + + PR tree-optimization/78408 + PR tree-optimization/118947 + * gcc.dg/pr78408-3.c: New test. + +2025-04-18 Dimitar Dimitrov <dimitar@dinux.eu> + + * gcc.dg/pr116357.c: Use sizeof(int) instead of alignof(int). + +2025-04-18 Alexey Merzlyakov <alexey.merzlyakov@samsung.com> + + PR middle-end/108016 + * gcc.target/riscv/pr108016.c: New test. + +2025-04-18 kelefth <konstantinos.eleftheriou@vrull.eu> + + PR rtl-optimization/119160 + * gcc.dg/pr119160.c: New test. + +2025-04-18 Xing Li <lixing@loongson.cn> + + * gcc.target/loongarch/vector/loongarch-vector.exp: Change + {dg-do-what-default} save and restore logical. + +2025-04-17 Jason Merrill <jason@redhat.com> + + * g++.dg/cpp2a/constexpr-dtor16.C: Adjust diagnostic. + * g++.dg/cpp2a/constexpr-dynamic10.C: Likewise. + +2025-04-17 Jason Merrill <jason@redhat.com> + + * g++.dg/cpp1y/constexpr-new.C: Adjust diagnostics. + * g++.dg/cpp1z/constexpr-asm-5.C: Likewise. + * g++.dg/cpp26/static_assert1.C: Likewise. + * g++.dg/cpp2a/constexpr-dtor7.C: Likewise. + * g++.dg/cpp2a/constexpr-new26.C: Likewise. + * g++.dg/cpp2a/constexpr-new3.C: Likewise. + * g++.dg/cpp2a/constinit14.C: Likewise. + +2025-04-17 Jason Merrill <jason@redhat.com> + + * g++.dg/cpp26/pack-indexing2.C: Adjust diagnostics. + * g++.dg/ext/type_pack_element2.C: Likewise. + * g++.dg/ext/type_pack_element4.C: Likewise. + +2025-04-17 Tamar Christina <tamar.christina@arm.com> + + PR tree-optimization/119351 + * gcc.target/aarch64/sve/pr119351.c: New test. + * gcc.target/aarch64/sve/pr119351_run.c: New test. + +2025-04-17 Jakub Jelinek <jakub@redhat.com> + + PR target/119834 + * g++.target/s390/pr119834.C: New test. + +2025-04-17 Iain Buclaw <ibuclaw@gdcproject.org> + + * gdc.test/fail_compilation/test21247.d: New test. + * gdc.test/fail_compilation/test21247b.d: New test. + +2025-04-17 Jason Merrill <jason@redhat.com> + + PR c++/113360 + * g++.dg/cpp23/constexpr-nonlit18.C: Remove redundant message. + * g++.dg/cpp1y/constexpr-diag2.C: New test. + * g++.dg/cpp1y/pr63996.C: Adjust expected errors. + * g++.dg/template/explicit-args6.C: Likewise. + * g++.dg/cpp0x/constexpr-ice21.C: Likewise. + +2025-04-16 Alexandre Oliva <oliva@adacore.com> + + * gcc.dg/ipa/ipa-sra-19.c: Add -Wno-psabi on ppc-elf too. + +2025-04-16 Peter Bergner <bergner@linux.ibm.com> + + PR tree-optimization/112822 + * g++.dg/pr112822.C: Replace altivec vector attribute with a generic + vector attribute. + +2025-04-16 Eric Botcazou <ebotcazou@gcc.gnu.org> + + * gnat.dg/opt105.adb: New test. + * gnat.dg/opt105_pkg.ads, gnat.dg/opt105_pkg.adb: New helper. + +2025-04-16 Jason Merrill <jason@redhat.com> + + PR c++/114772 + PR c++/101180 + * g++.dg/ext/pragma-target2.C: New test. + +2025-04-16 Jason Merrill <jason@redhat.com> + + PR c++/116954 + * g++.dg/warn/Wformat-3.C: New test. + +2025-04-16 Ard Biesheuvel <ardb@kernel.org> + + PR target/119386 + * gcc.target/i386/pr119386-3.c: New test. + +2025-04-16 Ard Biesheuvel <ardb@kernel.org> + + PR target/119386 + * gcc.target/i386/pr119386-1.c: New test. + * gcc.target/i386/pr119386-2.c: New test. + +2025-04-16 Harald Anlauf <anlauf@gmx.de> + + PR fortran/106948 + * gfortran.dg/pure_formal_proc_4.f90: New test. + +2025-04-16 Jan Hubicka <hubicka@ucw.cz> + + * g++.dg/lto/pr119614_0.C: New test. + +2025-04-16 Tamar Christina <tamar.christina@arm.com> + + PR target/119286 + * gcc.dg/vect/vect-early-break_18.c: Force -march=gfx908 for amdgcn. + +2025-04-16 Tamar Christina <tamar.christina@arm.com> + + PR tree-optimization/119351 + * gcc.target/aarch64/sve/peel_ind_10.c: New test. + * gcc.target/aarch64/sve/peel_ind_10_run.c: New test. + * gcc.target/aarch64/sve/peel_ind_5.c: New test. + * gcc.target/aarch64/sve/peel_ind_5_run.c: New test. + * gcc.target/aarch64/sve/peel_ind_6.c: New test. + * gcc.target/aarch64/sve/peel_ind_6_run.c: New test. + * gcc.target/aarch64/sve/peel_ind_7.c: New test. + * gcc.target/aarch64/sve/peel_ind_7_run.c: New test. + * gcc.target/aarch64/sve/peel_ind_8.c: New test. + * gcc.target/aarch64/sve/peel_ind_8_run.c: New test. + * gcc.target/aarch64/sve/peel_ind_9.c: New test. + * gcc.target/aarch64/sve/peel_ind_9_run.c: New test. + +2025-04-16 Jakub Jelinek <jakub@redhat.com> + + PR middle-end/119808 + * gcc.dg/bitint-121.c: New test. + +2025-04-16 Jesse Huang <jesse.huang@sifive.com> + + * gcc.target/riscv/gnu-property-align-rv32.c: New file. + * gcc.target/riscv/gnu-property-align-rv64.c: New file. + +2025-04-16 Kito Cheng <kito.cheng@sifive.com> + + * gcc.target/riscv/jump-table-large-code-model.c: New test. + +2025-04-16 Jakub Jelinek <jakub@redhat.com> + + PR tree-optimization/116093 + * gcc.dg/bitint-122.c: New test. + +2025-04-16 Alice Carlotti <alice.carlotti@arm.com> + + * gcc.target/aarch64/acle/rwsr-ungated.c: New test. + +2025-04-15 Iain Buclaw <ibuclaw@gdcproject.org> + + PR d/119826 + * gdc.dg/debug/imports/pr119826b.d: New test. + * gdc.dg/debug/pr119826.d: New test. + +2025-04-15 Nathaniel Shead <nathanieloshead@gmail.com> + + PR c++/119755 + * g++.dg/modules/lambda-10_a.H: New test. + * g++.dg/modules/lambda-10_b.C: New test. + +2025-04-15 Jakub Jelinek <jakub@redhat.com> + + * gcc.dg/completion-2.c: Expect also -flto-partition=default line. + +2025-04-15 Qing Zhao <qing.zhao@oracle.com> + + PR c/119717 + * gcc.dg/pr119717.c: New test. + +2025-04-15 H.J. Lu <hjl.tools@gmail.com> + + PR target/119784 + * gcc.target/i386/apx-interrupt-1.c: Expect 31 .cfi_restore + directives. + +2025-04-15 Vineet Gupta <vineetg@rivosinc.com> + + PR target/119533 + * go.dg/pr119533-riscv.go: New test. + * go.dg/pr119533-riscv-2.go: New test. + +2025-04-15 Robin Dapp <rdapp@ventanamicro.com> + + PR target/119547 + * gcc.target/riscv/rvv/vsetvl/avl_single-68.c: xfail. + * g++.target/riscv/rvv/autovec/pr119547.C: New test. + * g++.target/riscv/rvv/autovec/pr119547-2.C: New test. + * gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-10.c: Adjust. + +2025-04-15 Tobias Burnus <tburnus@baylibre.com> + + * gfortran.dg/gomp/map-alloc-comp-1.f90: Remove dg-error. + * gfortran.dg/gomp/polymorphic-mapping-2.f90: Update warn wording. + * gfortran.dg/gomp/polymorphic-mapping.f90: Change expected + diagnostic; some tests moved to ... + * gfortran.dg/gomp/polymorphic-mapping-1.f90: ... here as new test. + * gfortran.dg/gomp/polymorphic-mapping-3.f90: New test. + * gfortran.dg/gomp/polymorphic-mapping-4.f90: New test. + * gfortran.dg/gomp/polymorphic-mapping-5.f90: New test. + +2025-04-15 Martin Jambor <mjambor@suse.cz> + Jakub Jelinek <jakub@redhat.com> + + PR ipa/119803 + * gcc.dg/ipa/pr119803.c: New test. + +2025-04-15 Iain Buclaw <ibuclaw@gdcproject.org> + + PR d/119799 + * gdc.dg/import-c/pr119799.d: New test. + * gdc.dg/import-c/pr119799c.c: New test. + +2025-04-15 Patrick Palka <ppalka@redhat.com> + + PR c++/119807 + PR c++/112288 + * g++.dg/template/friend86.C: New test. + * g++.dg/template/friend87.C: New test. + +2025-04-15 Iain Buclaw <ibuclaw@gdcproject.org> + + PR d/119817 + * gdc.dg/debug/imports/m119817/a.d: New test. + * gdc.dg/debug/imports/m119817/b.d: New test. + * gdc.dg/debug/imports/m119817/package.d: New test. + * gdc.dg/debug/pr119817.d: New test. + +2025-04-15 Jakub Jelinek <jakub@redhat.com> + + PR sanitizer/119801 + * c-c++-common/tsan/pr119801.c: New test. + +2025-04-15 Jonathan Yong <10walls@gmail.com> + + * gcc.dg/Wbuiltin-declaration-mismatch-4.c: Make diagnostic + accept long long. + +2025-04-15 Jakub Jelinek <jakub@redhat.com> + + PR ipa/119318 + * gcc.dg/ipa/pr119318.c: Remove dg-additional-options, add -w to + dg-options. + +2025-04-15 Jason Merrill <jason@redhat.com> + + PR c++/113835 + * g++.dg/cpp2a/constexpr-vector1.C: New test. + +2025-04-14 Thomas Schwinge <tschwinge@baylibre.com> + + PR target/118794 + * g++.target/gcn/exceptions-bad_cast-2.C: Set + '-mno-fake-exceptions'. + * g++.target/gcn/exceptions-pr118794-1.C: Likewise. + * g++.target/gcn/exceptions-throw-2.C: Likewise. + * g++.target/nvptx/exceptions-bad_cast-2.C: Likewise. + * g++.target/nvptx/exceptions-pr118794-1.C: Likewise. + * g++.target/nvptx/exceptions-throw-2.C: Likewise. + * g++.target/gcn/exceptions-bad_cast-2_-mfake-exceptions.C: New. + * g++.target/gcn/exceptions-pr118794-1_-mfake-exceptions.C: + Likewise. + * g++.target/gcn/exceptions-throw-2_-mfake-exceptions.C: Likewise. + * g++.target/nvptx/exceptions-bad_cast-2_-mfake-exceptions.C: + Likewise. + * g++.target/nvptx/exceptions-pr118794-1_-mfake-exceptions.C: + Likewise. + * g++.target/nvptx/exceptions-throw-2_-mfake-exceptions.C: + Likewise. + +2025-04-14 Thomas Schwinge <tschwinge@baylibre.com> + + * g++.target/gcn/exceptions-throw-3.C: New. + * g++.target/nvptx/exceptions-throw-3.C: Likewise. + +2025-04-14 Thomas Schwinge <tschwinge@baylibre.com> + + * g++.target/gcn/exceptions-throw-2.C: New. + * g++.target/nvptx/exceptions-throw-2.C: Likewise. + +2025-04-14 Thomas Schwinge <tschwinge@baylibre.com> + + * g++.target/gcn/exceptions-throw-1.C: New. + * g++.target/nvptx/exceptions-throw-1.C: Likewise. + +2025-04-14 Thomas Schwinge <tschwinge@baylibre.com> + + * g++.target/gcn/exceptions-bad_cast-3.C: New. + * g++.target/nvptx/exceptions-bad_cast-3.C: Likewise. + +2025-04-14 Thomas Schwinge <tschwinge@baylibre.com> + + * g++.target/gcn/exceptions-bad_cast-2.C: New. + * g++.target/nvptx/exceptions-bad_cast-2.C: Likewise. + +2025-04-14 Thomas Schwinge <tschwinge@baylibre.com> + + * g++.target/gcn/exceptions-bad_cast-1.C: New. + * g++.target/nvptx/exceptions-bad_cast-1.C: Likewise. + +2025-04-14 Thomas Schwinge <tschwinge@baylibre.com> + + PR target/118794 + * g++.target/gcn/exceptions-pr118794-1.C: New. + * g++.target/nvptx/exceptions-pr118794-1.C: Likewise. + +2025-04-14 Thomas Schwinge <tschwinge@baylibre.com> + + PR c++/119692 + * g++.target/gcn/pr119692-1-1.C: New. + * g++.target/nvptx/pr119692-1-1.C: Likewise. + +2025-04-14 Thomas Schwinge <tschwinge@baylibre.com> + + * g++.target/gcn/gcn.exp: New. + +2025-04-14 Thomas Schwinge <tschwinge@baylibre.com> + + * lib/gcc-dg.exp (${tool}_load): Polish 'dg-output-file' test + logs. + +2025-04-14 Jakub Jelinek <jakub@redhat.com> + + PR ipa/119318 + * gcc.dg/ipa/pr119530.c (d): Change type from char to signed char. + (e): Change argument type from long to long long. + +2025-04-14 beamandala <mandalapubhavesh@gmail.com> + + * rust/compile/track_caller.rs: New test. + +2025-04-14 Owen Avery <powerboat9.gamer@gmail.com> + + * rust/compile/enum_discriminant2.rs: New test. + +2025-04-14 Arthur Cohen <arthur.cohen@embecosm.com> + + * rust/compile/format_args_extra_comma.rs: New test. + +2025-04-14 Arthur Cohen <arthur.cohen@embecosm.com> + + * rust/compile/macros/mbe/macro-issue3709-1.rs: New test. + * rust/compile/macros/mbe/macro-issue3709-2.rs: New test. + * rust/compile/macros/mbe/macro-issue3693.rs: New file. + +2025-04-14 Arthur Cohen <arthur.cohen@embecosm.com> + + * rust/compile/macros/mbe/macro-issue3708.rs: New test. + +2025-04-14 Arthur Cohen <arthur.cohen@embecosm.com> + + * rust/execute/torture/min_specialization2.rs: New test. + * rust/execute/torture/min_specialization3.rs: New test. + +2025-04-14 Andrew Pinski <quic_apinski@quicinc.com> + + PR tree-optimization/118476 + * gcc.dg/torture/pr118476-1.c: New test. + +2025-04-14 Patrick Palka <ppalka@redhat.com> + + PR c++/99214 + * g++.dg/concepts/diagnostic20.C: New test. + +2025-04-14 H.J. Lu <hjl.tools@gmail.com> + + PR target/119784 + * gcc.target/i386/pr119784a.c: New test. + * gcc.target/i386/pr119784b.c: Likewise. + +2025-04-14 Martin Jambor <mjambor@suse.cz> + + PR ipa/119318 + * gcc.dg/ipa/pr119318.c: New test. + * gcc.dg/ipa/pr119530.c: Likwise. + +2025-04-14 Richard Biener <rguenther@suse.de> + + PR tree-optimization/119757 + * gcc.dg/vect/pr119757.c: New testcase. + +2025-04-14 Richard Biener <rguenther@suse.de> + + PR tree-optimization/119778 + * g++.dg/torture/pr119778.C: New testcase. + +2025-04-14 Gaius Mulley <gaiusmod2@gmail.com> + + PR modula2/119779 + * gm2.dg/doc/examples/pass/doc-examples-pass.exp: New test. + * gm2.dg/doc/examples/pass/exampleadd.mod: New test. + * gm2.dg/doc/examples/pass/exampleadd2.mod: New test. + * gm2.dg/doc/examples/pass/hello.mod: New test. + * gm2.dg/doc/examples/pass/hellopim.mod: New test. + +2025-04-14 Eric Botcazou <ebotcazou@adacore.com> + + PR lto/119792 + * gnat.dg/lto29.adb: New test. + * gnat.dg/lto29_pkg.ads: New helper. + +2025-04-13 Jerry DeLisle <jvdelisle@gcc.gnu.org> + + PR libfortran/119502 + * gfortran.dg/pr119502.f90: New test. + +2025-04-13 Nathaniel Shead <nathanieloshead@gmail.com> + + * g++.dg/modules/noexcept-4_a.H: New test. + * g++.dg/modules/noexcept-4_b.C: New test. + +2025-04-13 Nathaniel Shead <nathanieloshead@gmail.com> + + * g++.dg/modules/lambda-8_b.C: Adjust error. + * g++.dg/modules/leg-merge-4_c.C: Likewise. + +2025-04-13 Thomas Koenig <tkoenig@gcc.gnu.org> + + PR fortran/119669 + * gfortran.dg/interface_59.f90: New test. + +2025-04-12 Iain Buclaw <ibuclaw@gdcproject.org> + + PR d/119761 + * gdc.dg/import-c/import-c.exp: New test. + * gdc.dg/import-c/pr119761.d: New test. + * gdc.dg/import-c/pr119761c.c: New test. + +2025-04-12 Iain Buclaw <ibuclaw@gdcproject.org> + + PR d/109023 + * gdc.dg/torture/imports/pr109023.d: New test. + * gdc.dg/torture/pr109023.d: New test. + +2025-04-12 Iain Buclaw <ibuclaw@gdcproject.org> + + PR d/119758 + * gdc.dg/driver_fonly1.d: New test. + * gdc.dg/driver_fonly2.d: New test. + * gdc.dg/driver_fonly3.d: New test. + * gdc.dg/imports/fonly.d: New test. + +2025-04-12 Andrew Pinski <quic_apinski@quicinc.com> + + PR testsuite/117706 + * gcc.dg/ira-shrinkwrap-prep-1.c: Unxfail for i?68-*-* and x86_64-*-*. + * gcc.dg/ira-shrinkwrap-prep-2.c: Likewise. + +2025-04-12 Patrick Palka <ppalka@redhat.com> + + PR c++/116416 + * g++.dg/cpp1y/constexpr-prvalue1.C: Adjust to instead inspect + the 'original' dump. + * g++.dg/cpp1y/constexpr-prvalue1a.C: New test. + +2025-04-12 Jakub Jelinek <jakub@redhat.com> + + PR tree-optimization/119722 + * gcc.dg/torture/bitint-77.c: New test. + +2025-04-12 Eric Botcazou <ebotcazou@adacore.com> + + * gnat.dg/renaming17.adb: New test. + +2025-04-12 Bob Dubner <rdubner@symas.com> + + PR cobol/119694 + * cobol.dg/group2/ACCEPT_DATE___DAY_and_intrinsic_functions__2_.cob: GCOBOL_CURRENT_DATE. + * cobol.dg/group2/ACCEPT_FROM_TIME___DATE___DAY___DAY-OF-WEEK__2_.cob: Likewise + * cobol.dg/group2/FUNCTION_DATE___TIME_OMNIBUS.cob: Likewise + 2025-04-11 Christophe Lyon <christophe.lyon@linaro.org> * lib/target-supports.exp: Rename arm_v8_1_lob_ok into diff --git a/gcc/testsuite/c-c++-common/tsan/pr119801.c b/gcc/testsuite/c-c++-common/tsan/pr119801.c new file mode 100644 index 0000000..d3a6bb4 --- /dev/null +++ b/gcc/testsuite/c-c++-common/tsan/pr119801.c @@ -0,0 +1,24 @@ +/* PR sanitizer/119801 */ +/* { dg-do compile } */ +/* { dg-options "-fsanitize=thread" } */ + +[[gnu::noipa]] int +bar (int *p) +{ + return ++*p; +} + +int +foo (int *p) +{ + ++*p; + [[gnu::musttail]] return bar (p); +} + +[[gnu::noinline]] int +baz (int x) +{ + if (x < 10) + return x; + [[gnu::musttail]] return baz (x - 2); +} diff --git a/gcc/testsuite/cobol.dg/group2/FUNCTION_DATE___TIME_OMNIBUS.cob b/gcc/testsuite/cobol.dg/group2/FUNCTION_DATE___TIME_OMNIBUS.cob index cc2a4e1..88b1b84 100644 --- a/gcc/testsuite/cobol.dg/group2/FUNCTION_DATE___TIME_OMNIBUS.cob +++ b/gcc/testsuite/cobol.dg/group2/FUNCTION_DATE___TIME_OMNIBUS.cob @@ -1,4 +1,5 @@ *> { dg-do run } + *> { dg-set-target-env-var TZ UTC0 } identification division. program-id. test. diff --git a/gcc/testsuite/g++.dg/abi/ref-temp1.C b/gcc/testsuite/g++.dg/abi/ref-temp1.C index 70c9a7a..b02dcf6 100644 --- a/gcc/testsuite/g++.dg/abi/ref-temp1.C +++ b/gcc/testsuite/g++.dg/abi/ref-temp1.C @@ -7,11 +7,16 @@ struct B { const A (&x)[2]; }; template <typename T> B &&b = { { { { 1, 2, 3 } }, { { 4, 5, 6 } } } }; B &temp = b<void>; -// { dg-final { scan-assembler ".weak\(_definition\)?\[ \t\]_?_ZGR1bIvE_" } } -// { dg-final { scan-assembler ".weak\(_definition\)?\[ \t\]_?_ZGR1bIvE0_" } } -// { dg-final { scan-assembler ".weak\(_definition\)?\[ \t\]_?_ZGR1bIvE1_" } } -// { dg-final { scan-assembler ".weak\(_definition\)?\[ \t\]_?_ZGR1bIvE2_" } } +// { dg-final { scan-assembler ".weak\(_definition\)?\[ \t\]_?_ZGR1bIvE_" { target { ! pe } } } } +// { dg-final { scan-assembler ".weak\(_definition\)?\[ \t\]_?_ZGR1bIvE0_" { target { ! pe } } } } +// { dg-final { scan-assembler ".weak\(_definition\)?\[ \t\]_?_ZGR1bIvE1_" { target { ! pe } } } } +// { dg-final { scan-assembler ".weak\(_definition\)?\[ \t\]_?_ZGR1bIvE2_" { target { ! pe } } } } +// { dg-final { scan-assembler "\.section\t\.data\\\$_ZGR1bIvE_,\"w\"\n\t\.linkonce same_size" { target pe } } } +// { dg-final { scan-assembler "\.section\t\.rdata\\\$_ZGR1bIvE0_,\"dr\"\n\t\.linkonce same_size" { target pe } } } +// { dg-final { scan-assembler "\.section\t\.rdata\\\$_ZGR1bIvE1_,\"dr\"\n\t\.linkonce same_size" { target pe } } } +// { dg-final { scan-assembler "\.section\t\.rdata\\\$_ZGR1bIvE2_,\"dr\"\n\t\.linkonce same_size" { target pe } } } +// // { dg-final { scan-assembler "_ZGR1bIvE_:\n\[^\n]+_ZGR1bIvE0_" } } // { dg-final { scan-assembler "_ZGR1bIvE0_:\n\[^\n]+_ZGR1bIvE1_" } } // { dg-final { scan-assembler "_ZGR1bIvE1_:\n\[^\n]+\[ \t\]1" } } diff --git a/gcc/testsuite/g++.dg/concepts/diagnostic20.C b/gcc/testsuite/g++.dg/concepts/diagnostic20.C new file mode 100644 index 0000000..2bb01db --- /dev/null +++ b/gcc/testsuite/g++.dg/concepts/diagnostic20.C @@ -0,0 +1,13 @@ +// PR c++/99214 +// { dg-do compile { target c++20 } } + +template <class T> +struct A { + template <class U> static void f() requires requires { T::fail; }; +}; + +int main() { + A<int>::f<char>(); // { dg-error "no match" } +} + +// { dg-message "In substitution of '\[^\r\n\]* \\\[with U = char\\\]'" "" { target *-*-* } 0 } diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-ice21.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-ice21.C index 4627365..dcc4044 100644 --- a/gcc/testsuite/g++.dg/cpp0x/constexpr-ice21.C +++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-ice21.C @@ -3,7 +3,7 @@ struct NoMut1 { int a, b; }; struct NoMut3 : virtual NoMut1 { - constexpr NoMut3(int a, int b) // { dg-error "virtual base" "" { target c++23 } } + constexpr NoMut3(int a, int b) : NoMut1{a, b} {} // { dg-error "virtual base" } }; diff --git a/gcc/testsuite/g++.dg/cpp1y/constexpr-diag2.C b/gcc/testsuite/g++.dg/cpp1y/constexpr-diag2.C new file mode 100644 index 0000000..93f3f10 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1y/constexpr-diag2.C @@ -0,0 +1,12 @@ +// PR c++/113360 +// { dg-do compile { target c++14 } } + +constexpr bool init_list() // { dg-bogus "because" } +{ + int total{}; + for (int x : {1, 2, 3}) // { dg-error "initializer list" } + total += x; + return total == 6; +} + +static_assert(init_list(), ""); // { dg-error "constant" } diff --git a/gcc/testsuite/g++.dg/cpp1y/constexpr-new.C b/gcc/testsuite/g++.dg/cpp1y/constexpr-new.C index d0ca0b7..f4c6d2e 100644 --- a/gcc/testsuite/g++.dg/cpp1y/constexpr-new.C +++ b/gcc/testsuite/g++.dg/cpp1y/constexpr-new.C @@ -6,7 +6,9 @@ constexpr int *f4(bool b) { return nullptr; } else { return new int{42}; // { dg-error "call to non-.constexpr." "" { target c++17_down } } - } // { dg-error "is not a constant expression because allocated storage has not been deallocated" "" { target c++2a } .-1 } + // { dg-message "allocated here" "" { target c++20 } .-1 } + } } static_assert(f4(true) == nullptr, ""); -static_assert(f4(false) == nullptr, ""); // { dg-error "non-.constant. condition|" } +static_assert(f4(false) == nullptr, ""); // { dg-error "non-constant condition" } +// { dg-error "is not a constant expression because allocated storage has not been deallocated" "" { target c++20 } .-1 } diff --git a/gcc/testsuite/g++.dg/cpp1y/pr63996.C b/gcc/testsuite/g++.dg/cpp1y/pr63996.C index 8eee2e0..347c86c 100644 --- a/gcc/testsuite/g++.dg/cpp1y/pr63996.C +++ b/gcc/testsuite/g++.dg/cpp1y/pr63996.C @@ -1,5 +1,4 @@ // { dg-do compile { target c++14 } } -// { dg-additional-options "-Wno-return-type" } constexpr int foo (int i) @@ -8,4 +7,4 @@ foo (int i) if (i == 23) return 0; } -constexpr int j = foo (1); // { dg-error "flows off the end|in .constexpr. expansion of" } +constexpr int j = foo (1); diff --git a/gcc/testsuite/g++.dg/cpp1z/constexpr-asm-5.C b/gcc/testsuite/g++.dg/cpp1z/constexpr-asm-5.C index bcecea9..35beb27 100644 --- a/gcc/testsuite/g++.dg/cpp1z/constexpr-asm-5.C +++ b/gcc/testsuite/g++.dg/cpp1z/constexpr-asm-5.C @@ -28,7 +28,7 @@ struct M { constexpr K size () const { return {}; } constexpr L data () const { return {}; } }; #if __cpp_constexpr_dynamic_alloc >= 201907L struct N { constexpr int size () const { return 3; } - constexpr const char *data () const { return new char[3] { 'b', 'a', 'd' }; } }; // { dg-error "'\\\* N\\\(\\\).N::data\\\(\\\)' is not a constant expression because allocated storage has not been deallocated" "" { target c++20 } } + constexpr const char *data () const { return new char[3] { 'b', 'a', 'd' }; } }; #endif constexpr const char a[] = { 't', 'e', 's', 't' }; struct O { constexpr int size () const { return 4; } @@ -117,6 +117,7 @@ foo () asm ((M {})); #if __cpp_constexpr_dynamic_alloc >= 201907L asm ((N {})); // { dg-error "constexpr string 'data\\\(\\\)\\\[0\\\]' must be a constant expression" "" { target c++20 } } + // { dg-error "'\\\* N\\\(\\\).N::data\\\(\\\)' is not a constant expression because allocated storage has not been deallocated" "" { target c++20 } .-1 } #endif asm ((O {})); asm ((P (0))); @@ -190,6 +191,7 @@ bar () asm ((M {})); #if __cpp_constexpr_dynamic_alloc >= 201907L asm ((N {})); // { dg-error "constexpr string 'data\\\(\\\)\\\[0\\\]' must be a constant expression" "" { target c++20 } } + // { dg-error "'\\\* N\\\(\\\).N::data\\\(\\\)' is not a constant expression because allocated storage has not been deallocated" "" { target c++20 } .-1 } #endif asm ((O {})); asm ((P (0))); diff --git a/gcc/testsuite/g++.dg/cpp23/constexpr-nonlit18.C b/gcc/testsuite/g++.dg/cpp23/constexpr-nonlit18.C index 8e230ef..f891814 100644 --- a/gcc/testsuite/g++.dg/cpp23/constexpr-nonlit18.C +++ b/gcc/testsuite/g++.dg/cpp23/constexpr-nonlit18.C @@ -24,7 +24,7 @@ f3 () } constexpr int -f4 () // { dg-message "declared here" "" { target c++20_down } } +f4 () { // { dg-message "is not usable as a 'constexpr' function because:" "" { target c++23 } .-1 } static const int a = f1 (1); // { dg-error "'a' defined 'static' in 'constexpr' function only available with" "" { target c++20_down } } return 0; // { dg-error "'a' defined 'static' in 'constexpr' context" "" { target c++23 } .-1 } diff --git a/gcc/testsuite/g++.dg/cpp26/pack-indexing2.C b/gcc/testsuite/g++.dg/cpp26/pack-indexing2.C index fdc8320..4a7e494 100644 --- a/gcc/testsuite/g++.dg/cpp26/pack-indexing2.C +++ b/gcc/testsuite/g++.dg/cpp26/pack-indexing2.C @@ -49,7 +49,7 @@ template<int N> int getT2 (auto... Ts) { - return Ts...[N]; // { dg-error "pack index is negative" } + return Ts...[N]; // { dg-error "pack index '-1' is negative" } } template<auto N, typename... Ts> @@ -63,7 +63,7 @@ template<auto N, typename... Ts> void badtype2 () { - Ts...[N] t; // { dg-error "pack index is out of range" } + Ts...[N] t; // { dg-error "pack index '1' is out of range for pack of length '1'" } } template<auto N, typename... Ts> @@ -77,7 +77,7 @@ template<auto N, typename... Ts> void badtype4 () { - Ts...[N] t; // { dg-error "pack index is negative" } + Ts...[N] t; // { dg-error "pack index '-1' is negative" } } int nonconst () { return 42; } diff --git a/gcc/testsuite/g++.dg/cpp26/static_assert1.C b/gcc/testsuite/g++.dg/cpp26/static_assert1.C index f9ac831..1d0e6f2 100644 --- a/gcc/testsuite/g++.dg/cpp26/static_assert1.C +++ b/gcc/testsuite/g++.dg/cpp26/static_assert1.C @@ -69,10 +69,11 @@ static_assert (false, M {}); // { dg-warning "'static_assert' with non-string me // { dg-error "static assertion failed: test" "" { target *-*-* } .-1 } #if __cpp_constexpr_dynamic_alloc >= 201907L struct N { constexpr int size () const { return 3; } - constexpr const char *data () const { return new char[3] { 'b', 'a', 'd' }; } }; // { dg-error "'\\\* N\\\(\\\).N::data\\\(\\\)' is not a constant expression because allocated storage has not been deallocated" "" { target c++20 } } + constexpr const char *data () const { return new char[3] { 'b', 'a', 'd' }; } }; static_assert (true, N {}); // { dg-warning "'static_assert' with non-string message only available with" "" { target { c++20 && c++23_down } } } static_assert (false, N {}); // { dg-warning "'static_assert' with non-string message only available with" "" { target { c++20 && c++23_down } } } // { dg-error "constexpr string 'data\\\(\\\)\\\[0\\\]' must be a constant expression" "" { target c++20 } .-1 } + // { dg-error "'\\\* N\\\(\\\).N::data\\\(\\\)' is not a constant expression because allocated storage has not been deallocated" "" { target c++20 } .-2 } #endif constexpr const char a[] = { 't', 'e', 's', 't' }; struct O { constexpr int size () const { return 4; } diff --git a/gcc/testsuite/g++.dg/cpp2a/constexpr-dtor16.C b/gcc/testsuite/g++.dg/cpp2a/constexpr-dtor16.C index b84aaf9..99d1307 100644 --- a/gcc/testsuite/g++.dg/cpp2a/constexpr-dtor16.C +++ b/gcc/testsuite/g++.dg/cpp2a/constexpr-dtor16.C @@ -3,5 +3,5 @@ struct A { virtual ~A (); }; struct B : virtual A { constexpr ~B () {} }; -// { dg-error "'struct B' has virtual base classes" "" { target c++20 } .-1 } +// { dg-error "'constexpr' destructor in 'struct B' that has virtual base classes" "" { target c++20 } .-1 } // { dg-error "'constexpr' destructors only available with" "" { target c++17_down } .-2 } diff --git a/gcc/testsuite/g++.dg/cpp2a/constexpr-dtor7.C b/gcc/testsuite/g++.dg/cpp2a/constexpr-dtor7.C index 463eaca..f4546c1 100644 --- a/gcc/testsuite/g++.dg/cpp2a/constexpr-dtor7.C +++ b/gcc/testsuite/g++.dg/cpp2a/constexpr-dtor7.C @@ -3,7 +3,7 @@ struct S { int *s; - constexpr S () : s(new int) {} // { dg-error "is not a constant expression because allocated storage has not been deallocated" } + constexpr S () : s(new int) {} S (const S &) = delete; S &operator= (const S &) = delete; constexpr ~S () { delete s; } @@ -17,3 +17,4 @@ foo (S v) } static_assert (foo (S ())); // { dg-error "non-constant condition for static assertion" } +// { dg-error "is not a constant expression because allocated storage has not been deallocated" "" { target *-*-* } .-1 } diff --git a/gcc/testsuite/g++.dg/cpp2a/constexpr-dynamic10.C b/gcc/testsuite/g++.dg/cpp2a/constexpr-dynamic10.C index f9f8223..e543ce4 100644 --- a/gcc/testsuite/g++.dg/cpp2a/constexpr-dynamic10.C +++ b/gcc/testsuite/g++.dg/cpp2a/constexpr-dynamic10.C @@ -5,7 +5,7 @@ struct C { virtual void a(); }; struct B { virtual void b(); }; -struct A : virtual B, C { virtual void c(); }; // { dg-error ".struct A. has virtual base classes" } +struct A : virtual B, C { virtual void c(); }; // { dg-error "virtual base classes" } constexpr A a; // { dg-error "call" } diff --git a/gcc/testsuite/g++.dg/cpp2a/constexpr-new24.C b/gcc/testsuite/g++.dg/cpp2a/constexpr-new24.C index ee62f18..17c9f54 100644 --- a/gcc/testsuite/g++.dg/cpp2a/constexpr-new24.C +++ b/gcc/testsuite/g++.dg/cpp2a/constexpr-new24.C @@ -6,14 +6,14 @@ int a; constexpr char * f1 () { - constexpr auto p = new char[(long int) &a]; // { dg-error "size not constant" } + constexpr auto p = new char[(long int) &a]; // { dg-error "conversion from pointer" } return p; } constexpr char * f2 () { - auto p = new char[(long int) &a]; // { dg-error "size not constant" } + auto p = new char[(long int) &a]; // { dg-error "conversion from pointer" } return p; } diff --git a/gcc/testsuite/g++.dg/cpp2a/constexpr-new26.C b/gcc/testsuite/g++.dg/cpp2a/constexpr-new26.C index c82bd43..d8e53b2 100644 --- a/gcc/testsuite/g++.dg/cpp2a/constexpr-new26.C +++ b/gcc/testsuite/g++.dg/cpp2a/constexpr-new26.C @@ -4,7 +4,7 @@ constexpr int * f7 () { - int *p = new int (2); // { dg-error "is not a constant expression because it refers to a result of" } + int *p = new int (2); // { dg-message "allocated here" } delete p; return p; } @@ -12,6 +12,5 @@ f7 () void g () { - constexpr auto v7 = f7 (); + constexpr auto v7 = f7 (); // { dg-error "is not a constant expression because it refers to a result of" } } - diff --git a/gcc/testsuite/g++.dg/cpp2a/constexpr-new3.C b/gcc/testsuite/g++.dg/cpp2a/constexpr-new3.C index 5d9f1925..30e453e 100644 --- a/gcc/testsuite/g++.dg/cpp2a/constexpr-new3.C +++ b/gcc/testsuite/g++.dg/cpp2a/constexpr-new3.C @@ -5,19 +5,19 @@ constexpr int * f1 () { - return new int (2); // { dg-error "is not a constant expression because it refers to a result of" } + return new int (2); // { dg-message "allocated here" } } -constexpr auto v1 = f1 (); +constexpr auto v1 = f1 (); // { dg-error "is not a constant expression because it refers to a result of" } constexpr bool f2 () { - int *p = new int (3); // { dg-error "is not a constant expression because allocated storage has not been deallocated" } + int *p = new int (3); // { dg-message "allocated here" } return false; } -constexpr auto v2 = f2 (); +constexpr auto v2 = f2 (); // { dg-error "is not a constant expression because allocated storage has not been deallocated" } constexpr bool f3 () @@ -64,12 +64,12 @@ constexpr auto v6 = f6 (); // { dg-message "in 'constexpr' expansion of" } constexpr int * f7 () { - int *p = new int (2); // { dg-error "is not a constant expression because it refers to a result of" } + int *p = new int (2); // { dg-message "allocated here" } delete p; return p; } -constexpr auto v7 = f7 (); +constexpr auto v7 = f7 (); // { dg-error "is not a constant expression because it refers to a result of" } constexpr bool f8_impl (int *p) diff --git a/gcc/testsuite/g++.dg/cpp2a/constexpr-vector1.C b/gcc/testsuite/g++.dg/cpp2a/constexpr-vector1.C new file mode 100644 index 0000000..196c6ec --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/constexpr-vector1.C @@ -0,0 +1,8 @@ +// PR c++/113835 +// { dg-timeout-factor 0.05 } +// { dg-do compile { target c++20_only } } + +#include <vector> +const std::size_t N = 1'000'000; +std::vector<int> x(N); +int main() {} diff --git a/gcc/testsuite/g++.dg/cpp2a/constinit14.C b/gcc/testsuite/g++.dg/cpp2a/constinit14.C index 06c4cb4..26d82fe67 100644 --- a/gcc/testsuite/g++.dg/cpp2a/constinit14.C +++ b/gcc/testsuite/g++.dg/cpp2a/constinit14.C @@ -2,12 +2,13 @@ // { dg-do compile { target c++20 } } struct Value { - Value() : v{new int{42}} {} // { dg-error "result of 'operator new'" "" { target implicit_constexpr } } + Value() : v{new int{42}} {} int* v; }; struct S { static constinit inline Value v{}; // { dg-error "variable .S::v. does not have a constant initializer|call to non-.constexpr. function" } + // { dg-error "result of 'operator new'" "" { target implicit_constexpr } .-1 } }; int main() { return *S::v.v; } diff --git a/gcc/testsuite/g++.dg/eh/pr119507.C b/gcc/testsuite/g++.dg/eh/pr119507.C new file mode 100644 index 0000000..c68536f --- /dev/null +++ b/gcc/testsuite/g++.dg/eh/pr119507.C @@ -0,0 +1,19 @@ +// { dg-do compile { target comdat_group } } +// ARM EABI has its own exception handling data handling and does not use gcc_except_table +// { dg-skip-if "!TARGET_EXCEPTION_DATA" { arm_eabi } } +// Force off function sections +// Force on exceptions +// { dg-options "-fno-function-sections -fexceptions" } +// PR middle-end/119507 + + +inline int comdat() { try { throw 1; } catch (int) { return 1; } return 0; } +int another_func_with_exception() { try { throw 1; } catch (int) { return 1; } return 0; } +inline int comdat1() { try { throw 1; } catch (int) { return 1; } return 0; } +int foo() { return comdat() + comdat1(); } + +// Make sure the gcc puts the exception table for both comdat and comdat1 in their own section +// { dg-final { scan-assembler-times ".section\[\t \]\[^\n\]*.gcc_except_table._Z6comdatv" 1 } } +// { dg-final { scan-assembler-times ".section\[\t \]\[^\n\]*.gcc_except_table._Z7comdat1v" 1 } } +// There should be 3 exception tables, +// { dg-final { scan-assembler-times ".section\[\t \]\[^\n\]*.gcc_except_table" 3 } } diff --git a/gcc/testsuite/g++.dg/ext/pragma-target2.C b/gcc/testsuite/g++.dg/ext/pragma-target2.C new file mode 100644 index 0000000..53eb7dd --- /dev/null +++ b/gcc/testsuite/g++.dg/ext/pragma-target2.C @@ -0,0 +1,18 @@ +// PR c++/114772 +// { dg-do compile { target x86_64-*-* } } + +template<typename V, bool STREAMING> +inline __attribute__((always_inline)) +__attribute__((warn_unused_result)) +int walk_document(V visitor) {return 0;} + +template<bool STREAMING> +void parse_document() { + int r = walk_document<bool, STREAMING>(false); +} + +void stage2_next() { + parse_document<true>(); +} + +#pragma GCC target("pclmul") diff --git a/gcc/testsuite/g++.dg/ext/type_pack_element2.C b/gcc/testsuite/g++.dg/ext/type_pack_element2.C index 1bf7753..1b07673 100644 --- a/gcc/testsuite/g++.dg/ext/type_pack_element2.C +++ b/gcc/testsuite/g++.dg/ext/type_pack_element2.C @@ -2,7 +2,7 @@ int p; -using type = __type_pack_element<&p, int>; // { dg-error "not an integral constant" } +using type = __type_pack_element<&p, int>; // { dg-error "non-integral type" } using type = __type_pack_element<1, int>; // { dg-error "out of range" } using type = __type_pack_element<2, int, char>; // { dg-error "out of range" } using type = __type_pack_element<-1, int>; // { dg-error "negative" } diff --git a/gcc/testsuite/g++.dg/ext/type_pack_element4.C b/gcc/testsuite/g++.dg/ext/type_pack_element4.C index aa508c7..5a39194 100644 --- a/gcc/testsuite/g++.dg/ext/type_pack_element4.C +++ b/gcc/testsuite/g++.dg/ext/type_pack_element4.C @@ -3,7 +3,7 @@ template <typename... _Elements> class tuple{}; template <unsigned long __i, typename... _Elements> -__type_pack_element<__i, _Elements...> &get(tuple<_Elements...> &__t) noexcept; // { dg-error "index is out of range" } +__type_pack_element<__i, _Elements...> &get(tuple<_Elements...> &__t) noexcept; // { dg-error "out of range" } tuple<int,int> data; template <unsigned long Level> unsigned take_impl(unsigned idx) { diff --git a/gcc/testsuite/g++.dg/lto/pr119614_0.C b/gcc/testsuite/g++.dg/lto/pr119614_0.C new file mode 100644 index 0000000..09c07fb --- /dev/null +++ b/gcc/testsuite/g++.dg/lto/pr119614_0.C @@ -0,0 +1,34 @@ +// PR tree-optimization/119614 +// { dg-lto-do link } +// { dg-lto-options { { -O2 -fPIC -flto -flto-partition=max } } } +// { dg-require-effective-target shared } +// { dg-require-effective-target fpic } +// { dg-require-effective-target musttail } +// { dg-extra-ld-options "-shared" } + +struct S {} b; +char *foo (); +int e, g; +void bar (); +void corge (S); + +[[gnu::noinline]] static char * +baz () +{ + bar (); + return 0; +} + +const char * +qux () +{ + if (e) + { + S a = b; + corge (a); + if (g) + return 0; + [[gnu::musttail]] return baz (); + } + return foo (); +} diff --git a/gcc/testsuite/g++.dg/modules/lambda-10_a.H b/gcc/testsuite/g++.dg/modules/lambda-10_a.H new file mode 100644 index 0000000..1ad1a80 --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/lambda-10_a.H @@ -0,0 +1,17 @@ +// PR c++/119755 +// { dg-additional-options "-fmodule-header" } +// { dg-module-cmi {} } + +template <typename _Out> void format(_Out) { + constexpr int __term = 1; + [&] { __term; }; + [&] { const int outer = __term; { __term; } }; + [&]() noexcept { __term; }; + [&]() noexcept { const int outer = __term; { __term; } }; + [&](auto) { int n[__term]; }(0); + [&](auto) noexcept { int n[__term]; }(0); +} + +inline void vformat() { + format(0); +} diff --git a/gcc/testsuite/g++.dg/modules/lambda-10_b.C b/gcc/testsuite/g++.dg/modules/lambda-10_b.C new file mode 100644 index 0000000..3556bce --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/lambda-10_b.C @@ -0,0 +1,7 @@ +// PR c++/119755 +// { dg-additional-options "-fmodules" } + +import "lambda-10_a.H"; +int main() { + vformat(); +} diff --git a/gcc/testsuite/g++.dg/modules/lambda-8_b.C b/gcc/testsuite/g++.dg/modules/lambda-8_b.C index 7ace494..96578ba 100644 --- a/gcc/testsuite/g++.dg/modules/lambda-8_b.C +++ b/gcc/testsuite/g++.dg/modules/lambda-8_b.C @@ -4,4 +4,4 @@ #include "lambda-8.h" import "lambda-8_a.H"; -// { dg-error "conflicting global module declaration" "" { target *-*-* } 0 } +// { dg-error "conflicting imported declaration" "" { target *-*-* } 0 } diff --git a/gcc/testsuite/g++.dg/modules/leg-merge-4_c.C b/gcc/testsuite/g++.dg/modules/leg-merge-4_c.C index f1b1aeb..5756057 100644 --- a/gcc/testsuite/g++.dg/modules/leg-merge-4_c.C +++ b/gcc/testsuite/g++.dg/modules/leg-merge-4_c.C @@ -11,8 +11,8 @@ void foo () X *p; } -// { dg-regexp "\nIn module \[^\n]*leg-merge-4_b.H, imported at \[^\n]*leg-merge-4_c.C:\[0-9]*:\n\[^\n]*leg-merge-4_b.H:4:\[0-9]*: error: conflicting global module declaration 'float bob'\nIn module \[^\n]*leg-merge-4_a.H, imported at \[^\n]*leg-merge-4_c.C:\[0-9]*:\n\[^\n]*leg-merge-4_a.H:4:\[0-9]*: note: existing declaration 'int bob'\n\[^\n]*leg-merge-4_c.C:9:\[0-9]*: note: during load of binding '::bob'$" } +// { dg-regexp "\nIn module \[^\n]*leg-merge-4_b.H, imported at \[^\n]*leg-merge-4_c.C:\[0-9]*:\n\[^\n]*leg-merge-4_b.H:4:\[0-9]*: error: conflicting type for imported declaration 'float bob'\nIn module \[^\n]*leg-merge-4_a.H, imported at \[^\n]*leg-merge-4_c.C:\[0-9]*:\n\[^\n]*leg-merge-4_a.H:4:\[0-9]*: note: existing declaration 'int bob'\n\[^\n]*leg-merge-4_c.C:9:\[0-9]*: note: during load of binding '::bob'$" } -// { dg-regexp "\nIn module \[^\n]*leg-merge-4_b.H, imported at \[^\n]*leg-merge-4_c.C:\[0-9]*:\n\[^\n]*leg-merge-4_b.H:5:\[0-9]*: error: conflicting global module declaration 'int frob\\(\\)'\nIn module \[^\n]*leg-merge-4_a.H, imported at \[^\n]*leg-merge-4_c.C:\[0-9]*:\n\[^\n]*leg-merge-4_a.H:5:\[0-9]*: note: existing declaration 'void frob\\(\\)'\n\[^\n]*leg-merge-4_c.C:10:\[0-9]*: note: during load of binding '::frob'$" } +// { dg-regexp "\nIn module \[^\n]*leg-merge-4_b.H, imported at \[^\n]*leg-merge-4_c.C:\[0-9]*:\n\[^\n]*leg-merge-4_b.H:5:\[0-9]*: error: conflicting type for imported declaration 'int frob\\(\\)'\nIn module \[^\n]*leg-merge-4_a.H, imported at \[^\n]*leg-merge-4_c.C:\[0-9]*:\n\[^\n]*leg-merge-4_a.H:5:\[0-9]*: note: existing declaration 'void frob\\(\\)'\n\[^\n]*leg-merge-4_c.C:10:\[0-9]*: note: during load of binding '::frob'$" } -// { dg-regexp "In module \[^\n]*leg-merge-4_b.H, imported at \[^\n]*leg-merge-4_c.C:\[0-9]*:\n\[^\n]*leg-merge-4_b.H:6:\[0-9]*: error: conflicting global module declaration 'union X'\nIn module \[^\n]*leg-merge-4_a.H, imported at \[^\n]*leg-merge-4_c.C:\[0-9]*:\n\[^\n]*leg-merge-4_a.H:6:\[0-9]*: note: existing declaration 'class X'\n\[^\n]*leg-merge-4_c.C:11:\[0-9]*: note: during load of binding '::X'$" } +// { dg-regexp "In module \[^\n]*leg-merge-4_b.H, imported at \[^\n]*leg-merge-4_c.C:\[0-9]*:\n\[^\n]*leg-merge-4_b.H:6:\[0-9]*: error: conflicting type for imported declaration 'union X'\nIn module \[^\n]*leg-merge-4_a.H, imported at \[^\n]*leg-merge-4_c.C:\[0-9]*:\n\[^\n]*leg-merge-4_a.H:6:\[0-9]*: note: existing declaration 'class X'\n\[^\n]*leg-merge-4_c.C:11:\[0-9]*: note: during load of binding '::X'$" } diff --git a/gcc/testsuite/g++.dg/modules/noexcept-4_a.H b/gcc/testsuite/g++.dg/modules/noexcept-4_a.H new file mode 100644 index 0000000..b888a1b --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/noexcept-4_a.H @@ -0,0 +1,6 @@ +// { dg-additional-options "-fmodule-header -std=c++20" } +// { dg-module-cmi {} } + +struct exception_ptr { + friend bool operator==(const exception_ptr&, const exception_ptr&) = default; +}; diff --git a/gcc/testsuite/g++.dg/modules/noexcept-4_b.C b/gcc/testsuite/g++.dg/modules/noexcept-4_b.C new file mode 100644 index 0000000..7cc5531 --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/noexcept-4_b.C @@ -0,0 +1,18 @@ +// { dg-additional-options "-fmodules -std=c++20" } + +struct exception_ptr { + friend bool operator==(const exception_ptr&, const exception_ptr&) = default; +}; + +void enqueue() { + exception_ptr e; + e == e; +} + +import "noexcept-4_a.H"; + +int main() { + constexpr exception_ptr e; + static_assert(e == e); + static_assert(noexcept(e == e)); +} diff --git a/gcc/testsuite/g++.dg/pr112822.C b/gcc/testsuite/g++.dg/pr112822.C index a855752..f88bd83 100644 --- a/gcc/testsuite/g++.dg/pr112822.C +++ b/gcc/testsuite/g++.dg/pr112822.C @@ -89,7 +89,7 @@ template <typename aj, typename cm> struct cg<aj, cm> { typedef aj cn; }; namespace ai { template <typename cj, int> cj cp; template <typename bu, typename cj, int> void cl(bu *cr, cj cs) { ct(cr, cs); } -typedef __attribute__((altivec(vector__))) double co; +typedef double co __attribute__ ((vector_size (16))); void ct(double *cr, co cs) { *(co *)cr = cs; } struct cq { co q; diff --git a/gcc/testsuite/g++.dg/template/explicit-args6.C b/gcc/testsuite/g++.dg/template/explicit-args6.C index 18663d7b..0d9718c 100644 --- a/gcc/testsuite/g++.dg/template/explicit-args6.C +++ b/gcc/testsuite/g++.dg/template/explicit-args6.C @@ -24,10 +24,12 @@ frob() // narrowing check, reject negative values return unsigned{N}; // { dg-prune-output "narrowing" } -} // { dg-prune-output "flows off the end" } -// { dg-prune-output "not a return-statement" } +} -template<int N> void get_n(tuple& t) { get<frob<N>()>(t); } // { dg-error "" } +// This complains about calling frob only in C++11 because +// maybe_save_constexpr_fundef fails; in later standards it succeeds, +// and the evaluation failure is silent due to the earlier errors. +template<int N> void get_n(tuple& t) { get<frob<N>()>(t); } // { dg-error "" "" { target c++11_only } } int main() { diff --git a/gcc/testsuite/g++.dg/template/friend86.C b/gcc/testsuite/g++.dg/template/friend86.C new file mode 100644 index 0000000..9e2c1af --- /dev/null +++ b/gcc/testsuite/g++.dg/template/friend86.C @@ -0,0 +1,25 @@ +// PR c++/119807 +// { dg-do run } + +template<int N> +struct A { + template<class T> friend int f(A<N>, T); +}; + +template struct A<0>; +template struct A<1>; + +int main() { + A<0> x; + A<1> y; + if (f(x, true) != 0) __builtin_abort(); + if (f(y, true) != 1) __builtin_abort(); +} + +template<int N> +struct B { + template<class T> friend int f(A<N>, T) { return N; } +}; + +template struct B<0>; +template struct B<1>; diff --git a/gcc/testsuite/g++.dg/template/friend87.C b/gcc/testsuite/g++.dg/template/friend87.C new file mode 100644 index 0000000..94c0dfc --- /dev/null +++ b/gcc/testsuite/g++.dg/template/friend87.C @@ -0,0 +1,42 @@ +// PR c++/119807 +// { dg-do compile { target c++20 } } + +using size_t = decltype(sizeof(0)); + +template<auto tag, size_t current> +struct CounterReader { + template<typename> + friend auto counterFlag(CounterReader<tag, current>) noexcept; +}; + +template<auto tag, size_t current> +struct CounterWriter { + static constexpr size_t value = current; + + template<typename> + friend auto counterFlag(CounterReader<tag, current>) noexcept {} +}; + +template<auto tag, auto unique, size_t current = 0, size_t mask = size_t(1) << (sizeof(size_t) * 8 - 1)> +[[nodiscard]] constexpr size_t counterAdvance() noexcept { + if constexpr (!mask) { + return CounterWriter<tag, current + 1>::value; + } else if constexpr (requires { counterFlag<void>(CounterReader<tag, current | mask>()); }) { + return counterAdvance<tag, unique, current | mask, (mask >> 1)>(); + } + else { + return counterAdvance<tag, unique, current, (mask >> 1)>(); + } +} + +constexpr auto defaultCounterTag = [] {}; + +template<auto tag = defaultCounterTag, auto unique = [] {}> +constexpr size_t counter() noexcept { + return counterAdvance<tag, unique>(); +} + +int main() { + static_assert(counter() == 1); + static_assert(counter() == 2); +} diff --git a/gcc/testsuite/g++.dg/torture/pr119778.C b/gcc/testsuite/g++.dg/torture/pr119778.C new file mode 100644 index 0000000..4948056 --- /dev/null +++ b/gcc/testsuite/g++.dg/torture/pr119778.C @@ -0,0 +1,20 @@ +// { dg-do compile } +// { dg-additional-options "-Wall" } + +struct jmp_buf { long l[16]; }; +extern "C" int setjmp (jmp_buf *); +struct S { + void foo () { bar (); } + virtual char bar () { return 0; } +}; +void baz (); +jmp_buf *a; + +void +qux (bool x, S *y) +{ + if (x) + setjmp (a); + y->foo (); + baz (); +} diff --git a/gcc/testsuite/g++.dg/warn/Wformat-3.C b/gcc/testsuite/g++.dg/warn/Wformat-3.C new file mode 100644 index 0000000..e308530 --- /dev/null +++ b/gcc/testsuite/g++.dg/warn/Wformat-3.C @@ -0,0 +1,19 @@ +// PR c++/116954 +// { dg-additional-options -Wformat } + +#ifndef WORKS +template<int N> +int fn(char (&buf)[N], const char fmt[], ...) + __attribute__ ((__format__ (__printf__, 2, 3))); +#endif + +template<int N> +__attribute__ ((__format__ (__printf__, 2, 3))) +int fn(char (&)[N], const char [], ...) +{ return 0; } + +int main() +{ + char buf[20]; + return fn(buf, "%s", 42); /* { dg-warning "Wformat" } */ +} diff --git a/gcc/testsuite/g++.target/gcn/exceptions-bad_cast-1.C b/gcc/testsuite/g++.target/gcn/exceptions-bad_cast-1.C new file mode 100644 index 0000000..f3e3099 --- /dev/null +++ b/gcc/testsuite/g++.target/gcn/exceptions-bad_cast-1.C @@ -0,0 +1,15 @@ +/* 'std::bad_cast' exception. */ + +/* { dg-do run } */ +/* Via the magic string "-std=*++" indicate that testing one (the default) C++ standard is sufficient. */ +/* { dg-additional-options -fexceptions } */ +/* { dg-additional-options -fdump-tree-optimized-raw } */ + +#include "../../../../libgomp/testsuite/libgomp.oacc-c++/exceptions-bad_cast-1.C" + +/* { dg-output {CheCKpOInT[\r\n]+} } + + { dg-final { scan-tree-dump-times {gimple_call <__cxa_bad_cast, } 1 optimized } } + We don't print anything, but just 'abort'. + + { dg-shouldfail {'std::bad_cast' exception} } */ diff --git a/gcc/testsuite/g++.target/gcn/exceptions-bad_cast-2.C b/gcc/testsuite/g++.target/gcn/exceptions-bad_cast-2.C new file mode 100644 index 0000000..b047cbed --- /dev/null +++ b/gcc/testsuite/g++.target/gcn/exceptions-bad_cast-2.C @@ -0,0 +1,13 @@ +/* 'std::bad_cast' exception, caught. */ + +/* Via the magic string "-std=*++" indicate that testing one (the default) C++ standard is sufficient. */ +/* { dg-additional-options -fexceptions } */ +/* { dg-additional-options -mno-fake-exceptions } */ +/* { dg-additional-options -fdump-tree-optimized-raw } */ + +#include "../../../../libgomp/testsuite/libgomp.oacc-c++/exceptions-bad_cast-2.C" + +/* { dg-final { scan-tree-dump-times {gimple_call <__cxa_bad_cast, } 1 optimized } } + Compilation fails: + { dg-regexp {[^\r\n]+: In function 'int main\(\)':[\r\n]+(?:[^\r\n]+: sorry, unimplemented: exception handling not supported[\r\n]+)+} } + (Note, using 'dg-regexp' instead of 'dg-message', as the former runs before the auto-mark-UNSUPPORTED.) */ diff --git a/gcc/testsuite/g++.target/gcn/exceptions-bad_cast-2_-mfake-exceptions.C b/gcc/testsuite/g++.target/gcn/exceptions-bad_cast-2_-mfake-exceptions.C new file mode 100644 index 0000000..2904188 --- /dev/null +++ b/gcc/testsuite/g++.target/gcn/exceptions-bad_cast-2_-mfake-exceptions.C @@ -0,0 +1,18 @@ +/* 'std::bad_cast' exception, caught, '-mfake-exceptions'. */ + +/* { dg-do run } */ +/* Via the magic string "-std=*++" indicate that testing one (the default) C++ standard is sufficient. */ +/* { dg-additional-options -fexceptions } */ +/* { dg-additional-options -mfake-exceptions } + { dg-bogus {sorry, unimplemented: exception handling not supported} {} { target *-*-* } 0 } */ +/* { dg-additional-options -fdump-tree-optimized-raw } */ + +#include "exceptions-bad_cast-2.C" + +/* { dg-output {CheCKpOInT[\r\n]+} } + + { dg-final { scan-tree-dump-times {gimple_call <__cxa_bad_cast, } 1 optimized } } + We don't print anything, but just 'abort'. + + There is no 'catch'ing; any exception is fatal. + { dg-shouldfail {'std::bad_cast' exception} } */ diff --git a/gcc/testsuite/g++.target/gcn/exceptions-bad_cast-3.C b/gcc/testsuite/g++.target/gcn/exceptions-bad_cast-3.C new file mode 100644 index 0000000..3d0118c --- /dev/null +++ b/gcc/testsuite/g++.target/gcn/exceptions-bad_cast-3.C @@ -0,0 +1,10 @@ +/* 'std::bad_cast' exception, dead code. */ + +/* { dg-do run } */ +/* Via the magic string "-std=*++" indicate that testing one (the default) C++ standard is sufficient. */ +/* { dg-additional-options -fexceptions } */ +/* { dg-additional-options -fdump-tree-optimized-raw } */ + +#include "../../../../libgomp/testsuite/libgomp.oacc-c++/exceptions-bad_cast-3.C" + +/* { dg-final { scan-tree-dump-times {gimple_call <__cxa_bad_cast, } 1 optimized } } */ diff --git a/gcc/testsuite/g++.target/gcn/exceptions-pr118794-1.C b/gcc/testsuite/g++.target/gcn/exceptions-pr118794-1.C new file mode 100644 index 0000000..20f9d49 --- /dev/null +++ b/gcc/testsuite/g++.target/gcn/exceptions-pr118794-1.C @@ -0,0 +1,17 @@ +/* Exception handling constructs in dead code. */ + +/* Via the magic string "-std=*++" indicate that testing one (the default) C++ standard is sufficient. */ +/* { dg-additional-options -fexceptions } */ +/* { dg-additional-options -mno-fake-exceptions } */ +/* { dg-additional-options -O0 } */ +/* { dg-additional-options -fdump-tree-optimized-raw } */ + +#include "../../../../libgomp/testsuite/libgomp.c++/target-exceptions-pr118794-1.C" + +/* In this specific C++ arrangement, distilled from PR118794, GCC synthesizes + '__builtin_eh_pointer', '__builtin_unwind_resume' calls as dead code in 'f': + { dg-final { scan-tree-dump-times {gimple_call <__builtin_eh_pointer, } 1 optimized } } + { dg-final { scan-tree-dump-times {gimple_call <__builtin_unwind_resume, } 1 optimized } } + Given '-O0', compilation fails: + { dg-regexp {[^\r\n]+: In function 'void f\(\)':[\r\n]+(?:[^\r\n]+: sorry, unimplemented: exception handling not supported[\r\n]+)+} } + (Note, using 'dg-regexp' instead of 'dg-message', as the former runs before the auto-mark-UNSUPPORTED.) */ diff --git a/gcc/testsuite/g++.target/gcn/exceptions-pr118794-1_-mfake-exceptions.C b/gcc/testsuite/g++.target/gcn/exceptions-pr118794-1_-mfake-exceptions.C new file mode 100644 index 0000000..a5f0da2 --- /dev/null +++ b/gcc/testsuite/g++.target/gcn/exceptions-pr118794-1_-mfake-exceptions.C @@ -0,0 +1,16 @@ +/* Exception handling constructs in dead code, '-mfake-exceptions'. */ + +/* { dg-do run } */ +/* Via the magic string "-std=*++" indicate that testing one (the default) C++ standard is sufficient. */ +/* { dg-additional-options -fexceptions } */ +/* { dg-additional-options -mfake-exceptions } + { dg-bogus {sorry, unimplemented: exception handling not supported} {} { target *-*-* } 0 } */ +/* { dg-additional-options -O0 } */ +/* { dg-additional-options -fdump-tree-optimized-raw } */ + +#include "exceptions-pr118794-1.C" + +/* In this specific C++ arrangement, distilled from PR118794, GCC synthesizes + '__builtin_eh_pointer', '__builtin_unwind_resume' calls as dead code in 'f': + { dg-final { scan-tree-dump-times {gimple_call <__builtin_eh_pointer, } 1 optimized } } + { dg-final { scan-tree-dump-times {gimple_call <__builtin_unwind_resume, } 1 optimized } } */ diff --git a/gcc/testsuite/g++.target/gcn/exceptions-throw-1.C b/gcc/testsuite/g++.target/gcn/exceptions-throw-1.C new file mode 100644 index 0000000..6cadf58 --- /dev/null +++ b/gcc/testsuite/g++.target/gcn/exceptions-throw-1.C @@ -0,0 +1,16 @@ +/* 'throw'. */ + +/* { dg-do run } */ +/* Via the magic string "-std=*++" indicate that testing one (the default) C++ standard is sufficient. */ +/* { dg-additional-options -fexceptions } */ +/* { dg-additional-options -fdump-tree-optimized-raw } */ + +#include "../../../../libgomp/testsuite/libgomp.oacc-c++/exceptions-throw-1.C" + +/* { dg-output {CheCKpOInT[\r\n]+} } + + { dg-final { scan-tree-dump-times {gimple_call <__cxa_allocate_exception, } 1 optimized } } + { dg-final { scan-tree-dump-times {gimple_call <__cxa_throw, } 1 optimized } } + We don't print anything, but just 'abort'. + + { dg-shouldfail {'MyException' exception} } */ diff --git a/gcc/testsuite/g++.target/gcn/exceptions-throw-2.C b/gcc/testsuite/g++.target/gcn/exceptions-throw-2.C new file mode 100644 index 0000000..671c810 --- /dev/null +++ b/gcc/testsuite/g++.target/gcn/exceptions-throw-2.C @@ -0,0 +1,14 @@ +/* 'throw', caught. */ + +/* Via the magic string "-std=*++" indicate that testing one (the default) C++ standard is sufficient. */ +/* { dg-additional-options -fexceptions } */ +/* { dg-additional-options -mno-fake-exceptions } */ +/* { dg-additional-options -fdump-tree-optimized-raw } */ + +#include "../../../../libgomp/testsuite/libgomp.oacc-c++/exceptions-throw-2.C" + +/* { dg-final { scan-tree-dump-times {gimple_call <__cxa_allocate_exception, } 1 optimized } } + { dg-final { scan-tree-dump-times {gimple_call <__cxa_throw, } 1 optimized } } + Compilation fails: + { dg-regexp {[^\r\n]+: In function 'int main\(\)':[\r\n]+(?:[^\r\n]+: sorry, unimplemented: exception handling not supported[\r\n]+)+} } + (Note, using 'dg-regexp' instead of 'dg-message', as the former runs before the auto-mark-UNSUPPORTED.) */ diff --git a/gcc/testsuite/g++.target/gcn/exceptions-throw-2_-mfake-exceptions.C b/gcc/testsuite/g++.target/gcn/exceptions-throw-2_-mfake-exceptions.C new file mode 100644 index 0000000..f1fd505 --- /dev/null +++ b/gcc/testsuite/g++.target/gcn/exceptions-throw-2_-mfake-exceptions.C @@ -0,0 +1,19 @@ +/* 'throw', caught, '-mfake-exceptions'. */ + +/* { dg-do run } */ +/* Via the magic string "-std=*++" indicate that testing one (the default) C++ standard is sufficient. */ +/* { dg-additional-options -fexceptions } */ +/* { dg-additional-options -mfake-exceptions } + { dg-bogus {sorry, unimplemented: exception handling not supported} {} { target *-*-* } 0 } */ +/* { dg-additional-options -fdump-tree-optimized-raw } */ + +#include "exceptions-throw-2.C" + +/* { dg-output {CheCKpOInT[\r\n]+} } + + { dg-final { scan-tree-dump-times {gimple_call <__cxa_allocate_exception, } 1 optimized } } + { dg-final { scan-tree-dump-times {gimple_call <__cxa_throw, } 1 optimized } } + We don't print anything, but just 'abort'. + + There is no 'catch'ing; any exception is fatal. + { dg-shouldfail {'MyException' exception} } */ diff --git a/gcc/testsuite/g++.target/gcn/exceptions-throw-3.C b/gcc/testsuite/g++.target/gcn/exceptions-throw-3.C new file mode 100644 index 0000000..5c1ad7a --- /dev/null +++ b/gcc/testsuite/g++.target/gcn/exceptions-throw-3.C @@ -0,0 +1,11 @@ +/* 'throw', dead code. */ + +/* { dg-do run } */ +/* Via the magic string "-std=*++" indicate that testing one (the default) C++ standard is sufficient. */ +/* { dg-additional-options -fexceptions } */ +/* { dg-additional-options -fdump-tree-optimized-raw } */ + +#include "../../../../libgomp/testsuite/libgomp.oacc-c++/exceptions-throw-3.C" + +/* { dg-final { scan-tree-dump-times {gimple_call <__cxa_allocate_exception, } 1 optimized } } + { dg-final { scan-tree-dump-times {gimple_call <__cxa_throw, } 1 optimized } } */ diff --git a/gcc/testsuite/g++.target/gcn/gcn.exp b/gcc/testsuite/g++.target/gcn/gcn.exp new file mode 100644 index 0000000..a3bd75f --- /dev/null +++ b/gcc/testsuite/g++.target/gcn/gcn.exp @@ -0,0 +1,56 @@ +# Specific regression driver for GCN. +# Copyright (C) 2000-2025 Free Software Foundation, Inc. + +# This program 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 of the License, or +# (at your option) any later version. +# +# This program 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 +# <http://www.gnu.org/licenses/>. + +# G++ testsuite that uses the `dg.exp' driver. + +# Exit immediately if this isn't a GCN target. +if ![istarget amdgcn*-*-*] then { + return +} + +# Load support procs. +load_lib g++-dg.exp + +# If a testcase doesn't have special options, use these. +global DEFAULT_CXXFLAGS +if ![info exists DEFAULT_CXXFLAGS] then { + set DEFAULT_CXXFLAGS " -pedantic-errors -Wno-long-long" +} + +# Initialize `dg'. +dg-init + +# Recursively find files in $dir and subdirs, do not walk into subdirs +# that contain their own .exp file. +proc find-cxx-tests { dir suffix } { + set tests [lsort [glob -nocomplain -directory $dir "*.$suffix" ]] + foreach subdir [lsort [glob -nocomplain -type d -directory $dir *]] { + if { [glob -nocomplain -directory $subdir *.exp] eq "" } { + eval lappend tests [find-cxx-tests $subdir $suffix] + } + } + return $tests +} + +set tests [find-cxx-tests $srcdir/$subdir {C}] + +# Main loop. +g++-dg-runtest $tests "" $DEFAULT_CXXFLAGS + + +# All done. +dg-finish diff --git a/gcc/testsuite/g++.target/gcn/pr119692-1-1.C b/gcc/testsuite/g++.target/gcn/pr119692-1-1.C new file mode 100644 index 0000000..b44b08d --- /dev/null +++ b/gcc/testsuite/g++.target/gcn/pr119692-1-1.C @@ -0,0 +1,6 @@ +/* PR119692 "C++ 'typeinfo', 'vtable' vs. OpenACC, OpenMP 'target' offloading" */ + +/* { dg-do run } */ +/* Via the magic string "-std=*++" indicate that testing one (the default) C++ standard is sufficient. */ + +#include "../../../../libgomp/testsuite/libgomp.oacc-c++/pr119692-1-1.C" diff --git a/gcc/testsuite/g++.target/nvptx/exceptions-bad_cast-1.C b/gcc/testsuite/g++.target/nvptx/exceptions-bad_cast-1.C new file mode 100644 index 0000000..f3e3099 --- /dev/null +++ b/gcc/testsuite/g++.target/nvptx/exceptions-bad_cast-1.C @@ -0,0 +1,15 @@ +/* 'std::bad_cast' exception. */ + +/* { dg-do run } */ +/* Via the magic string "-std=*++" indicate that testing one (the default) C++ standard is sufficient. */ +/* { dg-additional-options -fexceptions } */ +/* { dg-additional-options -fdump-tree-optimized-raw } */ + +#include "../../../../libgomp/testsuite/libgomp.oacc-c++/exceptions-bad_cast-1.C" + +/* { dg-output {CheCKpOInT[\r\n]+} } + + { dg-final { scan-tree-dump-times {gimple_call <__cxa_bad_cast, } 1 optimized } } + We don't print anything, but just 'abort'. + + { dg-shouldfail {'std::bad_cast' exception} } */ diff --git a/gcc/testsuite/g++.target/nvptx/exceptions-bad_cast-2.C b/gcc/testsuite/g++.target/nvptx/exceptions-bad_cast-2.C new file mode 100644 index 0000000..b047cbed --- /dev/null +++ b/gcc/testsuite/g++.target/nvptx/exceptions-bad_cast-2.C @@ -0,0 +1,13 @@ +/* 'std::bad_cast' exception, caught. */ + +/* Via the magic string "-std=*++" indicate that testing one (the default) C++ standard is sufficient. */ +/* { dg-additional-options -fexceptions } */ +/* { dg-additional-options -mno-fake-exceptions } */ +/* { dg-additional-options -fdump-tree-optimized-raw } */ + +#include "../../../../libgomp/testsuite/libgomp.oacc-c++/exceptions-bad_cast-2.C" + +/* { dg-final { scan-tree-dump-times {gimple_call <__cxa_bad_cast, } 1 optimized } } + Compilation fails: + { dg-regexp {[^\r\n]+: In function 'int main\(\)':[\r\n]+(?:[^\r\n]+: sorry, unimplemented: exception handling not supported[\r\n]+)+} } + (Note, using 'dg-regexp' instead of 'dg-message', as the former runs before the auto-mark-UNSUPPORTED.) */ diff --git a/gcc/testsuite/g++.target/nvptx/exceptions-bad_cast-2_-mfake-exceptions.C b/gcc/testsuite/g++.target/nvptx/exceptions-bad_cast-2_-mfake-exceptions.C new file mode 100644 index 0000000..3f40951 --- /dev/null +++ b/gcc/testsuite/g++.target/nvptx/exceptions-bad_cast-2_-mfake-exceptions.C @@ -0,0 +1,19 @@ +/* 'std::bad_cast' exception, caught, '-mfake-exceptions'. */ + +/* { dg-do run } */ +/* Via the magic string "-std=*++" indicate that testing one (the default) C++ standard is sufficient. */ +/* { dg-additional-options -fexceptions } */ +/* { dg-additional-options -mfake-exceptions } + { dg-bogus {sorry, unimplemented: exception handling not supported} {} { target *-*-* } 0 } */ +/* { dg-additional-options -fdump-tree-optimized-raw } */ +/* { dg-bogus {_ZTISt8bad_cast} PR119734 { xfail *-*-* } 0 } */ + +#include "exceptions-bad_cast-2.C" + +/* { dg-output {CheCKpOInT[\r\n]+} } + + { dg-final { scan-tree-dump-times {gimple_call <__cxa_bad_cast, } 1 optimized } } + We don't print anything, but just 'abort'. + + There is no 'catch'ing; any exception is fatal. + { dg-shouldfail {'std::bad_cast' exception} } */ diff --git a/gcc/testsuite/g++.target/nvptx/exceptions-bad_cast-3.C b/gcc/testsuite/g++.target/nvptx/exceptions-bad_cast-3.C new file mode 100644 index 0000000..3d0118c --- /dev/null +++ b/gcc/testsuite/g++.target/nvptx/exceptions-bad_cast-3.C @@ -0,0 +1,10 @@ +/* 'std::bad_cast' exception, dead code. */ + +/* { dg-do run } */ +/* Via the magic string "-std=*++" indicate that testing one (the default) C++ standard is sufficient. */ +/* { dg-additional-options -fexceptions } */ +/* { dg-additional-options -fdump-tree-optimized-raw } */ + +#include "../../../../libgomp/testsuite/libgomp.oacc-c++/exceptions-bad_cast-3.C" + +/* { dg-final { scan-tree-dump-times {gimple_call <__cxa_bad_cast, } 1 optimized } } */ diff --git a/gcc/testsuite/g++.target/nvptx/exceptions-pr118794-1.C b/gcc/testsuite/g++.target/nvptx/exceptions-pr118794-1.C new file mode 100644 index 0000000..20f9d49 --- /dev/null +++ b/gcc/testsuite/g++.target/nvptx/exceptions-pr118794-1.C @@ -0,0 +1,17 @@ +/* Exception handling constructs in dead code. */ + +/* Via the magic string "-std=*++" indicate that testing one (the default) C++ standard is sufficient. */ +/* { dg-additional-options -fexceptions } */ +/* { dg-additional-options -mno-fake-exceptions } */ +/* { dg-additional-options -O0 } */ +/* { dg-additional-options -fdump-tree-optimized-raw } */ + +#include "../../../../libgomp/testsuite/libgomp.c++/target-exceptions-pr118794-1.C" + +/* In this specific C++ arrangement, distilled from PR118794, GCC synthesizes + '__builtin_eh_pointer', '__builtin_unwind_resume' calls as dead code in 'f': + { dg-final { scan-tree-dump-times {gimple_call <__builtin_eh_pointer, } 1 optimized } } + { dg-final { scan-tree-dump-times {gimple_call <__builtin_unwind_resume, } 1 optimized } } + Given '-O0', compilation fails: + { dg-regexp {[^\r\n]+: In function 'void f\(\)':[\r\n]+(?:[^\r\n]+: sorry, unimplemented: exception handling not supported[\r\n]+)+} } + (Note, using 'dg-regexp' instead of 'dg-message', as the former runs before the auto-mark-UNSUPPORTED.) */ diff --git a/gcc/testsuite/g++.target/nvptx/exceptions-pr118794-1_-mfake-exceptions.C b/gcc/testsuite/g++.target/nvptx/exceptions-pr118794-1_-mfake-exceptions.C new file mode 100644 index 0000000..a5f0da2 --- /dev/null +++ b/gcc/testsuite/g++.target/nvptx/exceptions-pr118794-1_-mfake-exceptions.C @@ -0,0 +1,16 @@ +/* Exception handling constructs in dead code, '-mfake-exceptions'. */ + +/* { dg-do run } */ +/* Via the magic string "-std=*++" indicate that testing one (the default) C++ standard is sufficient. */ +/* { dg-additional-options -fexceptions } */ +/* { dg-additional-options -mfake-exceptions } + { dg-bogus {sorry, unimplemented: exception handling not supported} {} { target *-*-* } 0 } */ +/* { dg-additional-options -O0 } */ +/* { dg-additional-options -fdump-tree-optimized-raw } */ + +#include "exceptions-pr118794-1.C" + +/* In this specific C++ arrangement, distilled from PR118794, GCC synthesizes + '__builtin_eh_pointer', '__builtin_unwind_resume' calls as dead code in 'f': + { dg-final { scan-tree-dump-times {gimple_call <__builtin_eh_pointer, } 1 optimized } } + { dg-final { scan-tree-dump-times {gimple_call <__builtin_unwind_resume, } 1 optimized } } */ diff --git a/gcc/testsuite/g++.target/nvptx/exceptions-throw-1.C b/gcc/testsuite/g++.target/nvptx/exceptions-throw-1.C new file mode 100644 index 0000000..6cadf58 --- /dev/null +++ b/gcc/testsuite/g++.target/nvptx/exceptions-throw-1.C @@ -0,0 +1,16 @@ +/* 'throw'. */ + +/* { dg-do run } */ +/* Via the magic string "-std=*++" indicate that testing one (the default) C++ standard is sufficient. */ +/* { dg-additional-options -fexceptions } */ +/* { dg-additional-options -fdump-tree-optimized-raw } */ + +#include "../../../../libgomp/testsuite/libgomp.oacc-c++/exceptions-throw-1.C" + +/* { dg-output {CheCKpOInT[\r\n]+} } + + { dg-final { scan-tree-dump-times {gimple_call <__cxa_allocate_exception, } 1 optimized } } + { dg-final { scan-tree-dump-times {gimple_call <__cxa_throw, } 1 optimized } } + We don't print anything, but just 'abort'. + + { dg-shouldfail {'MyException' exception} } */ diff --git a/gcc/testsuite/g++.target/nvptx/exceptions-throw-2.C b/gcc/testsuite/g++.target/nvptx/exceptions-throw-2.C new file mode 100644 index 0000000..671c810 --- /dev/null +++ b/gcc/testsuite/g++.target/nvptx/exceptions-throw-2.C @@ -0,0 +1,14 @@ +/* 'throw', caught. */ + +/* Via the magic string "-std=*++" indicate that testing one (the default) C++ standard is sufficient. */ +/* { dg-additional-options -fexceptions } */ +/* { dg-additional-options -mno-fake-exceptions } */ +/* { dg-additional-options -fdump-tree-optimized-raw } */ + +#include "../../../../libgomp/testsuite/libgomp.oacc-c++/exceptions-throw-2.C" + +/* { dg-final { scan-tree-dump-times {gimple_call <__cxa_allocate_exception, } 1 optimized } } + { dg-final { scan-tree-dump-times {gimple_call <__cxa_throw, } 1 optimized } } + Compilation fails: + { dg-regexp {[^\r\n]+: In function 'int main\(\)':[\r\n]+(?:[^\r\n]+: sorry, unimplemented: exception handling not supported[\r\n]+)+} } + (Note, using 'dg-regexp' instead of 'dg-message', as the former runs before the auto-mark-UNSUPPORTED.) */ diff --git a/gcc/testsuite/g++.target/nvptx/exceptions-throw-2_-mfake-exceptions.C b/gcc/testsuite/g++.target/nvptx/exceptions-throw-2_-mfake-exceptions.C new file mode 100644 index 0000000..f1fd505 --- /dev/null +++ b/gcc/testsuite/g++.target/nvptx/exceptions-throw-2_-mfake-exceptions.C @@ -0,0 +1,19 @@ +/* 'throw', caught, '-mfake-exceptions'. */ + +/* { dg-do run } */ +/* Via the magic string "-std=*++" indicate that testing one (the default) C++ standard is sufficient. */ +/* { dg-additional-options -fexceptions } */ +/* { dg-additional-options -mfake-exceptions } + { dg-bogus {sorry, unimplemented: exception handling not supported} {} { target *-*-* } 0 } */ +/* { dg-additional-options -fdump-tree-optimized-raw } */ + +#include "exceptions-throw-2.C" + +/* { dg-output {CheCKpOInT[\r\n]+} } + + { dg-final { scan-tree-dump-times {gimple_call <__cxa_allocate_exception, } 1 optimized } } + { dg-final { scan-tree-dump-times {gimple_call <__cxa_throw, } 1 optimized } } + We don't print anything, but just 'abort'. + + There is no 'catch'ing; any exception is fatal. + { dg-shouldfail {'MyException' exception} } */ diff --git a/gcc/testsuite/g++.target/nvptx/exceptions-throw-3.C b/gcc/testsuite/g++.target/nvptx/exceptions-throw-3.C new file mode 100644 index 0000000..5c1ad7a --- /dev/null +++ b/gcc/testsuite/g++.target/nvptx/exceptions-throw-3.C @@ -0,0 +1,11 @@ +/* 'throw', dead code. */ + +/* { dg-do run } */ +/* Via the magic string "-std=*++" indicate that testing one (the default) C++ standard is sufficient. */ +/* { dg-additional-options -fexceptions } */ +/* { dg-additional-options -fdump-tree-optimized-raw } */ + +#include "../../../../libgomp/testsuite/libgomp.oacc-c++/exceptions-throw-3.C" + +/* { dg-final { scan-tree-dump-times {gimple_call <__cxa_allocate_exception, } 1 optimized } } + { dg-final { scan-tree-dump-times {gimple_call <__cxa_throw, } 1 optimized } } */ diff --git a/gcc/testsuite/g++.target/nvptx/pr119692-1-1.C b/gcc/testsuite/g++.target/nvptx/pr119692-1-1.C new file mode 100644 index 0000000..b44b08d --- /dev/null +++ b/gcc/testsuite/g++.target/nvptx/pr119692-1-1.C @@ -0,0 +1,6 @@ +/* PR119692 "C++ 'typeinfo', 'vtable' vs. OpenACC, OpenMP 'target' offloading" */ + +/* { dg-do run } */ +/* Via the magic string "-std=*++" indicate that testing one (the default) C++ standard is sufficient. */ + +#include "../../../../libgomp/testsuite/libgomp.oacc-c++/pr119692-1-1.C" diff --git a/gcc/testsuite/g++.target/riscv/rvv/autovec/pr119547-2.C b/gcc/testsuite/g++.target/riscv/rvv/autovec/pr119547-2.C new file mode 100644 index 0000000..1b98d3d --- /dev/null +++ b/gcc/testsuite/g++.target/riscv/rvv/autovec/pr119547-2.C @@ -0,0 +1,212 @@ +/* { dg-do run { target rv64 } } */ +/* { dg-require-effective-target riscv_v_ok } */ +/* { dg-options "-O3 -march=rv64gcv -mabi=lp64d --param=logical-op-non-short-circuit=0" } */ + +#include <riscv_vector.h> + +using v_uint8 = vuint8m2_t; +using v_int8 = vint8m2_t; +using v_uint16 = vuint16m2_t; +using v_int16 = vint16m2_t; +using v_uint32 = vuint32m2_t; +using v_int32 = vint32m2_t; +using v_uint64 = vuint64m2_t; +using v_int64 = vint64m2_t; +using v_float32 = vfloat32m2_t; +using v_float64 = vfloat64m2_t; + +using uchar = unsigned char; +using schar = signed char; +using ushort = unsigned short; +using uint = unsigned int; +using uint64 = unsigned long int; +using int64 = long int; + +struct Size +{ + int width; + int height; +}; + +template <class T> struct VTraits; + +template <> struct VTraits<vint32m1_t> +{ + static inline int vlanes () { return __riscv_vsetvlmax_e32m1 (); } + using lane_type = int32_t; + static const int max_nlanes = 1024 / 32 * 2; +}; +template <> struct VTraits<vint32m2_t> +{ + static inline int vlanes () { return __riscv_vsetvlmax_e32m2 (); } + using lane_type = int32_t; + static const int max_nlanes = 1024 / 32 * 2; +}; +template <> struct VTraits<vint32m4_t> +{ + static inline int vlanes () { return __riscv_vsetvlmax_e32m4 (); } + using lane_type = int32_t; + static const int max_nlanes = 1024 / 32 * 2; +}; +template <> struct VTraits<vint32m8_t> +{ + static inline int vlanes () { return __riscv_vsetvlmax_e32m8 (); } + using lane_type = int32_t; + static const int max_nlanes = 1024 / 32 * 2; +}; + +template <> struct VTraits<vfloat64m1_t> +{ + static inline int vlanes () { return __riscv_vsetvlmax_e64m1 (); } + using lane_type = double; + static const int max_nlanes = 1024 / 64 * 2; +}; +template <> struct VTraits<vfloat64m2_t> +{ + static inline int vlanes () { return __riscv_vsetvlmax_e64m2 (); } + using lane_type = double; + static const int max_nlanes = 1024 / 64 * 2; +}; +template <> struct VTraits<vfloat64m4_t> +{ + static inline int vlanes () { return __riscv_vsetvlmax_e64m4 (); } + using lane_type = double; + static const int max_nlanes = 1024 / 64 * 2; +}; +template <> struct VTraits<vfloat64m8_t> +{ + static inline int vlanes () { return __riscv_vsetvlmax_e64m8 (); } + using lane_type = double; + static const int max_nlanes = 1024 / 64 * 2; +}; + +static inline v_float64 +v_setall_f64 (double v) +{ + return __riscv_vfmv_v_f_f64m2 (v, VTraits<v_float64>::vlanes ()); +} +static inline v_float64 +vx_setall_f64 (double v) +{ + return v_setall_f64 (v); +} + +inline v_int32 +v_load_expand_q (const schar *ptr) +{ + return __riscv_vwcvt_x ( + __riscv_vwcvt_x (__riscv_vle8_v_i8mf2 (ptr, VTraits<v_int32>::vlanes ()), + VTraits<v_int32>::vlanes ()), + VTraits<v_int32>::vlanes ()); +} + +static inline v_int32 +vx_load_expand_q (const schar *ptr) +{ + return v_load_expand_q (ptr); +} + +inline v_float64 +v_cvt_f64 (const v_int32 &a) +{ + return __riscv_vget_f64m2 (__riscv_vfwcvt_f (a, VTraits<v_int32>::vlanes ()), + 0); +} + +inline v_float64 +v_cvt_f64_high (const v_int32 &a) +{ + return __riscv_vget_f64m2 (__riscv_vfwcvt_f (a, VTraits<v_int32>::vlanes ()), + 1); +} + +inline void +v_store (double *ptr, const v_float64 &a) +{ + __riscv_vse64 (ptr, a, VTraits<v_float64>::vlanes ()); +} + +static inline void +v_store_pair_as (double *ptr, const v_float64 &a, const v_float64 &b) +{ + v_store (ptr, a); + v_store (ptr + VTraits<v_float64>::vlanes (), b); +} + +static inline void +vx_load_pair_as (const schar *ptr, v_float64 &a, v_float64 &b) +{ + v_int32 v0 = vx_load_expand_q (ptr); + a = v_cvt_f64 (v0); + b = v_cvt_f64_high (v0); +} + +inline v_float64 +v_fma (const v_float64 &a, const v_float64 &b, const v_float64 &c) +{ + return __riscv_vfmacc_vv_f64m2 (c, a, b, VTraits<v_float64>::vlanes ()); +} + +template <typename _Tp> +static inline _Tp +saturate_cast (double v) +{ + return _Tp (v); +} + +template <typename _Ts, typename _Td> +__attribute__ ((noipa)) void +cvt_64f (const _Ts *src, size_t sstep, _Td *dst, size_t dstep, Size size, + double a, double b) +{ + v_float64 va = vx_setall_f64 (a), vb = vx_setall_f64 (b); + const int VECSZ = VTraits<v_float64>::vlanes () * 2; + + sstep /= sizeof (src[0]); + dstep /= sizeof (dst[0]); + + for (int i = 0; i < size.height; i++, src += sstep, dst += dstep) + { + int j = 0; + + for (; j < size.width; j += VECSZ) + { + if (j > size.width - VECSZ) + { + if (j == 0 || src == (_Ts *) dst) + break; + j = size.width - VECSZ; + } + v_float64 v0, v1; + vx_load_pair_as (src + j, v0, v1); + v0 = v_fma (v0, va, vb); + v1 = v_fma (v1, va, vb); + v_store_pair_as (dst + j, v0, v1); + } + + for (; j < size.width; j++) + dst[j] = saturate_cast<_Td> (src[j] * a + b); + } +} + +void +__attribute__ ((noipa)) +cvtScale8s64f (const uchar *src_, size_t sstep, const uchar *, size_t, + uchar *dst_, size_t dstep, Size size, void *scale_) +{ + const schar *src = (const schar *) src_; + double *dst = (double *) dst_; + double *scale = (double *) scale_; + cvt_64f (src, sstep, dst, dstep, size, (double) scale[0], (double) scale[1]); +} + +int main () +{ + uchar src[1024]; + uchar dst[1024]; + + double scale[2] = {2.0, 3.0}; + Size size {4, 1}; + + cvtScale8s64f (src, 4, NULL, 0, dst, 32, size, (void *)scale); +} diff --git a/gcc/testsuite/g++.target/riscv/rvv/autovec/pr119547.C b/gcc/testsuite/g++.target/riscv/rvv/autovec/pr119547.C new file mode 100644 index 0000000..bac0fb1 --- /dev/null +++ b/gcc/testsuite/g++.target/riscv/rvv/autovec/pr119547.C @@ -0,0 +1,82 @@ +/* { dg-do run { target rv64 } } */ +/* { dg-require-effective-target riscv_v_ok } */ +/* { dg-options "-O3 -march=rv64gcv -mabi=lp64d --param=logical-op-non-short-circuit=0" } */ + +#include <riscv_vector.h> +using v_int32 = vint32m2_t; +using v_float64 = vfloat64m2_t; +struct Size +{ + int width; + int height; +}; +template <class> struct VTraits +{ + static int vlanes () { return __riscv_vsetvlmax_e32m2 (); } +}; +v_int32 +v_load_expand_q (const signed char *ptr) +{ + return __riscv_vwcvt_x ( + __riscv_vwcvt_x (__riscv_vle8_v_i8mf2 (ptr, VTraits<v_int32>::vlanes ()), + VTraits<v_int32>::vlanes ()), + VTraits<v_int32>::vlanes ()); +} +v_float64 +v_cvt_f64_high (v_int32 a) +{ + return __riscv_vget_f64m2 (__riscv_vfwcvt_f (a, VTraits<v_int32>::vlanes ()), + 1); +} +void +v_store (double *ptr, v_float64 a) +{ + __riscv_vse64 (ptr, a, __riscv_vsetvlmax_e64m2 ()); +} +void +v_store_pair_as (double *ptr, v_float64 b) +{ + v_store (ptr, b); +} +void +vx_load_pair_as (const signed char *ptr, v_float64, v_float64 &b) +{ + v_int32 v0; + b = v_cvt_f64_high (v0); +}; +void +cvt_64f (const signed char *src, double *dst, Size size) +{ + int VECSZ = __riscv_vsetvlmax_e64m2 (); + for (int i; i < size.height; i++) + { + int j; + for (;; j += VECSZ) + { + if (j > -VECSZ) + if (j == 0 || dst) + break; + v_float64 v0, v1; + vx_load_pair_as (src, v0, v1); + v_store_pair_as (dst, v1); + } + for (; j < size.width; j++) + dst[j] = (src[j]); + } +} +void +cvtScale8s64f (unsigned char *src_, unsigned char *dst_, + size_t, Size size, void *) +{ + signed char src; + double dst = *dst_; + cvt_64f (&src, &dst, size); +} +int main () +{ + unsigned char src[1]; + unsigned char dst[1024]; + double scale[1]; + Size size{4, 1}; + cvtScale8s64f (src, dst, 32, size, scale); +} diff --git a/gcc/testsuite/g++.target/s390/pr119834.C b/gcc/testsuite/g++.target/s390/pr119834.C new file mode 100644 index 0000000..66c0a69 --- /dev/null +++ b/gcc/testsuite/g++.target/s390/pr119834.C @@ -0,0 +1,76 @@ +// PR target/119834 +// { dg-do compile { target c++11 } } +// { dg-options "-O2 -march=z900" } + +int *a; +struct A; +struct B { + A begin (); + A end (); + operator bool * (); + void operator++ (); +}; +template <typename T> +auto operator| (int, T x) -> decltype (x (0)); +struct A : B { bool a; }; +struct C { A operator () (int); }; +enum D {} d; +int e; +void foo (); +struct E { + template <typename T> + T *garply () + { + if (d) + return 0; + if (e) + foo (); + return reinterpret_cast<T *> (f); + } + template <typename> + void bar (long x, bool) + { + if (&g - f) + __builtin_memset (a, 0, x); + f += x; + } + template <typename T> + T *baz (T *x, long y, bool z = true) + { + if (d) + return nullptr; + bar<T> ((char *)x + y - f, z); + return x; + } + template <typename T> + void qux (T x) { baz (x, x->j); } + char *f, g; +} *h; +struct F { + template <typename T> + int corge (T x) { x.freddy (this); return 0; } + template <typename T> + int boo (T x) { corge (x); return 0; } +} i; +template <typename T> +struct G { + template <typename U> friend T operator+ (U, G); + template <typename U> + void waldo (F *x, G y, U z) { x->boo (z + y); } + template <typename... Ts> + void plugh (E *y, Ts... z) { T *x = y->garply<T> (); x->thud (y, z...); } +}; +template <typename T> using H = G<T>; +struct I { + static constexpr unsigned j = 2; + void thud (E *x, A y) { x->qux (this); for (auto g : y) ; } +}; +H<I> k; +struct J { + void freddy (F *) { C a; auto b = 0 | a; k.plugh (h, b); } +}; +H<J> l; +struct K { + void freddy () { l.waldo (&i, l, this); } +}; +void grault () { K m; m.freddy (); } diff --git a/gcc/testsuite/gcc.dg/Wbuiltin-declaration-mismatch-4.c b/gcc/testsuite/gcc.dg/Wbuiltin-declaration-mismatch-4.c index c48fe5f..09aaaa6 100644 --- a/gcc/testsuite/gcc.dg/Wbuiltin-declaration-mismatch-4.c +++ b/gcc/testsuite/gcc.dg/Wbuiltin-declaration-mismatch-4.c @@ -77,9 +77,9 @@ void test_integer_conversion_memset (void *d) /* Passing a ptrdiff_t where size_t is expected may not be unsafe but because GCC may emits suboptimal code for such calls warning for them helps improve efficiency. */ - memset (d, 0, diffi); /* { dg-warning ".memset. argument 3 promotes to .ptrdiff_t. {aka .\(long \)?\(int\)?\(__int20\)?.} where .\(long \)?\(__int20 \)?unsigned\( int\)?. is expected" } */ + memset (d, 0, diffi); /* { dg-warning ".memset. argument 3 promotes to .ptrdiff_t. {aka .\(long \)*\(int\)?\(__int20\)?.} where .\(long \)*\(__int20 \)?unsigned\( int\)?. is expected" } */ - memset (d, 0, 2.0); /* { dg-warning ".memset. argument 3 type is .double. where '\(long \)?\(__int20 \)?unsigned\( int\)?' is expected" } */ + memset (d, 0, 2.0); /* { dg-warning ".memset. argument 3 type is .double. where '\(long \)*\(__int20 \)?unsigned\( int\)?' is expected" } */ /* Verify that the same call as above but to the built-in doesn't trigger a warning. */ diff --git a/gcc/testsuite/gcc.dg/bitint-121.c b/gcc/testsuite/gcc.dg/bitint-121.c new file mode 100644 index 0000000..335b9a1 --- /dev/null +++ b/gcc/testsuite/gcc.dg/bitint-121.c @@ -0,0 +1,24 @@ +/* PR middle-end/119808 */ +/* { dg-do run { target { bitint && fstack_protector } } } */ +/* { dg-options "-O0 -ftree-coalesce-vars -fstack-protector-strong" } */ + +#if __BITINT_MAXWIDTH__ >= 129 +_BitInt(129) +foo () +{ + _BitInt(129) b = 0; + _BitInt(8) a + =__builtin_stdc_rotate_right (0x8c82111b5d2d37c57e9ada7213ed95a49uwb, b); + return b; +} +#endif + +int +main () +{ +#if __BITINT_MAXWIDTH__ >= 129 + _BitInt(129) x = foo (); + if (x) + __builtin_abort (); +#endif +} diff --git a/gcc/testsuite/gcc.dg/bitint-122.c b/gcc/testsuite/gcc.dg/bitint-122.c new file mode 100644 index 0000000..c791969 --- /dev/null +++ b/gcc/testsuite/gcc.dg/bitint-122.c @@ -0,0 +1,20 @@ +/* PR tree-optimization/116093 */ +/* { dg-do run { target bitint } } */ +/* { dg-options "-Og -ftree-vrp -fno-tree-dce" } */ + +#if __BITINT_MAXWIDTH__ >= 129 +char +foo (int a, _BitInt (129) b, char c) +{ + return c << (5 / b % (0xdb75dbf5 | a)); +} +#endif + +int +main () +{ +#if __BITINT_MAXWIDTH__ >= 129 + if (foo (0, 6, 1) != 1) + __builtin_abort (); +#endif +} diff --git a/gcc/testsuite/gcc.dg/completion-2.c b/gcc/testsuite/gcc.dg/completion-2.c index 99e6531..46c511c 100644 --- a/gcc/testsuite/gcc.dg/completion-2.c +++ b/gcc/testsuite/gcc.dg/completion-2.c @@ -5,6 +5,7 @@ -flto-partition=1to1 -flto-partition=balanced -flto-partition=cache +-flto-partition=default -flto-partition=max -flto-partition=none -flto-partition=one diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-sra-19.c b/gcc/testsuite/gcc.dg/ipa/ipa-sra-19.c index c34c89e..39874ad 100644 --- a/gcc/testsuite/gcc.dg/ipa/ipa-sra-19.c +++ b/gcc/testsuite/gcc.dg/ipa/ipa-sra-19.c @@ -1,7 +1,7 @@ /* { dg-do compile } */ /* { dg-options "-O2" } */ /* { dg-additional-options "-msse2" { target ia32 } } */ -/* { dg-additional-options "-Wno-psabi" { target powerpc-ibm-aix* powerpc-wrs-vxworks* } } */ +/* { dg-additional-options "-Wno-psabi" { target powerpc-ibm-aix* powerpc-wrs-vxworks* powerpc-*-elf } } */ typedef int __attribute__((__vector_size__(16))) vectype; diff --git a/gcc/testsuite/gcc.dg/ipa/pr119318.c b/gcc/testsuite/gcc.dg/ipa/pr119318.c new file mode 100644 index 0000000..f179aed --- /dev/null +++ b/gcc/testsuite/gcc.dg/ipa/pr119318.c @@ -0,0 +1,37 @@ +/* { dg-do run } */ +/* { dg-require-effective-target int128 } */ +/* { dg-options "-Wno-psabi -w -O2" } */ + +typedef unsigned V __attribute__((vector_size (64))); +typedef unsigned __int128 W __attribute__((vector_size (64))); + +W a; +W b; +W c = { -0xffff, -0xffff, -0xffff, -0xffff }; + +static __attribute__((__noinline__, __noclone__)) W +bar (unsigned __int128 u) +{ + return u + c; +} + +static inline W +foo (unsigned short s, V v) +{ + V y = (V) bar ((unsigned short) ~s); + v >>= y; + b ^= (W) a; + v *= v; + return (W) v + b; +} + + +int +main () +{ + W x = foo (0, (V) { 0, 5 }); + for (unsigned i = 0; i < sizeof(x)/sizeof(x[0]); i++) + if (x[i] != (i ? 0 : 0x1900000000)) + __builtin_abort(); + return 0; +} diff --git a/gcc/testsuite/gcc.dg/ipa/pr119530.c b/gcc/testsuite/gcc.dg/ipa/pr119530.c new file mode 100644 index 0000000..f99c4fd --- /dev/null +++ b/gcc/testsuite/gcc.dg/ipa/pr119530.c @@ -0,0 +1,21 @@ +/* { dg-do run } */ +/* { dg-options "-O3 -fno-tree-vrp -fno-inline" } */ + +struct a { + int b; +}; +int c; +signed char d; +static int e(long long f) { return f < 0; } +static void g(unsigned f) { c = e(~f); } +int main() { + int h; + struct a i = {128}; + h = d > i.b; + g(h); + if (h) + __builtin_abort(); + if (c) + __builtin_abort(); + return 0; +} diff --git a/gcc/testsuite/gcc.dg/ipa/pr119803.c b/gcc/testsuite/gcc.dg/ipa/pr119803.c new file mode 100644 index 0000000..1a7bfd2 --- /dev/null +++ b/gcc/testsuite/gcc.dg/ipa/pr119803.c @@ -0,0 +1,16 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ + +extern void f(int p); +int a, b; +char c; +static int d(int e) { return !e || a == 1 ? 0 : a / e; } +static void h(short e) { + int g = d(e); + f(g); +} +void i() { + c = 128; + h(c); + b = d(65536); +} diff --git a/gcc/testsuite/gcc.dg/memcpy-4.c b/gcc/testsuite/gcc.dg/memcpy-4.c index 4c726f0..b17b369 100644 --- a/gcc/testsuite/gcc.dg/memcpy-4.c +++ b/gcc/testsuite/gcc.dg/memcpy-4.c @@ -1,13 +1,8 @@ /* { dg-do compile } */ -/* { dg-options "-O2 -fdump-rtl-expand" } */ +/* { dg-options "-O2" } */ -#ifdef __mips -__attribute__((nomips16)) -#endif void f1 (char *p) { __builtin_memcpy (p, "12345", 5); } - -/* { dg-final { scan-rtl-dump "mem/u.*mem/u" "expand" { target mips*-*-* } } } */ diff --git a/gcc/testsuite/gcc.dg/pr116357.c b/gcc/testsuite/gcc.dg/pr116357.c index 07effa1..12aaf62 100644 --- a/gcc/testsuite/gcc.dg/pr116357.c +++ b/gcc/testsuite/gcc.dg/pr116357.c @@ -2,9 +2,9 @@ /* { dg-do compile } */ /* { dg-options "" } */ -typedef int A __attribute__((aligned (2 * alignof (int)))); +typedef int A __attribute__((aligned (2 * sizeof (int)))); A a[4]; /* { dg-error "alignment of array elements is greater than element size" } */ -typedef volatile int B __attribute__((aligned (2 * alignof (int)))); +typedef volatile int B __attribute__((aligned (2 * sizeof (int)))); B b[4]; /* { dg-error "alignment of array elements is greater than element size" } */ -typedef const int C __attribute__((aligned (2 * alignof (int)))); +typedef const int C __attribute__((aligned (2 * sizeof (int)))); C c[4]; /* { dg-error "alignment of array elements is greater than element size" } */ diff --git a/gcc/testsuite/gcc.dg/pr118947-1.c b/gcc/testsuite/gcc.dg/pr118947-1.c new file mode 100644 index 0000000..8733e8d --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr118947-1.c @@ -0,0 +1,15 @@ +/* PR tree-optimization/118947 */ +/* { dg-do compile { target size32plus } } */ +/* { dg-options "-O2 -fdump-tree-forwprop1-details" } */ +/* { dg-final { scan-tree-dump-times "after previous" 1 "forwprop1" } } */ + +void* aaa(); +void* bbb() +{ + char buf[1025] = {}; + /* Tha call to aaa should not matter and clobber buf. */ + void* ret = aaa(); + __builtin_memcpy(ret, buf, sizeof(buf)); + return ret; +} + diff --git a/gcc/testsuite/gcc.dg/pr119160.c b/gcc/testsuite/gcc.dg/pr119160.c new file mode 100644 index 0000000..b4629a1 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr119160.c @@ -0,0 +1,26 @@ +/* { dg-do run } */ +/* { dg-options "-O2 -finstrument-functions-once -favoid-store-forwarding -fnon-call-exceptions -fschedule-insns -mgeneral-regs-only -Wno-psabi" } */ + +typedef __attribute__((__vector_size__ (32))) int V; + +void +foo (V v, V, V, V *r) +{ + V u = (V){} + v[0]; + *r = u; +} + +__attribute__((__noipa__)) void +bar(int x) +{ + if (x != 2) __builtin_abort(); +} + +int +main () +{ + V x; + foo ((V){ 2, 3 }, (V){ }, (V){ }, &x); + for (unsigned i = 0; i < sizeof(x)/sizeof(x[0]); i++) + bar(x[i]); +}
\ No newline at end of file diff --git a/gcc/testsuite/gcc.dg/pr119717.c b/gcc/testsuite/gcc.dg/pr119717.c new file mode 100644 index 0000000..e5eedc5 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr119717.c @@ -0,0 +1,24 @@ +/* PR c/119717 */ +/* { dg-additional-options "-std=c23" } */ +/* { dg-do compile } */ + +struct annotated { + unsigned count; + [[gnu::counted_by(count)]] char array[]; +}; + +[[gnu::noinline,gnu::noipa]] +static unsigned +size_of (bool x, struct annotated *a) +{ + char *p = (x ? a : 0)->array; + return __builtin_dynamic_object_size (p, 1); +} + +int main() +{ + struct annotated *p = __builtin_malloc(sizeof *p); + p->count = 0; + __builtin_printf ("the bdos whole is %ld\n", size_of (0, p)); + return 0; +} diff --git a/gcc/testsuite/gcc.dg/pr78408-3.c b/gcc/testsuite/gcc.dg/pr78408-3.c new file mode 100644 index 0000000..5ea5458 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr78408-3.c @@ -0,0 +1,14 @@ +/* PR tree-optimization/78408 */ +/* { dg-do compile { target size32plus } } */ +/* { dg-options "-O2 -fdump-tree-forwprop1-details" } */ +/* { dg-final { scan-tree-dump-times "after previous" 1 "forwprop1" } } */ + +void* aaa(); +void* bbb() +{ + void* ret = aaa(); + char buf[1025] = {}; + __builtin_memcpy(ret, buf, sizeof(buf)); + return ret; +} + diff --git a/gcc/testsuite/gcc.dg/rtl/i386/vector_eq-2.c b/gcc/testsuite/gcc.dg/rtl/i386/vector_eq-2.c new file mode 100644 index 0000000..871d489 --- /dev/null +++ b/gcc/testsuite/gcc.dg/rtl/i386/vector_eq-2.c @@ -0,0 +1,71 @@ +/* { dg-do compile { target { i?86-*-* x86_64-*-* } } } */ +/* { dg-additional-options "-O2 -march=x86-64-v3" } */ + +typedef int v4si __attribute__((vector_size(16))); +typedef int v8si __attribute__((vector_size(32))); +typedef int v2di __attribute__((vector_size(16))); + +v4si __RTL (startwith ("vregs1")) foo1 (void) +{ +(function "foo1" + (insn-chain + (block 2 + (edge-from entry (flags "FALLTHRU")) + (cnote 1 [bb 2] NOTE_INSN_BASIC_BLOCK) + (cnote 2 NOTE_INSN_FUNCTION_BEG) + (cinsn 3 (set (reg:V4SI <0>) (const_vector:V4SI [(const_int -1) (const_int -1) (const_int -1) (const_int -1)]))) + (cinsn 4 (set (reg:V4SI <1>) (const_vector:V4SI [(const_int -1) (const_int -1) (const_int -1) (const_int -1)]))) + (cinsn 5 (set (reg:V4SI <2>) + (eq:V4SI (reg:V4SI <0>) (reg:V4SI <1>)))) + (cinsn 6 (set (reg:V4SI <3>) (reg:V4SI <2>))) + (cinsn 7 (set (reg:V4SI xmm0) (reg:V4SI <3>))) + (edge-to exit (flags "FALLTHRU")) + ) + ) + (crtl (return_rtx (reg/i:V4SI xmm0))) +) +} + +v8si __RTL (startwith ("vregs1")) foo2 (void) +{ +(function "foo2" + (insn-chain + (block 2 + (edge-from entry (flags "FALLTHRU")) + (cnote 1 [bb 2] NOTE_INSN_BASIC_BLOCK) + (cnote 2 NOTE_INSN_FUNCTION_BEG) + (cinsn 3 (set (reg:V8SI <0>) (const_vector:V8SI [(const_int -1) (const_int -1) (const_int -1) (const_int -1) (const_int -1) (const_int -1) (const_int -1) (const_int -1)]))) + (cinsn 4 (set (reg:V8SI <1>) (const_vector:V8SI [(const_int -1) (const_int -1) (const_int -1) (const_int -1) (const_int -1) (const_int -1) (const_int -1) (const_int -1)]))) + (cinsn 5 (set (reg:V8SI <2>) + (eq:V8SI (reg:V8SI <0>) (reg:V8SI <1>)))) + (cinsn 6 (set (reg:V8SI <3>) (reg:V8SI <2>))) + (cinsn 7 (set (reg:V8SI xmm0) (reg:V8SI <3>))) + (edge-to exit (flags "FALLTHRU")) + ) + ) + (crtl (return_rtx (reg/i:V8SI xmm0))) +) +} + +v2di __RTL (startwith ("vregs1")) foo3 (void) +{ +(function "foo3" + (insn-chain + (block 2 + (edge-from entry (flags "FALLTHRU")) + (cnote 1 [bb 2] NOTE_INSN_BASIC_BLOCK) + (cnote 2 NOTE_INSN_FUNCTION_BEG) + (cinsn 3 (set (reg:V2DI <0>) (const_vector:V2DI [(const_int -1) (const_int -1)]))) + (cinsn 4 (set (reg:V2DI <1>) (const_vector:V2DI [(const_int -1) (const_int -1)]))) + (cinsn 5 (set (reg:V2DI <2>) + (eq:V2DI (reg:V2DI <0>) (reg:V2DI <1>)))) + (cinsn 6 (set (reg:V2DI <3>) (reg:V2DI <2>))) + (cinsn 7 (set (reg:V2DI xmm0) (reg:V2DI <3>))) + (edge-to exit (flags "FALLTHRU")) + ) + ) + (crtl (return_rtx (reg/i:V2DI xmm0))) +) +} + +/* { dg-final { scan-assembler-times "vpcmpeq" 3 } } */ diff --git a/gcc/testsuite/gcc.dg/rtl/i386/vector_eq-3.c b/gcc/testsuite/gcc.dg/rtl/i386/vector_eq-3.c new file mode 100644 index 0000000..276c4c2 --- /dev/null +++ b/gcc/testsuite/gcc.dg/rtl/i386/vector_eq-3.c @@ -0,0 +1,74 @@ +/* { dg-do compile { target { i?86-*-* x86_64-*-* } } } */ +/* { dg-additional-options "-O2 -march=x86-64-v3" } */ + +typedef int v4si __attribute__((vector_size(16))); +typedef int v8si __attribute__((vector_size(32))); +typedef int v2di __attribute__((vector_size(16))); + +v4si __RTL (startwith ("vregs1")) foo1 (void) +{ +(function "foo1" + (insn-chain + (block 2 + (edge-from entry (flags "FALLTHRU")) + (cnote 1 [bb 2] NOTE_INSN_BASIC_BLOCK) + (cnote 2 NOTE_INSN_FUNCTION_BEG) + (cinsn 3 (set (reg:V4SI <1>) + (mem:V4SI (reg:SI di) [0 ptr S128 A128]))) + (cinsn 4 (set (reg:V4SI <2>) + (eq:V4SI (reg:V4SI <1>) + (mem:V4SI (reg:SI di) [0 ptr S128 A128])))) + (cinsn 5 (set (reg:V4SI <3>) (reg:V4SI <2>))) + (cinsn 6 (set (reg:V4SI xmm0) (reg:V4SI <3>))) + (edge-to exit (flags "FALLTHRU")) + ) + ) + (crtl (return_rtx (reg/i:V4SI xmm0))) +) +} + +v8si __RTL (startwith ("vregs1")) foo2 (void) +{ +(function "foo2" + (insn-chain + (block 2 + (edge-from entry (flags "FALLTHRU")) + (cnote 1 [bb 2] NOTE_INSN_BASIC_BLOCK) + (cnote 2 NOTE_INSN_FUNCTION_BEG) + (cinsn 3 (set (reg:V8SI <1>) + (mem:V8SI (reg:SI di) [0 ptr S256 A256]))) + (cinsn 4 (set (reg:V8SI <2>) + (eq:V8SI (mem:V8SI (reg:SI di) [0 ptr S256 A256]) + (reg:V8SI <1>)))) + (cinsn 5 (set (reg:V8SI <3>) (reg:V8SI <2>))) + (cinsn 6 (set (reg:V8SI xmm0) (reg:V8SI <3>))) + (edge-to exit (flags "FALLTHRU")) + ) + ) + (crtl (return_rtx (reg/i:V8SI xmm0))) +) +} + +v2di __RTL (startwith ("vregs1")) foo3 (void) +{ +(function "foo3" + (insn-chain + (block 2 + (edge-from entry (flags "FALLTHRU")) + (cnote 1 [bb 2] NOTE_INSN_BASIC_BLOCK) + (cnote 2 NOTE_INSN_FUNCTION_BEG) + (cinsn 3 (set (reg:V2DI <1>) + (mem:V2DI (reg:SI di) [0 ptr S128 A128]))) + (cinsn 4 (set (reg:V2DI <2>) + (eq:V2DI (reg:V2DI <1>) + (mem:V2DI (reg:SI di) [0 ptr S128 A128])))) + (cinsn 5 (set (reg:V2DI <3>) (reg:V2DI <2>))) + (cinsn 6 (set (reg:V2DI xmm0) (reg:V2DI <3>))) + (edge-to exit (flags "FALLTHRU")) + ) + ) + (crtl (return_rtx (reg/i:V2DI xmm0))) +) +} + +/* { dg-final { scan-assembler-times "vpcmpeq" 3 } } */ diff --git a/gcc/testsuite/gcc.dg/torture/pr118476-1.c b/gcc/testsuite/gcc.dg/torture/pr118476-1.c new file mode 100644 index 0000000..33509403 --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/pr118476-1.c @@ -0,0 +1,14 @@ +/* { dg-do compile } */ + +/* PR tree-optimization/118476 */ + +typedef unsigned long long poly64x1 __attribute__((__vector_size__(1*sizeof(long long)))); + +poly64x1 vext_p64(poly64x1 a, poly64x1 b, const int n) +{ + poly64x1 r = a; + unsigned src = (unsigned)n; + long long t = b[0]; + r[0] = (src < 1) ? a[src] : t; + return r; +} diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr118902-1.c b/gcc/testsuite/gcc.dg/tree-ssa/pr118902-1.c new file mode 100644 index 0000000..fa21b8a --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/pr118902-1.c @@ -0,0 +1,21 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-optimized" } */ + +void foo(int); +void l(int**); +int f1(int j, int t) +{ + int p = 0; + int *a = &p; + l(&a); + if (a == &p) + return 0; + for(int i = 0; i < j; i++) + { + if (a == &p) foo(p); + } + return 0; +} + +/* We should be able to remove the call to foo because a is never equal to &p inside the loop. */ +/* { dg-final { scan-tree-dump-not "foo " "optimized"} } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-cse-2.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-cse-2.c index a879d30..6fa52f6 100644 --- a/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-cse-2.c +++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-cse-2.c @@ -27,4 +27,4 @@ foo () but the loop reads only one element at a time, and DOM cannot resolve these. The same happens on powerpc depending on the SIMD support available. */ -/* { dg-final { scan-tree-dump "return 28;" "optimized" { xfail { { alpha*-*-* hppa*64*-*-* nvptx*-*-* mmix-knuth-mmixware } || { { { lp64 && { powerpc*-*-* sparc*-*-* riscv*-*-* } } || aarch64_sve } || { arm*-*-* && { ! arm_neon } } } } } } } */ +/* { dg-final { scan-tree-dump "return 28;" "optimized" { xfail { { alpha*-*-* hppa*64*-*-* nvptx*-*-* mmix-knuth-mmixware } || { { { lp64 && { mips*-*-* powerpc*-*-* sparc*-*-* riscv*-*-* } } || aarch64_sve } || { arm*-*-* && { ! arm_neon } } } } } } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-dse-52.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-dse-52.c new file mode 100644 index 0000000..9e605ac --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-dse-52.c @@ -0,0 +1,30 @@ +/* { dg-options "-O2 -fdump-tree-dse-details -fno-tree-fre -fdump-tree-optimized" } */ + +/* PR tree-optimization/87901 */ + +char z[32]; +void foo1(void) +{ + char z1[17]; + char z2[24]; + __builtin_memset (z1, 0, 17); + __builtin_memcpy (z, z1, 17); + __builtin_memset (z2, 0, 24); + __builtin_memcpy (z+8, z2, 24); +} + +/* we should get: + MEM <unsigned char[8]> [(char * {ref-all})&z] = {}; + MEM <unsigned char[24]> [(char * {ref-all})&z + 8B] = {}; + after DSE; trimming the first memset to z (which was memcpy) to 8 bytes + from the original 17. + and not have a [17] in the IR after DSE. + The two memset to z1/z2 will also be removed. + */ +/* { dg-final { scan-tree-dump-not "\\\[17\\\]" "optimized" } } */ +/* { dg-final { scan-tree-dump "\\\[8\\\]" "dse1" } } */ + +/* { dg-final { scan-tree-dump-times "Trimming statement " 1 "dse1" } } */ +/* { dg-final { scan-tree-dump-times "Deleted dead call:" 2 "dse1" } } */ + + diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-dse-53.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-dse-53.c new file mode 100644 index 0000000..a2df591 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-dse-53.c @@ -0,0 +1,26 @@ +/* { dg-options "-O2 -fno-strict-aliasing -fdump-tree-dse-details -fno-tree-fre -fdump-tree-optimized" } */ + +/* PR tree-optimization/87901 */ + + +int i; +int foo () +{ + i = 0; + *((short *)&i + 1) = 1; + return i; +} + +/* we should get: + MEM <char[2]> [(int *)&i] = {}; + MEM[(short int *)&i + 2B] = 1; + in DSE1. + + Note later on the stores will be merged. */ +/* { dg-final { scan-tree-dump "return 65536;" "optimized" { target le } } } */ +/* { dg-final { scan-tree-dump "return 1;" "optimized" { target be } } } */ +/* { dg-final { scan-tree-dump "\\\[2\\\]" "dse1" } } */ + +/* { dg-final { scan-tree-dump-times "Trimming statement " 1 "dse1" } } */ + + diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-dse-54.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-dse-54.c new file mode 100644 index 0000000..7e79a73 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-dse-54.c @@ -0,0 +1,25 @@ +/* { dg-options "-O2 -fdump-tree-dse-details -fno-tree-fre -fdump-tree-optimized" } */ + +/* PR tree-optimization/87901 */ + +int z[128]; +void foo1(void) +{ + int z1; + int z2[24/sizeof(int)]; + __builtin_memset (&z1, 0, sizeof(int)); + __builtin_memcpy (z, &z1, sizeof(int)); + __builtin_memset (z2, 0, 24); + __builtin_memcpy (((char*)z)+1, z2, 24); +} + +/* we should get: + MEM[(char * {ref-all})&z] = {}; + __builtin_memset (&MEM <int[128]> [(void *)&z + 1B], 0, 24); + */ + +/* { dg-final { scan-tree-dump-not "MEM <unsigned int>" "optimized" } } */ +/* { dg-final { scan-tree-dump-not "MEM \\\[" "dse1" } } */ +/* { dg-final { scan-tree-dump-times "Trimming statement " 1 "dse1" } } */ +/* { dg-final { scan-tree-dump-times "Deleted dead call:" 1 "dse1" } } */ + diff --git a/gcc/testsuite/gcc.dg/vect/pr119757.c b/gcc/testsuite/gcc.dg/vect/pr119757.c new file mode 100644 index 0000000..8644299 --- /dev/null +++ b/gcc/testsuite/gcc.dg/vect/pr119757.c @@ -0,0 +1,17 @@ +/* { dg-do compile } */ + +void base64_encode(const char *table64, + const char *inputbuff, int insize, + char * __restrict output) +{ + const unsigned char *in = (const unsigned char *)inputbuff; + + while(insize >= 3) { + *output++ = table64[ in[0] >> 2 ]; + *output++ = table64[ ((in[0] & 0x03) << 4) | (in[1] >> 4) ]; + *output++ = table64[ ((in[1] & 0x0F) << 2) | ((in[2] & 0xC0) >> 6) ]; + *output++ = table64[ in[2] & 0x3F ]; + insize -= 3; + in += 3; + } +} diff --git a/gcc/testsuite/gcc.dg/vect/vect-early-break_18.c b/gcc/testsuite/gcc.dg/vect/vect-early-break_18.c index edddb44..cd39704 100644 --- a/gcc/testsuite/gcc.dg/vect/vect-early-break_18.c +++ b/gcc/testsuite/gcc.dg/vect/vect-early-break_18.c @@ -2,7 +2,7 @@ /* { dg-do compile } */ /* { dg-require-effective-target vect_early_break } */ /* { dg-require-effective-target vect_int } */ - +/* { dg-additional-options "-march=gfx908" { target amdgcn*-*-* } } */ /* { dg-additional-options "-Ofast" } */ /* { dg-final { scan-tree-dump "LOOP VECTORIZED" "vect" { target vect_load_lanes } } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/acle/rwsr-ungated.c b/gcc/testsuite/gcc.target/aarch64/acle/rwsr-ungated.c new file mode 100644 index 0000000..d67a426 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/acle/rwsr-ungated.c @@ -0,0 +1,13 @@ +/* Test that __arm_[r,w]sr intrinsics aren't gated (by default). */ + +/* { dg-do compile } */ +/* { dg-options "-march=armv8-a" } */ + +#include <arm_acle.h> + +uint64_t +foo (uint64_t a) +{ + __arm_wsr64 ("zcr_el1", a); + return __arm_rsr64 ("smcr_el1"); +} diff --git a/gcc/testsuite/gcc.target/aarch64/bic-1.c b/gcc/testsuite/gcc.target/aarch64/bic-1.c new file mode 100644 index 0000000..65e1514 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/bic-1.c @@ -0,0 +1,40 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ +/* { dg-final { check-function-bodies "**" "" "" } } */ + +/* PR rtl-optmization/111949 */ + +/* +**func1: +** bic w([0-9]+), w0, w1 +** and w0, w\1, 1 +** ret +*/ + +unsigned func1(unsigned a, bool b) +{ + int c = a & b; + return (c ^ a)&1; +} + +/* +**func2: +** bic w([0-9]+), w1, w0 +** and w0, w\1, 255 +** ret +*/ +unsigned func2(bool a, bool b) +{ + return ~a & b; +} + +/* +**func3: +** bic w([0-9]+), w1, w0 +** and w0, w\1, 1 +** ret +*/ +bool func3(bool a, unsigned char b) +{ + return !a & b; +} diff --git a/gcc/testsuite/gcc.target/aarch64/sve/peel_ind_10.c b/gcc/testsuite/gcc.target/aarch64/sve/peel_ind_10.c new file mode 100644 index 0000000..b7a7bc5 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/peel_ind_10.c @@ -0,0 +1,24 @@ +/* Fix for PR119351 alignment peeling with vectors and VLS. */ +/* { dg-do compile } */ +/* { dg-options "-Ofast -msve-vector-bits=256 --param aarch64-autovec-preference=sve-only -fdump-tree-vect-details" } */ + +#define N 512 +#define START 0 +#define END 505 + +int x[N] __attribute__((aligned(32))); + +int __attribute__((noipa)) +foo (int start) +{ + for (unsigned int i = start; i < END; ++i) + { + if (x[i] == 0) + return i; + } + return -1; +} + +/* { dg-final { scan-tree-dump "LOOP VECTORIZED" "vect" } } */ +/* { dg-final { scan-tree-dump "pfa_iv_offset" "vect" } } */ +/* { dg-final { scan-tree-dump "Alignment of access forced using peeling" "vect" } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/sve/peel_ind_10_run.c b/gcc/testsuite/gcc.target/aarch64/sve/peel_ind_10_run.c new file mode 100644 index 0000000..6169aeb --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/peel_ind_10_run.c @@ -0,0 +1,17 @@ +/* Fix for PR119351 alignment peeling with vectors and VLS. */ +/* { dg-do run { target aarch64_sve_hw } } */ +/* { dg-options "-Ofast --param aarch64-autovec-preference=sve-only" } */ +/* { dg-additional-options "-msve-vector-bits=256" { target aarch64_sve256_hw } } */ +/* { dg-additional-options "-msve-vector-bits=128" { target aarch64_sve128_hw } } */ + +#include "peel_ind_10.c" + +int __attribute__ ((optimize (1))) +main (void) +{ + int res = foo (START); + asm volatile (""); + if (res != START) + __builtin_abort (); + return 0; +} diff --git a/gcc/testsuite/gcc.target/aarch64/sve/peel_ind_5.c b/gcc/testsuite/gcc.target/aarch64/sve/peel_ind_5.c new file mode 100644 index 0000000..a03bb1d --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/peel_ind_5.c @@ -0,0 +1,24 @@ +/* Fix for PR119351 alignment peeling with vectors and VLS. */ +/* { dg-do compile } */ +/* { dg-options "-Ofast -msve-vector-bits=256 --param aarch64-autovec-preference=sve-only -fdump-tree-vect-details" } */ + +#define N 512 +#define START 2 +#define END 505 + +int x[N] __attribute__((aligned(32))); + +int __attribute__((noipa)) +foo (void) +{ + for (signed int i = START; i < END; ++i) + { + if (x[i] == 0) + return i; + } + return -1; +} + +/* { dg-final { scan-tree-dump "LOOP VECTORIZED" "vect" } } */ +/* { dg-final { scan-tree-dump "pfa_iv_offset" "vect" } } */ +/* { dg-final { scan-tree-dump "Alignment of access forced using peeling" "vect" } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/sve/peel_ind_5_run.c b/gcc/testsuite/gcc.target/aarch64/sve/peel_ind_5_run.c new file mode 100644 index 0000000..f26befe --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/peel_ind_5_run.c @@ -0,0 +1,17 @@ +/* Fix for PR119351 alignment peeling with vectors and VLS. */ +/* { dg-do run { target aarch64_sve_hw } } */ +/* { dg-options "-Ofast --param aarch64-autovec-preference=sve-only" } */ +/* { dg-additional-options "-msve-vector-bits=256" { target aarch64_sve256_hw } } */ +/* { dg-additional-options "-msve-vector-bits=128" { target aarch64_sve128_hw } } */ + +#include "peel_ind_5.c" + +int __attribute__ ((optimize (1))) +main (void) +{ + int res = foo (); + asm volatile (""); + if (res != START) + __builtin_abort (); + return 0; +} diff --git a/gcc/testsuite/gcc.target/aarch64/sve/peel_ind_6.c b/gcc/testsuite/gcc.target/aarch64/sve/peel_ind_6.c new file mode 100644 index 0000000..9bfd1a6 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/peel_ind_6.c @@ -0,0 +1,24 @@ +/* Fix for PR119351 alignment peeling with vectors and VLS. */ +/* { dg-do compile } */ +/* { dg-options "-Ofast -msve-vector-bits=256 --param aarch64-autovec-preference=sve-only -fdump-tree-vect-details" } */ + +#define N 512 +#define START 1 +#define END 505 + +int x[N] __attribute__((aligned(32))); + +int __attribute__((noipa)) +foo (int start) +{ + for (unsigned int i = start; i < END; ++i) + { + if (x[i] == 0) + return i; + } + return -1; +} + +/* { dg-final { scan-tree-dump "LOOP VECTORIZED" "vect" } } */ +/* { dg-final { scan-tree-dump "pfa_iv_offset" "vect" } } */ +/* { dg-final { scan-tree-dump "Alignment of access forced using peeling" "vect" } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/sve/peel_ind_6_run.c b/gcc/testsuite/gcc.target/aarch64/sve/peel_ind_6_run.c new file mode 100644 index 0000000..4fdf3e4 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/peel_ind_6_run.c @@ -0,0 +1,17 @@ +/* Fix for PR119351 alignment peeling with vectors and VLS. */ +/* { dg-do run { target aarch64_sve_hw } } */ +/* { dg-options "-Ofast --param aarch64-autovec-preference=sve-only" } */ +/* { dg-additional-options "-msve-vector-bits=256" { target aarch64_sve256_hw } } */ +/* { dg-additional-options "-msve-vector-bits=128" { target aarch64_sve128_hw } } */ + +#include "peel_ind_6.c" + +int __attribute__ ((optimize (1))) +main (void) +{ + int res = foo (START); + asm volatile (""); + if (res != START) + __builtin_abort (); + return 0; +} diff --git a/gcc/testsuite/gcc.target/aarch64/sve/peel_ind_7.c b/gcc/testsuite/gcc.target/aarch64/sve/peel_ind_7.c new file mode 100644 index 0000000..0182e13 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/peel_ind_7.c @@ -0,0 +1,24 @@ +/* Fix for PR119351 alignment peeling with vectors and VLS. */ +/* { dg-do compile } */ +/* { dg-options "-Ofast -msve-vector-bits=256 --param aarch64-autovec-preference=sve-only -fdump-tree-vect-details" } */ + +#define N 512 +#define START 1 +#define END 505 + +int x[N] __attribute__((aligned(32))); + +int __attribute__((noipa)) +foo (void) +{ + for (unsigned int i = START; i < END; ++i) + { + if (x[i] == 0) + return i; + } + return -1; +} + +/* { dg-final { scan-tree-dump "LOOP VECTORIZED" "vect" } } */ +/* { dg-final { scan-tree-dump "pfa_iv_offset" "vect" } } */ +/* { dg-final { scan-tree-dump "Alignment of access forced using peeling" "vect" } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/sve/peel_ind_7_run.c b/gcc/testsuite/gcc.target/aarch64/sve/peel_ind_7_run.c new file mode 100644 index 0000000..05608dd --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/peel_ind_7_run.c @@ -0,0 +1,17 @@ +/* Fix for PR119351 alignment peeling with vectors and VLS. */ +/* { dg-do run { target aarch64_sve_hw } } */ +/* { dg-options "-Ofast --param aarch64-autovec-preference=sve-only" } */ +/* { dg-additional-options "-msve-vector-bits=256" { target aarch64_sve256_hw } } */ +/* { dg-additional-options "-msve-vector-bits=128" { target aarch64_sve128_hw } } */ + +#include "peel_ind_7.c" + +int __attribute__ ((optimize (1))) +main (void) +{ + int res = foo (); + asm volatile (""); + if (res != START) + __builtin_abort (); + return 0; +} diff --git a/gcc/testsuite/gcc.target/aarch64/sve/peel_ind_8.c b/gcc/testsuite/gcc.target/aarch64/sve/peel_ind_8.c new file mode 100644 index 0000000..043348b --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/peel_ind_8.c @@ -0,0 +1,24 @@ +/* Fix for PR119351 alignment peeling with vectors and VLS. */ +/* { dg-do compile } */ +/* { dg-options "-Ofast -msve-vector-bits=256 --param aarch64-autovec-preference=sve-only -fdump-tree-vect-details" } */ + +#define N 512 +#define START 1 +#define END 505 + +int x[N] __attribute__((aligned(32))); + +int __attribute__((noipa)) +foo (void) +{ + for (unsigned int i = START; i < END; i*=2) + { + if (x[i] == 0) + return i; + } + return -1; +} + +/* { dg-final { scan-tree-dump-not "LOOP VECTORIZED" "vect" } } */ +/* { dg-final { scan-tree-dump-not "pfa_iv_offset" "vect" } } */ +/* { dg-final { scan-tree-dump-not "Alignment of access forced using peeling" "vect" } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/sve/peel_ind_8_run.c b/gcc/testsuite/gcc.target/aarch64/sve/peel_ind_8_run.c new file mode 100644 index 0000000..aa86122 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/peel_ind_8_run.c @@ -0,0 +1,17 @@ +/* Fix for PR119351 alignment peeling with vectors and VLS. */ +/* { dg-do run { target aarch64_sve_hw } } */ +/* { dg-options "-Ofast --param aarch64-autovec-preference=sve-only" } */ +/* { dg-additional-options "-msve-vector-bits=256" { target aarch64_sve256_hw } } */ +/* { dg-additional-options "-msve-vector-bits=128" { target aarch64_sve128_hw } } */ + +#include "peel_ind_8.c" + +int __attribute__ ((optimize (1))) +main (void) +{ + int res = foo (); + asm volatile (""); + if (res != START) + __builtin_abort (); + return 0; +} diff --git a/gcc/testsuite/gcc.target/aarch64/sve/peel_ind_9.c b/gcc/testsuite/gcc.target/aarch64/sve/peel_ind_9.c new file mode 100644 index 0000000..cc904e8 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/peel_ind_9.c @@ -0,0 +1,25 @@ +/* Fix for PR119351 alignment peeling with vectors and VLS. */ +/* { dg-do compile } */ +/* { dg-options "-Ofast -msve-vector-bits=256 --param aarch64-autovec-preference=sve-only -fdump-tree-vect-details" } */ + +#define N 512 +#define START 1 +#define END 505 + +int x[N] __attribute__((aligned(32))); + +int __attribute__((noipa)) +foo (void) +{ + for (int *p = x + START; p < x + END; p++) + { + if (*p == 0) + return START; + } + return -1; +} + +/* { dg-final { scan-tree-dump "LOOP VECTORIZED" "vect" } } */ +/* Peels using a scalar loop. */ +/* { dg-final { scan-tree-dump-not "pfa_iv_offset" "vect" } } */ +/* { dg-final { scan-tree-dump "Alignment of access forced using peeling" "vect" } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/sve/peel_ind_9_run.c b/gcc/testsuite/gcc.target/aarch64/sve/peel_ind_9_run.c new file mode 100644 index 0000000..767f8bd --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/peel_ind_9_run.c @@ -0,0 +1,17 @@ +/* Fix for PR119351 alignment peeling with vectors and VLS. */ +/* { dg-do run { target aarch64_sve_hw } } */ +/* { dg-options "-Ofast --param aarch64-autovec-preference=sve-only" } */ +/* { dg-additional-options "-msve-vector-bits=256" { target aarch64_sve256_hw } } */ +/* { dg-additional-options "-msve-vector-bits=128" { target aarch64_sve128_hw } } */ + +#include "peel_ind_9.c" + +int __attribute__ ((optimize (1))) +main (void) +{ + int res = foo (); + asm volatile (""); + if (res != START) + __builtin_abort (); + return 0; +} diff --git a/gcc/testsuite/gcc.target/aarch64/sve/pr119351.c b/gcc/testsuite/gcc.target/aarch64/sve/pr119351.c new file mode 100644 index 0000000..85aab35 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/pr119351.c @@ -0,0 +1,39 @@ +/* Fix for PR119351 alignment peeling with vectors and VLS. */ +/* { dg-do compile } */ +/* { dg-options "-Ofast -msve-vector-bits=256 --param aarch64-autovec-preference=sve-only -fdump-tree-vect-details" } */ +/* { dg-final { check-function-bodies "**" "" ""} } */ + +#define N 512 +#define START 1 +#define END 505 + +int x[N] __attribute__((aligned(32))); + +/* +** foo: +** ... +** ld1w z[0-9]+.s, p[0-9]+/z, \[x[0-9], x[0-9], lsl 2\] +** cmple p[0-9]+.s, p[0-9]+/z, z[0-9]+.s, #0 +** ptest p[0-9]+, p[0-9]+.b +** ... +*/ + +int __attribute__((noipa)) +foo (void) +{ + int z = 0; + for (unsigned int i = START; i < END; ++i) + { + z++; + if (x[i] > 0) + continue; + + return z; + } + return -1; +} + +/* { dg-final { scan-tree-dump "LOOP VECTORIZED" "vect" } } */ +/* { dg-final { scan-tree-dump "pfa_iv_offset" "vect" } } */ +/* { dg-final { scan-tree-dump "Alignment of access forced using peeling" "vect" } } */ + diff --git a/gcc/testsuite/gcc.target/aarch64/sve/pr119351_run.c b/gcc/testsuite/gcc.target/aarch64/sve/pr119351_run.c new file mode 100644 index 0000000..d36ab0e --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/pr119351_run.c @@ -0,0 +1,20 @@ +/* Fix for PR119351 alignment peeling with vectors and VLS. */ +/* { dg-do run { target aarch64_sve_hw } } */ +/* { dg-options "-Ofast --param aarch64-autovec-preference=sve-only" } */ +/* { dg-additional-options "-msve-vector-bits=256" { target aarch64_sve256_hw } } */ +/* { dg-additional-options "-msve-vector-bits=128" { target aarch64_sve128_hw } } */ + +#include "pr119351.c" + +int __attribute__ ((optimize (1))) +main (void) +{ + x[0] = 1; + x[1] = 21; + x[2] = 39; + x[3] = 59; + int res = foo (); + if (res != 4) + __builtin_abort (); + return 0; +} diff --git a/gcc/testsuite/gcc.target/alpha/memcpy-nested-offset-long.c b/gcc/testsuite/gcc.target/alpha/memcpy-nested-offset-long.c new file mode 100644 index 0000000..631d14f --- /dev/null +++ b/gcc/testsuite/gcc.target/alpha/memcpy-nested-offset-long.c @@ -0,0 +1,76 @@ +/* { dg-do compile } */ +/* { dg-options "" } */ +/* { dg-skip-if "" { *-*-* } { "-O0" } } */ + +typedef unsigned int __attribute__ ((mode (DI))) int64_t; +typedef unsigned int __attribute__ ((mode (SI))) int32_t; + +typedef union + { + int32_t l[8]; + } +val; + +typedef struct + { + int32_t l[2]; + val v; + } +tre; + +typedef struct + { + int32_t l[3]; + tre t; + } +due; + +typedef struct + { + val v; + int64_t q; + int32_t l[2]; + due d; + } +uno; + +void +memcpy_nested_offset_long (uno *u) +{ + u->d.t.v = u->v; +} + +/* Expect assembly such as: + + ldq $4,0($16) + ldq $3,8($16) + ldq $2,16($16) + srl $4,32,$7 + ldq $1,24($16) + srl $3,32,$6 + stl $4,68($16) + srl $2,32,$5 + stl $7,72($16) + srl $1,32,$4 + stl $3,76($16) + stl $6,80($16) + stl $2,84($16) + stl $5,88($16) + stl $1,92($16) + stl $4,96($16) + + that is with four quadword loads at offsets 0, 8, 16, 24 each and + eight longword stores at offsets 68, 72, 76, 80, 84, 88, 92, 96 each. */ + +/* { dg-final { scan-assembler-times "\\sldq\\s\\\$\[0-9\]+,0\\\(\\\$16\\\)\\s" 1 } } */ +/* { dg-final { scan-assembler-times "\\sldq\\s\\\$\[0-9\]+,8\\\(\\\$16\\\)\\s" 1 } } */ +/* { dg-final { scan-assembler-times "\\sldq\\s\\\$\[0-9\]+,16\\\(\\\$16\\\)\\s" 1 } } */ +/* { dg-final { scan-assembler-times "\\sldq\\s\\\$\[0-9\]+,24\\\(\\\$16\\\)\\s" 1 } } */ +/* { dg-final { scan-assembler-times "\\sstl\\s\\\$\[0-9\]+,68\\\(\\\$16\\\)\\s" 1 } } */ +/* { dg-final { scan-assembler-times "\\sstl\\s\\\$\[0-9\]+,72\\\(\\\$16\\\)\\s" 1 } } */ +/* { dg-final { scan-assembler-times "\\sstl\\s\\\$\[0-9\]+,76\\\(\\\$16\\\)\\s" 1 } } */ +/* { dg-final { scan-assembler-times "\\sstl\\s\\\$\[0-9\]+,80\\\(\\\$16\\\)\\s" 1 } } */ +/* { dg-final { scan-assembler-times "\\sstl\\s\\\$\[0-9\]+,84\\\(\\\$16\\\)\\s" 1 } } */ +/* { dg-final { scan-assembler-times "\\sstl\\s\\\$\[0-9\]+,88\\\(\\\$16\\\)\\s" 1 } } */ +/* { dg-final { scan-assembler-times "\\sstl\\s\\\$\[0-9\]+,92\\\(\\\$16\\\)\\s" 1 } } */ +/* { dg-final { scan-assembler-times "\\sstl\\s\\\$\[0-9\]+,96\\\(\\\$16\\\)\\s" 1 } } */ diff --git a/gcc/testsuite/gcc.target/alpha/memcpy-nested-offset-quad.c b/gcc/testsuite/gcc.target/alpha/memcpy-nested-offset-quad.c new file mode 100644 index 0000000..1d2227e --- /dev/null +++ b/gcc/testsuite/gcc.target/alpha/memcpy-nested-offset-quad.c @@ -0,0 +1,64 @@ +/* { dg-do compile } */ +/* { dg-options "" } */ +/* { dg-skip-if "" { *-*-* } { "-O0" } } */ + +typedef unsigned int __attribute__ ((mode (DI))) int64_t; +typedef unsigned int __attribute__ ((mode (SI))) int32_t; + +typedef union + { + int32_t l[8]; + } +val; + +typedef struct + { + int32_t l[2]; + val v; + } +tre; + +typedef struct + { + int32_t l[3]; + tre t; + } +due; + +typedef struct + { + val v; + int64_t q; + int32_t l[3]; + due d; + } +uno; + +void +memcpy_nested_offset_quad (uno *u) +{ + u->d.t.v = u->v; +} + +/* Expect assembly such as: + + ldq $4,0($16) + ldq $3,8($16) + ldq $2,16($16) + ldq $1,24($16) + stq $4,72($16) + stq $3,80($16) + stq $2,88($16) + stq $1,96($16) + + that is with four quadword loads at offsets 0, 8, 16, 24 each + and four quadword stores at offsets 72, 80, 88, 96 each. */ + +/* { dg-final { scan-assembler-times "\\sldq\\s\\\$\[0-9\]+,0\\\(\\\$16\\\)\\s" 1 } } */ +/* { dg-final { scan-assembler-times "\\sldq\\s\\\$\[0-9\]+,8\\\(\\\$16\\\)\\s" 1 } } */ +/* { dg-final { scan-assembler-times "\\sldq\\s\\\$\[0-9\]+,16\\\(\\\$16\\\)\\s" 1 } } */ +/* { dg-final { scan-assembler-times "\\sldq\\s\\\$\[0-9\]+,24\\\(\\\$16\\\)\\s" 1 } } */ +/* { dg-final { scan-assembler-times "\\sstq\\s\\\$\[0-9\]+,72\\\(\\\$16\\\)\\s" 1 } } */ +/* { dg-final { scan-assembler-times "\\sstq\\s\\\$\[0-9\]+,80\\\(\\\$16\\\)\\s" 1 } } */ +/* { dg-final { scan-assembler-times "\\sstq\\s\\\$\[0-9\]+,88\\\(\\\$16\\\)\\s" 1 } } */ +/* { dg-final { scan-assembler-times "\\sstq\\s\\\$\[0-9\]+,96\\\(\\\$16\\\)\\s" 1 } } */ diff --git a/gcc/testsuite/gcc.target/i386/apx-interrupt-1.c b/gcc/testsuite/gcc.target/i386/apx-interrupt-1.c index fefe2e6..fa1acc7 100644 --- a/gcc/testsuite/gcc.target/i386/apx-interrupt-1.c +++ b/gcc/testsuite/gcc.target/i386/apx-interrupt-1.c @@ -66,7 +66,7 @@ void foo (void *frame) /* { dg-final { scan-assembler-times {\t\.cfi_offset 132, -120} 1 } } */ /* { dg-final { scan-assembler-times {\t\.cfi_offset 131, -128} 1 } } */ /* { dg-final { scan-assembler-times {\t\.cfi_offset 130, -136} 1 } } */ -/* { dg-final { scan-assembler-times ".cfi_restore" 15} } */ +/* { dg-final { scan-assembler-times ".cfi_restore" 31 } } */ /* { dg-final { scan-assembler-times "pop(?:l|q)\[\\t \]*%(?:e|r)ax" 1 } } */ /* { dg-final { scan-assembler-times "pop(?:l|q)\[\\t \]*%(?:e|r)bx" 1 } } */ /* { dg-final { scan-assembler-times "pop(?:l|q)\[\\t \]*%(?:e|r)cx" 1 } } */ diff --git a/gcc/testsuite/gcc.target/i386/pr119386-1.c b/gcc/testsuite/gcc.target/i386/pr119386-1.c new file mode 100644 index 0000000..9a0dc64 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr119386-1.c @@ -0,0 +1,10 @@ +/* PR target/119386 */ +/* { dg-do compile { target *-*-linux* } } */ +/* { dg-options "-O2 -fpic -pg" } */ +/* { dg-final { scan-assembler "call\[ \t\]+mcount@PLT" } } */ + +int +main () +{ + return 0; +} diff --git a/gcc/testsuite/gcc.target/i386/pr119386-2.c b/gcc/testsuite/gcc.target/i386/pr119386-2.c new file mode 100644 index 0000000..3ea978e --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr119386-2.c @@ -0,0 +1,12 @@ +/* PR target/119386 */ +/* { dg-do compile { target *-*-linux* } } */ +/* { dg-options "-O2 -fpic -fno-plt -pg" } */ +/* { dg-final { scan-assembler "call\[ \t\]+\\*mcount@GOTPCREL\\(" { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler "call\[ \t\]+\\*mcount@GOT\\(" { target ia32 } } } */ + + +int +main () +{ + return 0; +} diff --git a/gcc/testsuite/gcc.target/i386/pr119386-3.c b/gcc/testsuite/gcc.target/i386/pr119386-3.c new file mode 100644 index 0000000..287410b --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr119386-3.c @@ -0,0 +1,10 @@ +/* PR target/119386 */ +/* { dg-do compile { target *-*-linux* } } */ +/* { dg-options "-O2 -fpic -pg -mnop-mcount" } */ +/* { dg-final { scan-assembler ".byte\[ \t\]+0x0f, 0x1f, 0x44, 0x00, 0x00" } } */ + +int +main () +{ + return 0; +} diff --git a/gcc/testsuite/gcc.target/i386/pr119784a.c b/gcc/testsuite/gcc.target/i386/pr119784a.c new file mode 100644 index 0000000..8a119d4 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr119784a.c @@ -0,0 +1,96 @@ +/* { dg-do compile { target { *-*-linux* && lp64 } } } */ +/* { dg-options "-O2 -fno-pic -mtune=generic -mgeneral-regs-only -mapxf -mtune-ctrl=prologue_using_move,epilogue_using_move" } */ +/* Keep labels and directives ('.cfi_startproc', '.cfi_endproc'). */ +/* { dg-final { check-function-bodies "**" "" "" { target "*-*-*" } {^\t?\.} } } */ + +/* start must save and restore all caller saved registers. */ + +/* +**start: +**.LFB[0-9]+: +** .cfi_startproc +** subq \$248, %rsp +**... +** movq %rax, \(%rsp\) +** movq %rdx, 8\(%rsp\) +** movq %rcx, 16\(%rsp\) +** movq %rbx, 24\(%rsp\) +** movq %rsi, 32\(%rsp\) +** movq %rdi, 40\(%rsp\) +**... +** movq %rbp, 48\(%rsp\) +** movq %r8, 56\(%rsp\) +** movq %r9, 64\(%rsp\) +** movq %r10, 72\(%rsp\) +** movq %r11, 80\(%rsp\) +** movq %r12, 88\(%rsp\) +** movq %r13, 96\(%rsp\) +** movq %r14, 104\(%rsp\) +** movq %r15, 112\(%rsp\) +** movq %r16, 120\(%rsp\) +** movq %r17, 128\(%rsp\) +** movq %r18, 136\(%rsp\) +** movq %r19, 144\(%rsp\) +** movq %r20, 152\(%rsp\) +** movq %r21, 160\(%rsp\) +** movq %r22, 168\(%rsp\) +** movq %r23, 176\(%rsp\) +** movq %r24, 184\(%rsp\) +** movq %r25, 192\(%rsp\) +** movq %r26, 200\(%rsp\) +** movq %r27, 208\(%rsp\) +** movq %r28, 216\(%rsp\) +** movq %r29, 224\(%rsp\) +** movq %r30, 232\(%rsp\) +** movq %r31, 240\(%rsp\) +**... +** call \*code\(%rip\) +** movq \(%rsp\), %rax +** movq 8\(%rsp\), %rdx +** movq 16\(%rsp\), %rcx +** movq 24\(%rsp\), %rbx +** movq 32\(%rsp\), %rsi +** movq 40\(%rsp\), %rdi +** movq 48\(%rsp\), %rbp +** movq 56\(%rsp\), %r8 +** movq 64\(%rsp\), %r9 +** movq 72\(%rsp\), %r10 +** movq 80\(%rsp\), %r11 +** movq 88\(%rsp\), %r12 +** movq 96\(%rsp\), %r13 +** movq 104\(%rsp\), %r14 +** movq 112\(%rsp\), %r15 +** movq 120\(%rsp\), %r16 +** movq 128\(%rsp\), %r17 +** movq 136\(%rsp\), %r18 +** movq 144\(%rsp\), %r19 +** movq 152\(%rsp\), %r20 +** movq 160\(%rsp\), %r21 +** movq 168\(%rsp\), %r22 +** movq 176\(%rsp\), %r23 +** movq 184\(%rsp\), %r24 +** movq 192\(%rsp\), %r25 +** movq 200\(%rsp\), %r26 +** movq 208\(%rsp\), %r27 +** movq 216\(%rsp\), %r28 +** movq 224\(%rsp\), %r29 +** movq 232\(%rsp\), %r30 +** movq 240\(%rsp\), %r31 +** addq \$248, %rsp +**... +** ret +** .cfi_endproc +**... +*/ + +#define DONT_SAVE_REGS __attribute__((no_callee_saved_registers)) +#define SAVE_REGS __attribute__((no_caller_saved_registers)) + +typedef DONT_SAVE_REGS void (*op_t)(void); + +extern op_t code[]; + +SAVE_REGS void start() +{ + code[0](); +} diff --git a/gcc/testsuite/gcc.target/i386/pr119784b.c b/gcc/testsuite/gcc.target/i386/pr119784b.c new file mode 100644 index 0000000..c676197 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr119784b.c @@ -0,0 +1,87 @@ +/* { dg-do compile { target { *-*-linux* && x32 } } } */ +/* { dg-options "-O2 -fno-pic -mtune=generic -mgeneral-regs-only -mapxf -mtune-ctrl=prologue_using_move,epilogue_using_move" } */ +/* Keep labels and directives ('.cfi_startproc', '.cfi_endproc'). */ +/* { dg-final { check-function-bodies "**" "" "" { target "*-*-*" } {^\t?\.} } } */ + +/* start must save and restore all caller saved registers. */ + +/* +**start: +**.LFB[0-9]+: +** .cfi_startproc +** subl \$248, %esp +**... +** movq %rax, \(%rsp\) +** movq %rdx, 8\(%rsp\) +** movq %rcx, 16\(%rsp\) +** movq %rbx, 24\(%rsp\) +** movq %rsi, 32\(%rsp\) +** movq %rdi, 40\(%rsp\) +**... +** movq %rbp, 48\(%rsp\) +** movq %r8, 56\(%rsp\) +** movq %r9, 64\(%rsp\) +** movq %r10, 72\(%rsp\) +** movq %r11, 80\(%rsp\) +** movq %r12, 88\(%rsp\) +** movq %r13, 96\(%rsp\) +** movq %r14, 104\(%rsp\) +** movq %r15, 112\(%rsp\) +** movq %r16, 120\(%rsp\) +** movq %r17, 128\(%rsp\) +** movq %r18, 136\(%rsp\) +** movq %r19, 144\(%rsp\) +** movq %r20, 152\(%rsp\) +** movq %r21, 160\(%rsp\) +** movq %r22, 168\(%rsp\) +** movq %r23, 176\(%rsp\) +** movq %r24, 184\(%rsp\) +** movq %r25, 192\(%rsp\) +** movq %r26, 200\(%rsp\) +** movq %r27, 208\(%rsp\) +** movq %r28, 216\(%rsp\) +** movq %r29, 224\(%rsp\) +** movq %r30, 232\(%rsp\) +** movq %r31, 240\(%rsp\) +**... +** movl code\(%rip\), %ebp +** call \*%rbp +** movq \(%rsp\), %rax +** movq 8\(%rsp\), %rdx +** movq 16\(%rsp\), %rcx +** movq 24\(%rsp\), %rbx +** movq 32\(%rsp\), %rsi +** movq 40\(%rsp\), %rdi +** movq 48\(%rsp\), %rbp +** movq 56\(%rsp\), %r8 +** movq 64\(%rsp\), %r9 +** movq 72\(%rsp\), %r10 +** movq 80\(%rsp\), %r11 +** movq 88\(%rsp\), %r12 +** movq 96\(%rsp\), %r13 +** movq 104\(%rsp\), %r14 +** movq 112\(%rsp\), %r15 +** movq 120\(%rsp\), %r16 +** movq 128\(%rsp\), %r17 +** movq 136\(%rsp\), %r18 +** movq 144\(%rsp\), %r19 +** movq 152\(%rsp\), %r20 +** movq 160\(%rsp\), %r21 +** movq 168\(%rsp\), %r22 +** movq 176\(%rsp\), %r23 +** movq 184\(%rsp\), %r24 +** movq 192\(%rsp\), %r25 +** movq 200\(%rsp\), %r26 +** movq 208\(%rsp\), %r27 +** movq 216\(%rsp\), %r28 +** movq 224\(%rsp\), %r29 +** movq 232\(%rsp\), %r30 +** movq 240\(%rsp\), %r31 +** addl \$248, %esp +**... +** ret +** .cfi_endproc +**... +*/ + +#include "pr119784a.c" diff --git a/gcc/testsuite/gcc.target/i386/recip-vec-divf-fma.c b/gcc/testsuite/gcc.target/i386/recip-vec-divf-fma.c new file mode 100644 index 0000000..ad9e07b --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/recip-vec-divf-fma.c @@ -0,0 +1,12 @@ +/* { dg-do compile } */ +/* { dg-options "-Ofast -mfma -mavx2" } */ +/* { dg-final { scan-assembler-times {(?n)vfn?m(add|sub)[1-3]*ps} 2 } } */ + +typedef float v4sf __attribute__((vector_size(16))); +/* (a - (rcp(b) * a * b)) * rcp(b) + rcp(b) * a */ + +v4sf +foo (v4sf a, v4sf b) +{ + return a / b; +} diff --git a/gcc/testsuite/gcc.target/loongarch/vector/loongarch-vector.exp b/gcc/testsuite/gcc.target/loongarch/vector/loongarch-vector.exp index f56d2f1..9df3f29 100644 --- a/gcc/testsuite/gcc.target/loongarch/vector/loongarch-vector.exp +++ b/gcc/testsuite/gcc.target/loongarch/vector/loongarch-vector.exp @@ -35,7 +35,7 @@ dg-init # If the target hardware supports LSX, the default action is "run", otherwise # just "compile". -global dg-do-what-default +set saved-dg-do-what-default ${dg-do-what-default} if {[check_effective_target_loongarch_sx_hw]} then { set dg-do-what-default run } else { @@ -45,6 +45,7 @@ if {[check_effective_target_loongarch_sx_hw]} then { #Main loop. dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/lsx/*.\[cS\]]] \ " -mlsx" $DEFAULT_CFLAGS +set dg-do-what-default ${saved-dg-do-what-default} dg-finish @@ -52,7 +53,7 @@ dg-init # If the target hardware supports LASX, the default action is "run", otherwise # just "compile". -global dg-do-what-default +set saved-dg-do-what-default ${dg-do-what-default} if {[check_effective_target_loongarch_asx_hw]} then { set dg-do-what-default run } else { @@ -61,5 +62,6 @@ if {[check_effective_target_loongarch_asx_hw]} then { dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/lasx/*.\[cS\]]] \ " -mlasx" $DEFAULT_CFLAGS +set dg-do-what-default ${saved-dg-do-what-default} # All done. dg-finish diff --git a/gcc/testsuite/gcc.target/mips/clear-cache-1.c b/gcc/testsuite/gcc.target/mips/clear-cache-1.c index f1554f5..cd11c66 100644 --- a/gcc/testsuite/gcc.target/mips/clear-cache-1.c +++ b/gcc/testsuite/gcc.target/mips/clear-cache-1.c @@ -1,7 +1,7 @@ /* { dg-do compile } */ /* { dg-options "-msynci isa_rev>=2" } */ /* { dg-final { scan-assembler "\tsynci\t" } } */ -/* { dg-final { scan-assembler "\tjr.hb\t" } } */ +/* { dg-final { scan-assembler "\tjrc?.hb\t" } } */ /* { dg-final { scan-assembler-not "_flush_cache|mips_sync_icache|_cacheflush" } } */ NOMIPS16 void f() diff --git a/gcc/testsuite/gcc.target/mips/memcpy-2.c b/gcc/testsuite/gcc.target/mips/memcpy-2.c new file mode 100644 index 0000000..df0cd18 --- /dev/null +++ b/gcc/testsuite/gcc.target/mips/memcpy-2.c @@ -0,0 +1,12 @@ +/* { dg-do compile } */ +/* { dg-options "isa_rev<=5 -fdump-rtl-expand" } */ +/* { dg-skip-if "code quality test" { *-*-* } { "-Os" } { "" } } */ + +__attribute__((nomips16)) +void +f1 (char *p) +{ + __builtin_memcpy (p, "12345", 5); +} + +/* { dg-final { scan-rtl-dump "mem/u.*mem/u" "expand" } } */ diff --git a/gcc/testsuite/gcc.target/powerpc/power11-3.c b/gcc/testsuite/gcc.target/powerpc/power11-3.c index fa1aedd..56bf881 100644 --- a/gcc/testsuite/gcc.target/powerpc/power11-3.c +++ b/gcc/testsuite/gcc.target/powerpc/power11-3.c @@ -1,5 +1,6 @@ /* { dg-do compile } */ /* { dg-options "-mdejagnu-cpu=power8 -O2" } */ +/* { dg-require-ifunc "" } */ /* Check if we can set the power11 target via a target_clones attribute. */ diff --git a/gcc/testsuite/gcc.target/riscv/bext-ext-2.c b/gcc/testsuite/gcc.target/riscv/bext-ext-2.c new file mode 100644 index 0000000..aa170d0 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/bext-ext-2.c @@ -0,0 +1,74 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gcb -mabi=lp64" } */ +/* { dg-skip-if "" { *-*-* } { "-O0" } } */ + +struct obstack; +struct bitmap_head_def; +typedef struct bitmap_head_def *bitmap; +struct obstack +{ + long chunk_size; + struct _obstack_chunk *chunk; + char *object_base; + char *next_free; + char *chunk_limit; + long int temp; + int alignment_mask; + + + + struct _obstack_chunk *(*chunkfun) (void *, long); + void (*freefun) (void *, struct _obstack_chunk *); + void *extra_arg; + unsigned use_extra_arg:1; + unsigned maybe_empty_object:1; + + + + unsigned alloc_failed:1; + + +}; + +typedef unsigned long BITMAP_WORD; +typedef struct bitmap_obstack { + struct bitmap_element_def *elements; + struct bitmap_head_def *heads; + struct obstack obstack; +} bitmap_obstack; +typedef struct bitmap_element_def { + struct bitmap_element_def *next; + struct bitmap_element_def *prev; + unsigned int indx; + BITMAP_WORD bits[((128 + (8 + * 8 * 1u) - 1) / (8 + * 8 * 1u))]; +} bitmap_element; +bitmap_element *bitmap_find_bit (bitmap, unsigned int); + + +int +bitmap_bit_p (bitmap head, int bit) +{ + bitmap_element *ptr; + unsigned bit_num; + unsigned word_num; + + ptr = bitmap_find_bit (head, bit); + if (ptr == 0) + return 0; + + bit_num = bit % (8 + * 8 * 1u); + word_num = bit / (8 + * 8 * 1u) % ((128 + (8 + * 8 * 1u) - 1) / (8 + * 8 * 1u)); + + return (ptr->bits[word_num] >> bit_num) & 1; +} + +/* { dg-final { scan-assembler-times "bext\t" 1 } } */ +/* { dg-final { scan-assembler-not "slr\t"} } */ +/* { dg-final { scan-assembler-not "andi\t"} } */ + diff --git a/gcc/testsuite/gcc.target/riscv/gnu-property-align-rv32.c b/gcc/testsuite/gcc.target/riscv/gnu-property-align-rv32.c new file mode 100644 index 0000000..4f48cff --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/gnu-property-align-rv32.c @@ -0,0 +1,7 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv32g_zicfiss -fcf-protection=return -mabi=ilp32d " } */ + +void foo() {} + +/* { dg-final { scan-assembler-times ".p2align\t2" 3 } } */ +/* { dg-final { scan-assembler-not ".p2align\t3" } } */ diff --git a/gcc/testsuite/gcc.target/riscv/gnu-property-align-rv64.c b/gcc/testsuite/gcc.target/riscv/gnu-property-align-rv64.c new file mode 100644 index 0000000..1bfd127 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/gnu-property-align-rv64.c @@ -0,0 +1,7 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64g_zicfiss -fcf-protection=return -mabi=lp64d " } */ + +void foo() {} + +/* { dg-final { scan-assembler-times ".p2align\t3" 3 } } */ +/* { dg-final { scan-assembler-not ".p2align\t2" } } */ diff --git a/gcc/testsuite/gcc.target/riscv/jump-table-large-code-model.c b/gcc/testsuite/gcc.target/riscv/jump-table-large-code-model.c new file mode 100644 index 0000000..1ee7f6c --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/jump-table-large-code-model.c @@ -0,0 +1,24 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gc -mabi=lp64 -mcmodel=large" } */ + +int foo(int x, int y) +{ + switch(x){ + case 0: + return 123 + y; + case 1: + return 456 + y; + case 2: + return 789 - y; + case 3: + return 12 * y; + case 4: + return 13 % y; + case 5: + return 11 *y; + } + return 0; +} + + +/* { dg-final { scan-assembler-not "\.section \.rodata" } } */ diff --git a/gcc/testsuite/gcc.target/riscv/pr108016.c b/gcc/testsuite/gcc.target/riscv/pr108016.c new file mode 100644 index 0000000..b60df42 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/pr108016.c @@ -0,0 +1,33 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gc -mabi=lp64" } */ +/* { dg-skip-if "" { *-*-* } { "-O0" } } */ + +unsigned int addu (unsigned int a, unsigned int b) +{ + unsigned int out; + unsigned int overflow = __builtin_add_overflow (a, b, &out); + return overflow & out; +} + +int addi (int a, int b) +{ + int out; + int overflow = __builtin_add_overflow (a, b, &out); + return overflow & out; +} + +unsigned int subu (unsigned int a, unsigned int b) +{ + unsigned int out; + unsigned int overflow = __builtin_sub_overflow (a, b, &out); + return overflow & out; +} + +int subi (int a, int b) +{ + int out; + int overflow = __builtin_sub_overflow (a, b, &out); + return overflow & out; +} + +/* { dg-final { scan-assembler-not "sext\.w\t" } } */ diff --git a/gcc/testsuite/gcc.target/riscv/pr118410-1.c b/gcc/testsuite/gcc.target/riscv/pr118410-1.c new file mode 100644 index 0000000..4a8b847 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/pr118410-1.c @@ -0,0 +1,9 @@ +/* { dg-do compile } */ +/* { dg-skip-if "" { *-*-* } { "-O0" "-Og" } } */ +/* { dg-options "-march=rv64gcb -mabi=lp64d" { target { rv64} } } */ +/* { dg-options "-march=rv32gcb -mabi=ilp32" { target { rv32} } } */ + +long orlow(long x) { return x | ((1L << 24) - 1); } + +/* { dg-final { scan-assembler-times "orn\t" 1 } } */ +/* { dg-final { scan-assembler-not "addi\t" } } */ diff --git a/gcc/testsuite/gcc.target/riscv/pr118410-2.c b/gcc/testsuite/gcc.target/riscv/pr118410-2.c new file mode 100644 index 0000000..b63a1d9 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/pr118410-2.c @@ -0,0 +1,9 @@ +/* { dg-do compile } */ +/* { dg-skip-if "" { *-*-* } { "-O0" "-Og" } } */ +/* { dg-options "-march=rv64gcb -mabi=lp64d" { target { rv64} } } */ +/* { dg-options "-march=rv32gcb -mabi=ilp32" { target { rv32} } } */ + +long xorlow(long x) { return x ^ ((1L << 24) - 1); } + +/* { dg-final { scan-assembler-times "xnor\t" 1 } } */ +/* { dg-final { scan-assembler-not "addi\t" } } */ 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 bf95e1c..64666d3 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,12 @@ void f2 (void * restrict in, void * restrict out, int l, int n, int m) } } +/* The second check is XFAILed because we currently don't lift + vsetvls into non-transparent (in LCM parlance) blocks. + See PR119547. + In this test it is still possible because the conflicting + register only ever feeds vsetvls. */ + /* { 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 {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" } xfail { *-*-* } } } } */ /* { 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/vlmax_switch_vtype-10.c b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-10.c index ddf53ca..0dbf34a 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-10.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-10.c @@ -43,6 +43,6 @@ void foo (int8_t * restrict in, int8_t * restrict out, int n, int cond) } } -/* { dg-final { scan-assembler-times {vsetvli} 15 { target { no-opts "-O0" no-opts "-O1" no-opts "-Os" no-opts "-Oz" no-opts "-funroll-loops" no-opts "-g" no-opts "-flto" } } } } */ +/* { dg-final { scan-assembler-times {vsetvli} 14 { target { no-opts "-O0" no-opts "-O1" no-opts "-Os" no-opts "-Oz" no-opts "-funroll-loops" no-opts "-g" no-opts "-flto" } } } } */ /* { 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*e16,\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+[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" } } } } */ diff --git a/gcc/testsuite/gcc.target/sh/pr111814.c b/gcc/testsuite/gcc.target/sh/pr111814.c new file mode 100644 index 0000000..a88e5d7 --- /dev/null +++ b/gcc/testsuite/gcc.target/sh/pr111814.c @@ -0,0 +1,7 @@ +/* Verify that __builtin_nan("") produces a constant matches + architecture specification. */ +/* { dg-do compile } */ + +double d = __builtin_nan (""); + +/* { dg-final { scan-assembler "\t.long\t-1\n\t.long\t2146959359\n" } } */ diff --git a/gcc/testsuite/gdc.dg/debug/imports/m119817/a.d b/gcc/testsuite/gdc.dg/debug/imports/m119817/a.d new file mode 100644 index 0000000..a137472 --- /dev/null +++ b/gcc/testsuite/gdc.dg/debug/imports/m119817/a.d @@ -0,0 +1,2 @@ +module imports.m119817.a; +void f119817()() { } diff --git a/gcc/testsuite/gdc.dg/debug/imports/m119817/b.d b/gcc/testsuite/gdc.dg/debug/imports/m119817/b.d new file mode 100644 index 0000000..aef0e37 --- /dev/null +++ b/gcc/testsuite/gdc.dg/debug/imports/m119817/b.d @@ -0,0 +1,2 @@ +module imports.m119817.b; +void f119817() { } diff --git a/gcc/testsuite/gdc.dg/debug/imports/m119817/package.d b/gcc/testsuite/gdc.dg/debug/imports/m119817/package.d new file mode 100644 index 0000000..188827e --- /dev/null +++ b/gcc/testsuite/gdc.dg/debug/imports/m119817/package.d @@ -0,0 +1,4 @@ +module imports.m119817; +public import + imports.m119817.a, + imports.m119817.b; diff --git a/gcc/testsuite/gdc.dg/debug/imports/pr119826b.d b/gcc/testsuite/gdc.dg/debug/imports/pr119826b.d new file mode 100644 index 0000000..3c5a6ac --- /dev/null +++ b/gcc/testsuite/gdc.dg/debug/imports/pr119826b.d @@ -0,0 +1,14 @@ +module imports.pr119826b; + +import pr119826 : t119826; + +class C119826 +{ + enum E119826 { Evalue } + const E119826 em = void; +} + +void f119826(C119826 c) +{ + t119826(c.em); +} diff --git a/gcc/testsuite/gdc.dg/debug/pr119817.d b/gcc/testsuite/gdc.dg/debug/pr119817.d new file mode 100644 index 0000000..3eea6ba --- /dev/null +++ b/gcc/testsuite/gdc.dg/debug/pr119817.d @@ -0,0 +1,6 @@ +// { dg-do compile } +// { dg-additional-sources "imports/m119817/package.d" } +// { dg-additional-sources "imports/m119817/a.d" } +// { dg-additional-sources "imports/m119817/b.d" } +module pr119817; +import imports.m119817 : f119817; diff --git a/gcc/testsuite/gdc.dg/debug/pr119826.d b/gcc/testsuite/gdc.dg/debug/pr119826.d new file mode 100644 index 0000000..2fb98c7 --- /dev/null +++ b/gcc/testsuite/gdc.dg/debug/pr119826.d @@ -0,0 +1,8 @@ +// { dg-do compile } +// { dg-additional-sources "imports/pr119826b.d" } +module pr119826; + +int t119826(A)(A args) +{ + assert(false); +} diff --git a/gcc/testsuite/gdc.dg/import-c/import-c.exp b/gcc/testsuite/gdc.dg/import-c/import-c.exp new file mode 100644 index 0000000..53d1478 --- /dev/null +++ b/gcc/testsuite/gdc.dg/import-c/import-c.exp @@ -0,0 +1,29 @@ +# Copyright (C) 2025 Free Software Foundation, Inc. + +# This program 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 of the License, or +# (at your option) any later version. +# +# This program 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 +# <http://www.gnu.org/licenses/>. + +# Load support procs. +load_lib gdc-dg.exp + +# Initialize `dg'. +dg-init + +# Main loop. +gdc-dg-runtest [lsort \ + [glob -nocomplain $srcdir/$subdir/*.d ] ] "" \ + "-I $srcdir/$subdir -finclude-imports" + +# All done. +dg-finish diff --git a/gcc/testsuite/gdc.dg/import-c/pr119761.d b/gcc/testsuite/gdc.dg/import-c/pr119761.d new file mode 100644 index 0000000..20eff31 --- /dev/null +++ b/gcc/testsuite/gdc.dg/import-c/pr119761.d @@ -0,0 +1,2 @@ +// { dg-do compile } +import pr119761c; diff --git a/gcc/testsuite/gdc.dg/import-c/pr119761c.c b/gcc/testsuite/gdc.dg/import-c/pr119761c.c new file mode 100644 index 0000000..522f1bf --- /dev/null +++ b/gcc/testsuite/gdc.dg/import-c/pr119761c.c @@ -0,0 +1,4 @@ +int f119761(const char *, ...) +{ + return 0; +} diff --git a/gcc/testsuite/gdc.dg/import-c/pr119799.d b/gcc/testsuite/gdc.dg/import-c/pr119799.d new file mode 100644 index 0000000..d8b0fa2 --- /dev/null +++ b/gcc/testsuite/gdc.dg/import-c/pr119799.d @@ -0,0 +1,2 @@ +// { dg-do compile } +import pr119799c; diff --git a/gcc/testsuite/gdc.dg/import-c/pr119799c.c b/gcc/testsuite/gdc.dg/import-c/pr119799c.c new file mode 100644 index 0000000..b80e856 --- /dev/null +++ b/gcc/testsuite/gdc.dg/import-c/pr119799c.c @@ -0,0 +1 @@ +static struct {} s119799; diff --git a/gcc/testsuite/gdc.dg/torture/imports/pr109023.d b/gcc/testsuite/gdc.dg/torture/imports/pr109023.d new file mode 100644 index 0000000..e85e0ed --- /dev/null +++ b/gcc/testsuite/gdc.dg/torture/imports/pr109023.d @@ -0,0 +1,3 @@ +module imports.pr109023; + +void f109023() { } diff --git a/gcc/testsuite/gdc.dg/torture/pr109023.d b/gcc/testsuite/gdc.dg/torture/pr109023.d new file mode 100644 index 0000000..3060446 --- /dev/null +++ b/gcc/testsuite/gdc.dg/torture/pr109023.d @@ -0,0 +1,6 @@ +// { dg-do "compile" } +// { dg-additional-options "-I[srcdir] -finclude-imports" } +// { dg-additional-files "imports/pr109023.d" } +// { dg-final { scan-assembler "_D7imports8pr1090237f109023FZv" } } +module pr109023; +import imports.pr109023; diff --git a/gcc/testsuite/gdc.test/fail_compilation/test21247.d b/gcc/testsuite/gdc.test/fail_compilation/test21247.d new file mode 100644 index 0000000..c3e4105 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/test21247.d @@ -0,0 +1,20 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/test21247.d(13): Error: anonymous union can only be a part of an aggregate, not function `hang_dmd` +fail_compilation/test21247.d(17): Error: undefined identifier `u` +fail_compilation/test21247.d(18): Error: undefined identifier `b` +fail_compilation/test21247.d(20): called from here: `hang_dmd(0u)` +--- + */ +// https://github.com/dlang/dmd/issues/21247 +ubyte[4] hang_dmd(uint a) +{ + union { + uint u = void; + ubyte[4] b; + } + u = a; + return b; +} +enum T = hang_dmd(0); diff --git a/gcc/testsuite/gdc.test/fail_compilation/test21247b.d b/gcc/testsuite/gdc.test/fail_compilation/test21247b.d new file mode 100644 index 0000000..ecd4603 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/test21247b.d @@ -0,0 +1,14 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/test21247b.d(10): Error: anonymous union can only be a part of an aggregate, not function `test21247` +--- + */ +// https://github.com/dlang/dmd/issues/21247 +void test21247() +{ + union { + uint u = void; + ubyte[4] b; + } +} diff --git a/gcc/testsuite/gfortran.dg/do_concurrent_all_clauses.f90 b/gcc/testsuite/gfortran.dg/do_concurrent_all_clauses.f90 index 0c8a6ad..a7fa7c3 100644 --- a/gcc/testsuite/gfortran.dg/do_concurrent_all_clauses.f90 +++ b/gcc/testsuite/gfortran.dg/do_concurrent_all_clauses.f90 @@ -18,7 +18,7 @@ program do_concurrent_all_clauses squared = i * i arr(i) = temp2 + squared sum = sum + arr(i) - max_val = max(max_val, arr(i)) ! { dg-error "Reference to impure function" } + max_val = max(max_val, arr(i)) end block end do print *, arr, sum, max_val diff --git a/gcc/testsuite/gfortran.dg/gomp/map-alloc-comp-1.f90 b/gcc/testsuite/gfortran.dg/gomp/map-alloc-comp-1.f90 index 0c44296..f48addc 100644 --- a/gcc/testsuite/gfortran.dg/gomp/map-alloc-comp-1.f90 +++ b/gcc/testsuite/gfortran.dg/gomp/map-alloc-comp-1.f90 @@ -10,5 +10,5 @@ type sct end type type(sct) var -!$omp target enter data map(to:var) ! { dg-error "allocatable components is not permitted in map clause" } +!$omp target enter data map(to:var) end diff --git a/gcc/testsuite/gfortran.dg/gomp/polymorphic-mapping-1.f90 b/gcc/testsuite/gfortran.dg/gomp/polymorphic-mapping-1.f90 new file mode 100644 index 0000000..750cec9 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/gomp/polymorphic-mapping-1.f90 @@ -0,0 +1,30 @@ +type t + integer :: t +end type t +class(t), target, allocatable :: c, ca(:) +class(t), pointer :: p, pa(:) +integer :: x +allocate( t :: c, ca(5)) +p => c +pa => ca + +! 11111111112222222222333333333344 +!2345678901234567890123456789012345678901 +!$omp target enter data map(c, ca, p, pa) +! { dg-warning "29:Mapping of polymorphic list item 'c' is unspecified behavior \\\[-Wopenmp\\\]" "" { target *-*-* } .-1 } +! { dg-warning "32:Mapping of polymorphic list item 'ca' is unspecified behavior \\\[-Wopenmp\\\]" "" { target *-*-* } .-2 } +! { dg-warning "36:Mapping of polymorphic list item 'p' is unspecified behavior \\\[-Wopenmp\\\]" "" { target *-*-* } .-3 } +! { dg-warning "39:Mapping of polymorphic list item 'pa' is unspecified behavior \\\[-Wopenmp\\\]" "" { target *-*-* } .-4 } + +! 11111111112222222222333333333344 +!2345678901234567890123456789012345678901 + +! 11111111112222222222333333333344 +!2345678901234567890123456789012345678901 +!$omp target update from(c,ca), to(p,pa) +! { dg-warning "26:Mapping of polymorphic list item 'c' is unspecified behavior \\\[-Wopenmp\\\]" "" { target *-*-* } .-1 } +! { dg-warning "28:Mapping of polymorphic list item 'ca' is unspecified behavior \\\[-Wopenmp\\\]" "" { target *-*-* } .-2 } +! { dg-warning "36:Mapping of polymorphic list item 'p' is unspecified behavior \\\[-Wopenmp\\\]" "" { target *-*-* } .-3 } +! { dg-warning "38:Mapping of polymorphic list item 'pa' is unspecified behavior \\\[-Wopenmp\\\]" "" { target *-*-* } .-4 } + +end diff --git a/gcc/testsuite/gfortran.dg/gomp/polymorphic-mapping-2.f90 b/gcc/testsuite/gfortran.dg/gomp/polymorphic-mapping-2.f90 index e25db68..3bedc9b 100644 --- a/gcc/testsuite/gfortran.dg/gomp/polymorphic-mapping-2.f90 +++ b/gcc/testsuite/gfortran.dg/gomp/polymorphic-mapping-2.f90 @@ -9,7 +9,7 @@ allocate( t :: c, ca(5)) p => c pa => ca -!$omp target ! { dg-warning "Implicit mapping of polymorphic variable 'ca' is unspecified behavior \\\[-Wopenmp\\\]" } +!$omp target ! { dg-warning "Mapping of polymorphic list item 'ca' is unspecified behavior \\\[-Wopenmp\\\]" } ll = allocated(ca) !$omp end target diff --git a/gcc/testsuite/gfortran.dg/gomp/polymorphic-mapping-3.f90 b/gcc/testsuite/gfortran.dg/gomp/polymorphic-mapping-3.f90 new file mode 100644 index 0000000..9777ecf --- /dev/null +++ b/gcc/testsuite/gfortran.dg/gomp/polymorphic-mapping-3.f90 @@ -0,0 +1,23 @@ +subroutine sub(var, var2) +type t + integer :: x +end type t + +type t2 + integer :: x + integer, allocatable :: y +end type + +class(t) var, var2 +type(t2) :: var3, var4 +!$omp target firstprivate(var) & ! { dg-error "Polymorphic list item 'var' at .1. in FIRSTPRIVATE clause has unspecified behavior and unsupported" } +!$omp& private(var2) ! { dg-error "Polymorphic list item 'var2' at .1. in PRIVATE clause has unspecified behavior and unsupported" } + var%x = 5 + var2%x = 5 +!$omp end target +!$omp target firstprivate(var3) & ! { dg-error "Sorry, list item 'var3' at .1. with allocatable components is not yet supported in FIRSTPRIVATE clause" } +!$omp& private(var4) ! { dg-error "Sorry, list item 'var4' at .1. with allocatable components is not yet supported in PRIVATE clause" } + var3%x = 5 + var4%x = 5 +!$omp end target +end diff --git a/gcc/testsuite/gfortran.dg/gomp/polymorphic-mapping-4.f90 b/gcc/testsuite/gfortran.dg/gomp/polymorphic-mapping-4.f90 new file mode 100644 index 0000000..5a1a70a --- /dev/null +++ b/gcc/testsuite/gfortran.dg/gomp/polymorphic-mapping-4.f90 @@ -0,0 +1,9 @@ +subroutine one +implicit none +type t + class(*), allocatable :: ul +end type + +type(t) :: var +!$omp target enter data map(to:var) ! { dg-error "Mapping of unlimited polymorphic list item 'var.ul' is unspecified behavior and unsupported" } +end diff --git a/gcc/testsuite/gfortran.dg/gomp/polymorphic-mapping-5.f90 b/gcc/testsuite/gfortran.dg/gomp/polymorphic-mapping-5.f90 new file mode 100644 index 0000000..4b5814e --- /dev/null +++ b/gcc/testsuite/gfortran.dg/gomp/polymorphic-mapping-5.f90 @@ -0,0 +1,9 @@ +subroutine one +implicit none +type t + class(*), allocatable :: ul +end type + +class(*), allocatable :: ul_var +!$omp target enter data map(to: ul_var) ! { dg-error "Mapping of unlimited polymorphic list item 'ul_var' is unspecified behavior and unsupported" } +end diff --git a/gcc/testsuite/gfortran.dg/gomp/polymorphic-mapping.f90 b/gcc/testsuite/gfortran.dg/gomp/polymorphic-mapping.f90 index dd7eb31..752cca2 100644 --- a/gcc/testsuite/gfortran.dg/gomp/polymorphic-mapping.f90 +++ b/gcc/testsuite/gfortran.dg/gomp/polymorphic-mapping.f90 @@ -10,37 +10,21 @@ pa => ca ! 11111111112222222222333333333344 !2345678901234567890123456789012345678901 -!$omp target enter data map(c, ca, p, pa) -! { dg-warning "29:Mapping polymorphic list item at .1. is unspecified behavior \\\[-Wopenmp\\\]" "" { target *-*-* } .-1 } -! { dg-warning "32:Mapping polymorphic list item at .1. is unspecified behavior \\\[-Wopenmp\\\]" "" { target *-*-* } .-2 } -! { dg-warning "36:Mapping polymorphic list item at .1. is unspecified behavior \\\[-Wopenmp\\\]" "" { target *-*-* } .-3 } -! { dg-warning "39:Mapping polymorphic list item at .1. is unspecified behavior \\\[-Wopenmp\\\]" "" { target *-*-* } .-4 } - -! 11111111112222222222333333333344 -!2345678901234567890123456789012345678901 -!$omp target firstprivate(ca) ! { dg-warning "27:FIRSTPRIVATE with polymorphic list item at .1. is unspecified behavior \\\[-Wopenmp\\\]" } +!$omp target firstprivate(ca) ! { dg-error "27:Polymorphic list item 'ca' at .1. in FIRSTPRIVATE clause has unspecified behavior and unsupported" } !$omp end target -!$omp target parallel do firstprivate(ca) ! { dg-warning "39:FIRSTPRIVATE with polymorphic list item at .1. is unspecified behavior \\\[-Wopenmp\\\]" } +!$omp target parallel do firstprivate(ca) ! { dg-error "39:Polymorphic list item 'ca' at .1. in FIRSTPRIVATE clause has unspecified behavior and unsupported" } do x = 0, 5 end do -!$omp target parallel do private(ca) ! OK; should map declared type +!$omp target parallel do private(ca) ! { dg-error "34:Polymorphic list item 'ca' at .1. in PRIVATE clause has unspecified behavior and unsupported" } do x = 0, 5 end do -!$omp target private(ca) ! OK; should map declared type +!$omp target private(ca) ! { dg-error "22:Polymorphic list item 'ca' at .1. in PRIVATE clause has unspecified behavior and unsupported" } block end block -! 11111111112222222222333333333344 -!2345678901234567890123456789012345678901 -!$omp target update from(c,ca), to(p,pa) -! { dg-warning "26:Mapping polymorphic list item at .1. is unspecified behavior \\\[-Wopenmp\\\]" "" { target *-*-* } .-1 } -! { dg-warning "28:Mapping polymorphic list item at .1. is unspecified behavior \\\[-Wopenmp\\\]" "" { target *-*-* } .-2 } -! { dg-warning "36:Mapping polymorphic list item at .1. is unspecified behavior \\\[-Wopenmp\\\]" "" { target *-*-* } .-3 } -! { dg-warning "38:Mapping polymorphic list item at .1. is unspecified behavior \\\[-Wopenmp\\\]" "" { target *-*-* } .-4 } - ! ------------------------- !$omp target parallel map(release: x) ! { dg-error "36:TARGET with map-type other than TO, FROM, TOFROM, or ALLOC on MAP clause" } diff --git a/gcc/testsuite/gfortran.dg/interface_59.f90 b/gcc/testsuite/gfortran.dg/interface_59.f90 new file mode 100644 index 0000000..c9ccd67 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/interface_59.f90 @@ -0,0 +1,15 @@ +! { dg-do compile } +! PR fortran/119669 - this used to generate an ICE. + +program a + implicit real(a-h,o-z) + external abstract_caller, caller, func +! real func + call abstract_caller (caller, func, 1.5) + call abstract_caller (caller, func, 1.5) +end program a + +function func (x) + real func, x + func = x * x - 1. +end diff --git a/gcc/testsuite/gfortran.dg/pr119502.f90 b/gcc/testsuite/gfortran.dg/pr119502.f90 new file mode 100644 index 0000000..80d7c61 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/pr119502.f90 @@ -0,0 +1,15 @@ +! { dg-do run } + +! PR119502, negative unit numbers are not allowed without using NEWUNIT + +program foo + integer :: iun = -1 + integer :: ios + open (iun, iostat=ios) + if (ios == 0) stop 1 + write(iun,*, iostat=ios) "This is a test." + if (ios == 0) stop 2 + close (iun, iostat=ios) + if (ios == 0) stop 3 +end + diff --git a/gcc/testsuite/gfortran.dg/pr119836_1.f90 b/gcc/testsuite/gfortran.dg/pr119836_1.f90 new file mode 100644 index 0000000..984e2d0 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/pr119836_1.f90 @@ -0,0 +1,18 @@ +! +! { dg-do run } +! +! PR fortran/119836 +! +program p + implicit none + integer, parameter :: n = 4 + integer :: i + integer :: y(n), x(n) + do concurrent (i=1:n) + x(i) = shiftl (i,1) ! accepted + block + y(i) = shiftl (i,1) ! wrongly rejected + end block + end do + if (any(x /= y)) stop 1 +end program p diff --git a/gcc/testsuite/gfortran.dg/pr119836_2.f90 b/gcc/testsuite/gfortran.dg/pr119836_2.f90 new file mode 100644 index 0000000..5e2d0c9 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/pr119836_2.f90 @@ -0,0 +1,21 @@ +! +! { dg-do compile } +! +! PR fortran/119836 +! +! Although intrinsic functions contained within the Fortran standard +! are pure procedures, many of the additional intrinsic functions +! supplied in libgfortran are impure. RAND() is one such function. +! +program foo + implicit none + integer i + real x(4) + do concurrent (i=1:4) + x = rand() ! { dg-error "Reference to impure function" } + block + x = rand() ! { dg-error "Reference to impure function" } + end block + end do + print *, x +end program foo diff --git a/gcc/testsuite/gfortran.dg/pr119836_3.f90 b/gcc/testsuite/gfortran.dg/pr119836_3.f90 new file mode 100644 index 0000000..69a5fcf --- /dev/null +++ b/gcc/testsuite/gfortran.dg/pr119836_3.f90 @@ -0,0 +1,30 @@ +! +! { dg-do run } +! +! PR fortran/119836 +! +program p + implicit none + integer, parameter :: n = 4 + integer :: i + integer :: y(n), x(n) + x = [(i,i=1,n)] + do concurrent (i=1:n) + call bar(x, y) + end do + if (any(x /= y)) stop 1 + x = 2 * x + do concurrent (i=1:n) + block + call bar(x, y) + end block + end do + if (any(x /= y)) stop 1 + + contains + elemental subroutine bar(x, y) + integer, intent(in) :: x + integer, intent(out) :: y + y = x + end subroutine +end program p diff --git a/gcc/testsuite/gfortran.dg/pr119836_4.f90 b/gcc/testsuite/gfortran.dg/pr119836_4.f90 new file mode 100644 index 0000000..dc6f72b --- /dev/null +++ b/gcc/testsuite/gfortran.dg/pr119836_4.f90 @@ -0,0 +1,30 @@ +! +! { dg-do compile } +! +! PR fortran/119836 +! +program p + implicit none + integer, parameter :: n = 4 + integer :: i + integer :: y(n), x(n) + x = [(i,i=1,n)] + do concurrent (i=1:n) + call bar(x, y) ! { dg-error "Subroutine call" } + end do + if (any(x /= y)) stop 1 + x = 2 * x + do concurrent (i=1:n) + block + call bar(x, y) ! { dg-error "Subroutine call" } + end block + end do + if (any(x /= y)) stop 1 + + contains + subroutine bar(x, y) + integer, intent(in) :: x(:) + integer, intent(out) :: y(:) + y = x + end subroutine +end program p diff --git a/gcc/testsuite/gfortran.dg/pure_formal_proc_4.f90 b/gcc/testsuite/gfortran.dg/pure_formal_proc_4.f90 new file mode 100644 index 0000000..92640e2 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/pure_formal_proc_4.f90 @@ -0,0 +1,49 @@ +! { dg-do compile } +! PR fortran/106948 - check that passing of PURE procedures works +! +! Contributed by Jim Feng + +module a + implicit none + + interface new + pure module subroutine b(x, f) + integer, intent(inout) :: x + interface + pure function f(x) result(r) + real, intent(in) :: x + real :: r + end function f + end interface + end subroutine b + end interface new +end module a + +submodule(a) a_b + implicit none + +contains + module procedure b + x = int(f(real(x)) * 0.15) + end procedure b +end submodule a_b + +program test + use a + implicit none + + integer :: x + + x = 100 + call new(x, g) + print *, x + +contains + + pure function g(y) result(r) + real, intent(in) :: y + real :: r + + r = sqrt(y) + end function g +end program test diff --git a/gcc/testsuite/gm2.dg/doc/examples/pass/doc-examples-pass.exp b/gcc/testsuite/gm2.dg/doc/examples/pass/doc-examples-pass.exp new file mode 100644 index 0000000..0bfcea0 --- /dev/null +++ b/gcc/testsuite/gm2.dg/doc/examples/pass/doc-examples-pass.exp @@ -0,0 +1,18 @@ +# Compile tests, no torture testing. +# +# These tests should all pass. + +# Load support procs. +load_lib gm2-dg.exp + +gm2_init_pim4 $srcdir/$subdir + +# Initialize `dg'. +dg-init + +# Main loop. + +dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.mod]] "" "" + +# All done. +dg-finish diff --git a/gcc/testsuite/gm2.dg/doc/examples/pass/exampleadd.mod b/gcc/testsuite/gm2.dg/doc/examples/pass/exampleadd.mod new file mode 100644 index 0000000..84020a8 --- /dev/null +++ b/gcc/testsuite/gm2.dg/doc/examples/pass/exampleadd.mod @@ -0,0 +1,32 @@ +(* { dg-do assemble { target { x86_64-*-* } } } *) +(* { dg-options "-g" } *) + +MODULE exampleadd ; + +FROM libc IMPORT printf, exit ; + + +PROCEDURE Example (foo, bar: CARDINAL) : CARDINAL ; +VAR + myout: CARDINAL ; +BEGIN + ASM VOLATILE ("movl %1,%%eax; addl %2,%%eax; movl %%eax,%0" + : "=rm" (myout) (* outputs *) + : "rm" (foo), "rm" (bar) (* inputs *) + : "eax") ; (* we trash *) + RETURN( myout ) +END Example ; + + +VAR + a, b, c: CARDINAL ; +BEGIN + a := 1 ; + b := 2 ; + c := Example (a, b) ; + IF c # 3 + THEN + printf ("Example procedure function failed to return 3, seen %d", c) ; + exit (1) + END +END exampleadd. diff --git a/gcc/testsuite/gm2.dg/doc/examples/pass/exampleadd2.mod b/gcc/testsuite/gm2.dg/doc/examples/pass/exampleadd2.mod new file mode 100644 index 0000000..f25397f --- /dev/null +++ b/gcc/testsuite/gm2.dg/doc/examples/pass/exampleadd2.mod @@ -0,0 +1,32 @@ +(* { dg-do assemble { target { x86_64-*-* } } } *) +(* { dg-options "-g" } *) + +MODULE exampleadd2 ; + +FROM libc IMPORT printf, exit ; + + +PROCEDURE Example (foo, bar: CARDINAL) : CARDINAL ; +VAR + myout: CARDINAL ; +BEGIN + ASM VOLATILE ( + "movl %[left],%%eax; addl %[right],%%eax; movl %%eax,%[output]" + : [output] "=rm" (myout) (* outputs *) + : [left] "rm" (foo), [right] "rm" (bar) (* inputs *) + : "eax") ; (* we trash *) + RETURN( myout ) +END Example ; + +VAR + a, b, c: CARDINAL ; +BEGIN + a := 1 ; + b := 2 ; + c := Example (a, b) ; + IF c # 3 + THEN + printf ("Example procedure function failed to return 3, seen %d", c) ; + exit (1) + END +END exampleadd2. diff --git a/gcc/testsuite/gm2.dg/doc/examples/pass/hello.mod b/gcc/testsuite/gm2.dg/doc/examples/pass/hello.mod new file mode 100644 index 0000000..f9770ec --- /dev/null +++ b/gcc/testsuite/gm2.dg/doc/examples/pass/hello.mod @@ -0,0 +1,10 @@ +(* { dg-do run } *) +(* { dg-options "-g -fno-scaffold-dynamic" } *) + +MODULE hello ; + +FROM libc IMPORT printf ; + +BEGIN + printf ("hello world\n") +END hello. diff --git a/gcc/testsuite/gm2.dg/doc/examples/pass/hellopim.mod b/gcc/testsuite/gm2.dg/doc/examples/pass/hellopim.mod new file mode 100644 index 0000000..b7876cd --- /dev/null +++ b/gcc/testsuite/gm2.dg/doc/examples/pass/hellopim.mod @@ -0,0 +1,10 @@ +(* { dg-do run } *) +(* { dg-options "-g -fno-scaffold-dynamic" } *) + +MODULE hellopim ; + +FROM StrIO IMPORT WriteString, WriteLn ; + +BEGIN + WriteString ("hello world") ; WriteLn +END hellopim. diff --git a/gcc/testsuite/gnat.dg/lto29.adb b/gcc/testsuite/gnat.dg/lto29.adb new file mode 100644 index 0000000..44f556f --- /dev/null +++ b/gcc/testsuite/gnat.dg/lto29.adb @@ -0,0 +1,9 @@ +-- { dg-do run } +-- { dg-options "-O -flto" { target lto } } + +with Lto29_Pkg; + +procedure Lto29 is +begin + null; +end; diff --git a/gcc/testsuite/gnat.dg/lto29_pkg.ads b/gcc/testsuite/gnat.dg/lto29_pkg.ads new file mode 100644 index 0000000..6008dc5 --- /dev/null +++ b/gcc/testsuite/gnat.dg/lto29_pkg.ads @@ -0,0 +1,15 @@ +with Ada.Strings.Bounded; + +package Lto29_Pkg is + + package M is new Ada.Strings.Bounded.Generic_Bounded_Length (10); + + type T is new M.Bounded_String; + + Null_T : constant T; + +private + + Null_T : constant T := To_Bounded_String (""); + +end Lto29_Pkg; diff --git a/gcc/testsuite/gnat.dg/opt105.adb b/gcc/testsuite/gnat.dg/opt105.adb new file mode 100644 index 0000000..eb2c197 --- /dev/null +++ b/gcc/testsuite/gnat.dg/opt105.adb @@ -0,0 +1,30 @@ +-- { dg-do run } +-- { dg-options "-O" } + +with Opt105_Pkg; use Opt105_Pkg; + +procedure Opt105 is + + Val : constant Enum := + (if Enabled then (if Disabled then Two else One) else Three); + +begin + if Cond1 then + return; + end if; + + if Cond2 then + return; + end if; + + case Val is + when One => + raise Program_Error; + + when Two => + raise Constraint_Error; + + when Three => + null; + end case; +end; diff --git a/gcc/testsuite/gnat.dg/opt105_pkg.adb b/gcc/testsuite/gnat.dg/opt105_pkg.adb new file mode 100644 index 0000000..e00de94 --- /dev/null +++ b/gcc/testsuite/gnat.dg/opt105_pkg.adb @@ -0,0 +1,6 @@ +package body Opt105_Pkg is + + function Cond1 return Boolean is (False); + function Cond2 return Boolean is (False); + +end Opt105_Pkg; diff --git a/gcc/testsuite/gnat.dg/opt105_pkg.ads b/gcc/testsuite/gnat.dg/opt105_pkg.ads new file mode 100644 index 0000000..2b373b7 --- /dev/null +++ b/gcc/testsuite/gnat.dg/opt105_pkg.ads @@ -0,0 +1,11 @@ +package Opt105_Pkg is + + type Enum is (One, Two, Three); + + Enabled : Boolean := False; + Disabled : Boolean := False; + + function Cond1 return Boolean; + function Cond2 return Boolean; + +end Opt105_Pkg; diff --git a/gcc/testsuite/go.dg/pr119533-riscv-2.go b/gcc/testsuite/go.dg/pr119533-riscv-2.go new file mode 100644 index 0000000..ce3ffaf --- /dev/null +++ b/gcc/testsuite/go.dg/pr119533-riscv-2.go @@ -0,0 +1,42 @@ +// { dg-do compile { target riscv64*-*-* } } +// { dg-options "-O2 -march=rv64gcv -mabi=lp64d" } + +package ast + +type as struct { + bt []struct{} + an string +} + +func bj(a *as) string { + if b := a.bt; len(a.an) == 1 { + _ = b[0] + } + return a.an +} + +func MergePackageFiles(f map[string][]interface{}, g uint) []interface{} { + bl := make([]string, len(f)) + var bo []interface{} + bu := make(map[string]int) + for _, bm := range bl { + a := f[bm] + for _, d := range a { + if g != 0 { + if a, p := d.(*as); p { + n := bj(a) + if j, bp := bu[n]; bp { + _ = j + } + } + } + } + } + for _, bm := range bl { + _ = bm + } + for _, bm := range bl { + _ = f[bm] + } + return bo +} diff --git a/gcc/testsuite/go.dg/pr119533-riscv.go b/gcc/testsuite/go.dg/pr119533-riscv.go new file mode 100644 index 0000000..30f52d2 --- /dev/null +++ b/gcc/testsuite/go.dg/pr119533-riscv.go @@ -0,0 +1,120 @@ +// { dg-do compile { target riscv64*-*-* } } +// { dg-options "-O2 -march=rv64gcv -mabi=lp64d" } + +// Reduced from libgo build (multi-file reduction, merged mnaully +// and hand reduced again). + +package ast +import ( + "go/token" + "go/scanner" + "reflect" +) +type v struct {} +type w func( string, reflect.Value) bool +func x( string, reflect.Value) bool +type r struct { + scanner.ErrorList +} +type ab interface {} +type ae interface {} +type af interface {} +type ag struct {} +func (ag) Pos() token.Pos +func (ag) ah() token.Pos +type c struct { + aj ae } +type ak struct { + al []c } +type ( + am struct { + an string } + bs struct { + Value string + } +) +func ao(string) *am +type ( + ap interface {} + aq struct { + ar bs } +as struct { + bt ak + an am } +) +type File struct { + *ag + token.Pos + *am + at []af + *v + au []*aq + av *am + aw []*ag } +type ax struct { + an string + *v + ay map[string]File } +func a(az *token.FileSet, b token.Pos) int +type k struct { + l token.Pos + ah token.Pos +} +type m struct { + bb bool + bc *ag +} + +type bi uint +func bj(a *as) string { + if b := a.bt; len(b.al) == 1 { + c := b.al[0].aj + if e := c; e != nil {} + } + return a.an.an +} +func MergePackageFiles(f ax, g bi) *File { + h := 0 + bk := 0 + k := 0 + bl := make([]string, len(f.ay)) + i := 0 + for bm, a := range f.ay { + bl[i] = bm + k += len(a.at) + } + var bn *ag + var l token.Pos + if h > 0 {} + var bo []af + bu := make(map[string]int) + m := 0 + for _, bm := range bl { + a := f.ay[bm] + for _, d := range a.at { + if g!= 0 { + if a, p := d.(*as); p { + n := bj(a) + if j, bp := bu[n]; bp { + if bo != nil && bo[j]== nil {} + } + } + } + } + } + if m > 0 {} + var bq []*aq + q := make(map[string]bool) + for _, bm := range bl { + a := f.ay[bm] + for _, br := range a.au { + if o := br.ar.Value; q[o] {} + } + } + var bh = make([]*ag, bk) + for _, bm := range bl { + a := f.ay[bm] + copy(bh, a.aw) + } + return &File{bn, l, ao(f.an), bo, f.v, bq, nil, bh} +} diff --git a/gcc/testsuite/lib/gcc-dg.exp b/gcc/testsuite/lib/gcc-dg.exp index eadc1cd..6dd8fa3 100644 --- a/gcc/testsuite/lib/gcc-dg.exp +++ b/gcc/testsuite/lib/gcc-dg.exp @@ -507,8 +507,7 @@ if { [info procs ${tool}_load] != [list] \ set linenum 1 set outfile [open [lindex ${output-file} 1]] set do_fail 0 - set name [file tail [lindex ${output-file} 1]] - verbose "output-file args is $args program is $program" 1 + set name [testname-for-summary] while { [gets $outfile line] >= 0 } { if { $linenum != 1 } { set c [string index $output $idx] diff --git a/gcc/testsuite/lib/target-supports.exp b/gcc/testsuite/lib/target-supports.exp index a62f459..869d150 100644 --- a/gcc/testsuite/lib/target-supports.exp +++ b/gcc/testsuite/lib/target-supports.exp @@ -562,6 +562,16 @@ proc check_effective_target_elf { } { } } +# Returns 1 if the target uses the PE/COFF object format, 0 otherwise. + +proc check_effective_target_pe { } { + if { [gcc_target_object_format] == "pe" } { + return 1; + } else { + return 0; + } +} + # Returns 1 if the target toolchain supports ifunc, 0 otherwise. proc check_ifunc_available { } { diff --git a/gcc/testsuite/rust/compile/enum_discriminant2.rs b/gcc/testsuite/rust/compile/enum_discriminant2.rs new file mode 100644 index 0000000..351dfbb --- /dev/null +++ b/gcc/testsuite/rust/compile/enum_discriminant2.rs @@ -0,0 +1,9 @@ +fn test() -> isize { + 1 +} + +enum Foo { + Bar = test() // { dg-error "only functions marked as .const." } +} + +fn main() {} diff --git a/gcc/testsuite/rust/compile/format_args_extra_comma.rs b/gcc/testsuite/rust/compile/format_args_extra_comma.rs new file mode 100644 index 0000000..fcc435c --- /dev/null +++ b/gcc/testsuite/rust/compile/format_args_extra_comma.rs @@ -0,0 +1,47 @@ +#![feature(rustc_attrs)] + +#[rustc_builtin_macro] +macro_rules! format_args { + () => {}; +} + +#[lang = "sized"] +trait Sized {} + +pub mod core { + pub mod fmt { + pub struct Formatter; + pub struct Result; + + pub struct Arguments<'a>; + + impl<'a> Arguments<'a> { + pub fn new_v1(_: &'a [&'static str], _: &'a [ArgumentV1<'a>]) -> Arguments<'a> { + Arguments + } + } + + pub struct ArgumentV1<'a>; + + impl<'a> ArgumentV1<'a> { + pub fn new<'b, T>(_: &'b T, _: fn(&T, &mut Formatter) -> Result) -> ArgumentV1 { + ArgumentV1 + } + } + + pub trait Display { + fn fmt(&self, _: &mut Formatter) -> Result; + } + + impl Display for i32 { + fn fmt(&self, _: &mut Formatter) -> Result { + // { dg-warning "unused name .self." "" { target *-*-* } .-1 } + Result + } + } + } +} + +fn main() { + let _formatted = format_args!("extra commas {} {}", 15, 14,); +} diff --git a/gcc/testsuite/rust/compile/macros/mbe/macro-issue3693.rs b/gcc/testsuite/rust/compile/macros/mbe/macro-issue3693.rs new file mode 100644 index 0000000..e990c8b --- /dev/null +++ b/gcc/testsuite/rust/compile/macros/mbe/macro-issue3693.rs @@ -0,0 +1,10 @@ +macro_rules! generate_pattern_iterators { + { + $(#[$forward_iterator_attribute:meta])* + } => { + } +} + +generate_pattern_iterators! { + /// Created with the method [`split`]. +} diff --git a/gcc/testsuite/rust/compile/macros/mbe/macro-issue3708.rs b/gcc/testsuite/rust/compile/macros/mbe/macro-issue3708.rs new file mode 100644 index 0000000..e5b38bb --- /dev/null +++ b/gcc/testsuite/rust/compile/macros/mbe/macro-issue3708.rs @@ -0,0 +1,80 @@ +// { dg-additional-options "-frust-name-resolution-2.0 -frust-compile-until=lowering" } + +macro_rules! impl_fn_for_zst { + ($( + $( #[$attr: meta] )* + struct $Name: ident impl$( <$( $lifetime : lifetime ),+> )? Fn = + |$( $arg: ident: $ArgTy: ty ),*| -> $ReturnTy: ty + $body: block; + )+) => { + $( + $( #[$attr] )* + struct $Name; + + impl $( <$( $lifetime ),+> )? Fn<($( $ArgTy, )*)> for $Name { + #[inline] + extern "rust-call" fn call(&self, ($( $arg, )*): ($( $ArgTy, )*)) -> $ReturnTy { + $body + } + } + + impl $( <$( $lifetime ),+> )? FnMut<($( $ArgTy, )*)> for $Name { + #[inline] + extern "rust-call" fn call_mut( + &mut self, + ($( $arg, )*): ($( $ArgTy, )*) + ) -> $ReturnTy { + Fn::call(&*self, ($( $arg, )*)) + } + } + + impl $( <$( $lifetime ),+> )? FnOnce<($( $ArgTy, )*)> for $Name { + type Output = $ReturnTy; + + #[inline] + extern "rust-call" fn call_once(self, ($( $arg, )*): ($( $ArgTy, )*)) -> $ReturnTy { + Fn::call(&self, ($( $arg, )*)) + } + } + )+ + } +} + +#[lang = "sized"] +trait Sized {} + +#[lang = "copy"] +trait Copy {} + +#[lang = "fn"] +pub trait Fn<Args>: FnMut<Args> { + /// Performs the call operation. + #[unstable(feature = "fn_traits", issue = "29625")] + extern "rust-call" fn call(&self, args: Args) -> Self::Output; +} + +#[lang = "fn_mut"] +#[must_use = "closures are lazy and do nothing unless called"] +pub trait FnMut<Args>: FnOnce<Args> { + /// Performs the call operation. + #[unstable(feature = "fn_traits", issue = "29625")] + extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output; +} + +#[lang = "fn_once"] +pub trait FnOnce<Args> { + /// The returned type after the call operator is used. + #[lang = "fn_once_output"] + #[stable(feature = "fn_once_output", since = "1.12.0")] + type Output; + + /// Performs the call operation. + #[unstable(feature = "fn_traits", issue = "29625")] + extern "rust-call" fn call_once(self, args: Args) -> Self::Output; +} + +impl_fn_for_zst! { + #[derive(Copy)] + struct LinesAnyMap impl<'a> Fn = |line: &'a str| -> () { + }; +} diff --git a/gcc/testsuite/rust/compile/macros/mbe/macro-issue3709-1.rs b/gcc/testsuite/rust/compile/macros/mbe/macro-issue3709-1.rs new file mode 100644 index 0000000..6fc3a31 --- /dev/null +++ b/gcc/testsuite/rust/compile/macros/mbe/macro-issue3709-1.rs @@ -0,0 +1,10 @@ +macro_rules! doc_comment { + (#[ $attr: meta ]) => { + #[$attr] + struct Generated; // { dg-warning "never constructed" } + }; +} + +doc_comment! { + /// This is a generated struct +} diff --git a/gcc/testsuite/rust/compile/macros/mbe/macro-issue3709-2.rs b/gcc/testsuite/rust/compile/macros/mbe/macro-issue3709-2.rs new file mode 100644 index 0000000..cfc8ab4 --- /dev/null +++ b/gcc/testsuite/rust/compile/macros/mbe/macro-issue3709-2.rs @@ -0,0 +1,81 @@ +// { dg-additional-options "-frust-name-resolution-2.0 -frust-compile-until=lowering" } + +macro_rules! impl_fn_for_zst { + ($( + $( #[$attr: meta] )* + struct $Name: ident impl$( <$( $lifetime : lifetime ),+> )? Fn = + |$( $arg: ident: $ArgTy: ty ),*| -> $ReturnTy: ty + $body: block; + )+) => { + $( + $( #[$attr] )* + struct $Name; + + impl $( <$( $lifetime ),+> )? Fn<($( $ArgTy, )*)> for $Name { + #[inline] + extern "rust-call" fn call(&self, ($( $arg, )*): ($( $ArgTy, )*)) -> $ReturnTy { + $body + } + } + + impl $( <$( $lifetime ),+> )? FnMut<($( $ArgTy, )*)> for $Name { + #[inline] + extern "rust-call" fn call_mut( + &mut self, + ($( $arg, )*): ($( $ArgTy, )*) + ) -> $ReturnTy { + Fn::call(&*self, ($( $arg, )*)) + } + } + + impl $( <$( $lifetime ),+> )? FnOnce<($( $ArgTy, )*)> for $Name { + type Output = $ReturnTy; + + #[inline] + extern "rust-call" fn call_once(self, ($( $arg, )*): ($( $ArgTy, )*)) -> $ReturnTy { + Fn::call(&self, ($( $arg, )*)) + } + } + )+ + } +} + +#[lang = "sized"] +trait Sized {} + +#[lang = "copy"] +trait Copy {} + +#[lang = "fn"] +pub trait Fn<Args>: FnMut<Args> { + /// Performs the call operation. + #[unstable(feature = "fn_traits", issue = "29625")] + extern "rust-call" fn call(&self, args: Args) -> Self::Output; +} + +#[lang = "fn_mut"] +#[must_use = "closures are lazy and do nothing unless called"] +pub trait FnMut<Args>: FnOnce<Args> { + /// Performs the call operation. + #[unstable(feature = "fn_traits", issue = "29625")] + extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output; +} + +#[lang = "fn_once"] +pub trait FnOnce<Args> { + /// The returned type after the call operator is used. + #[lang = "fn_once_output"] + #[stable(feature = "fn_once_output", since = "1.12.0")] + type Output; + + /// Performs the call operation. + #[unstable(feature = "fn_traits", issue = "29625")] + extern "rust-call" fn call_once(self, args: Args) -> Self::Output; +} + +impl_fn_for_zst! { + /// Documentation for the zst + #[derive(Copy)] + struct LinesAnyMap impl<'a> Fn = |line: &'a str| -> () { + }; +} diff --git a/gcc/testsuite/rust/compile/nr2/compile.exp b/gcc/testsuite/rust/compile/nr2/compile.exp index 4d91dd0..9e15cdd 100644 --- a/gcc/testsuite/rust/compile/nr2/compile.exp +++ b/gcc/testsuite/rust/compile/nr2/compile.exp @@ -19,6 +19,15 @@ # Load support procs. load_lib rust-dg.exp +# These tests don't run runtest_file_p consistently if it +# doesn't return the same values, so disable parallelization +# of this *.exp file. The first parallel runtest to reach +# this will run all the tests serially. +if ![gcc_parallel_test_run_p compile] { + return +} +gcc_parallel_test_enable 0 + # Initialize `dg'. dg-init @@ -136,3 +145,5 @@ namespace eval rust-nr2-ns { # All done. dg-finish + +gcc_parallel_test_enable 1 diff --git a/gcc/testsuite/rust/compile/track_caller.rs b/gcc/testsuite/rust/compile/track_caller.rs new file mode 100644 index 0000000..fd1d842 --- /dev/null +++ b/gcc/testsuite/rust/compile/track_caller.rs @@ -0,0 +1,6 @@ +#[track_caller] +fn foo() {} + +fn main() { + foo(); +} diff --git a/gcc/testsuite/rust/execute/torture/min_specialization2.rs b/gcc/testsuite/rust/execute/torture/min_specialization2.rs new file mode 100644 index 0000000..d3239ee --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/min_specialization2.rs @@ -0,0 +1,31 @@ +#![feature(min_specialization)] + +#[lang = "sized"] +trait Sized {} + +trait Foo { + fn foo(&self) -> i32; +} + +impl<T> Foo for T { + default fn foo(&self) -> i32 { // { dg-warning "unused" } + 15 + } +} + +impl Foo for bool { + fn foo(&self) -> i32 { + if *self { + 1 + } else { + 0 + } + } +} + +fn main() -> i32 { + let a = 1.foo() - 15; + let b = true.foo() - 1; + + a + b +} diff --git a/gcc/testsuite/rust/execute/torture/min_specialization3.rs b/gcc/testsuite/rust/execute/torture/min_specialization3.rs new file mode 100644 index 0000000..9eccd97 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/min_specialization3.rs @@ -0,0 +1,36 @@ +#![feature(min_specialization)] + +#[lang = "sized"] +trait Sized {} + +trait Foo { + fn foo(&self) -> i32; +} + +struct Wrap<T>(T); + +impl<T> Foo for T { + default fn foo(&self) -> i32 { + 15 + } +} + +impl<T> Foo for Wrap<T> { + default fn foo(&self) -> i32 { + 16 + } +} + +impl Foo for Wrap<bool> { + fn foo(&self) -> i32 { + if self.0 { + 1 + } else { + 0 + } + } +} + +fn main() -> i32 { + Wrap(true).foo() - 1 +} diff --git a/gcc/timevar.def b/gcc/timevar.def index c1029d9..02ace46 100644 --- a/gcc/timevar.def +++ b/gcc/timevar.def @@ -105,6 +105,7 @@ DEFTIMEVAR (TV_IPA_PURE_CONST , "ipa pure const") DEFTIMEVAR (TV_IPA_ICF , "ipa icf") DEFTIMEVAR (TV_IPA_PTA , "ipa points-to") DEFTIMEVAR (TV_IPA_SRA , "ipa SRA") +DEFTIMEVAR (TV_IPA_LC , "ipa locality clone") DEFTIMEVAR (TV_IPA_FREE_LANG_DATA , "ipa free lang data") DEFTIMEVAR (TV_IPA_FREE_INLINE_SUMMARY, "ipa free inline summary") DEFTIMEVAR (TV_IPA_MODREF , "ipa modref") diff --git a/gcc/tree-inline.cc b/gcc/tree-inline.cc index 05843b8..3289b4f 100644 --- a/gcc/tree-inline.cc +++ b/gcc/tree-inline.cc @@ -2729,8 +2729,11 @@ copy_edges_for_bb (basic_block bb, profile_count num, profile_count den, && gimple_call_arg (copy_stmt, 0) == boolean_true_node) nonlocal_goto = false; else - make_single_succ_edge (copy_stmt_bb, abnormal_goto_dest, - EDGE_ABNORMAL); + { + make_single_succ_edge (copy_stmt_bb, abnormal_goto_dest, + EDGE_ABNORMAL); + gimple_call_set_ctrl_altering (copy_stmt, true); + } } if ((can_throw || nonlocal_goto) diff --git a/gcc/tree-pass.h b/gcc/tree-pass.h index 217c31f..7cb5a12 100644 --- a/gcc/tree-pass.h +++ b/gcc/tree-pass.h @@ -551,6 +551,7 @@ extern ipa_opt_pass_d *make_pass_ipa_cdtor_merge (gcc::context *ctxt); extern ipa_opt_pass_d *make_pass_ipa_single_use (gcc::context *ctxt); extern ipa_opt_pass_d *make_pass_ipa_comdats (gcc::context *ctxt); extern ipa_opt_pass_d *make_pass_ipa_modref (gcc::context *ctxt); +extern ipa_opt_pass_d *make_pass_ipa_locality_cloning (gcc::context *ctxt); extern gimple_opt_pass *make_pass_cleanup_cfg_post_optimizing (gcc::context *ctxt); diff --git a/gcc/tree-pretty-print.cc b/gcc/tree-pretty-print.cc index a2a4f5b..c1a21e7 100644 --- a/gcc/tree-pretty-print.cc +++ b/gcc/tree-pretty-print.cc @@ -3201,6 +3201,8 @@ dump_generic_node (pretty_printer *pp, tree node, int spc, dump_flags_t flags, pp_string (pp, " [return slot optimization]"); if (CALL_EXPR_TAILCALL (node)) pp_string (pp, " [tail call]"); + if (CALL_EXPR_MUST_TAIL_CALL (node)) + pp_string (pp, " [must tail call]"); break; case WITH_CLEANUP_EXPR: diff --git a/gcc/tree-ssa-dse.cc b/gcc/tree-ssa-dse.cc index bc632e3..d1d58bf 100644 --- a/gcc/tree-ssa-dse.cc +++ b/gcc/tree-ssa-dse.cc @@ -566,16 +566,17 @@ maybe_trim_complex_store (ao_ref *ref, sbitmap live, gimple *stmt) The most common case for getting here is a CONSTRUCTOR with no elements being used to zero initialize an object. We do not try to handle other cases as those would force us to fully cover the object with the - CONSTRUCTOR node except for the components that are dead. */ + CONSTRUCTOR node except for the components that are dead. + Also handles integer stores of 0 which can happen with memset/memcpy optimizations. */ static void -maybe_trim_constructor_store (ao_ref *ref, sbitmap live, gimple *stmt) +maybe_trim_constructor_store (ao_ref *ref, sbitmap live, gimple *stmt, bool was_integer_cst) { tree ctor = gimple_assign_rhs1 (stmt); /* This is the only case we currently handle. It actually seems to catch most cases of actual interest. */ - gcc_assert (CONSTRUCTOR_NELTS (ctor) == 0); + gcc_assert (was_integer_cst ? integer_zerop (ctor) : CONSTRUCTOR_NELTS (ctor) == 0); int head_trim = 0; int tail_trim = 0; @@ -588,6 +589,8 @@ maybe_trim_constructor_store (ao_ref *ref, sbitmap live, gimple *stmt) /* We want &lhs for the MEM_REF expression. */ tree lhs_addr = build_fold_addr_expr (gimple_assign_lhs (stmt)); + STRIP_USELESS_TYPE_CONVERSION (lhs_addr); + if (! is_gimple_min_invariant (lhs_addr)) return; @@ -802,11 +805,16 @@ maybe_trim_partially_dead_store (ao_ref *ref, sbitmap live, gimple *stmt) switch (gimple_assign_rhs_code (stmt)) { case CONSTRUCTOR: - maybe_trim_constructor_store (ref, live, stmt); + maybe_trim_constructor_store (ref, live, stmt, false); break; case COMPLEX_CST: maybe_trim_complex_store (ref, live, stmt); break; + case INTEGER_CST: + if (integer_zerop (gimple_assign_rhs1 (stmt)) + && type_has_mode_precision_p (TREE_TYPE (gimple_assign_lhs (stmt)))) + maybe_trim_constructor_store (ref, live, stmt, true); + break; default: break; } diff --git a/gcc/tree-ssa-phiopt.cc b/gcc/tree-ssa-phiopt.cc index 7d2d169..a194bf6 100644 --- a/gcc/tree-ssa-phiopt.cc +++ b/gcc/tree-ssa-phiopt.cc @@ -403,12 +403,15 @@ factor_out_conditional_operation (edge e0, edge e1, basic_block merge, if (dominated_by_p (CDI_DOMINATORS, gimple_bb (phi), gimple_bb (arg0_def_stmt))) return false; - /* Only handle if arg1 is a INTEGER_CST and one that fits - into the new type or if it is the same precision. */ + /* If arg1 is an INTEGER_CST, fold it to new type if it fits, or else + if the bits will not be modified during the conversion, except for + boolean types whose precision is not 1 (see int_fits_type_p). */ if (!INTEGRAL_TYPE_P (TREE_TYPE (new_arg0)) || !(int_fits_type_p (arg1, TREE_TYPE (new_arg0)) || (TYPE_PRECISION (TREE_TYPE (new_arg0)) - == TYPE_PRECISION (TREE_TYPE (arg1))))) + == TYPE_PRECISION (TREE_TYPE (arg1)) + && (TREE_CODE (TREE_TYPE (new_arg0)) != BOOLEAN_TYPE + || TYPE_PRECISION (TREE_TYPE (new_arg0)) == 1)))) return false; /* For the INTEGER_CST case, we are just moving the diff --git a/gcc/tree-tailcall.cc b/gcc/tree-tailcall.cc index d5c4c7b..f593363 100644 --- a/gcc/tree-tailcall.cc +++ b/gcc/tree-tailcall.cc @@ -51,6 +51,8 @@ along with GCC; see the file COPYING3. If not see #include "symbol-summary.h" #include "ipa-cp.h" #include "ipa-prop.h" +#include "attribs.h" +#include "asan.h" /* The file implements the tail recursion elimination. It is also used to analyze the tail calls in general, passing the results to the rtl level @@ -122,6 +124,9 @@ struct tailcall /* True if it is a call to the current function. */ bool tail_recursion; + /* True if there is __tsan_func_exit call after the call. */ + bool has_tsan_func_exit; + /* The return value of the caller is mult * f + add, where f is the return value of the call. */ tree mult, add; @@ -504,7 +509,7 @@ maybe_error_musttail (gcall *call, const char *err, bool diag_musttail) Search at most CNT basic blocks (so that we don't need to do trivial loop discovery). */ static bool -empty_eh_cleanup (basic_block bb, int cnt) +empty_eh_cleanup (basic_block bb, int *eh_has_tsan_func_exit, int cnt) { if (EDGE_COUNT (bb->succs) > 1) return false; @@ -515,6 +520,14 @@ empty_eh_cleanup (basic_block bb, int cnt) gimple *g = gsi_stmt (gsi); if (is_gimple_debug (g) || gimple_clobber_p (g)) continue; + if (eh_has_tsan_func_exit + && !*eh_has_tsan_func_exit + && sanitize_flags_p (SANITIZE_THREAD) + && gimple_call_builtin_p (g, BUILT_IN_TSAN_FUNC_EXIT)) + { + *eh_has_tsan_func_exit = 1; + continue; + } if (is_gimple_resx (g) && stmt_can_throw_external (cfun, g)) return true; return false; @@ -523,7 +536,7 @@ empty_eh_cleanup (basic_block bb, int cnt) return false; if (cnt == 1) return false; - return empty_eh_cleanup (single_succ (bb), cnt - 1); + return empty_eh_cleanup (single_succ (bb), eh_has_tsan_func_exit, cnt - 1); } /* Argument for compute_live_vars/live_vars_at_stmt and what compute_live_vars @@ -531,14 +544,22 @@ empty_eh_cleanup (basic_block bb, int cnt) static live_vars_map *live_vars; static vec<bitmap_head> live_vars_vec; -/* Finds tailcalls falling into basic block BB. The list of found tailcalls is +/* Finds tailcalls falling into basic block BB. The list of found tailcalls is added to the start of RET. When ONLY_MUSTTAIL is set only handle musttail. Update OPT_TAILCALLS as output parameter. If DIAG_MUSTTAIL, diagnose - failures for musttail calls. */ + failures for musttail calls. RETRY_TSAN_FUNC_EXIT is initially 0 and + in that case the last call is attempted to be tail called, including + __tsan_func_exit with -fsanitize=thread. It is set to -1 if we + detect __tsan_func_exit call and in that case tree_optimize_tail_calls_1 + will retry with it set to 1 (regardless of whether turning the + __tsan_func_exit was successfully detected as tail call or not) and that + will allow turning musttail calls before that call into tail calls as well + by adding __tsan_func_exit call before the call. */ static void find_tail_calls (basic_block bb, struct tailcall **ret, bool only_musttail, - bool &opt_tailcalls, bool diag_musttail) + bool &opt_tailcalls, bool diag_musttail, + int &retry_tsan_func_exit) { tree ass_var = NULL_TREE, ret_var, func, param; gimple *stmt; @@ -552,6 +573,8 @@ find_tail_calls (basic_block bb, struct tailcall **ret, bool only_musttail, size_t idx; tree var; bool only_tailr = false; + bool has_tsan_func_exit = false; + int eh_has_tsan_func_exit = -1; if (!single_succ_p (bb) && (EDGE_COUNT (bb->succs) || !cfun->has_musttail || !diag_musttail)) @@ -585,6 +608,17 @@ find_tail_calls (basic_block bb, struct tailcall **ret, bool only_musttail, || is_gimple_debug (stmt)) continue; + if (cfun->has_musttail + && sanitize_flags_p (SANITIZE_THREAD) + && gimple_call_builtin_p (stmt, BUILT_IN_TSAN_FUNC_EXIT) + && diag_musttail) + { + if (retry_tsan_func_exit == 0) + retry_tsan_func_exit = -1; + else if (retry_tsan_func_exit == 1) + continue; + } + if (!last_stmt) last_stmt = stmt; /* Check for a call. */ @@ -635,7 +669,7 @@ find_tail_calls (basic_block bb, struct tailcall **ret, bool only_musttail, /* Recurse to the predecessors. */ FOR_EACH_EDGE (e, ei, bb->preds) find_tail_calls (e->src, ret, only_musttail, opt_tailcalls, - diag_musttail); + diag_musttail, retry_tsan_func_exit); return; } @@ -715,8 +749,12 @@ find_tail_calls (basic_block bb, struct tailcall **ret, bool only_musttail, return; } + if (diag_musttail && gimple_call_must_tail_p (call)) + eh_has_tsan_func_exit = 0; if (!gimple_call_must_tail_p (call) - || !empty_eh_cleanup (e->dest, 20) + || !empty_eh_cleanup (e->dest, + eh_has_tsan_func_exit + ? NULL : &eh_has_tsan_func_exit, 20) || EDGE_COUNT (bb->succs) > 2) { maybe_error_musttail (call, _("call may throw exception caught " @@ -947,6 +985,17 @@ find_tail_calls (basic_block bb, struct tailcall **ret, bool only_musttail, || is_gimple_debug (stmt)) continue; + if (cfun->has_musttail + && sanitize_flags_p (SANITIZE_THREAD) + && retry_tsan_func_exit == 1 + && gimple_call_builtin_p (stmt, BUILT_IN_TSAN_FUNC_EXIT) + && !has_tsan_func_exit + && gimple_call_must_tail_p (call)) + { + has_tsan_func_exit = true; + continue; + } + if (gimple_code (stmt) != GIMPLE_ASSIGN) { maybe_error_musttail (call, _("unhandled code after call"), @@ -1110,6 +1159,19 @@ find_tail_calls (basic_block bb, struct tailcall **ret, bool only_musttail, return; } + if (eh_has_tsan_func_exit != -1 + && eh_has_tsan_func_exit != has_tsan_func_exit) + { + if (eh_has_tsan_func_exit) + maybe_error_musttail (call, _("call may throw exception caught " + "locally or perform cleanups"), + diag_musttail); + else + maybe_error_musttail (call, _("exception cleanups omit " + "__tsan_func_exit call"), diag_musttail); + return; + } + /* Move queued defs. */ if (tail_recursion) { @@ -1138,6 +1200,7 @@ find_tail_calls (basic_block bb, struct tailcall **ret, bool only_musttail, nw->call_gsi = gsi; nw->tail_recursion = tail_recursion; + nw->has_tsan_func_exit = has_tsan_func_exit; nw->mult = m; nw->add = a; @@ -1472,6 +1535,14 @@ static bool optimize_tail_call (struct tailcall *t, bool opt_tailcalls, class loop *&new_loop) { + if (t->has_tsan_func_exit && (t->tail_recursion || opt_tailcalls)) + { + tree builtin_decl = builtin_decl_implicit (BUILT_IN_TSAN_FUNC_EXIT); + gimple *g = gimple_build_call (builtin_decl, 0); + gimple_set_location (g, cfun->function_end_locus); + gsi_insert_before (&t->call_gsi, g, GSI_SAME_STMT); + } + if (t->tail_recursion) { eliminate_tail_call (t, new_loop); @@ -1490,6 +1561,7 @@ optimize_tail_call (struct tailcall *t, bool opt_tailcalls, print_gimple_stmt (dump_file, stmt, 0, dump_flags); fprintf (dump_file, " in bb %i\n", (gsi_bb (t->call_gsi))->index); } + return t->has_tsan_func_exit; } return false; @@ -1539,12 +1611,23 @@ tree_optimize_tail_calls_1 (bool opt_tailcalls, bool only_musttail, /* Only traverse the normal exits, i.e. those that end with return statement. */ if (safe_is_a <greturn *> (*gsi_last_bb (e->src))) - find_tail_calls (e->src, &tailcalls, only_musttail, opt_tailcalls, - diag_musttail); + { + int retry_tsan_func_exit = 0; + find_tail_calls (e->src, &tailcalls, only_musttail, opt_tailcalls, + diag_musttail, retry_tsan_func_exit); + if (retry_tsan_func_exit == -1) + { + retry_tsan_func_exit = 1; + find_tail_calls (e->src, &tailcalls, only_musttail, + opt_tailcalls, diag_musttail, + retry_tsan_func_exit); + } + } } if (cfun->has_musttail && diag_musttail) { basic_block bb; + int retry_tsan_func_exit = 0; FOR_EACH_BB_FN (bb, cfun) if (EDGE_COUNT (bb->succs) == 0 || (single_succ_p (bb) @@ -1554,7 +1637,7 @@ tree_optimize_tail_calls_1 (bool opt_tailcalls, bool only_musttail, && gimple_call_must_tail_p (as_a <gcall *> (c)) && gimple_call_noreturn_p (as_a <gcall *> (c))) find_tail_calls (bb, &tailcalls, only_musttail, opt_tailcalls, - diag_musttail); + diag_musttail, retry_tsan_func_exit); } if (live_vars) diff --git a/gcc/tree-vect-loop.cc b/gcc/tree-vect-loop.cc index 9413dce..2d35fa1 100644 --- a/gcc/tree-vect-loop.cc +++ b/gcc/tree-vect-loop.cc @@ -653,6 +653,10 @@ vect_analyze_scalar_cycles_1 (loop_vec_info loop_vinfo, class loop *loop, if (dump_enabled_p ()) dump_printf_loc (MSG_NOTE, vect_location, "Detected induction.\n"); STMT_VINFO_DEF_TYPE (stmt_vinfo) = vect_induction_def; + + /* Mark if we have a non-linear IV. */ + LOOP_VINFO_NON_LINEAR_IV (loop_vinfo) + = STMT_VINFO_LOOP_PHI_EVOLUTION_TYPE (stmt_vinfo) != vect_step_op_add; } @@ -1046,12 +1050,14 @@ _loop_vec_info::_loop_vec_info (class loop *loop_in, vec_info_shared *shared) suggested_unroll_factor (1), max_vectorization_factor (0), mask_skip_niters (NULL_TREE), + mask_skip_niters_pfa_offset (NULL_TREE), rgroup_compare_type (NULL_TREE), simd_if_cond (NULL_TREE), partial_vector_style (vect_partial_vectors_none), unaligned_dr (NULL), peeling_for_alignment (0), ptr_mask (0), + nonlinear_iv (false), ivexpr_map (NULL), scan_map (NULL), slp_unrolling_factor (1), @@ -10678,6 +10684,54 @@ vectorizable_induction (loop_vec_info loop_vinfo, LOOP_VINFO_MASK_SKIP_NITERS (loop_vinfo)); peel_mul = gimple_build_vector_from_val (&init_stmts, step_vectype, peel_mul); + + /* If early break then we have to create a new PHI which we can use as + an offset to adjust the induction reduction in early exits. + + This is because when peeling for alignment using masking, the first + few elements of the vector can be inactive. As such if we find the + entry in the first iteration we have adjust the starting point of + the scalar code. + + We do this by creating a new scalar PHI that keeps track of whether + we are the first iteration of the loop (with the additional masking) + or whether we have taken a loop iteration already. + + The generated sequence: + + pre-header: + bb1: + i_1 = <number of leading inactive elements> + + header: + bb2: + i_2 = PHI <i_1(bb1), 0(latch)> + … + + early-exit: + bb3: + i_3 = iv_step * i_2 + PHI<vector-iv> + + The first part of the adjustment to create i_1 and i_2 are done here + and the last part creating i_3 is done in + vectorizable_live_operations when the induction extraction is + materialized. */ + if (LOOP_VINFO_EARLY_BREAKS (loop_vinfo) + && !LOOP_VINFO_MASK_NITERS_PFA_OFFSET (loop_vinfo)) + { + auto skip_niters = LOOP_VINFO_MASK_SKIP_NITERS (loop_vinfo); + tree ty_skip_niters = TREE_TYPE (skip_niters); + tree break_lhs_phi = vect_get_new_vect_var (ty_skip_niters, + vect_scalar_var, + "pfa_iv_offset"); + gphi *nphi = create_phi_node (break_lhs_phi, bb); + add_phi_arg (nphi, skip_niters, pe, UNKNOWN_LOCATION); + add_phi_arg (nphi, build_zero_cst (ty_skip_niters), + loop_latch_edge (iv_loop), UNKNOWN_LOCATION); + + LOOP_VINFO_MASK_NITERS_PFA_OFFSET (loop_vinfo) + = PHI_RESULT (nphi); + } } tree step_mul = NULL_TREE; unsigned ivn; @@ -11565,8 +11619,10 @@ vectorizable_live_operation (vec_info *vinfo, stmt_vec_info stmt_info, /* For early exit where the exit is not in the BB that leads to the latch then we're restarting the iteration in the scalar loop. So get the first live value. */ - if ((all_exits_as_early_p || !main_exit_edge) - && STMT_VINFO_DEF_TYPE (stmt_info) == vect_induction_def) + bool early_break_first_element_p + = (all_exits_as_early_p || !main_exit_edge) + && STMT_VINFO_DEF_TYPE (stmt_info) == vect_induction_def; + if (early_break_first_element_p) { tmp_vec_lhs = vec_lhs0; tmp_bitstart = build_zero_cst (TREE_TYPE (bitstart)); @@ -11581,6 +11637,45 @@ vectorizable_live_operation (vec_info *vinfo, stmt_vec_info stmt_info, lhs_type, &exit_gsi); auto gsi = gsi_for_stmt (use_stmt); + if (early_break_first_element_p + && LOOP_VINFO_MASK_NITERS_PFA_OFFSET (loop_vinfo)) + { + tree step_expr + = STMT_VINFO_LOOP_PHI_EVOLUTION_PART (stmt_info); + tree break_lhs_phi + = LOOP_VINFO_MASK_NITERS_PFA_OFFSET (loop_vinfo); + tree ty_skip_niters = TREE_TYPE (break_lhs_phi); + gimple_seq iv_stmts = NULL; + + /* Now create the PHI for the outside loop usage to + retrieve the value for the offset counter. */ + tree rphi_step + = gimple_convert (&iv_stmts, ty_skip_niters, step_expr); + tree tmp2 + = gimple_build (&iv_stmts, MULT_EXPR, + ty_skip_niters, rphi_step, + break_lhs_phi); + + if (POINTER_TYPE_P (TREE_TYPE (new_tree))) + { + tmp2 = gimple_convert (&iv_stmts, sizetype, tmp2); + tmp2 = gimple_build (&iv_stmts, POINTER_PLUS_EXPR, + TREE_TYPE (new_tree), new_tree, + tmp2); + } + else + { + tmp2 = gimple_convert (&iv_stmts, TREE_TYPE (new_tree), + tmp2); + tmp2 = gimple_build (&iv_stmts, PLUS_EXPR, + TREE_TYPE (new_tree), new_tree, + tmp2); + } + + new_tree = tmp2; + gsi_insert_seq_before (&exit_gsi, iv_stmts, GSI_SAME_STMT); + } + tree lhs_phi = gimple_phi_result (use_stmt); remove_phi_node (&gsi, false); gimple *copy = gimple_build_assign (lhs_phi, new_tree); diff --git a/gcc/tree-vect-slp.cc b/gcc/tree-vect-slp.cc index ecb4a65..19beeed 100644 --- a/gcc/tree-vect-slp.cc +++ b/gcc/tree-vect-slp.cc @@ -1099,7 +1099,7 @@ vect_build_slp_tree_1 (vec_info *vinfo, unsigned char *swap, tree first_lhs = NULL_TREE; tree first_op1 = NULL_TREE; stmt_vec_info first_load = NULL, prev_first_load = NULL; - bool first_stmt_ldst_p = false; + bool first_stmt_ldst_p = false, first_stmt_ldst_masklen_p = false; bool first_stmt_phi_p = false; int first_reduc_idx = -1; bool maybe_soft_fail = false; @@ -1133,6 +1133,7 @@ vect_build_slp_tree_1 (vec_info *vinfo, unsigned char *swap, FOR_EACH_VEC_ELT (stmts, i, stmt_info) { bool ldst_p = false; + bool ldst_masklen_p = false; bool phi_p = false; code_helper rhs_code = ERROR_MARK; @@ -1195,17 +1196,22 @@ vect_build_slp_tree_1 (vec_info *vinfo, unsigned char *swap, else rhs_code = CALL_EXPR; - if (cfn == CFN_MASK_LOAD - || cfn == CFN_GATHER_LOAD - || cfn == CFN_MASK_GATHER_LOAD - || cfn == CFN_MASK_LEN_GATHER_LOAD - || cfn == CFN_SCATTER_STORE - || cfn == CFN_MASK_SCATTER_STORE - || cfn == CFN_MASK_LEN_SCATTER_STORE) + if (cfn == CFN_GATHER_LOAD + || cfn == CFN_SCATTER_STORE) ldst_p = true; + else if (cfn == CFN_MASK_LOAD + || cfn == CFN_MASK_GATHER_LOAD + || cfn == CFN_MASK_LEN_GATHER_LOAD + || cfn == CFN_MASK_SCATTER_STORE + || cfn == CFN_MASK_LEN_SCATTER_STORE) + { + ldst_p = true; + ldst_masklen_p = true; + } else if (cfn == CFN_MASK_STORE) { ldst_p = true; + ldst_masklen_p = true; rhs_code = CFN_MASK_STORE; } else if (cfn == CFN_GOMP_SIMD_LANE) @@ -1246,6 +1252,7 @@ vect_build_slp_tree_1 (vec_info *vinfo, unsigned char *swap, first_lhs = lhs; first_stmt_code = rhs_code; first_stmt_ldst_p = ldst_p; + first_stmt_ldst_masklen_p = ldst_masklen_p; first_stmt_phi_p = phi_p; first_reduc_idx = STMT_VINFO_REDUC_IDX (stmt_info); @@ -1364,6 +1371,7 @@ vect_build_slp_tree_1 (vec_info *vinfo, unsigned char *swap, && (STMT_VINFO_GATHER_SCATTER_P (stmt_info) != STMT_VINFO_GATHER_SCATTER_P (first_stmt_info))) || first_stmt_ldst_p != ldst_p + || (ldst_p && first_stmt_ldst_masklen_p != ldst_masklen_p) || first_stmt_phi_p != phi_p) { if (dump_enabled_p ()) diff --git a/gcc/tree-vect-stmts.cc b/gcc/tree-vect-stmts.cc index 7f87435..5af1973 100644 --- a/gcc/tree-vect-stmts.cc +++ b/gcc/tree-vect-stmts.cc @@ -13615,29 +13615,23 @@ vectorizable_early_exit (vec_info *vinfo, stmt_vec_info stmt_info, codegen so we must replace the original insn. */ gimple *orig_stmt = STMT_VINFO_STMT (vect_orig_stmt (stmt_info)); gcond *cond_stmt = as_a <gcond *>(orig_stmt); + + tree cst = build_zero_cst (vectype); + auto bb = gimple_bb (cond_stmt); + edge exit_true_edge = EDGE_SUCC (bb, 0); + if (exit_true_edge->flags & EDGE_FALSE_VALUE) + exit_true_edge = EDGE_SUCC (bb, 1); + gcc_assert (exit_true_edge->flags & EDGE_TRUE_VALUE); + /* When vectorizing we assume that if the branch edge is taken that we're exiting the loop. This is not however always the case as the compiler will rewrite conditions to always be a comparison against 0. To do this it sometimes flips the edges. This is fine for scalar, but for vector we - then have to flip the test, as we're still assuming that if you take the - branch edge that we found the exit condition. i.e. we need to know whether - we are generating a `forall` or an `exist` condition. */ - auto new_code = NE_EXPR; - auto reduc_optab = ior_optab; - auto reduc_op = BIT_IOR_EXPR; - tree cst = build_zero_cst (vectype); - edge exit_true_edge = EDGE_SUCC (gimple_bb (cond_stmt), 0); - if (exit_true_edge->flags & EDGE_FALSE_VALUE) - exit_true_edge = EDGE_SUCC (gimple_bb (cond_stmt), 1); - gcc_assert (exit_true_edge->flags & EDGE_TRUE_VALUE); - if (flow_bb_inside_loop_p (LOOP_VINFO_LOOP (loop_vinfo), - exit_true_edge->dest)) - { - new_code = EQ_EXPR; - reduc_optab = and_optab; - reduc_op = BIT_AND_EXPR; - cst = build_minus_one_cst (vectype); - } + then have to negate the result of the test, as we're still assuming that if + you take the branch edge that we found the exit condition. i.e. we need to + know whether we are generating a `forall` or an `exist` condition. */ + bool flipped = flow_bb_inside_loop_p (LOOP_VINFO_LOOP (loop_vinfo), + exit_true_edge->dest); /* Analyze only. */ if (!vec_stmt) @@ -13653,14 +13647,13 @@ vectorizable_early_exit (vec_info *vinfo, stmt_vec_info stmt_info, } if (ncopies > 1 - && direct_optab_handler (reduc_optab, mode) == CODE_FOR_nothing) + && direct_optab_handler (ior_optab, mode) == CODE_FOR_nothing) { if (dump_enabled_p ()) dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, "can't vectorize early exit because the " - "target does not support boolean vector %s " + "target does not support boolean vector IOR " "for type %T.\n", - reduc_optab == ior_optab ? "OR" : "AND", vectype); return false; } @@ -13720,6 +13713,29 @@ vectorizable_early_exit (vec_info *vinfo, stmt_vec_info stmt_info, stmts.quick_push (gimple_assign_lhs (stmt)); } + /* If we're comparing against a previous forall we need to negate the resullts + before we do the final comparison or reduction. */ + if (flipped) + { + /* Rewrite the if(all(mask)) into if (!all(mask)) which is the same as + if (any(~mask)) by negating the masks and flipping the branches. + + 1. For unmasked loops we simply reduce the ~mask. + 2. For masked loops we reduce (~mask & loop_mask) which is the same as + doing (mask & loop_mask) ^ loop_mask. */ + for (unsigned i = 0; i < stmts.length (); i++) + { + tree inv_lhs = make_temp_ssa_name (vectype, NULL, "vexit_inv"); + auto inv_stmt = gimple_build_assign (inv_lhs, BIT_NOT_EXPR, stmts[i]); + vect_finish_stmt_generation (loop_vinfo, stmt_info, inv_stmt, + &cond_gsi); + stmts[i] = inv_lhs; + } + + EDGE_SUCC (bb, 0)->flags ^= (EDGE_TRUE_VALUE|EDGE_FALSE_VALUE); + EDGE_SUCC (bb, 1)->flags ^= (EDGE_TRUE_VALUE|EDGE_FALSE_VALUE); + } + /* Determine if we need to reduce the final value. */ if (stmts.length () > 1) { @@ -13758,7 +13774,7 @@ vectorizable_early_exit (vec_info *vinfo, stmt_vec_info stmt_info, new_temp = make_temp_ssa_name (vectype, NULL, "vexit_reduc"); tree arg0 = workset.pop (); tree arg1 = workset.pop (); - new_stmt = gimple_build_assign (new_temp, reduc_op, arg0, arg1); + new_stmt = gimple_build_assign (new_temp, BIT_IOR_EXPR, arg0, arg1); vect_finish_stmt_generation (loop_vinfo, stmt_info, new_stmt, &cond_gsi); workset.quick_insert (0, new_temp); @@ -13781,7 +13797,7 @@ vectorizable_early_exit (vec_info *vinfo, stmt_vec_info stmt_info, gcc_assert (new_temp); - gimple_cond_set_condition (cond_stmt, new_code, new_temp, cst); + gimple_cond_set_condition (cond_stmt, NE_EXPR, new_temp, cst); update_stmt (orig_stmt); if (slp_node) diff --git a/gcc/tree-vectorizer.h b/gcc/tree-vectorizer.h index 97caf61..01d19c7 100644 --- a/gcc/tree-vectorizer.h +++ b/gcc/tree-vectorizer.h @@ -818,6 +818,11 @@ public: elements that should be false in the first mask). */ tree mask_skip_niters; + /* If we are using a loop mask to align memory addresses and we're in an + early break loop then this variable contains the number of elements that + were skipped during the initial iteration of the loop. */ + tree mask_skip_niters_pfa_offset; + /* The type that the loop control IV should be converted to before testing which of the VF scalars are active and inactive. Only meaningful if LOOP_VINFO_USING_PARTIAL_VECTORS_P. */ @@ -854,6 +859,9 @@ public: /* The mask used to check the alignment of pointers or arrays. */ int ptr_mask; + /* Indicates whether the loop has any non-linear IV. */ + bool nonlinear_iv; + /* Data Dependence Relations defining address ranges that are candidates for a run-time aliasing check. */ auto_vec<ddr_p> may_alias_ddrs; @@ -1064,6 +1072,7 @@ public: #define LOOP_VINFO_MASKS(L) (L)->masks #define LOOP_VINFO_LENS(L) (L)->lens #define LOOP_VINFO_MASK_SKIP_NITERS(L) (L)->mask_skip_niters +#define LOOP_VINFO_MASK_NITERS_PFA_OFFSET(L) (L)->mask_skip_niters_pfa_offset #define LOOP_VINFO_RGROUP_COMPARE_TYPE(L) (L)->rgroup_compare_type #define LOOP_VINFO_RGROUP_IV_TYPE(L) (L)->rgroup_iv_type #define LOOP_VINFO_PARTIAL_VECTORS_STYLE(L) (L)->partial_vector_style @@ -1073,6 +1082,7 @@ public: #define LOOP_VINFO_DDRS(L) (L)->shared->ddrs #define LOOP_VINFO_INT_NITERS(L) (TREE_INT_CST_LOW ((L)->num_iters)) #define LOOP_VINFO_PEELING_FOR_ALIGNMENT(L) (L)->peeling_for_alignment +#define LOOP_VINFO_NON_LINEAR_IV(L) (L)->nonlinear_iv #define LOOP_VINFO_UNALIGNED_DR(L) (L)->unaligned_dr #define LOOP_VINFO_MAY_MISALIGN_STMTS(L) (L)->may_misalign_stmts #define LOOP_VINFO_MAY_ALIAS_DDRS(L) (L)->may_alias_ddrs @@ -2138,8 +2148,14 @@ unlimited_cost_model (loop_p loop) inline bool vect_use_loop_mask_for_alignment_p (loop_vec_info loop_vinfo) { + /* With early break vectorization we don't know whether the accesses will stay + inside the loop or not. TODO: The early break adjustment code can be + implemented the same way as vectorizable_linear_induction. However we + can't test this today so reject it. */ return (LOOP_VINFO_FULLY_MASKED_P (loop_vinfo) - && LOOP_VINFO_PEELING_FOR_ALIGNMENT (loop_vinfo)); + && LOOP_VINFO_PEELING_FOR_ALIGNMENT (loop_vinfo) + && !(LOOP_VINFO_NON_LINEAR_IV (loop_vinfo) + && LOOP_VINFO_EARLY_BREAKS (loop_vinfo))); } /* Return the number of vectors of type VECTYPE that are needed to get diff --git a/gcc/tree.def b/gcc/tree.def index c4ad8d0..2c37e44 100644 --- a/gcc/tree.def +++ b/gcc/tree.def @@ -135,7 +135,11 @@ DEFTREECODE (OFFSET_TYPE, "offset_type", tcc_type, 0) DEFTREECODE (ENUMERAL_TYPE, "enumeral_type", tcc_type, 0) /* Boolean type (true or false are the only values). Looks like an - INTEGRAL_TYPE. */ + INTEGER_TYPE, but must be dealt with specially because TYPE_PRECISION + may be arbitrary despite the restricted set of valid values (in other + words, boolean types with TYPE_PRECISION > 1 exist in some languages). + Similarly, TYPE_UNSIGNED may be false for components of vector masks, + as well as for boolean types in languages other than C. */ DEFTREECODE (BOOLEAN_TYPE, "boolean_type", tcc_type, 0) /* Integer types in all languages, including char in C. @@ -2395,11 +2395,11 @@ public: array_slice (vec<OtherT, A, vl_embed> *v) : m_base (v ? v->address () : nullptr), m_size (v ? v->length () : 0) {} - iterator begin () { return m_base; } - iterator end () { return m_base + m_size; } + iterator begin () { gcc_checking_assert (is_valid ()); return m_base; } + iterator end () { gcc_checking_assert (is_valid ()); return m_base + m_size; } - const_iterator begin () const { return m_base; } - const_iterator end () const { return m_base + m_size; } + const_iterator begin () const { gcc_checking_assert (is_valid ()); return m_base; } + const_iterator end () const { gcc_checking_assert (is_valid ()); return m_base + m_size; } value_type &front (); value_type &back (); diff --git a/libatomic/ChangeLog b/libatomic/ChangeLog index ac7e729..62e6c4e 100644 --- a/libatomic/ChangeLog +++ b/libatomic/ChangeLog @@ -1,3 +1,23 @@ +2025-04-16 Jakub Jelinek <jakub@redhat.com> + + PR libgcc/101075 + PR libgcc/119796 + * config/mingw/lock.c (libat_lock_n, libat_unlock_n): Start with + computing how many locks will be needed and take into account + ((uintptr_t)ptr % WATCH_SIZE). If some locks from the end of the + locks array and others from the start of it will be needed, first + lock the ones from the start followed by ones from the end. + +2025-04-16 Jakub Jelinek <jakub@redhat.com> + + PR libgcc/101075 + PR libgcc/119796 + * config/posix/lock.c (libat_lock_n, libat_unlock_n): Start with + computing how many locks will be needed and take into account + ((uintptr_t)ptr % WATCH_SIZE). If some locks from the end of the + locks array and others from the start of it will be needed, first + lock the ones from the start followed by ones from the end. + 2025-01-10 Wilco Dijkstra <wilco.dijkstra@arm.com> * config/linux/aarch64/host-config.h (has_lse2): Cleanup. diff --git a/libatomic/config/mingw/lock.c b/libatomic/config/mingw/lock.c index 17faa66..8b0b4dd 100644 --- a/libatomic/config/mingw/lock.c +++ b/libatomic/config/mingw/lock.c @@ -87,21 +87,30 @@ libat_lock_n (void *ptr, size_t n) { uintptr_t h = addr_hash (ptr); size_t i = 0; + size_t nlocks + = (n + ((uintptr_t)ptr % WATCH_SIZE) + WATCH_SIZE - 1) / WATCH_SIZE; /* Don't lock more than all the locks we have. */ - if (n > PAGE_SIZE) - n = PAGE_SIZE; + if (nlocks > NLOCKS) + nlocks = NLOCKS; - do + if (__builtin_expect (h + nlocks > NLOCKS, 0)) + { + size_t j = h + nlocks - NLOCKS; + for (; i < j; ++i) + { + if (!locks[i].mutex) + locks[i].mutex = CreateMutex (NULL, FALSE, NULL); + WaitForSingleObject (locks[i].mutex, INFINITE); + } + } + + for (; i < nlocks; ++i) { if (!locks[h].mutex) - locks[h].mutex = CreateMutex (NULL, FALSE, NULL); - WaitForSingleObject (locks[h].mutex, INFINITE); - if (++h == NLOCKS) - h = 0; - i += WATCH_SIZE; + locks[h].mutex = CreateMutex (NULL, FALSE, NULL); + WaitForSingleObject (locks[h++].mutex, INFINITE); } - while (i < n); } void @@ -109,17 +118,22 @@ libat_unlock_n (void *ptr, size_t n) { uintptr_t h = addr_hash (ptr); size_t i = 0; + size_t nlocks + = (n + ((uintptr_t)ptr % WATCH_SIZE) + WATCH_SIZE - 1) / WATCH_SIZE; - if (n > PAGE_SIZE) - n = PAGE_SIZE; + /* Don't lock more than all the locks we have. */ + if (nlocks > NLOCKS) + nlocks = NLOCKS; - do + if (__builtin_expect (h + nlocks > NLOCKS, 0)) { - if (locks[h].mutex) - ReleaseMutex (locks[h].mutex); - if (++h == NLOCKS) - h = 0; - i += WATCH_SIZE; + size_t j = h + nlocks - NLOCKS; + for (; i < j; ++i) + if (locks[i].mutex) + ReleaseMutex (locks[i].mutex); } - while (i < n); + + for (; i < nlocks; ++i, ++h) + if (locks[h].mutex) + ReleaseMutex (locks[h].mutex); } diff --git a/libatomic/config/posix/lock.c b/libatomic/config/posix/lock.c index 6ee4240..5662b77 100644 --- a/libatomic/config/posix/lock.c +++ b/libatomic/config/posix/lock.c @@ -81,19 +81,22 @@ libat_lock_n (void *ptr, size_t n) { uintptr_t h = addr_hash (ptr); size_t i = 0; + size_t nlocks + = (n + ((uintptr_t)ptr % WATCH_SIZE) + WATCH_SIZE - 1) / WATCH_SIZE; /* Don't lock more than all the locks we have. */ - if (n > PAGE_SIZE) - n = PAGE_SIZE; + if (nlocks > NLOCKS) + nlocks = NLOCKS; - do + if (__builtin_expect (h + nlocks > NLOCKS, 0)) { - pthread_mutex_lock (&locks[h].mutex); - if (++h == NLOCKS) - h = 0; - i += WATCH_SIZE; + size_t j = h + nlocks - NLOCKS; + for (; i < j; ++i) + pthread_mutex_lock (&locks[i].mutex); } - while (i < n); + + for (; i < nlocks; ++i) + pthread_mutex_lock (&locks[h++].mutex); } void @@ -101,16 +104,20 @@ libat_unlock_n (void *ptr, size_t n) { uintptr_t h = addr_hash (ptr); size_t i = 0; + size_t nlocks + = (n + ((uintptr_t)ptr % WATCH_SIZE) + WATCH_SIZE - 1) / WATCH_SIZE; - if (n > PAGE_SIZE) - n = PAGE_SIZE; + /* Don't lock more than all the locks we have. */ + if (nlocks > NLOCKS) + nlocks = NLOCKS; - do + if (__builtin_expect (h + nlocks > NLOCKS, 0)) { - pthread_mutex_unlock (&locks[h].mutex); - if (++h == NLOCKS) - h = 0; - i += WATCH_SIZE; + size_t j = h + nlocks - NLOCKS; + for (; i < j; ++i) + pthread_mutex_unlock (&locks[i].mutex); } - while (i < n); + + for (; i < nlocks; ++i) + pthread_mutex_unlock (&locks[h++].mutex); } diff --git a/libgcc/ChangeLog b/libgcc/ChangeLog index 9df44ba..66feed5 100644 --- a/libgcc/ChangeLog +++ b/libgcc/ChangeLog @@ -1,3 +1,83 @@ +2025-04-19 Jiaxun Yang <jiaxun.yang@flygoat.com> + + PR target/118257 + * config/sh/sfp-machine.h (_FPU_GETCW): Implement with builtin. + (_FPU_SETCW): Likewise. + (FP_EX_ENABLE_SHIFT): Derive from arch spec. + (FP_EX_CAUSE_SHIFT): Likewise. + (FP_RND_MASK): Likewise. + (FP_EX_INVALID): Likewise. + (FP_EX_DIVZERO): Likewise. + (FP_EX_ALL): Likewise. + (FP_EX_OVERFLOW): Likewise. + (FP_EX_UNDERFLOW): Likewise. + (FP_EX_INEXACT): Likewise. + (_FP_DECL_EX): Declear default FCSR value. + (FP_RND_NEAREST): Derive from arch spec. + (FP_RND_ZERO): Likewise. + (FP_INIT_ROUNDMODE): Likewise. + (FP_ROUNDMODE): Likewise. + (FP_TRAPPING_EXCEPTIONS): Likewise. + (FP_HANDLE_EXCEPTIONS): Implement with _FPU_SETCW. + +2025-04-19 Jiaxun Yang <jiaxun.yang@flygoat.com> + + PR target/111814 + * config/sh/sfp-machine.h (_FP_NANFRAC_B): Reverse signaling bit. + (_FP_NANFRAC_H): Likewise. + (_FP_NANFRAC_S): Likewise. + (_FP_NANFRAC_D): Likewise. + (_FP_NANFRAC_Q): Likewise. + (_FP_KEEPNANFRACP): Enable for target. + (_FP_QNANNEGATEDP): Enable for target. + (_FP_CHOOSENAN): Port from MIPS. + +2025-04-14 Thomas Schwinge <tschwinge@baylibre.com> + + PR target/118794 + * config/gcn/unwind-gcn.c (_Unwind_Resume): New. + * config/nvptx/unwind-nvptx.c (_Unwind_Resume): Likewise. + +2025-04-14 Eric Botcazou <ebotcazou@adacore.com> + + PR target/119673 + * config/i386/gthr-win32.h (__GTHREAD_ALWAYS_INLINE): New macro. + (__GTHREAD_INLINE): Likewise. + (__GTHR_W32_InterlockedCompareExchange): Delete. + (__gthread_active_p): Mark as __GTHREAD_INLINE instead of + static inline. + (__gthread_create): Likewise. + (__gthread_join): Likewise. + (__gthread_self): Likewise. + (__gthread_detach): Likewise. + (__gthread_equal): Likewise. + (__gthread_yield): Likewise. + (__gthread_once): Likewise. + (__gthread_key_create): Likewise. + (__gthread_key_delete): Likewise. + (__gthread_getspecific): Likewise. + (__gthread_setspecific): Likewise. + (__gthread_mutex_init_function): Likewise. + (__gthread_mutex_destroy): Likewise. + (__gthread_mutex_lock): Likewise. + (__gthread_mutex_trylock): Likewise. + (__gthread_mutex_timedlock): Likewise. + (__gthread_mutex_unlock): Likewise. + (__gthread_recursive_mutex_trylock): Likewise. + (__gthread_cond_init_function): Likewise. + (__gthread_cond_broadcast): Likewise. + (__gthread_cond_signal): Likewise. + (__gthread_cond_wait): Likewise. + (__gthread_cond_timedwait): Likewise. + (__GTHREAD_WIN32_INLINE): Likewise. + (__GTHREAD_WIN32_COND_INLINE): Likewise. + (__gthread_recursive_mutex_init_function): Likewise. + (__gthread_recursive_mutex_destroy): Likewise. + (__gthread_recursive_mutex_lock): Likewise. + (__gthread_recursive_mutex_unlock): Likewise. + (__gthread_cond_destroy): Likewise. + (__gthread_cond_wait_recursive): Likewise. + 2025-04-08 Thomas Schwinge <tschwinge@baylibre.com> * config/gcn/unwind-gcn.c (_Unwind_RaiseException) diff --git a/libgcc/config/gcn/unwind-gcn.c b/libgcc/config/gcn/unwind-gcn.c index eae741c..97e22c0 100644 --- a/libgcc/config/gcn/unwind-gcn.c +++ b/libgcc/config/gcn/unwind-gcn.c @@ -38,6 +38,12 @@ _Unwind_DeleteException (struct _Unwind_Exception *exc) (*exc->exception_cleanup) (_URC_FOREIGN_EXCEPTION_CAUGHT, exc); } +void +_Unwind_Resume (struct _Unwind_Exception *exc __attribute__ ((__unused__))) +{ + __builtin_abort (); +} + _Unwind_Reason_Code _Unwind_Resume_or_Rethrow (struct _Unwind_Exception *exc __attribute__ ((__unused__))) { diff --git a/libgcc/config/i386/gthr-win32.h b/libgcc/config/i386/gthr-win32.h index 98e11b4..34988d4 100644 --- a/libgcc/config/i386/gthr-win32.h +++ b/libgcc/config/i386/gthr-win32.h @@ -71,6 +71,21 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see #error Timed lock primitives are not supported on Windows targets #endif +#ifdef __has_attribute +# if __has_attribute(__always_inline__) +# define __GTHREAD_ALWAYS_INLINE __attribute__((__always_inline__)) +# endif +#endif +#ifndef __GTHREAD_ALWAYS_INLINE +# define __GTHREAD_ALWAYS_INLINE +#endif + +#ifdef __cplusplus +# define __GTHREAD_INLINE inline __GTHREAD_ALWAYS_INLINE +#else +# define __GTHREAD_INLINE static inline +#endif + /* Make sure CONST_CAST2 (origin in system.h) is declared. */ #ifndef CONST_CAST2 #ifdef __cplusplus @@ -398,11 +413,7 @@ extern int _CRT_MT; extern int __mingwthr_key_dtor (unsigned long, void (*) (void *)); #endif /* _WIN32 && !__CYGWIN__ */ -/* __GTHR_W32_InterlockedCompareExchange is left over from win95, - which did not support InterlockedCompareExchange. */ -#define __GTHR_W32_InterlockedCompareExchange InterlockedCompareExchange - -static inline int +__GTHREAD_INLINE int __gthread_active_p (void) { #ifdef MINGW32_SUPPORTS_MT_EH @@ -438,20 +449,20 @@ extern int __gthr_win32_cond_timedwait (__gthread_cond_t *, __gthread_mutex_t *, const __gthread_time_t *); #endif -static inline int +__GTHREAD_INLINE int __gthread_create (__gthread_t *__thr, void *(*__func) (void*), void *__args) { return __gthr_win32_create (__thr, __func, __args); } -static inline int +__GTHREAD_INLINE int __gthread_join (__gthread_t __thr, void **__value_ptr) { return __gthr_win32_join (__thr, __value_ptr); } -static inline __gthread_t +__GTHREAD_INLINE __gthread_t __gthread_self (void) { return __gthr_win32_self (); @@ -463,25 +474,25 @@ __gthread_self (void) Only stubs are exposed to avoid polluting the C++ namespace with Win32 API definitions. */ -static inline int +__GTHREAD_INLINE int __gthread_detach (__gthread_t __thr) { return __gthr_win32_detach (__thr); } -static inline int +__GTHREAD_INLINE int __gthread_equal (__gthread_t __thr1, __gthread_t __thr2) { return __gthr_win32_equal (__thr1, __thr2); } -static inline int +__GTHREAD_INLINE int __gthread_yield (void) { return __gthr_win32_yield (); } -static inline int +__GTHREAD_INLINE int __gthread_once (__gthread_once_t *__once, void (*__func) (void)) { if (__gthread_active_p ()) @@ -490,43 +501,43 @@ __gthread_once (__gthread_once_t *__once, void (*__func) (void)) return -1; } -static inline int +__GTHREAD_INLINE int __gthread_key_create (__gthread_key_t *__key, void (*__dtor) (void *)) { return __gthr_win32_key_create (__key, __dtor); } -static inline int +__GTHREAD_INLINE int __gthread_key_delete (__gthread_key_t __key) { return __gthr_win32_key_delete (__key); } -static inline void * +__GTHREAD_INLINE void * __gthread_getspecific (__gthread_key_t __key) { return __gthr_win32_getspecific (__key); } -static inline int +__GTHREAD_INLINE int __gthread_setspecific (__gthread_key_t __key, const void *__ptr) { return __gthr_win32_setspecific (__key, __ptr); } -static inline void +__GTHREAD_INLINE void __gthread_mutex_init_function (__gthread_mutex_t *__mutex) { __gthr_win32_mutex_init_function (__mutex); } -static inline void +__GTHREAD_INLINE void __gthread_mutex_destroy (__gthread_mutex_t *__mutex) { __gthr_win32_mutex_destroy (__mutex); } -static inline int +__GTHREAD_INLINE int __gthread_mutex_lock (__gthread_mutex_t *__mutex) { if (__gthread_active_p ()) @@ -535,7 +546,7 @@ __gthread_mutex_lock (__gthread_mutex_t *__mutex) return 0; } -static inline int +__GTHREAD_INLINE int __gthread_mutex_trylock (__gthread_mutex_t *__mutex) { if (__gthread_active_p ()) @@ -544,7 +555,7 @@ __gthread_mutex_trylock (__gthread_mutex_t *__mutex) return 0; } -static inline int +__GTHREAD_INLINE int __gthread_mutex_unlock (__gthread_mutex_t *__mutex) { if (__gthread_active_p ()) @@ -553,7 +564,7 @@ __gthread_mutex_unlock (__gthread_mutex_t *__mutex) return 0; } -static inline int +__GTHREAD_INLINE int __gthread_recursive_mutex_trylock (__gthread_recursive_mutex_t *__mutex) { if (__gthread_active_p ()) @@ -564,31 +575,31 @@ __gthread_recursive_mutex_trylock (__gthread_recursive_mutex_t *__mutex) #if __GTHREAD_HAS_COND -static inline void +__GTHREAD_INLINE void __gthread_cond_init_function (__gthread_cond_t *__cond) { __gthr_win32_cond_init_function (__cond); } -static inline int +__GTHREAD_INLINE int __gthread_cond_broadcast (__gthread_cond_t *__cond) { return __gthr_win32_cond_broadcast (__cond); } -static inline int +__GTHREAD_INLINE int __gthread_cond_signal (__gthread_cond_t *__cond) { return __gthr_win32_cond_signal (__cond); } -static inline int +__GTHREAD_INLINE int __gthread_cond_wait (__gthread_cond_t *__cond, __gthread_mutex_t *__mutex) { return __gthr_win32_cond_wait (__cond, __mutex); } -static inline int +__GTHREAD_INLINE int __gthread_cond_timedwait (__gthread_cond_t *__cond, __gthread_mutex_t *__mutex, const __gthread_time_t *__abs_time) { @@ -600,11 +611,11 @@ __gthread_cond_timedwait (__gthread_cond_t *__cond, __gthread_mutex_t *__mutex, #else /* ! __GTHREAD_HIDE_WIN32API */ #ifndef __GTHREAD_WIN32_INLINE -#define __GTHREAD_WIN32_INLINE static inline +#define __GTHREAD_WIN32_INLINE __GTHREAD_INLINE #endif #ifndef __GTHREAD_WIN32_COND_INLINE -#define __GTHREAD_WIN32_COND_INLINE static inline +#define __GTHREAD_WIN32_COND_INLINE __GTHREAD_INLINE #endif #ifndef __GTHREAD_WIN32_ACTIVE_P @@ -828,25 +839,25 @@ __gthread_cond_timedwait (__gthread_cond_t *__cond, #endif /* __GTHREAD_HIDE_WIN32API */ -static inline void +__GTHREAD_INLINE void __gthread_recursive_mutex_init_function (__gthread_recursive_mutex_t *__mutex) { __gthread_mutex_init_function (__mutex); } -static inline void +__GTHREAD_INLINE void __gthread_recursive_mutex_destroy (__gthread_recursive_mutex_t *__mutex) { __gthread_mutex_destroy (__mutex); } -static inline int +__GTHREAD_INLINE int __gthread_recursive_mutex_lock (__gthread_recursive_mutex_t *__mutex) { return __gthread_mutex_lock (__mutex); } -static inline int +__GTHREAD_INLINE int __gthread_recursive_mutex_unlock (__gthread_recursive_mutex_t *__mutex) { return __gthread_mutex_unlock (__mutex); @@ -854,13 +865,13 @@ __gthread_recursive_mutex_unlock (__gthread_recursive_mutex_t *__mutex) #if __GTHREAD_HAS_COND -static inline int +__GTHREAD_INLINE int __gthread_cond_destroy (__gthread_cond_t *__cond ATTRIBUTE_UNUSED) { return 0; } -static inline int +__GTHREAD_INLINE int __gthread_cond_wait_recursive (__gthread_cond_t *__cond, __gthread_recursive_mutex_t *__mutex) { diff --git a/libgcc/config/nvptx/unwind-nvptx.c b/libgcc/config/nvptx/unwind-nvptx.c index eae741c..97e22c0 100644 --- a/libgcc/config/nvptx/unwind-nvptx.c +++ b/libgcc/config/nvptx/unwind-nvptx.c @@ -38,6 +38,12 @@ _Unwind_DeleteException (struct _Unwind_Exception *exc) (*exc->exception_cleanup) (_URC_FOREIGN_EXCEPTION_CAUGHT, exc); } +void +_Unwind_Resume (struct _Unwind_Exception *exc __attribute__ ((__unused__))) +{ + __builtin_abort (); +} + _Unwind_Reason_Code _Unwind_Resume_or_Rethrow (struct _Unwind_Exception *exc __attribute__ ((__unused__))) { diff --git a/libgcc/config/sh/sfp-machine.h b/libgcc/config/sh/sfp-machine.h index 66984d4..8030c80 100644 --- a/libgcc/config/sh/sfp-machine.h +++ b/libgcc/config/sh/sfp-machine.h @@ -39,11 +39,11 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see #define _FP_DIV_MEAT_D(R,X,Y) _FP_DIV_MEAT_2_udiv(D,R,X,Y) #define _FP_DIV_MEAT_Q(R,X,Y) _FP_DIV_MEAT_4_udiv(Q,R,X,Y) -#define _FP_NANFRAC_B _FP_QNANBIT_B -#define _FP_NANFRAC_H _FP_QNANBIT_H -#define _FP_NANFRAC_S _FP_QNANBIT_S -#define _FP_NANFRAC_D _FP_QNANBIT_D, 0 -#define _FP_NANFRAC_Q _FP_QNANBIT_Q, 0, 0, 0 +#define _FP_NANFRAC_B (_FP_QNANBIT_B - 1) +#define _FP_NANFRAC_H (_FP_QNANBIT_H - 1) +#define _FP_NANFRAC_S (_FP_QNANBIT_S - 1) +#define _FP_NANFRAC_D (_FP_QNANBIT_D - 1), -1 +#define _FP_NANFRAC_Q (_FP_QNANBIT_Q - 1), -1, -1, -1 /* The type of the result of a floating point comparison. This must match __libgcc_cmp_return__ in GCC for the target. */ @@ -56,15 +56,71 @@ typedef int __gcc_CMPtype __attribute__ ((mode (__libgcc_cmp_return__))); #define _FP_NANSIGN_D 0 #define _FP_NANSIGN_Q 0 -#define _FP_KEEPNANFRACP 0 -#define _FP_QNANNEGATEDP 0 +#define _FP_KEEPNANFRACP 1 +#define _FP_QNANNEGATEDP 1 + +/* X is chosen unless one of the NaNs is sNaN. */ +# define _FP_CHOOSENAN(fs, wc, R, X, Y, OP) \ + do { \ + if ((_FP_FRAC_HIGH_RAW_##fs(X) | \ + _FP_FRAC_HIGH_RAW_##fs(Y)) & _FP_QNANBIT_##fs) \ + { \ + R##_s = _FP_NANSIGN_##fs; \ + _FP_FRAC_SET_##wc(R,_FP_NANFRAC_##fs); \ + } \ + else \ + { \ + R##_s = X##_s; \ + _FP_FRAC_COPY_##wc(R,X); \ + } \ + R##_c = FP_CLS_NAN; \ + } while (0) + +#ifdef __SH_FPU_ANY__ +#define _FPU_GETCW(fpscr) fpscr = __builtin_sh_get_fpscr () +#define _FPU_SETCW(fpscr) __builtin_sh_set_fpscr (fpscr) +#define FP_EX_ENABLE_SHIFT 5 +#define FP_EX_CAUSE_SHIFT 10 -#define _FP_CHOOSENAN(fs, wc, R, X, Y, OP) \ - do { \ - R##_s = _FP_NANSIGN_##fs; \ - _FP_FRAC_SET_##wc(R,_FP_NANFRAC_##fs); \ - R##_c = FP_CLS_NAN; \ +#define FP_EX_INVALID 0x0040 +#define FP_EX_DIVZERO 0x0020 +#if defined (__SH2E__) +#define FP_EX_ALL (FP_EX_DIVZERO | FP_EX_INVALID) +#else +#define FP_EX_OVERFLOW 0x0010 +#define FP_EX_UNDERFLOW 0x0008 +#define FP_EX_INEXACT 0x0004 +#define FP_EX_ALL (FP_EX_DIVZERO | FP_EX_INEXACT | \ + FP_EX_INVALID | FP_EX_OVERFLOW | FP_EX_UNDERFLOW) +#endif +#define _FP_DECL_EX \ + unsigned int _fcsr __attribute__ ((unused)) = FP_RND_NEAREST +/* Rounding modes. */ +#define FP_RND_NEAREST 0x0 +#define FP_RND_ZERO 0x1 +/* Placeholder, hardware does not have PINF/MINF modes. */ +#define FP_RND_PINF 0x2 +#define FP_RND_MINF 0x3 +#define FP_RND_MASK 3 + +#define FP_INIT_ROUNDMODE _FPU_GETCW (_fcsr) +#define FP_ROUNDMODE (_fcsr & FP_RND_MASK) +#define FP_TRAPPING_EXCEPTIONS ((_fcsr >> FP_EX_ENABLE_SHIFT) & FP_EX_ALL) +#define FP_HANDLE_EXCEPTIONS \ + do { \ + _fcsr &= ~(FP_EX_ALL << FP_EX_CAUSE_SHIFT); \ + _fcsr |= _fex | (_fex << FP_EX_CAUSE_SHIFT); \ + _FPU_SETCW (_fcsr); \ } while (0) +#else +#define FP_EX_INVALID (1 << 4) +#define FP_EX_DIVZERO (1 << 3) +#if !defined (__SH2E__) +#define FP_EX_OVERFLOW (1 << 2) +#define FP_EX_UNDERFLOW (1 << 1) +#define FP_EX_INEXACT (1 << 0) +#endif +#endif #define _FP_TININESS_AFTER_ROUNDING 1 diff --git a/libgcobol/ChangeLog b/libgcobol/ChangeLog index 7165c2b..9de1714 100644 --- a/libgcobol/ChangeLog +++ b/libgcobol/ChangeLog @@ -1,3 +1,51 @@ +2025-04-21 Rainer Orth <ro@CeBiTec.Uni-Bielefeld.DE> + + * configure.ac: Check for struct tm.tm_zone. + * configure, config.h.in: Regenerate. + * intrinsic.cc (__gg__formatted_current_date): Guard tm.tm_zone + use with HAVE_STRUCT_TM_TM_ZONE. + +2025-04-15 Andreas Schwab <schwab@suse.de> + + * configure.tgt: Set LIBGCOBOL_SUPPORTED for riscv64-*-linux* with + 64-bit multilib. + +2025-04-15 Jakub Jelinek <jakub@redhat.com> + Rainer Orth <ro@CeBiTec.Uni-Bielefeld.DE> + + PR cobol/119244 + * acinclude.m4 (LIBGCOBOL_CHECK_FLOAT128): Ensure + libgcob_cv_have_float128 is not yes on targets with IEEE quad + long double. Don't check for --as-needed nor set LIBQUADSPEC + on targets which USE_IEC_60559. + * libgcobol-fp.h (FP128_FMT, strtofp128, strfromfp128): Define. + * intrinsic.cc (strtof128): Don't redefine. + (WEIRD_TRANSCENDENT_RETURN_VALUE): Use GCOB_FP128_LITERAL macro. + (__gg__numval_f): Use strtofp128 instead of strtof128. + * libgcobol.cc (strtof128): Don't redefine. + (format_for_display_internal): Use strfromfp128 instead of + strfromf128 or quadmath_snprintf and use FP128_FMT in the format + string. + (get_float128, __gg__compare_2, __gg__move, __gg__move_literala): + Use strtofp128 instead of strtof128. + * configure: Regenerate. + +2025-04-14 Andreas Schwab <schwab@suse.de> + + * libgcobol.cc (__gg__float64_from_128): Mark literal as float128 + literal. + +2025-04-13 Rainer Orth <ro@CeBiTec.Uni-Bielefeld.DE> + + * valconv.cc (__gg__string_to_numeric_edited): Use strchr instead + of index. + +2025-04-12 Bob Dubner <rdubner@symas.com> + + PR cobol/119694 + * gfileio.cc: Eliminate getenv() calls. + * libgcobol.cc: Likewise. + 2025-04-10 Iain Sandoe <iain@sandoe.co.uk> * configure.tgt: Enable for x86_64 Darwin. diff --git a/libgcobol/acinclude.m4 b/libgcobol/acinclude.m4 index aab0895..0e81b10 100644 --- a/libgcobol/acinclude.m4 +++ b/libgcobol/acinclude.m4 @@ -44,6 +44,10 @@ AC_DEFUN([LIBGCOBOL_CHECK_FLOAT128], [ AC_CACHE_CHECK([whether we have a usable _Float128 type], libgcob_cv_have_float128, [ GCC_TRY_COMPILE_OR_LINK([ +#if __LDBL_MANT_DIG__ == 113 && __LDBL_MIN_EXP__ == -16381 +#error "long double is IEEE quad, no need for libquadmath" +#endif + _Float128 foo (_Float128 x) { _Complex _Float128 z1, z2; @@ -90,32 +94,22 @@ AC_DEFUN([LIBGCOBOL_CHECK_FLOAT128], [ fi AC_DEFINE(HAVE_FLOAT128, 1, [Define if target has usable _Float128 and __float128 types.]) - dnl Check whether -Wl,--as-needed resp. -Wl,-zignore is supported - dnl - dnl Turn warnings into error to avoid testsuite breakage. So enable - dnl AC_LANG_WERROR, but there's currently (autoconf 2.64) no way to turn - dnl it off again. As a workaround, save and restore werror flag like - dnl AC_PATH_XTRA. - dnl Cf. http://gcc.gnu.org/ml/gcc-patches/2010-05/msg01889.html - ac_xsave_[]_AC_LANG_ABBREV[]_werror_flag=$ac_[]_AC_LANG_ABBREV[]_werror_flag - AC_CACHE_CHECK([whether --as-needed/-z ignore works], - [libgcob_cv_have_as_needed], - [ - # Test for native Solaris options first. - # No whitespace after -z to pass it through -Wl. - libgcob_cv_as_needed_option="-zignore" - libgcob_cv_no_as_needed_option="-zrecord" - save_LDFLAGS="$LDFLAGS" - LDFLAGS="$LDFLAGS -Wl,$libgcob_cv_as_needed_option -lm -Wl,$libgcob_cv_no_as_needed_option" - libgcob_cv_have_as_needed=no - AC_LANG_WERROR - AC_LINK_IFELSE([AC_LANG_PROGRAM([])], - [libgcob_cv_have_as_needed=yes], - [libgcob_cv_have_as_needed=no]) - LDFLAGS="$save_LDFLAGS" - if test "x$libgcob_cv_have_as_needed" = xno; then - libgcob_cv_as_needed_option="--as-needed" - libgcob_cv_no_as_needed_option="--no-as-needed" + if test "x$USE_IEC_60559" != xyes; then + dnl Check whether -Wl,--as-needed resp. -Wl,-zignore is supported + dnl + dnl Turn warnings into error to avoid testsuite breakage. So enable + dnl AC_LANG_WERROR, but there's currently (autoconf 2.64) no way to turn + dnl it off again. As a workaround, save and restore werror flag like + dnl AC_PATH_XTRA. + dnl Cf. http://gcc.gnu.org/ml/gcc-patches/2010-05/msg01889.html + ac_xsave_[]_AC_LANG_ABBREV[]_werror_flag=$ac_[]_AC_LANG_ABBREV[]_werror_flag + AC_CACHE_CHECK([whether --as-needed/-z ignore works], + [libgcob_cv_have_as_needed], + [ + # Test for native Solaris options first. + # No whitespace after -z to pass it through -Wl. + libgcob_cv_as_needed_option="-zignore" + libgcob_cv_no_as_needed_option="-zrecord" save_LDFLAGS="$LDFLAGS" LDFLAGS="$LDFLAGS -Wl,$libgcob_cv_as_needed_option -lm -Wl,$libgcob_cv_no_as_needed_option" libgcob_cv_have_as_needed=no @@ -124,45 +118,51 @@ AC_DEFUN([LIBGCOBOL_CHECK_FLOAT128], [ [libgcob_cv_have_as_needed=yes], [libgcob_cv_have_as_needed=no]) LDFLAGS="$save_LDFLAGS" - fi - ac_[]_AC_LANG_ABBREV[]_werror_flag=$ac_xsave_[]_AC_LANG_ABBREV[]_werror_flag - ]) - - dnl Determine -Bstatic ... -Bdynamic etc. support from gfortran -### stderr. - touch conftest1.$ac_objext conftest2.$ac_objext - LQUADMATH=-lquadmath - $CXX -static-libgcobol -### -o conftest \ - conftest1.$ac_objext -lgcobol conftest2.$ac_objext 2>&1 >/dev/null \ - | grep "conftest1.$ac_objext.*conftest2.$ac_objext" > conftest.cmd - if grep "conftest1.$ac_objext.* -Bstatic -lgcobol -Bdynamic .*conftest2.$ac_objext" \ - conftest.cmd >/dev/null 2>&1; then - LQUADMATH="%{static-libquadmath:-Bstatic} -lquadmath %{static-libquadmath:-Bdynamic}" - elif grep "conftest1.$ac_objext.* -bstatic -lgcobol -bdynamic .*conftest2.$ac_objext" \ - conftest.cmd >/dev/null 2>&1; then - LQUADMATH="%{static-libquadmath:-bstatic} -lquadmath %{static-libquadmath:-bdynamic}" - elif grep "conftest1.$ac_objext.* -aarchive_shared -lgcobol -adefault .*conftest2.$ac_objext" \ - conftest.cmd >/dev/null 2>&1; then - LQUADMATH="%{static-libquadmath:-aarchive_shared} -lquadmath %{static-libquadmath:-adefault}" - elif grep "conftest1.$ac_objext.*libgcobol.a .*conftest2.$ac_objext" \ + if test "x$libgcob_cv_have_as_needed" = xno; then + libgcob_cv_as_needed_option="--as-needed" + libgcob_cv_no_as_needed_option="--no-as-needed" + save_LDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS -Wl,$libgcob_cv_as_needed_option -lm -Wl,$libgcob_cv_no_as_needed_option" + libgcob_cv_have_as_needed=no + AC_LANG_WERROR + AC_LINK_IFELSE([AC_LANG_PROGRAM([])], + [libgcob_cv_have_as_needed=yes], + [libgcob_cv_have_as_needed=no]) + LDFLAGS="$save_LDFLAGS" + fi + ac_[]_AC_LANG_ABBREV[]_werror_flag=$ac_xsave_[]_AC_LANG_ABBREV[]_werror_flag + ]) + + dnl Determine -Bstatic ... -Bdynamic etc. support from gfortran -### stderr. + touch conftest1.$ac_objext conftest2.$ac_objext + LQUADMATH=-lquadmath + $CXX -static-libgcobol -### -o conftest \ + conftest1.$ac_objext -lgcobol conftest2.$ac_objext 2>&1 >/dev/null \ + | grep "conftest1.$ac_objext.*conftest2.$ac_objext" > conftest.cmd + if grep "conftest1.$ac_objext.* -Bstatic -lgcobol -Bdynamic .*conftest2.$ac_objext" \ + conftest.cmd >/dev/null 2>&1; then + LQUADMATH="%{static-libquadmath:-Bstatic} -lquadmath %{static-libquadmath:-Bdynamic}" + elif grep "conftest1.$ac_objext.* -bstatic -lgcobol -bdynamic .*conftest2.$ac_objext" \ + conftest.cmd >/dev/null 2>&1; then + LQUADMATH="%{static-libquadmath:-bstatic} -lquadmath %{static-libquadmath:-bdynamic}" + elif grep "conftest1.$ac_objext.* -aarchive_shared -lgcobol -adefault .*conftest2.$ac_objext" \ + conftest.cmd >/dev/null 2>&1; then + LQUADMATH="%{static-libquadmath:-aarchive_shared} -lquadmath %{static-libquadmath:-adefault}" + elif grep "conftest1.$ac_objext.*libgcobol.a .*conftest2.$ac_objext" \ conftest.cmd >/dev/null 2>&1; then - LQUADMATH="%{static-libquadmath:libquadmath.a%s;:-lquadmath}" - fi - rm -f conftest1.$ac_objext conftest2.$ac_objext conftest conftest.cmd - - dnl For static libgcobol linkage, depend on libquadmath only if needed. - dnl If using *f128 APIs from libc/libm, depend on libquadmath only if needed - dnl even for dynamic libgcobol linkage, and don't link libgcobol against - dnl -lquadmath. - if test "x$libgcob_cv_have_as_needed" = xyes; then - if test "x$USE_IEC_60559" = xyes; then - LIBQUADSPEC="$libgcob_cv_as_needed_option $LQUADMATH $libgcob_cv_no_as_needed_option" + LQUADMATH="%{static-libquadmath:libquadmath.a%s;:-lquadmath}" + fi + rm -f conftest1.$ac_objext conftest2.$ac_objext conftest conftest.cmd + + if test "x$libgcob_cv_have_as_needed" = xyes; then + if test "x$USE_IEC_60559" = xyes; then + LIBQUADSPEC="$libgcob_cv_as_needed_option $LQUADMATH $libgcob_cv_no_as_needed_option" + else + LIBQUADSPEC="%{static-libgcobol:$libgcob_cv_as_needed_option} $LQUADMATH %{static-libgcobol:$libgcob_cv_no_as_needed_option}" + fi else - LIBQUADSPEC="%{static-libgcobol:$libgcob_cv_as_needed_option} $LQUADMATH %{static-libgcobol:$libgcob_cv_no_as_needed_option}" + LIBQUADSPEC="$LQUADMATH" fi - else - LIBQUADSPEC="$LQUADMATH" - fi - if test "x$USE_IEC_60559" != xyes; then if test -f ../libquadmath/libquadmath.la; then LIBQUADLIB=../libquadmath/libquadmath.la LIBQUADLIB_DEP=../libquadmath/libquadmath.la diff --git a/libgcobol/config.h.in b/libgcobol/config.h.in index 6a53279..fdf5e3e 100644 --- a/libgcobol/config.h.in +++ b/libgcobol/config.h.in @@ -72,6 +72,9 @@ /* Define to 1 if you have the `strtof128' function. */ #undef HAVE_STRTOF128 +/* Define to 1 if `tm_zone' is a member of `struct tm'. */ +#undef HAVE_STRUCT_TM_TM_ZONE + /* Define to 1 if you have the <sys/stat.h> header file. */ #undef HAVE_SYS_STAT_H diff --git a/libgcobol/configure b/libgcobol/configure index 6c2747c..6821591 100755 --- a/libgcobol/configure +++ b/libgcobol/configure @@ -2449,6 +2449,63 @@ $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_cxx_check_func + +# ac_fn_cxx_check_member LINENO AGGR MEMBER VAR INCLUDES +# ------------------------------------------------------ +# Tries to find if the field MEMBER exists in type AGGR, after including +# INCLUDES, setting cache variable VAR accordingly. +ac_fn_cxx_check_member () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2.$3" >&5 +$as_echo_n "checking for $2.$3... " >&6; } +if eval \${$4+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$5 +int +main () +{ +static $2 ac_aggr; +if (ac_aggr.$3) +return 0; + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + eval "$4=yes" +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$5 +int +main () +{ +static $2 ac_aggr; +if (sizeof ac_aggr.$3) +return 0; + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + eval "$4=yes" +else + eval "$4=no" +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +eval ac_res=\$$4 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_cxx_check_member cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. @@ -11693,7 +11750,7 @@ else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF -#line 11696 "configure" +#line 11753 "configure" #include "confdefs.h" #if HAVE_DLFCN_H @@ -11799,7 +11856,7 @@ else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF -#line 11802 "configure" +#line 11859 "configure" #include "confdefs.h" #if HAVE_DLFCN_H @@ -17172,6 +17229,10 @@ else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ +#if __LDBL_MANT_DIG__ == 113 && __LDBL_MIN_EXP__ == -16381 +#error "long double is IEEE quad, no need for libquadmath" +#endif + _Float128 foo (_Float128 x) { _Complex _Float128 z1, z2; @@ -17225,6 +17286,10 @@ fi cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ +#if __LDBL_MANT_DIG__ == 113 && __LDBL_MIN_EXP__ == -16381 +#error "long double is IEEE quad, no need for libquadmath" +#endif + _Float128 foo (_Float128 x) { _Complex _Float128 z1, z2; @@ -17296,23 +17361,24 @@ $as_echo "#define USE_QUADMATH 1" >>confdefs.h $as_echo "#define HAVE_FLOAT128 1" >>confdefs.h - ac_xsave_cxx_werror_flag=$ac_cxx_werror_flag - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether --as-needed/-z ignore works" >&5 + if test "x$USE_IEC_60559" != xyes; then + ac_xsave_cxx_werror_flag=$ac_cxx_werror_flag + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether --as-needed/-z ignore works" >&5 $as_echo_n "checking whether --as-needed/-z ignore works... " >&6; } if ${libgcob_cv_have_as_needed+:} false; then : $as_echo_n "(cached) " >&6 else - # Test for native Solaris options first. - # No whitespace after -z to pass it through -Wl. - libgcob_cv_as_needed_option="-zignore" - libgcob_cv_no_as_needed_option="-zrecord" - save_LDFLAGS="$LDFLAGS" - LDFLAGS="$LDFLAGS -Wl,$libgcob_cv_as_needed_option -lm -Wl,$libgcob_cv_no_as_needed_option" - libgcob_cv_have_as_needed=no + # Test for native Solaris options first. + # No whitespace after -z to pass it through -Wl. + libgcob_cv_as_needed_option="-zignore" + libgcob_cv_no_as_needed_option="-zrecord" + save_LDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS -Wl,$libgcob_cv_as_needed_option -lm -Wl,$libgcob_cv_no_as_needed_option" + libgcob_cv_have_as_needed=no ac_cxx_werror_flag=yes - if test x$gcc_no_link = xyes; then + 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 @@ -17333,16 +17399,16 @@ else fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext - LDFLAGS="$save_LDFLAGS" - if test "x$libgcob_cv_have_as_needed" = xno; then - libgcob_cv_as_needed_option="--as-needed" - libgcob_cv_no_as_needed_option="--no-as-needed" - save_LDFLAGS="$LDFLAGS" - LDFLAGS="$LDFLAGS -Wl,$libgcob_cv_as_needed_option -lm -Wl,$libgcob_cv_no_as_needed_option" - libgcob_cv_have_as_needed=no + LDFLAGS="$save_LDFLAGS" + if test "x$libgcob_cv_have_as_needed" = xno; then + libgcob_cv_as_needed_option="--as-needed" + libgcob_cv_no_as_needed_option="--no-as-needed" + save_LDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS -Wl,$libgcob_cv_as_needed_option -lm -Wl,$libgcob_cv_no_as_needed_option" + libgcob_cv_have_as_needed=no ac_cxx_werror_flag=yes - if test x$gcc_no_link = xyes; then + 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 @@ -17363,44 +17429,43 @@ else fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext - LDFLAGS="$save_LDFLAGS" - fi - ac_cxx_werror_flag=$ac_xsave_cxx_werror_flag + LDFLAGS="$save_LDFLAGS" + fi + ac_cxx_werror_flag=$ac_xsave_cxx_werror_flag fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $libgcob_cv_have_as_needed" >&5 $as_echo "$libgcob_cv_have_as_needed" >&6; } - touch conftest1.$ac_objext conftest2.$ac_objext - LQUADMATH=-lquadmath - $CXX -static-libgcobol -### -o conftest \ - conftest1.$ac_objext -lgcobol conftest2.$ac_objext 2>&1 >/dev/null \ - | grep "conftest1.$ac_objext.*conftest2.$ac_objext" > conftest.cmd - if grep "conftest1.$ac_objext.* -Bstatic -lgcobol -Bdynamic .*conftest2.$ac_objext" \ - conftest.cmd >/dev/null 2>&1; then - LQUADMATH="%{static-libquadmath:-Bstatic} -lquadmath %{static-libquadmath:-Bdynamic}" - elif grep "conftest1.$ac_objext.* -bstatic -lgcobol -bdynamic .*conftest2.$ac_objext" \ + touch conftest1.$ac_objext conftest2.$ac_objext + LQUADMATH=-lquadmath + $CXX -static-libgcobol -### -o conftest \ + conftest1.$ac_objext -lgcobol conftest2.$ac_objext 2>&1 >/dev/null \ + | grep "conftest1.$ac_objext.*conftest2.$ac_objext" > conftest.cmd + if grep "conftest1.$ac_objext.* -Bstatic -lgcobol -Bdynamic .*conftest2.$ac_objext" \ + conftest.cmd >/dev/null 2>&1; then + LQUADMATH="%{static-libquadmath:-Bstatic} -lquadmath %{static-libquadmath:-Bdynamic}" + elif grep "conftest1.$ac_objext.* -bstatic -lgcobol -bdynamic .*conftest2.$ac_objext" \ + conftest.cmd >/dev/null 2>&1; then + LQUADMATH="%{static-libquadmath:-bstatic} -lquadmath %{static-libquadmath:-bdynamic}" + elif grep "conftest1.$ac_objext.* -aarchive_shared -lgcobol -adefault .*conftest2.$ac_objext" \ + conftest.cmd >/dev/null 2>&1; then + LQUADMATH="%{static-libquadmath:-aarchive_shared} -lquadmath %{static-libquadmath:-adefault}" + elif grep "conftest1.$ac_objext.*libgcobol.a .*conftest2.$ac_objext" \ conftest.cmd >/dev/null 2>&1; then - LQUADMATH="%{static-libquadmath:-bstatic} -lquadmath %{static-libquadmath:-bdynamic}" - elif grep "conftest1.$ac_objext.* -aarchive_shared -lgcobol -adefault .*conftest2.$ac_objext" \ - conftest.cmd >/dev/null 2>&1; then - LQUADMATH="%{static-libquadmath:-aarchive_shared} -lquadmath %{static-libquadmath:-adefault}" - elif grep "conftest1.$ac_objext.*libgcobol.a .*conftest2.$ac_objext" \ - conftest.cmd >/dev/null 2>&1; then - LQUADMATH="%{static-libquadmath:libquadmath.a%s;:-lquadmath}" - fi - rm -f conftest1.$ac_objext conftest2.$ac_objext conftest conftest.cmd + LQUADMATH="%{static-libquadmath:libquadmath.a%s;:-lquadmath}" + fi + rm -f conftest1.$ac_objext conftest2.$ac_objext conftest conftest.cmd - if test "x$libgcob_cv_have_as_needed" = xyes; then - if test "x$USE_IEC_60559" = xyes; then - LIBQUADSPEC="$libgcob_cv_as_needed_option $LQUADMATH $libgcob_cv_no_as_needed_option" + if test "x$libgcob_cv_have_as_needed" = xyes; then + if test "x$USE_IEC_60559" = xyes; then + LIBQUADSPEC="$libgcob_cv_as_needed_option $LQUADMATH $libgcob_cv_no_as_needed_option" + else + LIBQUADSPEC="%{static-libgcobol:$libgcob_cv_as_needed_option} $LQUADMATH %{static-libgcobol:$libgcob_cv_no_as_needed_option}" + fi else - LIBQUADSPEC="%{static-libgcobol:$libgcob_cv_as_needed_option} $LQUADMATH %{static-libgcobol:$libgcob_cv_no_as_needed_option}" + LIBQUADSPEC="$LQUADMATH" fi - else - LIBQUADSPEC="$LQUADMATH" - fi - if test "x$USE_IEC_60559" != xyes; then if test -f ../libquadmath/libquadmath.la; then LIBQUADLIB=../libquadmath/libquadmath.la LIBQUADLIB_DEP=../libquadmath/libquadmath.la @@ -17426,6 +17491,19 @@ $as_echo "#define USE_IEC_60559 1" >>confdefs.h +# struct tm tm_zone is a POSIX.1-2024 addition. +ac_fn_cxx_check_member "$LINENO" "struct tm" "tm_zone" "ac_cv_member_struct_tm_tm_zone" "#include <time.h> +" +if test "x$ac_cv_member_struct_tm_tm_zone" = xyes; then : + +cat >>confdefs.h <<_ACEOF +#define HAVE_STRUCT_TM_TM_ZONE 1 +_ACEOF + + +fi + + if test "${multilib}" = "yes"; then multilib_arg="--enable-multilib" else diff --git a/libgcobol/configure.ac b/libgcobol/configure.ac index a1e9513..4bb6905 100644 --- a/libgcobol/configure.ac +++ b/libgcobol/configure.ac @@ -231,6 +231,9 @@ elif test "${ENABLE_LIBQUADMATH_SUPPORT}" = "default" ; then fi LIBGCOBOL_CHECK_FLOAT128 +# struct tm tm_zone is a POSIX.1-2024 addition. +AC_CHECK_MEMBERS([struct tm.tm_zone],,,[#include <time.h>]) + if test "${multilib}" = "yes"; then multilib_arg="--enable-multilib" else diff --git a/libgcobol/configure.tgt b/libgcobol/configure.tgt index ebf044e..a239252 100644 --- a/libgcobol/configure.tgt +++ b/libgcobol/configure.tgt @@ -34,6 +34,11 @@ case "${target}" in LIBGCOBOL_SUPPORTED=yes fi ;; + riscv64-*-linux*) + if test x$ac_cv_sizeof_void_p = x8; then + LIBGCOBOL_SUPPORTED=yes + fi + ;; x86_64-*-linux* | i?86-*-linux* | x86_64-*-darwin*) if test x$ac_cv_sizeof_void_p = x8; then LIBGCOBOL_SUPPORTED=yes diff --git a/libgcobol/intrinsic.cc b/libgcobol/intrinsic.cc index 844cd38..97f2bdc 100644 --- a/libgcobol/intrinsic.cc +++ b/libgcobol/intrinsic.cc @@ -55,19 +55,11 @@ #include "charmaps.h" -#if !defined (HAVE_STRTOF128) -# if USE_QUADMATH -# define strtof128 strtoflt128 -# else -# error "no available string to float 128" -# endif -#endif - #pragma GCC diagnostic ignored "-Wformat-truncation" #define JD_OF_1601_01_02 2305812.5 -#define WEIRD_TRANSCENDENT_RETURN_VALUE (0.0Q) +#define WEIRD_TRANSCENDENT_RETURN_VALUE GCOB_FP128_LITERAL (0.0) #define NO_RDIGITS (0) struct cobol_tm @@ -1490,7 +1482,9 @@ __gg__formatted_current_date( cblc_field_t *dest, // Destination string __gg__clock_gettime(CLOCK_REALTIME, &ts); struct tm tm = {}; +#ifdef HAVE_STRUCT_TM_TM_ZONE tm.tm_zone = "GMT"; +#endif if( is_zulu ) { gmtime_r(&ts.tv_sec, &tm); @@ -5016,7 +5010,7 @@ __gg__numval_f( cblc_field_t *dest, } } *p++ = '\0'; - value = strtof128(ach, NULL); + value = strtofp128(ach, NULL); } __gg__float128_to_field(dest, value, diff --git a/libgcobol/libgcobol-fp.h b/libgcobol/libgcobol-fp.h index bd443f3..fcfa0a7 100644 --- a/libgcobol/libgcobol-fp.h +++ b/libgcobol/libgcobol-fp.h @@ -28,17 +28,26 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see # define GCOB_FP128 long double # define GCOB_FP128_LITERAL(lit) (lit ## l) # define FP128_FUNC(funcname) funcname ## l +# define FP128_FMT "L" +# define strtofp128(nptr, endptr) strtold(nptr, endptr) +# define strfromfp128(str, n, format, fp) snprintf(str, n, format, fp) #elif __FLT128_MANT_DIG__ == 113 && __FLT128_MIN_EXP__ == -16381 \ && defined(USE_IEC_60559) // Use _Float128, f128 suffix on calls, f128 or F128 suffix on literals # define GCOB_FP128 _Float128 # define GCOB_FP128_LITERAL(lit) (lit ## f128) # define FP128_FUNC(funcname) funcname ## f128 +# define FP128_FMT "" +# define strtofp128(nptr, endptr) strtof128(nptr, endptr) +# define strfromfp128(str, n, format, fp) strfromf128(str, n, format, fp) #elif __FLT128_MANT_DIG__ == 113 && __FLT128_MIN_EXP__ == -16381 // Use __float128, q suffix on calls, q or Q suffix on literals # define GCOB_FP128 __float128 # define GCOB_FP128_LITERAL(lit) (lit ## q) # define FP128_FUNC(funcname) funcname ## q +# define FP128_FMT "Q" +# define strtofp128(nptr, endptr) strtoflt128(nptr, endptr) +# define strfromfp128(str, n, format, fp) quadmath_snprintf(str, n, format, fp) #else # error "libgcobol requires 128b floating point" #endif diff --git a/libgcobol/libgcobol.cc b/libgcobol/libgcobol.cc index 1d4cdf8..c438d6b 100644 --- a/libgcobol/libgcobol.cc +++ b/libgcobol/libgcobol.cc @@ -93,20 +93,6 @@ strfromf64 (char *s, size_t n, const char *f, double v) # endif #endif -#if !defined (HAVE_STRFROMF128) -# if !USE_QUADMATH -# error "no available float 128 to string" -# endif -#endif - -#if !defined (HAVE_STRTOF128) -# if USE_QUADMATH -# define strtof128 strtoflt128 -# else -# error "no available string to float 128" -# endif -#endif - // This couldn't be defined in symbols.h because it conflicts with a LEVEL66 // in parse.h #define LEVEL66 (66) @@ -3262,11 +3248,7 @@ format_for_display_internal(char **dest, // on a 16-bit boundary. GCOB_FP128 floatval; memcpy(&floatval, actual_location, 16); -#if !defined (HAVE_STRFROMF128) && USE_QUADMATH - quadmath_snprintf(ach, sizeof(ach), "%.36QE", floatval); -#else - strfromf128(ach, sizeof(ach), "%.36E", floatval); -#endif + strfromfp128(ach, sizeof(ach), "%.36" FP128_FMT "E", floatval); char *p = strchr(ach, 'E'); if( !p ) { @@ -3288,13 +3270,8 @@ format_for_display_internal(char **dest, int precision = 36 - exp; char achFormat[24]; -#if !defined (HAVE_STRFROMF128) && USE_QUADMATH - sprintf(achFormat, "%%.%dQf", precision); - quadmath_snprintf(ach, sizeof(ach), achFormat, floatval); -#else - sprintf(achFormat, "%%.%df", precision); - strfromf128(ach, sizeof(ach), achFormat, floatval); -#endif + sprintf(achFormat, "%%.%d" FP128_FMT "f", precision); + strfromfp128(ach, sizeof(ach), achFormat, floatval); } __gg__remove_trailing_zeroes(ach); __gg__realloc_if_necessary(dest, dest_size, strlen(ach)+1); @@ -3533,7 +3510,7 @@ get_float128( cblc_field_t *field, { if( __gg__decimal_point == '.' ) { - retval = strtof128(field->initial, NULL); + retval = strtofp128(field->initial, NULL); } else { @@ -3551,7 +3528,7 @@ get_float128( cblc_field_t *field, { *p = '.'; } - retval = strtof128(buffer, NULL); + retval = strtofp128(buffer, NULL); } } else @@ -4248,7 +4225,7 @@ __gg__compare_2(cblc_field_t *left_side, //_Float128 left_value = *(_Float128 *)left_location; GCOB_FP128 left_value; memcpy(&left_value, left_location, 16); - GCOB_FP128 right_value = strtof128(buffer, NULL); + GCOB_FP128 right_value = strtofp128(buffer, NULL); retval = 0; retval = left_value < right_value ? -1 : retval; retval = left_value > right_value ? 1 : retval; @@ -5998,8 +5975,8 @@ __gg__move( cblc_field_t *fdest, } case 16: { - //*(_Float128 *)(fdest->data+dest_offset) = strtof128(ach, NULL); - GCOB_FP128 t = strtof128(ach, NULL); + //*(_Float128 *)(fdest->data+dest_offset) = strtofp128(ach, NULL); + GCOB_FP128 t = strtofp128(ach, NULL); memcpy(fdest->data+dest_offset, &t, 16); break; } @@ -6168,7 +6145,7 @@ __gg__move_literala(cblc_field_t *field, } case 16: { - GCOB_FP128 t = strtof128(ach, NULL); + GCOB_FP128 t = strtofp128(ach, NULL); memcpy(field->data+field_offset, &t, 16); break; } @@ -11708,7 +11685,7 @@ __gg__float64_from_128( cblc_field_t *dest, // _Float128 value = *(_Float128*)(source->data+source_offset); GCOB_FP128 value; memcpy(&value, source->data+source_offset, 16); - if( FP128_FUNC(fabs)(value) > 1.7976931348623157E308 ) + if( FP128_FUNC(fabs)(value) > GCOB_FP128_LITERAL(1.7976931348623157E308) ) { retval = 1; } diff --git a/libgcobol/valconv.cc b/libgcobol/valconv.cc index 33d9a0d..7e58301 100644 --- a/libgcobol/valconv.cc +++ b/libgcobol/valconv.cc @@ -853,14 +853,14 @@ got_float: } else { - const char *decimal_location = index(dest, __gg__decimal_point); + const char *decimal_location = strchr(dest, __gg__decimal_point); if( !decimal_location ) { - decimal_location = index(dest, ascii_v); + decimal_location = strchr(dest, ascii_v); } if( !decimal_location ) { - decimal_location = index(dest, ascii_V); + decimal_location = strchr(dest, ascii_V); } if( !decimal_location ) { diff --git a/libgfortran/ChangeLog b/libgfortran/ChangeLog index 3eaf75d..956b43d 100644 --- a/libgfortran/ChangeLog +++ b/libgfortran/ChangeLog @@ -1,3 +1,11 @@ +2025-04-13 Jerry DeLisle <jvdelisle@gcc.gnu.org> + + PR libfortran/119502 + * io/close.c (st_close): Issue an error and avoid + calling close_share when there is no stream assigned. + * io/open.c (st_open): If there is no stream assigned + to the unit, unlock the unit and issue an error. + 2025-04-09 Paul Thomas <pault@gcc.gnu.org> and Harald Anlauf <anlauf@gcc.gnu.org> diff --git a/libgfortran/io/close.c b/libgfortran/io/close.c index 8122311..41d278c 100644 --- a/libgfortran/io/close.c +++ b/libgfortran/io/close.c @@ -84,8 +84,17 @@ st_close (st_parameter_close *clp) if (u != NULL) { - if (close_share (u) < 0) - generate_error (&clp->common, LIBERROR_OS, "Problem in CLOSE"); + if (u->s == NULL) + { + if (u->unit_number < 0) + generate_error (&clp->common, LIBERROR_BAD_UNIT, + "Unit number is negative with no associated file"); + library_end (); + return; + } + else + if (close_share (u) < 0) + generate_error (&clp->common, LIBERROR_OS, "Problem in CLOSE"); if (u->flags.status == STATUS_SCRATCH) { if (status == CLOSE_KEEP) diff --git a/libgfortran/io/open.c b/libgfortran/io/open.c index 06ddf7f..e9fb0a7 100644 --- a/libgfortran/io/open.c +++ b/libgfortran/io/open.c @@ -912,6 +912,16 @@ st_open (st_parameter_open *opp) library_end (); return; } + + if (u->s == NULL) + { + unlock_unit (u); + generate_error (&opp->common, LIBERROR_BAD_OPTION, + "Unit number is negative and unit was not already " + "opened with OPEN(NEWUNIT=...)"); + library_end (); + return; + } } if (u == NULL) diff --git a/libgomp/ChangeLog b/libgomp/ChangeLog index 9d9ecfb..096e17b 100644 --- a/libgomp/ChangeLog +++ b/libgomp/ChangeLog @@ -1,3 +1,157 @@ +2025-04-17 Jakub Jelinek <jakub@redhat.com> + + PR libgomp/119849 + * testsuite/libgomp.c++/allocator-1.C (test_inequality, main): Guard + ompx::allocator::gnu_pinned_mem uses with #ifdef __gnu_linux__. + * testsuite/libgomp.c++/allocator-2.C (main): Likewise. + +2025-04-17 Tobias Burnus <tburnus@baylibre.com> + + * libgomp.texi (gcn interop, nvptx interop): For HIP with C/C++, add + a note about setting a preprocessor define. + +2025-04-16 Thomas Schwinge <tschwinge@baylibre.com> + + * testsuite/libgomp.c++/target-exceptions-pr118794-1.C: Remove + 'ALWAYS_INLINE' workaround. + +2025-04-16 Thomas Schwinge <tschwinge@baylibre.com> + + PR target/106445 + * testsuite/libgomp.c++/pr106445-1.C: New. + * testsuite/libgomp.c++/pr106445-1-O0.C: Likewise. + +2025-04-16 Thomas Schwinge <tschwinge@baylibre.com> + + PR target/97106 + * testsuite/libgomp.c++/pr96390.C: Un-XFAIL nvptx offloading. + * testsuite/libgomp.c-c++-common/pr96390.c: Adjust. + +2025-04-15 Tobias Burnus <tburnus@baylibre.com> + + * libgomp.texi (gcn, nvptx): Mention self_maps clause + besides unified_shared_memory in the requirements item. + +2025-04-15 waffl3x <waffl3x@baylibre.com> + + * omp.h.in: Add omp::allocator::* and ompx::allocator::* allocators. + (__detail::__allocator_templ<T, omp_allocator_handle_t>): + New struct template. + (null_allocator<T>): New struct template. + (default_mem<T>): Likewise. + (large_cap_mem<T>): Likewise. + (const_mem<T>): Likewise. + (high_bw_mem<T>): Likewise. + (low_lat_mem<T>): Likewise. + (cgroup_mem<T>): Likewise. + (pteam_mem<T>): Likewise. + (thread_mem<T>): Likewise. + (ompx::allocator::gnu_pinned_mem<T>): Likewise. + * testsuite/libgomp.c++/allocator-1.C: New test. + * testsuite/libgomp.c++/allocator-2.C: New test. + +2025-04-15 Tobias Burnus <tburnus@baylibre.com> + + * libgomp.texi (5.0 Impl. Status): Mark mapping alloc comps as 'Y'. + * testsuite/libgomp.fortran/allocatable-comp.f90: New test. + * testsuite/libgomp.fortran/map-alloc-comp-3.f90: New test. + * testsuite/libgomp.fortran/map-alloc-comp-4.f90: New test. + * testsuite/libgomp.fortran/map-alloc-comp-5.f90: New test. + * testsuite/libgomp.fortran/map-alloc-comp-6.f90: New test. + * testsuite/libgomp.fortran/map-alloc-comp-7.f90: New test. + * testsuite/libgomp.fortran/map-alloc-comp-8.f90: New test. + * testsuite/libgomp.fortran/map-alloc-comp-9.f90: New test. + +2025-04-14 Thomas Schwinge <tschwinge@baylibre.com> + + PR target/118794 + * testsuite/libgomp.c++/target-exceptions-bad_cast-2-offload-sorry-GCN.C: + Set '-foffload-options=-mno-fake-exceptions'. + * testsuite/libgomp.c++/target-exceptions-bad_cast-2-offload-sorry-nvptx.C: + Likewise. + * testsuite/libgomp.c++/target-exceptions-pr118794-1-offload-sorry-GCN.C: + Likewise. + * testsuite/libgomp.c++/target-exceptions-pr118794-1-offload-sorry-nvptx.C: + Likewise. + * testsuite/libgomp.c++/target-exceptions-throw-2-offload-sorry-GCN.C: + Likewise. + * testsuite/libgomp.c++/target-exceptions-throw-2-offload-sorry-nvptx.C: + Likewise. + * testsuite/libgomp.oacc-c++/exceptions-bad_cast-2-offload-sorry-GCN.C: + Likewise. + * testsuite/libgomp.oacc-c++/exceptions-bad_cast-2-offload-sorry-nvptx.C: + Likewise. + * testsuite/libgomp.oacc-c++/exceptions-throw-2-offload-sorry-GCN.C: + Likewise. + * testsuite/libgomp.oacc-c++/exceptions-throw-2-offload-sorry-nvptx.C: + Likewise. + * testsuite/libgomp.c++/target-exceptions-bad_cast-2.C: Adjust. + * testsuite/libgomp.c++/target-exceptions-pr118794-1.C: Likewise. + * testsuite/libgomp.c++/target-exceptions-throw-2.C: Likewise. + * testsuite/libgomp.oacc-c++/exceptions-bad_cast-2.C: Likewise. + * testsuite/libgomp.oacc-c++/exceptions-throw-2.C: Likewise. + * testsuite/libgomp.c++/target-exceptions-throw-2-O0.C: New. + +2025-04-14 Thomas Schwinge <tschwinge@baylibre.com> + + * testsuite/libgomp.c++/target-exceptions-throw-3.C: New. + * testsuite/libgomp.oacc-c++/exceptions-throw-3.C: Likewise. + +2025-04-14 Thomas Schwinge <tschwinge@baylibre.com> + + * testsuite/libgomp.c++/target-exceptions-throw-2.C: New. + * testsuite/libgomp.c++/target-exceptions-throw-2-offload-sorry-GCN.C: Likewise. + * testsuite/libgomp.c++/target-exceptions-throw-2-offload-sorry-nvptx.C: Likewise. + * testsuite/libgomp.oacc-c++/exceptions-throw-2.C: Likewise. + * testsuite/libgomp.oacc-c++/exceptions-throw-2-offload-sorry-GCN.C: Likewise. + * testsuite/libgomp.oacc-c++/exceptions-throw-2-offload-sorry-nvptx.C: Likewise. + +2025-04-14 Thomas Schwinge <tschwinge@baylibre.com> + + * testsuite/libgomp.c++/target-exceptions-throw-1.C: New. + * testsuite/libgomp.c++/target-exceptions-throw-1-O0.C: Likewise. + * testsuite/libgomp.oacc-c++/exceptions-throw-1.C: Likewise. + +2025-04-14 Thomas Schwinge <tschwinge@baylibre.com> + + * testsuite/libgomp.c++/target-exceptions-bad_cast-3.C: New. + * testsuite/libgomp.oacc-c++/exceptions-bad_cast-3.C: Likewise. + +2025-04-14 Thomas Schwinge <tschwinge@baylibre.com> + + * testsuite/libgomp.c++/target-exceptions-bad_cast-2.C: New. + * testsuite/libgomp.c++/target-exceptions-bad_cast-2-offload-sorry-GCN.C: Likewise. + * testsuite/libgomp.c++/target-exceptions-bad_cast-2-offload-sorry-nvptx.C: Likewise. + * testsuite/libgomp.oacc-c++/exceptions-bad_cast-2.C: Likewise. + * testsuite/libgomp.oacc-c++/exceptions-bad_cast-2-offload-sorry-GCN.C: Likewise. + * testsuite/libgomp.oacc-c++/exceptions-bad_cast-2-offload-sorry-nvptx.C: Likewise. + +2025-04-14 Thomas Schwinge <tschwinge@baylibre.com> + + * testsuite/libgomp.c++/target-exceptions-bad_cast-1.C: New. + * testsuite/libgomp.oacc-c++/exceptions-bad_cast-1.C: Likewise. + +2025-04-14 Thomas Schwinge <tschwinge@baylibre.com> + + PR target/118794 + * testsuite/libgomp.c++/target-exceptions-pr118794-1.C: New. + * testsuite/libgomp.c++/target-exceptions-pr118794-1-offload-sorry-GCN.C: + Likewise. + * testsuite/libgomp.c++/target-exceptions-pr118794-1-offload-sorry-nvptx.C: + Likewise. + +2025-04-14 Thomas Schwinge <tschwinge@baylibre.com> + + PR c++/119692 + * testsuite/libgomp.c++/pr119692-1-1.C: New. + * testsuite/libgomp.c++/pr119692-1-2.C: Likewise. + * testsuite/libgomp.c++/pr119692-1-3.C: Likewise. + * testsuite/libgomp.c++/pr119692-1-4.C: Likewise. + * testsuite/libgomp.c++/pr119692-1-5.C: Likewise. + * testsuite/libgomp.oacc-c++/pr119692-1-1.C: Likewise. + * testsuite/libgomp.oacc-c++/pr119692-1-2.C: Likewise. + * testsuite/libgomp.oacc-c++/pr119692-1-3.C: Likewise. + 2025-04-10 Richard Sandiford <richard.sandiford@arm.com> * testsuite/libgomp.c-target/aarch64/firstprivate.c: Add +sve pragma. diff --git a/libgomp/libgomp.texi b/libgomp/libgomp.texi index fed9d5e..6909c2b 100644 --- a/libgomp/libgomp.texi +++ b/libgomp/libgomp.texi @@ -258,7 +258,7 @@ The OpenMP 4.5 specification is fully supported. device memory mapped by an array section @tab P @tab @item Mapping of Fortran pointer and allocatable variables, including pointer and allocatable components of variables - @tab P @tab Mapping of vars with allocatable components unsupported + @tab Y @tab @item @code{defaultmap} extensions @tab Y @tab @item @code{declare mapper} directive @tab N @tab @item @code{omp_get_supported_active_levels} routine @tab Y @tab @@ -6888,7 +6888,7 @@ The implementation remark: @code{device(ancestor:1)}) are processed serially per @code{target} region such that the next reverse offload region is only executed after the previous one returned. -@item OpenMP code that has a @code{requires} directive with +@item OpenMP code that has a @code{requires} directive with @code{self_maps} or @code{unified_shared_memory} is only supported if all AMD GPUs have the @code{HSA_AMD_SYSTEM_INFO_SVM_ACCESSIBLE_BY_DEFAULT} property; for discrete GPUs, this may require setting the @code{HSA_XNACK} environment @@ -6945,6 +6945,9 @@ or string (str) data type, call @code{omp_get_interop_int}, Note that @code{device_num} is the OpenMP device number while @code{device} is the HIP device number or HSA device handle. +When using HIP with C and C++, the @code{__HIP_PLATFORM_AMD__} preprocessor +macro must be defined before including the HIP header files. + For the API routine call, add the prefix @code{omp_ipr_} to the property name; for instance: @smallexample @@ -7045,7 +7048,7 @@ The implementation remark: Per device, reverse offload regions are processed serially such that the next reverse offload region is only executed after the previous one returned. -@item OpenMP code that has a @code{requires} directive with +@item OpenMP code that has a @code{requires} directive with @code{self_maps} or @code{unified_shared_memory} runs on nvptx devices if and only if all of those support the @code{pageableMemoryAccess} property;@footnote{ @uref{https://docs.nvidia.com/cuda/cuda-c-programming-guide/index.html#um-requirements}} @@ -7107,6 +7110,9 @@ or string (str) data type, call @code{omp_get_interop_int}, Note that @code{device_num} is the OpenMP device number while @code{device} is the CUDA, CUDA Driver, or HIP device number. +When using HIP with C and C++, the @code{__HIP_PLATFORM_NVIDIA__} preprocessor +macro must be defined before including the HIP header files. + For the API routine call, add the prefix @code{omp_ipr_} to the property name; for instance: @smallexample diff --git a/libgomp/omp.h.in b/libgomp/omp.h.in index d5e8be4..8d17db1 100644 --- a/libgomp/omp.h.in +++ b/libgomp/omp.h.in @@ -432,4 +432,136 @@ extern const char *omp_get_uid_from_device (int) __GOMP_NOTHROW; } #endif +#if __cplusplus >= 201103L + +/* std::__throw_bad_alloc and std::__throw_bad_array_new_length. */ +#include <bits/functexcept.h> + +namespace omp +{ +namespace allocator +{ + +namespace __detail +{ + +template<typename __T, omp_allocator_handle_t __Handle> +struct __allocator_templ +{ + using value_type = __T; + using pointer = __T*; + using const_pointer = const __T*; + using size_type = __SIZE_TYPE__; + using difference_type = __PTRDIFF_TYPE__; + + __T* + allocate (size_type __n) + { + if (__SIZE_MAX__ / sizeof(__T) < __n) + std::__throw_bad_array_new_length (); + void *__p = omp_aligned_alloc (alignof(__T), __n * sizeof(__T), __Handle); + if (!__p) + std::__throw_bad_alloc (); + return static_cast<__T*>(__p); + } + + void + deallocate (__T *__p, size_type) __GOMP_NOTHROW + { + omp_free (static_cast<void*>(__p), __Handle); + } +}; + +template<typename __T, typename __U, omp_allocator_handle_t __Handle> +constexpr bool +operator== (const __allocator_templ<__T, __Handle>&, + const __allocator_templ<__U, __Handle>&) __GOMP_NOTHROW +{ + return true; +} + +template<typename __T, omp_allocator_handle_t __Handle, + typename __U, omp_allocator_handle_t __UHandle> +constexpr bool +operator== (const __allocator_templ<__T, __Handle>&, + const __allocator_templ<__U, __UHandle>&) __GOMP_NOTHROW +{ + return false; +} + +template<typename __T, typename __U, omp_allocator_handle_t __Handle> +constexpr bool +operator!= (const __allocator_templ<__T, __Handle>&, + const __allocator_templ<__U, __Handle>&) __GOMP_NOTHROW +{ + return false; +} + +template<typename __T, omp_allocator_handle_t __Handle, + typename __U, omp_allocator_handle_t __UHandle> +constexpr bool +operator!= (const __allocator_templ<__T, __Handle>&, + const __allocator_templ<__U, __UHandle>&) __GOMP_NOTHROW +{ + return true; +} + +} /* namespace __detail */ + +template<typename __T> +struct null_allocator + : __detail::__allocator_templ<__T, omp_null_allocator> {}; + +template<typename __T> +struct default_mem + : __detail::__allocator_templ<__T, omp_default_mem_alloc> {}; + +template<typename __T> +struct large_cap_mem + : __detail::__allocator_templ<__T, omp_large_cap_mem_alloc> {}; + +template<typename __T> +struct const_mem + : __detail::__allocator_templ<__T, omp_const_mem_alloc> {}; + +template<typename __T> +struct high_bw_mem + : __detail::__allocator_templ<__T, omp_high_bw_mem_alloc> {}; + +template<typename __T> +struct low_lat_mem + : __detail::__allocator_templ<__T, omp_low_lat_mem_alloc> {}; + +template<typename __T> +struct cgroup_mem + : __detail::__allocator_templ<__T, omp_cgroup_mem_alloc> {}; + +template<typename __T> +struct pteam_mem + : __detail::__allocator_templ<__T, omp_pteam_mem_alloc> {}; + +template<typename __T> +struct thread_mem + : __detail::__allocator_templ<__T, omp_thread_mem_alloc> {}; + +} /* namespace allocator */ + +} /* namespace omp */ + +namespace ompx +{ + +namespace allocator +{ + +template<typename __T> +struct gnu_pinned_mem + : omp::allocator::__detail::__allocator_templ<__T, ompx_gnu_pinned_mem_alloc> {}; + +} /* namespace allocator */ + +} /* namespace ompx */ + +#endif /* __cplusplus */ + #endif /* _OMP_H */ diff --git a/libgomp/testsuite/libgomp.c++/allocator-1.C b/libgomp/testsuite/libgomp.c++/allocator-1.C new file mode 100644 index 0000000..49425386 --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/allocator-1.C @@ -0,0 +1,171 @@ +// { dg-do run } + +#include <omp.h> +#include <memory> +#include <limits> + +template<typename T, template<typename> class Alloc> +void test (T const initial_value = T()) +{ + using Allocator = Alloc<T>; + Allocator a; + using Traits = std::allocator_traits<Allocator>; + static_assert (__is_same(typename Traits::allocator_type, Allocator )); + static_assert (__is_same(typename Traits::value_type, T )); + static_assert (__is_same(typename Traits::pointer, T* )); + static_assert (__is_same(typename Traits::const_pointer, T const* )); + static_assert (__is_same(typename Traits::void_pointer, void* )); + static_assert (__is_same(typename Traits::const_void_pointer, void const* )); + static_assert (__is_same(typename Traits::difference_type, __PTRDIFF_TYPE__)); + static_assert (__is_same(typename Traits::size_type, __SIZE_TYPE__ )); + static_assert (Traits::propagate_on_container_copy_assignment::value == false); + static_assert (Traits::propagate_on_container_move_assignment::value == false); + static_assert (Traits::propagate_on_container_swap::value == false); + static_assert (Traits::is_always_equal::value == true); + + static constexpr __SIZE_TYPE__ correct_max_size + = std::numeric_limits<__SIZE_TYPE__>::max () / sizeof (T); + if (Traits::max_size (a) != correct_max_size) + __builtin_abort (); + + static constexpr __SIZE_TYPE__ alloc_count = 1; + T *p = Traits::allocate (a, alloc_count); + if (p == nullptr) + __builtin_abort (); + Traits::construct (a, p, initial_value); + if (*p != initial_value) + __builtin_abort (); + Traits::destroy (a, p); + Traits::deallocate (a, p, alloc_count); + /* Not interesting but might as well test it. */ + static_cast<void>(Traits::select_on_container_copy_construction (a)); + + if (!(a == Allocator())) + __builtin_abort (); + if (a != Allocator()) + __builtin_abort (); + if (!(a == Alloc<void>())) + __builtin_abort (); + if (a != Alloc<void>()) + __builtin_abort (); +} + +#define CHECK_INEQUALITY(other_alloc_templ, type) \ +do { \ + /* Skip tests for itself, those are equal. Intantiate each */ \ + /* one with void so we can easily tell if they are the same. */ \ + if (!__is_same (AllocTempl<void>, other_alloc_templ<void>)) \ + { \ + other_alloc_templ<type> other; \ + if (a == other) \ + __builtin_abort (); \ + if (!(a != other)) \ + __builtin_abort (); \ + } \ +} while (false) + +template<typename T, template<typename> class AllocTempl> +void test_inequality () +{ + using Allocator = AllocTempl<T>; + Allocator a; + CHECK_INEQUALITY (omp::allocator::null_allocator, void); + CHECK_INEQUALITY (omp::allocator::default_mem, void); + CHECK_INEQUALITY (omp::allocator::large_cap_mem, void); + CHECK_INEQUALITY (omp::allocator::const_mem, void); + CHECK_INEQUALITY (omp::allocator::high_bw_mem, void); + CHECK_INEQUALITY (omp::allocator::low_lat_mem, void); + CHECK_INEQUALITY (omp::allocator::cgroup_mem, void); + CHECK_INEQUALITY (omp::allocator::pteam_mem, void); + CHECK_INEQUALITY (omp::allocator::thread_mem, void); +#ifdef __gnu_linux__ + /* Pinning not implemented on other targets. */ + CHECK_INEQUALITY (ompx::allocator::gnu_pinned_mem, void); +#endif + /* And again with the same type passed to the allocator. */ + CHECK_INEQUALITY (omp::allocator::null_allocator, T); + CHECK_INEQUALITY (omp::allocator::default_mem, T); + CHECK_INEQUALITY (omp::allocator::large_cap_mem, T); + CHECK_INEQUALITY (omp::allocator::const_mem, T); + CHECK_INEQUALITY (omp::allocator::high_bw_mem, T); + CHECK_INEQUALITY (omp::allocator::low_lat_mem, T); + CHECK_INEQUALITY (omp::allocator::cgroup_mem, T); + CHECK_INEQUALITY (omp::allocator::pteam_mem, T); + CHECK_INEQUALITY (omp::allocator::thread_mem, T); +#ifdef __gnu_linux__ + CHECK_INEQUALITY (ompx::allocator::gnu_pinned_mem, T); +#endif +} + +#undef CHECK_INEQUALITY + +struct S +{ + int _v0; + bool _v1; + float _v2; + + bool operator== (S const& other) const noexcept { + return _v0 == other._v0 + && _v1 == other._v1 + && _v2 == other._v2; + } + bool operator!= (S const& other) const noexcept { + return !this->operator==(other); + } +}; + +int main () +{ + test<int, omp::allocator::null_allocator>(42); + test<int, omp::allocator::default_mem>(42); + test<int, omp::allocator::large_cap_mem>(42); + test<int, omp::allocator::const_mem>(42); + test<int, omp::allocator::high_bw_mem>(42); + test<int, omp::allocator::low_lat_mem>(42); + test<int, omp::allocator::cgroup_mem>(42); + test<int, omp::allocator::pteam_mem>(42); + test<int, omp::allocator::thread_mem>(42); +#ifdef __gnu_linux__ + test<int, ompx::allocator::gnu_pinned_mem>(42); +#endif + + test<long long, omp::allocator::null_allocator>(42); + test<long long, omp::allocator::default_mem>(42); + test<long long, omp::allocator::large_cap_mem>(42); + test<long long, omp::allocator::const_mem>(42); + test<long long, omp::allocator::high_bw_mem>(42); + test<long long, omp::allocator::low_lat_mem>(42); + test<long long, omp::allocator::cgroup_mem>(42); + test<long long, omp::allocator::pteam_mem>(42); + test<long long, omp::allocator::thread_mem>(42); +#ifdef __gnu_linux__ + test<long long, ompx::allocator::gnu_pinned_mem>(42); +#endif + + test<S, omp::allocator::null_allocator>( S{42, true, 128.f}); + test<S, omp::allocator::default_mem>( S{42, true, 128.f}); + test<S, omp::allocator::large_cap_mem>( S{42, true, 128.f}); + test<S, omp::allocator::const_mem>( S{42, true, 128.f}); + test<S, omp::allocator::high_bw_mem>( S{42, true, 128.f}); + test<S, omp::allocator::low_lat_mem>( S{42, true, 128.f}); + test<S, omp::allocator::cgroup_mem>( S{42, true, 128.f}); + test<S, omp::allocator::pteam_mem>( S{42, true, 128.f}); + test<S, omp::allocator::thread_mem>( S{42, true, 128.f}); +#ifdef __gnu_linux__ + test<S, ompx::allocator::gnu_pinned_mem>(S{42, true, 128.f}); +#endif + + test_inequality<int, omp::allocator::null_allocator>(); + test_inequality<int, omp::allocator::default_mem>(); + test_inequality<int, omp::allocator::large_cap_mem>(); + test_inequality<int, omp::allocator::const_mem>(); + test_inequality<int, omp::allocator::high_bw_mem>(); + test_inequality<int, omp::allocator::low_lat_mem>(); + test_inequality<int, omp::allocator::cgroup_mem>(); + test_inequality<int, omp::allocator::pteam_mem>(); + test_inequality<int, omp::allocator::thread_mem>(); +#ifdef __gnu_linux__ + test_inequality<int, ompx::allocator::gnu_pinned_mem>(); +#endif +} diff --git a/libgomp/testsuite/libgomp.c++/allocator-2.C b/libgomp/testsuite/libgomp.c++/allocator-2.C new file mode 100644 index 0000000..ca94fc7 --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/allocator-2.C @@ -0,0 +1,141 @@ +// { dg-do run } +// { dg-additional-options "-Wno-psabi" } + +#include <omp.h> +#include <vector> + +template<typename T> +bool ptr_is_aligned(T *ptr, std::size_t alignment) +{ + /* ALIGNMENT must be a power of 2. */ + if ((alignment & (alignment - 1)) != 0) + __builtin_abort (); + __UINTPTR_TYPE__ ptr_value + = reinterpret_cast<__UINTPTR_TYPE__>(static_cast<void*>(ptr)); + return (ptr_value % alignment) == 0; +} + +template<typename T, template<typename> class Alloc> +void f (T v0, T v1, T v2, T v3) +{ + std::vector<T, Alloc<T>> vec; + vec.push_back (v0); + vec.push_back (v1); + vec.push_back (v2); + vec.push_back (v3); + if (vec.at (0) != v0) + __builtin_abort (); + if (vec.at (1) != v1) + __builtin_abort (); + if (vec.at (2) != v2) + __builtin_abort (); + if (vec.at (3) != v3) + __builtin_abort (); + if (!ptr_is_aligned (&vec.at (0), alignof (T))) + __builtin_abort (); + if (!ptr_is_aligned (&vec.at (1), alignof (T))) + __builtin_abort (); + if (!ptr_is_aligned (&vec.at (2), alignof (T))) + __builtin_abort (); + if (!ptr_is_aligned (&vec.at (3), alignof (T))) + __builtin_abort (); +} + +struct S0 +{ + int _v0; + bool _v1; + float _v2; + + bool operator== (S0 const& other) const noexcept { + return _v0 == other._v0 + && _v1 == other._v1 + && _v2 == other._v2; + } + bool operator!= (S0 const& other) const noexcept { + return !this->operator==(other); + } +}; + +struct alignas(128) S1 +{ + int _v0; + bool _v1; + float _v2; + + bool operator== (S1 const& other) const noexcept { + return _v0 == other._v0 + && _v1 == other._v1 + && _v2 == other._v2; + } + bool operator!= (S1 const& other) const noexcept { + return !this->operator==(other); + } +}; + +/* Note: the test for const_mem should be disabled in the future. */ + +int main () +{ + f<int, omp::allocator::null_allocator >(0, 1, 2, 3); + f<int, omp::allocator::default_mem >(0, 1, 2, 3); + f<int, omp::allocator::large_cap_mem >(0, 1, 2, 3); + f<int, omp::allocator::const_mem >(0, 1, 2, 3); + f<int, omp::allocator::high_bw_mem >(0, 1, 2, 3); + f<int, omp::allocator::low_lat_mem >(0, 1, 2, 3); + f<int, omp::allocator::cgroup_mem >(0, 1, 2, 3); + f<int, omp::allocator::pteam_mem >(0, 1, 2, 3); + f<int, omp::allocator::thread_mem >(0, 1, 2, 3); +#ifdef __gnu_linux__ + /* Pinning not implemented on other targets. */ + f<int, ompx::allocator::gnu_pinned_mem>(0, 1, 2, 3); +#endif + + f<long long, omp::allocator::null_allocator >(0, 1, 2, 3); + f<long long, omp::allocator::default_mem >(0, 1, 2, 3); + f<long long, omp::allocator::large_cap_mem >(0, 1, 2, 3); + f<long long, omp::allocator::const_mem >(0, 1, 2, 3); + f<long long, omp::allocator::high_bw_mem >(0, 1, 2, 3); + f<long long, omp::allocator::low_lat_mem >(0, 1, 2, 3); + f<long long, omp::allocator::cgroup_mem >(0, 1, 2, 3); + f<long long, omp::allocator::pteam_mem >(0, 1, 2, 3); + f<long long, omp::allocator::thread_mem >(0, 1, 2, 3); +#ifdef __gnu_linux__ + f<long long, ompx::allocator::gnu_pinned_mem>(0, 1, 2, 3); +#endif + + S0 s0_0{ 42, true, 111128.f}; + S0 s0_1{ 142, false, 11128.f}; + S0 s0_2{ 1142, true, 1128.f}; + S0 s0_3{11142, false, 128.f}; + f<S0, omp::allocator::null_allocator >(s0_0, s0_1, s0_2, s0_3); + f<S0, omp::allocator::default_mem >(s0_0, s0_1, s0_2, s0_3); + f<S0, omp::allocator::large_cap_mem >(s0_0, s0_1, s0_2, s0_3); + f<S0, omp::allocator::const_mem >(s0_0, s0_1, s0_2, s0_3); + f<S0, omp::allocator::high_bw_mem >(s0_0, s0_1, s0_2, s0_3); + f<S0, omp::allocator::low_lat_mem >(s0_0, s0_1, s0_2, s0_3); + f<S0, omp::allocator::cgroup_mem >(s0_0, s0_1, s0_2, s0_3); + f<S0, omp::allocator::pteam_mem >(s0_0, s0_1, s0_2, s0_3); + f<S0, omp::allocator::thread_mem >(s0_0, s0_1, s0_2, s0_3); +#ifdef __gnu_linux__ + f<S0, ompx::allocator::gnu_pinned_mem>(s0_0, s0_1, s0_2, s0_3); +#endif + + S1 s1_0{ 42, true, 111128.f}; + S1 s1_1{ 142, false, 11128.f}; + S1 s1_2{ 1142, true, 1128.f}; + S1 s1_3{11142, false, 128.f}; + + f<S1, omp::allocator::null_allocator >(s1_0, s1_1, s1_2, s1_3); + f<S1, omp::allocator::default_mem >(s1_0, s1_1, s1_2, s1_3); + f<S1, omp::allocator::large_cap_mem >(s1_0, s1_1, s1_2, s1_3); + f<S1, omp::allocator::const_mem >(s1_0, s1_1, s1_2, s1_3); + f<S1, omp::allocator::high_bw_mem >(s1_0, s1_1, s1_2, s1_3); + f<S1, omp::allocator::low_lat_mem >(s1_0, s1_1, s1_2, s1_3); + f<S1, omp::allocator::cgroup_mem >(s1_0, s1_1, s1_2, s1_3); + f<S1, omp::allocator::pteam_mem >(s1_0, s1_1, s1_2, s1_3); + f<S1, omp::allocator::thread_mem >(s1_0, s1_1, s1_2, s1_3); +#ifdef __gnu_linux__ + f<S1, ompx::allocator::gnu_pinned_mem>(s1_0, s1_1, s1_2, s1_3); +#endif +} diff --git a/libgomp/testsuite/libgomp.c++/pr106445-1-O0.C b/libgomp/testsuite/libgomp.c++/pr106445-1-O0.C new file mode 100644 index 0000000..bcd499c --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/pr106445-1-O0.C @@ -0,0 +1,3 @@ +// { dg-additional-options -O0 } + +#include "pr106445-1.C" diff --git a/libgomp/testsuite/libgomp.c++/pr106445-1.C b/libgomp/testsuite/libgomp.c++/pr106445-1.C new file mode 100644 index 0000000..329ce62 --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/pr106445-1.C @@ -0,0 +1,18 @@ +#include <vector> + +int main() +{ +#pragma omp target + { + { + std::vector<int> v; + if (!v.empty()) + __builtin_abort(); + } + { + std::vector<int> v(100); + if (v.capacity() < 100) + __builtin_abort(); + } + } +} diff --git a/libgomp/testsuite/libgomp.c++/pr119692-1-1.C b/libgomp/testsuite/libgomp.c++/pr119692-1-1.C new file mode 100644 index 0000000..1f59b15 --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/pr119692-1-1.C @@ -0,0 +1,10 @@ +/* PR119692 "C++ 'typeinfo', 'vtable' vs. OpenACC, OpenMP 'target' offloading" */ + +/* { dg-additional-options -UDEFAULT } + Wrong code for offloading execution. + { dg-additional-options -foffload=disable } */ +/* { dg-additional-options -fdump-tree-gimple } */ + +#include "../libgomp.oacc-c++/pr119692-1-1.C" + +/* { dg-final { scan-tree-dump-not {(?n)#pragma omp target .* map\(tofrom:_ZTI2C2 \[len: [0-9]+\] \[runtime_implicit\]\) map\(tofrom:_ZTI2C1 \[len: [0-9]+\] \[runtime_implicit\]\) map\(tofrom:_ZTV2C1 \[len: [0-9]+\] \[runtime_implicit\]\)$} gimple { xfail *-*-* } } } */ diff --git a/libgomp/testsuite/libgomp.c++/pr119692-1-2.C b/libgomp/testsuite/libgomp.c++/pr119692-1-2.C new file mode 100644 index 0000000..e7ac818 --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/pr119692-1-2.C @@ -0,0 +1,11 @@ +/* PR119692 "C++ 'typeinfo', 'vtable' vs. OpenACC, OpenMP 'target' offloading" */ + +/* { dg-additional-options -DDEFAULT=defaultmap(none) } + Fails to compile. + { dg-do compile } */ + +#include "pr119692-1-1.C" + +/* { dg-bogus {error: '_ZTV2C1' not specified in enclosing 'target'} PR119692 { xfail *-*-* } 0 } + { dg-bogus {error: '_ZTI2C2' not specified in enclosing 'target'} PR119692 { xfail *-*-* } 0 } + { dg-bogus {error: '_ZTI2C1' not specified in enclosing 'target'} PR119692 { xfail *-*-* } 0 } */ diff --git a/libgomp/testsuite/libgomp.c++/pr119692-1-3.C b/libgomp/testsuite/libgomp.c++/pr119692-1-3.C new file mode 100644 index 0000000..733feb8 --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/pr119692-1-3.C @@ -0,0 +1,10 @@ +/* PR119692 "C++ 'typeinfo', 'vtable' vs. OpenACC, OpenMP 'target' offloading" */ + +/* { dg-additional-options -DDEFAULT=defaultmap(present) } + Wrong code for offloading execution. + { dg-xfail-run-if PR119692 { offload_device } } */ +/* { dg-additional-options -fdump-tree-gimple } */ + +#include "pr119692-1-1.C" + +/* { dg-final { scan-tree-dump-not {(?n)#pragma omp target .* defaultmap\(present\) map\(force_present:_ZTI2C2 \[len: [0-9]+\] \[runtime_implicit\]\) map\(force_present:_ZTI2C1 \[len: [0-9]+\] \[runtime_implicit\]\) map\(force_present:_ZTV2C1 \[len: [0-9]+\] \[runtime_implicit\]\)$} gimple { xfail *-*-* } } } */ diff --git a/libgomp/testsuite/libgomp.c++/pr119692-1-4.C b/libgomp/testsuite/libgomp.c++/pr119692-1-4.C new file mode 100644 index 0000000..6995f26 --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/pr119692-1-4.C @@ -0,0 +1,10 @@ +/* PR119692 "C++ 'typeinfo', 'vtable' vs. OpenACC, OpenMP 'target' offloading" */ + +/* { dg-additional-options -DDEFAULT=defaultmap(firstprivate) } + Wrong code for offloading execution. + { dg-xfail-run-if PR119692 { offload_device } } */ +/* { dg-additional-options -fdump-tree-gimple } */ + +#include "pr119692-1-1.C" + +/* { dg-final { scan-tree-dump-not {(?n)#pragma omp target .* defaultmap\(firstprivate\) firstprivate\(_ZTI2C2\) firstprivate\(_ZTI2C1\) firstprivate\(_ZTV2C1\)$} gimple { xfail *-*-* } } } */ diff --git a/libgomp/testsuite/libgomp.c++/pr119692-1-5.C b/libgomp/testsuite/libgomp.c++/pr119692-1-5.C new file mode 100644 index 0000000..02121b6 --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/pr119692-1-5.C @@ -0,0 +1,10 @@ +/* PR119692 "C++ 'typeinfo', 'vtable' vs. OpenACC, OpenMP 'target' offloading" */ + +/* { dg-additional-options -DDEFAULT=defaultmap(to) } + Wrong code for offloading execution. + { dg-xfail-run-if PR119692 { offload_device } } */ +/* { dg-additional-options -fdump-tree-gimple } */ + +#include "pr119692-1-1.C" + +/* { dg-final { scan-tree-dump-not {(?n)#pragma omp target .* defaultmap\(to\) map\(to:_ZTI2C2 \[len: [0-9]+\] \[runtime_implicit\]\) map\(to:_ZTI2C1 \[len: [0-9]+\] \[runtime_implicit\]\) map\(to:_ZTV2C1 \[len: [0-9]+\] \[runtime_implicit\]\)$} gimple { xfail *-*-* } } } */ diff --git a/libgomp/testsuite/libgomp.c++/pr96390.C b/libgomp/testsuite/libgomp.c++/pr96390.C index 1f3c3e0..be19601 100644 --- a/libgomp/testsuite/libgomp.c++/pr96390.C +++ b/libgomp/testsuite/libgomp.c++/pr96390.C @@ -1,6 +1,4 @@ /* { dg-additional-options "-O0 -fdump-tree-omplower" } */ -/* { dg-additional-options "-foffload=-Wa,--verify" { target offload_target_nvptx } } */ -/* { dg-xfail-if "PR 97106/PR 97102 - .alias not (yet) supported for nvptx" { offload_target_nvptx } } */ #include <cstdlib> #include <type_traits> diff --git a/libgomp/testsuite/libgomp.c++/target-exceptions-bad_cast-1.C b/libgomp/testsuite/libgomp.c++/target-exceptions-bad_cast-1.C new file mode 100644 index 0000000..3848295 --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/target-exceptions-bad_cast-1.C @@ -0,0 +1,25 @@ +/* 'std::bad_cast' exception in OpenMP 'target' region. */ + +/* { dg-require-effective-target exceptions } + { dg-additional-options -fexceptions } */ +/* { dg-additional-options -fdump-tree-optimized-raw } + { dg-additional-options -foffload-options=-fdump-tree-optimized-raw } */ + +#include "../libgomp.oacc-c++/exceptions-bad_cast-1.C" + +/* { dg-output {CheCKpOInT[\r\n]+} } + + { dg-final { scan-tree-dump-times {gimple_call <__cxa_bad_cast, } 1 optimized } } + { dg-final { scan-offload-tree-dump-times {gimple_call <__cxa_bad_cast, } 1 optimized } } + For host execution, we print something like: + terminate called after throwing an instance of 'std::bad_cast' + what(): std::bad_cast + Aborted (core dumped) + { dg-output {.*std::bad_cast} { target { ! offload_device } } } + For GCN, nvptx offload execution, we don't print anything, but just 'abort'. + + TODO For GCN, nvptx offload execution, this currently doesn't 'abort' due to + the 'std::bad_cast' exception, but rather due to SIGSEGV in 'dynamic_cast'; + PR119692. + + { dg-shouldfail {'std::bad_cast' exception} } */ diff --git a/libgomp/testsuite/libgomp.c++/target-exceptions-bad_cast-2-offload-sorry-GCN.C b/libgomp/testsuite/libgomp.c++/target-exceptions-bad_cast-2-offload-sorry-GCN.C new file mode 100644 index 0000000..93884df --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/target-exceptions-bad_cast-2-offload-sorry-GCN.C @@ -0,0 +1,19 @@ +/* 'std::bad_cast' exception in OpenMP 'target' region, caught, '-foffload-options=-mno-fake-exceptions'. */ + +/* As this test case involves an expected offload compilation failure, we have to handle each offload target individually. + { dg-do link { target offload_target_amdgcn } } + { dg-additional-options -foffload=amdgcn-amdhsa } */ +/* { dg-require-effective-target exceptions } + { dg-additional-options -fexceptions } */ +/* { dg-additional-options -foffload-options=-mno-fake-exceptions } */ +/* { dg-additional-options -fdump-tree-optimized-raw } + { dg-additional-options -foffload-options=-fdump-tree-optimized-raw } */ + +#include "target-exceptions-bad_cast-2.C" + +/* { dg-final { scan-tree-dump-times {gimple_call <__cxa_bad_cast, } 1 optimized } } + { dg-final { only_for_offload_target amdgcn-amdhsa scan-offload-tree-dump-times {gimple_call <__cxa_bad_cast, } 1 optimized } } + Given '-foffload-options=-mno-fake-exceptions', offload compilation fails: + { dg-regexp {[^\r\n]+: In function 'main[^']+':[\r\n]+(?:[^\r\n]+: sorry, unimplemented: exception handling not supported[\r\n]+)+} } + (Note, using 'dg-regexp' instead of 'dg-message', as the former runs before the auto-mark-UNSUPPORTED.) + { dg-excess-errors {'mkoffload' failure etc.} } */ diff --git a/libgomp/testsuite/libgomp.c++/target-exceptions-bad_cast-2-offload-sorry-nvptx.C b/libgomp/testsuite/libgomp.c++/target-exceptions-bad_cast-2-offload-sorry-nvptx.C new file mode 100644 index 0000000..83ec89b --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/target-exceptions-bad_cast-2-offload-sorry-nvptx.C @@ -0,0 +1,19 @@ +/* 'std::bad_cast' exception in OpenMP 'target' region, caught, '-foffload-options=-mno-fake-exceptions'. */ + +/* As this test case involves an expected offload compilation failure, we have to handle each offload target individually. + { dg-do link { target offload_target_nvptx } } + { dg-additional-options -foffload=nvptx-none } */ +/* { dg-require-effective-target exceptions } + { dg-additional-options -fexceptions } */ +/* { dg-additional-options -foffload-options=-mno-fake-exceptions } */ +/* { dg-additional-options -fdump-tree-optimized-raw } + { dg-additional-options -foffload-options=-fdump-tree-optimized-raw } */ + +#include "target-exceptions-bad_cast-2.C" + +/* { dg-final { scan-tree-dump-times {gimple_call <__cxa_bad_cast, } 1 optimized } } + { dg-final { only_for_offload_target nvptx-none scan-offload-tree-dump-times {gimple_call <__cxa_bad_cast, } 1 optimized } } + Given '-foffload-options=-mno-fake-exceptions', offload compilation fails: + { dg-regexp {[^\r\n]+: In function 'main[^']+':[\r\n]+(?:[^\r\n]+: sorry, unimplemented: exception handling not supported[\r\n]+)+} } + (Note, using 'dg-regexp' instead of 'dg-message', as the former runs before the auto-mark-UNSUPPORTED.) + { dg-excess-errors {'mkoffload' failure etc.} } */ diff --git a/libgomp/testsuite/libgomp.c++/target-exceptions-bad_cast-2.C b/libgomp/testsuite/libgomp.c++/target-exceptions-bad_cast-2.C new file mode 100644 index 0000000..8861740 --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/target-exceptions-bad_cast-2.C @@ -0,0 +1,24 @@ +/* 'std::bad_cast' exception in OpenMP 'target' region, caught. */ + +/* { dg-require-effective-target exceptions } + { dg-additional-options -fexceptions } */ +/* { dg-additional-options -fdump-tree-optimized-raw } + { dg-additional-options -foffload-options=-fdump-tree-optimized-raw } */ +/* { dg-bogus {_ZTISt8bad_cast} PR119734 { target offload_target_nvptx xfail *-*-* } 0 } + { dg-excess-errors {'mkoffload' failure etc.} { xfail offload_target_nvptx } } */ + +#include "../libgomp.oacc-c++/exceptions-bad_cast-2.C" + +/* { dg-output {CheCKpOInT[\r\n]+} } + + { dg-final { scan-tree-dump-times {gimple_call <__cxa_bad_cast, } 1 optimized } } + { dg-final { scan-offload-tree-dump-times {gimple_call <__cxa_bad_cast, } 1 optimized } } + { dg-output {.*caught 'std::bad_cast'[\r\n]+} { target { ! offload_device } } } + For GCN, nvptx offload execution, we don't print anything, but just 'abort'. + + TODO For GCN, nvptx offload execution, this currently doesn't 'abort' due to + the 'std::bad_cast' exception, but rather due to SIGSEGV in 'dynamic_cast'; + PR119692. + + For GCN, nvptx offload execution, there is no 'catch'ing; any exception is fatal. + { dg-shouldfail {'MyException' exception} { offload_device } } */ diff --git a/libgomp/testsuite/libgomp.c++/target-exceptions-bad_cast-3.C b/libgomp/testsuite/libgomp.c++/target-exceptions-bad_cast-3.C new file mode 100644 index 0000000..efed64f --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/target-exceptions-bad_cast-3.C @@ -0,0 +1,17 @@ +/* 'std::bad_cast' exception in OpenMP 'target' region, dead code. */ + +/* { dg-require-effective-target exceptions } + { dg-additional-options -fexceptions } */ +/* { dg-additional-options -DDEFAULT=defaultmap(to) } + ... to avoid wrong code for offloading execution; PR119692. + With this, the device code still isn't correct, but the defects are in dead code. + { dg-additional-options -fdump-tree-gimple } */ +/* { dg-additional-options -fdump-tree-optimized-raw } + { dg-additional-options -foffload-options=-fdump-tree-optimized-raw } */ + +#include "../libgomp.oacc-c++/exceptions-bad_cast-3.C" + +/* { dg-final { scan-tree-dump-not {(?n)#pragma omp target .* defaultmap\(to\) map\(to:_ZTI2C2 \[len: [0-9]+\] \[runtime_implicit\]\) map\(to:_ZTI2C1 \[len: [0-9]+\] \[runtime_implicit\]\) map\(to:_ZTV2C1 \[len: [0-9]+\] \[runtime_implicit\]\)$} gimple { xfail *-*-* } } } */ + +/* { dg-final { scan-tree-dump-times {gimple_call <__cxa_bad_cast, } 1 optimized } } + { dg-final { scan-offload-tree-dump-times {gimple_call <__cxa_bad_cast, } 1 optimized } } */ diff --git a/libgomp/testsuite/libgomp.c++/target-exceptions-pr118794-1-offload-sorry-GCN.C b/libgomp/testsuite/libgomp.c++/target-exceptions-pr118794-1-offload-sorry-GCN.C new file mode 100644 index 0000000..3cdedf4 --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/target-exceptions-pr118794-1-offload-sorry-GCN.C @@ -0,0 +1,24 @@ +/* Exception handling constructs in dead code, '-foffload-options=-mno-fake-exceptions'. */ + +/* As this test case involves an expected offload compilation failure, we have to handle each offload target individually. + { dg-do link { target offload_target_amdgcn } } + { dg-additional-options -foffload=amdgcn-amdhsa } */ +/* { dg-require-effective-target exceptions } + { dg-additional-options -fexceptions } */ +/* { dg-additional-options -foffload-options=-mno-fake-exceptions } */ +/* { dg-additional-options -O0 } */ +/* { dg-additional-options -fdump-tree-optimized-raw } + { dg-additional-options -foffload-options=-fdump-tree-optimized-raw } */ + +#include "target-exceptions-pr118794-1.C" + +/* In this specific C++ arrangement, distilled from PR118794, GCC synthesizes + '__builtin_eh_pointer', '__builtin_unwind_resume' calls as dead code in 'f': + { dg-final { scan-tree-dump-times {gimple_call <__builtin_eh_pointer, } 1 optimized } } + { dg-final { scan-tree-dump-times {gimple_call <__builtin_unwind_resume, } 1 optimized } } + { dg-final { only_for_offload_target amdgcn-amdhsa scan-offload-tree-dump-times {gimple_call <__builtin_eh_pointer, } 1 optimized } } + { dg-final { only_for_offload_target amdgcn-amdhsa scan-offload-tree-dump-times {gimple_call <__builtin_unwind_resume, } 1 optimized } } + Given '-O0' and '-foffload-options=-mno-fake-exceptions', offload compilation fails: + { dg-regexp {[^\r\n]+: In function 'f':[\r\n]+(?:[^\r\n]+: sorry, unimplemented: exception handling not supported[\r\n]+)+} } + (Note, using 'dg-regexp' instead of 'dg-message', as the former runs before the auto-mark-UNSUPPORTED.) + { dg-excess-errors {'mkoffload' failure etc.} } */ diff --git a/libgomp/testsuite/libgomp.c++/target-exceptions-pr118794-1-offload-sorry-nvptx.C b/libgomp/testsuite/libgomp.c++/target-exceptions-pr118794-1-offload-sorry-nvptx.C new file mode 100644 index 0000000..ef996cf --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/target-exceptions-pr118794-1-offload-sorry-nvptx.C @@ -0,0 +1,24 @@ +/* Exception handling constructs in dead code, '-foffload-options=-mno-fake-exceptions'. */ + +/* As this test case involves an expected offload compilation failure, we have to handle each offload target individually. + { dg-do link { target offload_target_nvptx } } + { dg-additional-options -foffload=nvptx-none } */ +/* { dg-require-effective-target exceptions } + { dg-additional-options -fexceptions } */ +/* { dg-additional-options -foffload-options=-mno-fake-exceptions } */ +/* { dg-additional-options -O0 } */ +/* { dg-additional-options -fdump-tree-optimized-raw } + { dg-additional-options -foffload-options=-fdump-tree-optimized-raw } */ + +#include "target-exceptions-pr118794-1.C" + +/* In this specific C++ arrangement, distilled from PR118794, GCC synthesizes + '__builtin_eh_pointer', '__builtin_unwind_resume' calls as dead code in 'f': + { dg-final { scan-tree-dump-times {gimple_call <__builtin_eh_pointer, } 1 optimized } } + { dg-final { scan-tree-dump-times {gimple_call <__builtin_unwind_resume, } 1 optimized } } + { dg-final { only_for_offload_target nvptx-none scan-offload-tree-dump-times {gimple_call <__builtin_eh_pointer, } 1 optimized } } + { dg-final { only_for_offload_target nvptx-none scan-offload-tree-dump-times {gimple_call <__builtin_unwind_resume, } 1 optimized } } + Given '-O0' and '-foffload-options=-mno-fake-exceptions', offload compilation fails: + { dg-regexp {[^\r\n]+: In function 'f':[\r\n]+(?:[^\r\n]+: sorry, unimplemented: exception handling not supported[\r\n]+)+} } + (Note, using 'dg-regexp' instead of 'dg-message', as the former runs before the auto-mark-UNSUPPORTED.) + { dg-excess-errors {'mkoffload' failure etc.} } */ diff --git a/libgomp/testsuite/libgomp.c++/target-exceptions-pr118794-1.C b/libgomp/testsuite/libgomp.c++/target-exceptions-pr118794-1.C new file mode 100644 index 0000000..24e3d07 --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/target-exceptions-pr118794-1.C @@ -0,0 +1,57 @@ +/* Exception handling constructs in dead code. */ + +/* { dg-require-effective-target exceptions } + { dg-additional-options -fexceptions } */ +/* { dg-additional-options -O0 } */ +/* { dg-additional-options -fdump-tree-optimized-raw } + { dg-additional-options -foffload-options=-fdump-tree-optimized-raw } */ + +/* See also '../../../gcc/testsuite/g++.target/gcn/exceptions-pr118794-1.C', + '../../../gcc/testsuite/g++.target/nvptx/exceptions-pr118794-1.C'. */ + +#pragma omp begin declare target + +bool ok = false; + +template <typename T> +struct C +{ + C() + { + ok = true; + } + C(int) {}; + ~C() {}; + + __attribute__((noipa)) + void m() + { + C c; + } +}; + +inline void f() +{ + C<double> c(1); + c.m(); +} + +#pragma omp end declare target + +int main() +{ +#pragma omp target + { + f(); + } +#pragma omp target update from(ok) + if (!ok) + __builtin_abort(); +} + +/* In this specific C++ arrangement, distilled from PR118794, GCC synthesizes + '__builtin_eh_pointer', '__builtin_unwind_resume' calls as dead code in 'f': + { dg-final { scan-tree-dump-times {gimple_call <__builtin_eh_pointer, } 1 optimized } } + { dg-final { scan-tree-dump-times {gimple_call <__builtin_unwind_resume, } 1 optimized } } + { dg-final { scan-offload-tree-dump-times {gimple_call <__builtin_eh_pointer, } 1 optimized } } + { dg-final { scan-offload-tree-dump-times {gimple_call <__builtin_unwind_resume, } 1 optimized } } */ diff --git a/libgomp/testsuite/libgomp.c++/target-exceptions-throw-1-O0.C b/libgomp/testsuite/libgomp.c++/target-exceptions-throw-1-O0.C new file mode 100644 index 0000000..00d7c13 --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/target-exceptions-throw-1-O0.C @@ -0,0 +1,23 @@ +/* 'throw' in OpenMP 'target' region. */ + +/* { dg-additional-options -O0 } */ +/* { dg-require-effective-target exceptions } + { dg-additional-options -fexceptions } */ +/* { dg-additional-options -fdump-tree-optimized-raw } + { dg-additional-options -foffload-options=-fdump-tree-optimized-raw } */ + +#include "target-exceptions-throw-1.C" + +/* { dg-output {CheCKpOInT[\r\n]+} } + + { dg-final { scan-tree-dump-times {gimple_call <__cxa_allocate_exception, } 1 optimized } } + { dg-final { scan-tree-dump-times {gimple_call <__cxa_throw, } 1 optimized } } + { dg-final { scan-offload-tree-dump-times {gimple_call <__cxa_allocate_exception, } 1 optimized } } + { dg-final { scan-offload-tree-dump-times {gimple_call <__cxa_throw, } 1 optimized } } + For host execution, we print something like: + terminate called after throwing an instance of 'MyException' + Aborted (core dumped) + { dg-output {.*MyException} { target { ! offload_device } } } + For GCN, nvptx offload execution, we don't print anything, but just 'abort'. + + { dg-shouldfail {'MyException' exception} } */ diff --git a/libgomp/testsuite/libgomp.c++/target-exceptions-throw-1.C b/libgomp/testsuite/libgomp.c++/target-exceptions-throw-1.C new file mode 100644 index 0000000..2467061 --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/target-exceptions-throw-1.C @@ -0,0 +1,25 @@ +/* 'throw' in OpenMP 'target' region. */ + +/* { dg-require-effective-target exceptions } + { dg-additional-options -fexceptions } */ +/* { dg-additional-options -fdump-tree-optimized-raw } + { dg-additional-options -foffload-options=-fdump-tree-optimized-raw } */ +/* { dg-bogus {Size expression must be absolute\.} PR119737 { target offload_target_amdgcn xfail *-*-* } 0 } + { dg-ice PR119737 { offload_target_amdgcn } } + { dg-excess-errors {'mkoffload' failures etc.} { xfail offload_target_amdgcn } } */ + +#include "../libgomp.oacc-c++/exceptions-throw-1.C" + +/* { dg-output {CheCKpOInT[\r\n]+} } + + { dg-final { scan-tree-dump-times {gimple_call <__cxa_allocate_exception, } 1 optimized } } + { dg-final { scan-tree-dump-times {gimple_call <__cxa_throw, } 1 optimized } } + { dg-final { scan-offload-tree-dump-times {gimple_call <__cxa_allocate_exception, } 1 optimized } } + { dg-final { scan-offload-tree-dump-times {gimple_call <__cxa_throw, } 1 optimized } } + For host execution, we print something like: + terminate called after throwing an instance of 'MyException' + Aborted (core dumped) + { dg-output {.*MyException} { target { ! offload_device } } } + For GCN, nvptx offload execution, we don't print anything, but just 'abort'. + + { dg-shouldfail {'MyException' exception} } */ diff --git a/libgomp/testsuite/libgomp.c++/target-exceptions-throw-2-O0.C b/libgomp/testsuite/libgomp.c++/target-exceptions-throw-2-O0.C new file mode 100644 index 0000000..b7a311d --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/target-exceptions-throw-2-O0.C @@ -0,0 +1,25 @@ +/* 'throw' in OpenMP 'target' region, caught. */ + +/* { dg-additional-options -O0 } */ +/* { dg-require-effective-target exceptions } + { dg-additional-options -fexceptions } */ +/* { dg-additional-options -fdump-tree-optimized-raw } + { dg-additional-options -foffload-options=-fdump-tree-optimized-raw } */ +/* { dg-bogus {undefined symbol: typeinfo name for MyException} PR119806 { target offload_target_amdgcn xfail *-*-* } 0 } + { dg-excess-errors {'mkoffload' failure etc.} { xfail offload_target_amdgcn } } */ +/* { dg-bogus {Initial value type mismatch} PR119806 { target offload_target_nvptx xfail *-*-* } 0 } + { dg-excess-errors {'mkoffload' failure etc.} { xfail offload_target_nvptx } } */ + +#include "target-exceptions-throw-2.C" + +/* { dg-output {CheCKpOInT[\r\n]+} } + + { dg-final { scan-tree-dump-times {gimple_call <__cxa_allocate_exception, } 1 optimized } } + { dg-final { scan-tree-dump-times {gimple_call <__cxa_throw, } 1 optimized } } + { dg-final { scan-offload-tree-dump-times {gimple_call <__cxa_allocate_exception, } 1 optimized } } + { dg-final { scan-offload-tree-dump-times {gimple_call <__cxa_throw, } 1 optimized } } + { dg-output {.*caught 'MyException'[\r\n]+} { target { ! offload_device } } } + For GCN, nvptx offload execution, we don't print anything, but just 'abort'. + + For GCN, nvptx offload execution, there is no 'catch'ing; any exception is fatal. + { dg-shouldfail {'MyException' exception} { offload_device } } */ diff --git a/libgomp/testsuite/libgomp.c++/target-exceptions-throw-2-offload-sorry-GCN.C b/libgomp/testsuite/libgomp.c++/target-exceptions-throw-2-offload-sorry-GCN.C new file mode 100644 index 0000000..9905b1f --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/target-exceptions-throw-2-offload-sorry-GCN.C @@ -0,0 +1,21 @@ +/* 'throw' in OpenMP 'target' region, caught, -foffload-options=-mno-fake-exceptions. */ + +/* As this test case involves an expected offload compilation failure, we have to handle each offload target individually. + { dg-do link { target offload_target_amdgcn } } + { dg-additional-options -foffload=amdgcn-amdhsa } */ +/* { dg-require-effective-target exceptions } + { dg-additional-options -fexceptions } */ +/* { dg-additional-options -foffload-options=-mno-fake-exceptions } */ +/* { dg-additional-options -fdump-tree-optimized-raw } + { dg-additional-options -foffload-options=-fdump-tree-optimized-raw } */ + +#include "target-exceptions-throw-2.C" + +/* { dg-final { scan-tree-dump-times {gimple_call <__cxa_allocate_exception, } 1 optimized } } + { dg-final { scan-tree-dump-times {gimple_call <__cxa_throw, } 1 optimized } } + { dg-final { only_for_offload_target amdgcn-amdhsa scan-offload-tree-dump-times {gimple_call <__cxa_allocate_exception, } 1 optimized } } + { dg-final { only_for_offload_target amdgcn-amdhsa scan-offload-tree-dump-times {gimple_call <__cxa_throw, } 1 optimized } } + Given '-foffload-options=-mno-fake-exceptions', offload compilation fails: + { dg-regexp {[^\r\n]+: In function 'main[^']+':[\r\n]+(?:[^\r\n]+: sorry, unimplemented: exception handling not supported[\r\n]+)+} } + (Note, using 'dg-regexp' instead of 'dg-message', as the former runs before the auto-mark-UNSUPPORTED.) + { dg-excess-errors {'mkoffload' failure etc.} } */ diff --git a/libgomp/testsuite/libgomp.c++/target-exceptions-throw-2-offload-sorry-nvptx.C b/libgomp/testsuite/libgomp.c++/target-exceptions-throw-2-offload-sorry-nvptx.C new file mode 100644 index 0000000..da267d6 --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/target-exceptions-throw-2-offload-sorry-nvptx.C @@ -0,0 +1,21 @@ +/* 'throw' in OpenMP 'target' region, caught, '-foffload-options=-mno-fake-exceptions'. */ + +/* As this test case involves an expected offload compilation failure, we have to handle each offload target individually. + { dg-do link { target offload_target_nvptx } } + { dg-additional-options -foffload=nvptx-none } */ +/* { dg-require-effective-target exceptions } + { dg-additional-options -fexceptions } */ +/* { dg-additional-options -foffload-options=-mno-fake-exceptions } */ +/* { dg-additional-options -fdump-tree-optimized-raw } + { dg-additional-options -foffload-options=-fdump-tree-optimized-raw } */ + +#include "target-exceptions-throw-2.C" + +/* { dg-final { scan-tree-dump-times {gimple_call <__cxa_allocate_exception, } 1 optimized } } + { dg-final { scan-tree-dump-times {gimple_call <__cxa_throw, } 1 optimized } } + { dg-final { only_for_offload_target nvptx-none scan-offload-tree-dump-times {gimple_call <__cxa_allocate_exception, } 1 optimized } } + { dg-final { only_for_offload_target nvptx-none scan-offload-tree-dump-times {gimple_call <__cxa_throw, } 1 optimized } } + Given '-foffload-options=-mno-fake-exceptions', offload compilation fails: + { dg-regexp {[^\r\n]+: In function 'main[^']+':[\r\n]+(?:[^\r\n]+: sorry, unimplemented: exception handling not supported[\r\n]+)+} } + (Note, using 'dg-regexp' instead of 'dg-message', as the former runs before the auto-mark-UNSUPPORTED.) + { dg-excess-errors {'mkoffload' failure etc.} } */ diff --git a/libgomp/testsuite/libgomp.c++/target-exceptions-throw-2.C b/libgomp/testsuite/libgomp.c++/target-exceptions-throw-2.C new file mode 100644 index 0000000..e85e6c3 --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/target-exceptions-throw-2.C @@ -0,0 +1,23 @@ +/* 'throw' in OpenMP 'target' region, caught. */ + +/* { dg-require-effective-target exceptions } + { dg-additional-options -fexceptions } */ +/* { dg-additional-options -fdump-tree-optimized-raw } + { dg-additional-options -foffload-options=-fdump-tree-optimized-raw } */ +/* { dg-bogus {Size expression must be absolute\.} PR119737 { target offload_target_amdgcn xfail *-*-* } 0 } + { dg-ice PR119737 { offload_target_amdgcn } } + { dg-excess-errors {'mkoffload' failures etc.} { xfail offload_target_amdgcn } } */ + +#include "../libgomp.oacc-c++/exceptions-throw-2.C" + +/* { dg-output {CheCKpOInT[\r\n]+} } + + { dg-final { scan-tree-dump-times {gimple_call <__cxa_allocate_exception, } 1 optimized } } + { dg-final { scan-tree-dump-times {gimple_call <__cxa_throw, } 1 optimized } } + { dg-final { scan-offload-tree-dump-times {gimple_call <__cxa_allocate_exception, } 1 optimized } } + { dg-final { scan-offload-tree-dump-times {gimple_call <__cxa_throw, } 1 optimized } } + { dg-output {.*caught 'MyException'[\r\n]+} { target { ! offload_device } } } + For GCN, nvptx offload execution, we don't print anything, but just 'abort'. + + For GCN, nvptx offload execution, there is no 'catch'ing; any exception is fatal. + { dg-shouldfail {'MyException' exception} { offload_device } } */ diff --git a/libgomp/testsuite/libgomp.c++/target-exceptions-throw-3.C b/libgomp/testsuite/libgomp.c++/target-exceptions-throw-3.C new file mode 100644 index 0000000..c35180d --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/target-exceptions-throw-3.C @@ -0,0 +1,19 @@ +/* 'throw' in OpenMP 'target' region, dead code. */ + +/* { dg-require-effective-target exceptions } + { dg-additional-options -fexceptions } */ +/* { dg-additional-options -DDEFAULT=defaultmap(to) } + ... to avoid wrong code for offloading execution; PR119692. + With this, the device code still isn't correct, but the defects are in dead code. + { dg-additional-options -fdump-tree-gimple } */ +/* { dg-additional-options -fdump-tree-optimized-raw } + { dg-additional-options -foffload-options=-fdump-tree-optimized-raw } */ + +#include "../libgomp.oacc-c++/exceptions-throw-3.C" + +/* { dg-final { scan-tree-dump-not {(?n)#pragma omp target .* defaultmap\(to\) map\(to:_ZTI11MyException \[len: [0-9]+\] \[runtime_implicit\]\)$} gimple { xfail *-*-* } } } */ + +/* { dg-final { scan-tree-dump-times {gimple_call <__cxa_allocate_exception, } 1 optimized } } + { dg-final { scan-tree-dump-times {gimple_call <__cxa_throw, } 1 optimized } } + { dg-final { scan-offload-tree-dump-times {gimple_call <__cxa_allocate_exception, } 1 optimized } } + { dg-final { scan-offload-tree-dump-times {gimple_call <__cxa_throw, } 1 optimized } } */ diff --git a/libgomp/testsuite/libgomp.c-c++-common/pr96390.c b/libgomp/testsuite/libgomp.c-c++-common/pr96390.c index b89f934..ca7865d 100644 --- a/libgomp/testsuite/libgomp.c-c++-common/pr96390.c +++ b/libgomp/testsuite/libgomp.c-c++-common/pr96390.c @@ -1,7 +1,7 @@ /* { dg-additional-options "-O0 -fdump-tree-omplower" } */ /* { dg-additional-options "-foffload=-Wa,--verify" { target offload_target_nvptx } } */ /* { dg-require-alias "" } */ -/* { dg-xfail-if "PR 97102/PR 97106 - .alias not (yet) supported for nvptx" { offload_target_nvptx } } */ +/* { dg-xfail-if PR105018 { offload_target_nvptx } } */ #ifdef __cplusplus extern "C" { diff --git a/libgomp/testsuite/libgomp.fortran/allocatable-comp.f90 b/libgomp/testsuite/libgomp.fortran/allocatable-comp.f90 new file mode 100644 index 0000000..383ecba --- /dev/null +++ b/libgomp/testsuite/libgomp.fortran/allocatable-comp.f90 @@ -0,0 +1,53 @@ +implicit none +type t + integer, allocatable :: a, b(:) +end type t +type(t) :: x, y, z +integer :: i + +!$omp target map(to: x) + if (allocated(x%a)) stop 1 + if (allocated(x%b)) stop 2 +!$omp end target + +allocate(x%a, x%b(-4:6)) +x%b(:) = [(i, i=-4,6)] + +!$omp target map(to: x) + if (.not. allocated(x%a)) stop 3 + if (.not. allocated(x%b)) stop 4 + if (lbound(x%b,1) /= -4) stop 5 + if (ubound(x%b,1) /= 6) stop 6 + if (any (x%b /= [(i, i=-4,6)])) stop 7 +!$omp end target + + +! The following only works with arrays due to +! PR fortran/96668 + +!$omp target enter data map(to: y, z) + +!$omp target map(to: y, z) + if (allocated(y%b)) stop 8 + if (allocated(z%b)) stop 9 +!$omp end target + +allocate(y%b(5), z%b(3)) +y%b = 42 +z%b = 99 + +! (implicitly) 'tofrom' mapped +! Planned for OpenMP 6.0 (but common extension) +! OpenMP <= 5.0 unclear +!$omp target map(to: y) + if (.not.allocated(y%b)) stop 10 + if (any (y%b /= 42)) stop 11 +!$omp end target + +! always map: OpenMP 5.1 (clarified) +!$omp target map(always, tofrom: z) + if (.not.allocated(z%b)) stop 12 + if (any (z%b /= 99)) stop 13 +!$omp end target + +end diff --git a/libgomp/testsuite/libgomp.fortran/map-alloc-comp-3.f90 b/libgomp/testsuite/libgomp.fortran/map-alloc-comp-3.f90 new file mode 100644 index 0000000..9d48c7c --- /dev/null +++ b/libgomp/testsuite/libgomp.fortran/map-alloc-comp-3.f90 @@ -0,0 +1,121 @@ +type t2 + integer x, y, z +end type t2 +type t + integer, allocatable :: A + integer, allocatable :: B(:) + type(t2), allocatable :: C + type(t2), allocatable :: D(:,:) +end type t + +type t3 + type(t) :: Q + type(t) :: R(5) +end type + +type(t) :: var, var2 +type(t3) :: var3, var4 + +! -------------------------------------- +! Assign + allocate +var%A = 45 +var%B = [1,2,3] +var%C = t2(6,5,4) +var%D = reshape([t2(1,2,3), t2(4,5,6), t2(11,12,13), t2(14,15,16)], [2,2]) + +! Assign + allocate +var2%A = 145 +var2%B = [991,992,993] +var2%C = t2(996,995,994) +var2%D = reshape([t2(199,299,399), t2(499,599,699), t2(1199,1299,1399), t2(1499,1599,1699)], [2,2]) + + +!$omp target map(to: var) map(tofrom: var2) + call foo(var, var2) +!$omp end target + +if (var2%A /= 45) stop 9 +if (any (var2%B /= [1,2,3])) stop 10 +if (var2%C%x /= 6) stop 11 +if (var2%C%y /= 5) stop 11 +if (var2%C%z /= 4) stop 11 +if (any (var2%D(:,:)%x /= reshape([1, 4, 11, 14], [2,2]))) stop 12 +if (any (var2%D(:,:)%y /= reshape([2, 5, 12, 15], [2,2]))) stop 12 +if (any (var2%D(:,:)%z /= reshape([3, 6, 13, 16], [2,2]))) stop 12 + +! -------------------------------------- +! Assign + allocate +var3%Q%A = 45 +var3%Q%B = [1,2,3] +var3%Q%C = t2(6,5,4) +var3%Q%D = reshape([t2(1,2,3), t2(4,5,6), t2(11,12,13), t2(14,15,16)], [2,2]) + +var3%R(2)%A = 45 +var3%R(2)%B = [1,2,3] +var3%R(2)%C = t2(6,5,4) +var3%R(2)%D = reshape([t2(1,2,3), t2(4,5,6), t2(11,12,13), t2(14,15,16)], [2,2]) + +! Assign + allocate +var4%Q%A = 145 +var4%Q%B = [991,992,993] +var4%Q%C = t2(996,995,994) +var4%Q%D = reshape([t2(199,299,399), t2(499,599,699), t2(1199,1299,1399), t2(1499,1599,1699)], [2,2]) + +var4%R(3)%A = 145 +var4%R(3)%B = [991,992,993] +var4%R(3)%C = t2(996,995,994) +var4%R(3)%D = reshape([t2(199,299,399), t2(499,599,699), t2(1199,1299,1399), t2(1499,1599,1699)], [2,2]) + +!$omp target map(to: var3%Q) map(tofrom: var4%Q) + call foo(var3%Q, var4%Q) +!$omp end target + +!$omp target map(to: var3%R(2)) map(tofrom: var4%R(3)) + call foo(var3%R(2), var4%R(3)) +!$omp end target + +if (var4%Q%A /= 45) stop 13 +if (any (var4%Q%B /= [1,2,3])) stop 14 +if (var4%Q%C%x /= 6) stop 15 +if (var4%Q%C%y /= 5) stop 15 +if (var4%Q%C%z /= 4) stop 15 +if (any (var4%Q%D(:,:)%x /= reshape([1, 4, 11, 14], [2,2]))) stop 16 +if (any (var4%Q%D(:,:)%y /= reshape([2, 5, 12, 15], [2,2]))) stop 16 +if (any (var4%Q%D(:,:)%z /= reshape([3, 6, 13, 16], [2,2]))) stop 16 + +if (var4%R(3)%A /= 45) stop 17 +if (any (var4%R(3)%B /= [1,2,3])) stop 18 +if (var4%R(3)%C%x /= 6) stop 19 +if (var4%R(3)%C%y /= 5) stop 19 +if (var4%R(3)%C%z /= 4) stop 19 +if (any (var4%R(3)%D(:,:)%x /= reshape([1, 4, 11, 14], [2,2]))) stop 20 +if (any (var4%R(3)%D(:,:)%y /= reshape([2, 5, 12, 15], [2,2]))) stop 20 +if (any (var4%R(3)%D(:,:)%z /= reshape([3, 6, 13, 16], [2,2]))) stop 20 + +contains + subroutine foo(x, y) + type(t) :: x, y + if (x%A /= 45) stop 1 + if (any (x%B /= [1,2,3])) stop 2 + if (x%C%x /= 6) stop 3 + if (x%C%y /= 5) stop 3 + if (x%C%z /= 4) stop 3 + if (any (x%D(:,:)%x /= reshape([1, 4, 11, 14], [2,2]))) stop 4 + if (any (x%D(:,:)%y /= reshape([2, 5, 12, 15], [2,2]))) stop 4 + if (any (x%D(:,:)%z /= reshape([3, 6, 13, 16], [2,2]))) stop 4 + + if (y%A /= 145) stop 5 + if (any (y%B /= [991,992,993])) stop 6 + if (y%C%x /= 996) stop 7 + if (y%C%y /= 995) stop 7 + if (y%C%z /= 994) stop 7 + if (any (y%D(:,:)%x /= reshape([199, 499, 1199, 1499], [2,2]))) stop 8 + if (any (y%D(:,:)%y /= reshape([299, 599, 1299, 1599], [2,2]))) stop 8 + if (any (y%D(:,:)%z /= reshape([399, 699, 1399, 1699], [2,2]))) stop 8 + + y%A = x%A + y%B(:) = x%B + y%C = x%C + y%D(:,:) = x%D(:,:) + end +end diff --git a/libgomp/testsuite/libgomp.fortran/map-alloc-comp-4.f90 b/libgomp/testsuite/libgomp.fortran/map-alloc-comp-4.f90 new file mode 100644 index 0000000..fb9859d --- /dev/null +++ b/libgomp/testsuite/libgomp.fortran/map-alloc-comp-4.f90 @@ -0,0 +1,124 @@ +type t2 + integer x, y, z +end type t2 +type t + integer, allocatable :: A + integer, allocatable :: B(:) + type(t2), allocatable :: C + type(t2), allocatable :: D(:,:) +end type t + +type t3 + type(t) :: Q + type(t) :: R(5) +end type + +type(t) :: var, var2 +type(t3) :: var3, var4 + +! -------------------------------------- +! Assign + allocate +var%A = 45 +var%B = [1,2,3] +var%C = t2(6,5,4) +var%D = reshape([t2(1,2,3), t2(4,5,6), t2(11,12,13), t2(14,15,16)], [2,2]) + +! Assign + allocate +var2%A = 145 +var2%B = [991,992,993] +var2%C = t2(996,995,994) +var2%D = reshape([t2(199,299,399), t2(499,599,699), t2(1199,1299,1399), t2(1499,1599,1699)], [2,2]) + + +!$omp target map(to: var%A, var%B, var%C, var%D) & +!$omp& map(tofrom: var2%A, var2%B, var2%C, var2%D) + call foo(var, var2) +!$omp end target + +if (var2%A /= 45) stop 9 +if (any (var2%B /= [1,2,3])) stop 10 +if (var2%C%x /= 6) stop 11 +if (var2%C%y /= 5) stop 11 +if (var2%C%z /= 4) stop 11 +if (any (var2%D(:,:)%x /= reshape([1, 4, 11, 14], [2,2]))) stop 12 +if (any (var2%D(:,:)%y /= reshape([2, 5, 12, 15], [2,2]))) stop 12 +if (any (var2%D(:,:)%z /= reshape([3, 6, 13, 16], [2,2]))) stop 12 + +! -------------------------------------- +! Assign + allocate +var3%Q%A = 45 +var3%Q%B = [1,2,3] +var3%Q%C = t2(6,5,4) +var3%Q%D = reshape([t2(1,2,3), t2(4,5,6), t2(11,12,13), t2(14,15,16)], [2,2]) + +var3%R(2)%A = 45 +var3%R(2)%B = [1,2,3] +var3%R(2)%C = t2(6,5,4) +var3%R(2)%D = reshape([t2(1,2,3), t2(4,5,6), t2(11,12,13), t2(14,15,16)], [2,2]) + +! Assign + allocate +var4%Q%A = 145 +var4%Q%B = [991,992,993] +var4%Q%C = t2(996,995,994) +var4%Q%D = reshape([t2(199,299,399), t2(499,599,699), t2(1199,1299,1399), t2(1499,1599,1699)], [2,2]) + +var4%R(3)%A = 145 +var4%R(3)%B = [991,992,993] +var4%R(3)%C = t2(996,995,994) +var4%R(3)%D = reshape([t2(199,299,399), t2(499,599,699), t2(1199,1299,1399), t2(1499,1599,1699)], [2,2]) + +!$omp target map(to: var3%Q%A, var3%Q%B, var3%Q%C, var3%Q%D) & +!$omp& map(tofrom: var4%Q%A, var4%Q%B, var4%Q%C, var4%Q%D) + call foo(var3%Q, var4%Q) +!$omp end target + +if (var4%Q%A /= 45) stop 13 +if (any (var4%Q%B /= [1,2,3])) stop 14 +if (var4%Q%C%x /= 6) stop 15 +if (var4%Q%C%y /= 5) stop 15 +if (var4%Q%C%z /= 4) stop 15 +if (any (var4%Q%D(:,:)%x /= reshape([1, 4, 11, 14], [2,2]))) stop 16 +if (any (var4%Q%D(:,:)%y /= reshape([2, 5, 12, 15], [2,2]))) stop 16 +if (any (var4%Q%D(:,:)%z /= reshape([3, 6, 13, 16], [2,2]))) stop 16 + +!$omp target map(to: var3%R(2)%A, var3%R(2)%B, var3%R(2)%C, var3%R(2)%D) & +!$omp& map(tofrom: var4%R(3)%A, var4%R(3)%B, var4%R(3)%C, var4%R(3)%D) + call foo(var3%R(2), var4%R(3)) +!$omp end target + +if (var4%R(3)%A /= 45) stop 17 +if (any (var4%R(3)%B /= [1,2,3])) stop 18 +if (var4%R(3)%C%x /= 6) stop 19 +if (var4%R(3)%C%y /= 5) stop 19 +if (var4%R(3)%C%z /= 4) stop 19 +if (any (var4%R(3)%D(:,:)%x /= reshape([1, 4, 11, 14], [2,2]))) stop 20 +if (any (var4%R(3)%D(:,:)%y /= reshape([2, 5, 12, 15], [2,2]))) stop 20 +if (any (var4%R(3)%D(:,:)%z /= reshape([3, 6, 13, 16], [2,2]))) stop 20 + +contains + subroutine foo(x, y) + type(t) :: x, y + if (x%A /= 45) stop 1 + if (any (x%B /= [1,2,3])) stop 2 + if (x%C%x /= 6) stop 3 + if (x%C%y /= 5) stop 3 + if (x%C%z /= 4) stop 3 + if (any (x%D(:,:)%x /= reshape([1, 4, 11, 14], [2,2]))) stop 4 + if (any (x%D(:,:)%y /= reshape([2, 5, 12, 15], [2,2]))) stop 4 + if (any (x%D(:,:)%z /= reshape([3, 6, 13, 16], [2,2]))) stop 4 + + if (y%A /= 145) stop 5 + if (any (y%B /= [991,992,993])) stop 6 + if (y%C%x /= 996) stop 7 + if (y%C%y /= 995) stop 7 + if (y%C%z /= 994) stop 7 + if (any (y%D(:,:)%x /= reshape([199, 499, 1199, 1499], [2,2]))) stop 8 + if (any (y%D(:,:)%y /= reshape([299, 599, 1299, 1599], [2,2]))) stop 8 + if (any (y%D(:,:)%z /= reshape([399, 699, 1399, 1699], [2,2]))) stop 8 + + y%A = x%A + y%B(:) = x%B + y%C = x%C + y%D(:,:) = x%D(:,:) + end +end diff --git a/libgomp/testsuite/libgomp.fortran/map-alloc-comp-5.f90 b/libgomp/testsuite/libgomp.fortran/map-alloc-comp-5.f90 new file mode 100644 index 0000000..b2e36b2 --- /dev/null +++ b/libgomp/testsuite/libgomp.fortran/map-alloc-comp-5.f90 @@ -0,0 +1,53 @@ +implicit none +type t + integer, allocatable :: a, b(:) +end type t +type(t) :: x, y, z +integer :: i + +!$omp target + if (allocated(x%a)) stop 1 + if (allocated(x%b)) stop 2 +!$omp end target + +allocate(x%a, x%b(-4:6)) +x%b(:) = [(i, i=-4,6)] + +!$omp target + if (.not. allocated(x%a)) stop 3 + if (.not. allocated(x%b)) stop 4 + if (lbound(x%b,1) /= -4) stop 5 + if (ubound(x%b,1) /= 6) stop 6 + if (any (x%b /= [(i, i=-4,6)])) stop 7 +!$omp end target + + +! The following only works with arrays due to +! PR fortran/96668 + +!$omp target enter data map(to: y, z) + +!$omp target + if (allocated(y%b)) stop 8 + if (allocated(z%b)) stop 9 +!$omp end target + +allocate(y%b(5), z%b(3)) +y%b = 42 +z%b = 99 + +! (implicitly) 'tofrom' mapped +! Planned for OpenMP 6.0 (but common extension) +! OpenMP <= 5.0 unclear +!$omp target + if (.not.allocated(y%b)) stop 10 + if (any (y%b /= 42)) stop 11 +!$omp end target + +! always map: OpenMP 5.1 (clarified) +!$omp target map(always, tofrom: z) + if (.not.allocated(z%b)) stop 12 + if (any (z%b /= 99)) stop 13 +!$omp end target + +end diff --git a/libgomp/testsuite/libgomp.fortran/map-alloc-comp-6.f90 b/libgomp/testsuite/libgomp.fortran/map-alloc-comp-6.f90 new file mode 100644 index 0000000..48d4aea --- /dev/null +++ b/libgomp/testsuite/libgomp.fortran/map-alloc-comp-6.f90 @@ -0,0 +1,308 @@ +! NOTE: This code uses POINTER. +! While map(p, var%p) etc. maps the ptr/ptr comp p / var%p (incl. allocatable comps), +! map(var) does not map var%p. + +use iso_c_binding +implicit none +type t2 + integer, allocatable :: x, y, z +end type t2 +type t + integer, pointer :: A => null() + integer, pointer :: B(:) => null() + type(t2), pointer :: C => null() + type(t2), pointer :: D(:,:) => null() +end type t + +type t3 + type(t) :: Q + type(t) :: R(5) +end type + +type(t) :: var, var2 +type(t3) :: var3, var4 +integer(c_intptr_t) :: iptr + +! -------------------------------------- +! Assign + allocate +allocate (var%A, source=45) +allocate (var%B(3), source=[1,2,3]) +allocate (var%C) +var%C%x = 6; var%C%y = 5; var%C%z = 4 +allocate (var%D(2,2)) +var%D(1,1)%x = 1 +var%D(1,1)%y = 2 +var%D(1,1)%z = 3 +var%D(2,1)%x = 4 +var%D(2,1)%y = 5 +var%D(2,1)%z = 6 +var%D(1,2)%x = 11 +var%D(1,2)%y = 12 +var%D(1,2)%z = 13 +var%D(2,2)%x = 14 +var%D(2,2)%y = 15 +var%D(2,2)%z = 16 + +! Assign + allocate +allocate (var2%A, source=145) +allocate (var2%B, source=[991,992,993]) +allocate (var2%C) +var2%C%x = 996; var2%C%y = 995; var2%C%z = 994 +allocate (var2%D(2,2)) +var2%D(1,1)%x = 199 +var2%D(1,1)%y = 299 +var2%D(1,1)%z = 399 +var2%D(2,1)%x = 499 +var2%D(2,1)%y = 599 +var2%D(2,1)%z = 699 +var2%D(1,2)%x = 1199 +var2%D(1,2)%y = 1299 +var2%D(1,2)%z = 1399 +var2%D(2,2)%x = 1499 +var2%D(2,2)%y = 1599 +var2%D(2,2)%z = 1699 + +block + integer(c_intptr_t) :: loc_a, loc_b, loc_c, loc_d, loc2_a, loc2_b, loc2_c, loc2_d + loc_a = loc (var%a) + loc_b = loc (var%b) + loc_c = loc (var%d) + loc_d = loc (var%d) + loc2_a = loc (var2%a) + loc2_b = loc (var2%b) + loc2_c = loc (var2%c) + loc2_d = loc (var2%d) + ! var/var2 are mapped, but the pointer components aren't + !$omp target map(to: var) map(tofrom: var2) + if (loc_a /= loc (var%a)) stop 31 + if (loc_b /= loc (var%b)) stop 32 + if (loc_c /= loc (var%d)) stop 33 + if (loc_d /= loc (var%d)) stop 34 + if (loc2_a /= loc (var2%a)) stop 35 + if (loc2_b /= loc (var2%b)) stop 36 + if (loc2_c /= loc (var2%c)) stop 37 + if (loc2_d /= loc (var2%d)) stop 38 + !$omp end target + if (loc_a /= loc (var%a)) stop 41 + if (loc_b /= loc (var%b)) stop 42 + if (loc_c /= loc (var%d)) stop 43 + if (loc_d /= loc (var%d)) stop 44 + if (loc2_a /= loc (var2%a)) stop 45 + if (loc2_b /= loc (var2%b)) stop 46 + if (loc2_c /= loc (var2%c)) stop 47 + if (loc2_d /= loc (var2%d)) stop 48 +end block + +block + ! Map only (all) components, but this maps also the alloc comps + !$omp target map(to: var%a, var%b, var%c, var%d) map(tofrom: var2%a, var2%b, var2%c, var2%d) + call foo (var,var2) + !$omp end target +end block + +if (var2%A /= 45) stop 9 +if (any (var2%B /= [1,2,3])) stop 10 +if (var2%C%x /= 6) stop 11 +if (var2%C%y /= 5) stop 11 +if (var2%C%z /= 4) stop 11 +block + integer :: tmp_x(2,2), tmp_y(2,2), tmp_z(2,2), i, j + tmp_x = reshape([1, 4, 11, 14], [2,2]) + tmp_y = reshape([2, 5, 12, 15], [2,2]) + tmp_z = reshape([3, 6, 13, 16], [2,2]) + do j = 1, 2 + do i = 1, 2 + if (var2%D(i,j)%x /= tmp_x(i,j)) stop 12 + if (var2%D(i,j)%y /= tmp_y(i,j)) stop 12 + if (var2%D(i,j)%z /= tmp_z(i,j)) stop 12 + end do + end do +end block + +! Extra deallocates due to PR fortran/104697 +deallocate(var%C%x, var%C%y, var%C%z) +deallocate(var%D(1,1)%x, var%D(1,1)%y, var%D(1,1)%z) +deallocate(var%D(2,1)%x, var%D(2,1)%y, var%D(2,1)%z) +deallocate(var%D(1,2)%x, var%D(1,2)%y, var%D(1,2)%z) +deallocate(var%D(2,2)%x, var%D(2,2)%y, var%D(2,2)%z) +deallocate(var%A, var%B, var%C, var%D) + +deallocate(var2%C%x, var2%C%y, var2%C%z) +deallocate(var2%D(1,1)%x, var2%D(1,1)%y, var2%D(1,1)%z) +deallocate(var2%D(2,1)%x, var2%D(2,1)%y, var2%D(2,1)%z) +deallocate(var2%D(1,2)%x, var2%D(1,2)%y, var2%D(1,2)%z) +deallocate(var2%D(2,2)%x, var2%D(2,2)%y, var2%D(2,2)%z) +deallocate(var2%A, var2%B, var2%C, var2%D) + +! -------------------------------------- +! Assign + allocate +allocate (var3%Q%A, source=45) +allocate (var3%Q%B, source=[1,2,3]) +allocate (var3%Q%C, source=t2(6,5,4)) +allocate (var3%Q%D(2,2)) +var3%Q%D(1,1) = t2(1,2,3) +var3%Q%D(2,1) = t2(4,5,6) +var3%Q%D(1,2) = t2(11,12,13) +var3%Q%D(2,2) = t2(14,15,16) + +allocate (var3%R(2)%A, source=45) +allocate (var3%R(2)%B, source=[1,2,3]) +allocate (var3%R(2)%C, source=t2(6,5,4)) +allocate (var3%R(2)%D(2,2)) +var3%R(2)%D(1,1) = t2(1,2,3) +var3%R(2)%D(2,1) = t2(4,5,6) +var3%R(2)%D(1,2) = t2(11,12,13) +var3%R(2)%D(2,2) = t2(14,15,16) + +! Assign + allocate +allocate (var4%Q%A, source=145) +allocate (var4%Q%B, source=[991,992,993]) +allocate (var4%Q%C, source=t2(996,995,994)) +allocate (var4%Q%D(2,2)) +var4%Q%D(1,1) = t2(199,299,399) +var4%Q%D(2,1) = t2(499,599,699) +var4%Q%D(1,2) = t2(1199,1299,1399) +var4%Q%D(2,2) = t2(1499,1599,1699) + +allocate (var4%R(3)%A, source=145) +allocate (var4%R(3)%B, source=[991,992,993]) +allocate (var4%R(3)%C, source=t2(996,995,994)) +allocate (var4%R(3)%D(2,2)) +var4%R(3)%D(1,1) = t2(199,299,399) +var4%R(3)%D(2,1) = t2(499,599,699) +var4%R(3)%D(1,2) = t2(1199,1299,1399) +var4%R(3)%D(2,2) = t2(1499,1599,1699) + +!$omp target map(to: var3%Q%A, var3%Q%B, var3%Q%C, var3%Q%D) & +!$omp& map(tofrom: var4%Q%A, var4%Q%B, var4%Q%C, var4%Q%D) + call foo(var3%Q, var4%Q) +!$omp end target + +iptr = loc(var3%R(2)%A) + +!$omp target map(to: var3%R(2)%A, var3%R(2)%B, var3%R(2)%C, var3%R(2)%D) & +!$omp& map(tofrom: var4%R(3)%A, var4%R(3)%B, var4%R(3)%C, var4%R(3)%D) + call foo(var3%R(2), var4%R(3)) +!$omp end target + +if (var4%Q%A /= 45) stop 13 +if (any (var4%Q%B /= [1,2,3])) stop 14 +if (var4%Q%C%x /= 6) stop 15 +if (var4%Q%C%y /= 5) stop 15 +if (var4%Q%C%z /= 4) stop 15 +block + integer :: tmp_x(2,2), tmp_y(2,2), tmp_z(2,2), i, j + tmp_x = reshape([1, 4, 11, 14], [2,2]) + tmp_y = reshape([2, 5, 12, 15], [2,2]) + tmp_z = reshape([3, 6, 13, 16], [2,2]) + do j = 1, 2 + do i = 1, 2 + if (var4%Q%D(i,j)%x /= tmp_x(i,j)) stop 16 + if (var4%Q%D(i,j)%y /= tmp_y(i,j)) stop 16 + if (var4%Q%D(i,j)%z /= tmp_z(i,j)) stop 16 + end do + end do +end block + +! Cf. PR fortran/104696 +! { dg-output "valid mapping, OK" { xfail { offload_device_nonshared_as } } } +if (iptr /= loc(var3%R(2)%A)) then + print *, "invalid mapping, cf. PR fortran/104696" +else + +if (var4%R(3)%A /= 45) stop 17 +if (any (var4%R(3)%B /= [1,2,3])) stop 18 +if (var4%R(3)%C%x /= 6) stop 19 +if (var4%R(3)%C%y /= 5) stop 19 +if (var4%R(3)%C%z /= 4) stop 19 +block + integer :: tmp_x(2,2), tmp_y(2,2), tmp_z(2,2), i, j + tmp_x = reshape([1, 4, 11, 14], [2,2]) + tmp_y = reshape([2, 5, 12, 15], [2,2]) + tmp_z = reshape([3, 6, 13, 16], [2,2]) + do j = 1, 2 + do i = 1, 2 + if (var4%R(3)%D(i,j)%x /= tmp_x(i,j)) stop 20 + if (var4%R(3)%D(i,j)%y /= tmp_y(i,j)) stop 20 + if (var4%R(3)%D(i,j)%z /= tmp_z(i,j)) stop 20 + end do + end do +end block + +! Extra deallocates due to PR fortran/104697 +deallocate(var3%Q%C%x, var3%Q%D(1,1)%x, var3%Q%D(2,1)%x, var3%Q%D(1,2)%x, var3%Q%D(2,2)%x) +deallocate(var3%Q%C%y, var3%Q%D(1,1)%y, var3%Q%D(2,1)%y, var3%Q%D(1,2)%y, var3%Q%D(2,2)%y) +deallocate(var3%Q%C%z, var3%Q%D(1,1)%z, var3%Q%D(2,1)%z, var3%Q%D(1,2)%z, var3%Q%D(2,2)%z) +deallocate(var3%Q%A, var3%Q%B, var3%Q%C, var3%Q%D) + +deallocate(var4%Q%C%x, var4%Q%D(1,1)%x, var4%Q%D(2,1)%x, var4%Q%D(1,2)%x, var4%Q%D(2,2)%x) +deallocate(var4%Q%C%y, var4%Q%D(1,1)%y, var4%Q%D(2,1)%y, var4%Q%D(1,2)%y, var4%Q%D(2,2)%y) +deallocate(var4%Q%C%z, var4%Q%D(1,1)%z, var4%Q%D(2,1)%z, var4%Q%D(1,2)%z, var4%Q%D(2,2)%z) +deallocate(var4%Q%A, var4%Q%B, var4%Q%C, var4%Q%D) + +deallocate(var3%R(2)%C%x, var3%R(2)%D(1,1)%x, var3%R(2)%D(2,1)%x, var3%R(2)%D(1,2)%x, var3%R(2)%D(2,2)%x) +deallocate(var3%R(2)%C%y, var3%R(2)%D(1,1)%y, var3%R(2)%D(2,1)%y, var3%R(2)%D(1,2)%y, var3%R(2)%D(2,2)%y) +deallocate(var3%R(2)%C%z, var3%R(2)%D(1,1)%z, var3%R(2)%D(2,1)%z, var3%R(2)%D(1,2)%z, var3%R(2)%D(2,2)%z) +deallocate(var3%R(2)%A, var3%R(2)%B, var3%R(2)%C, var3%R(2)%D) + +deallocate(var4%R(3)%C%x, var4%R(3)%D(1,1)%x, var4%R(3)%D(2,1)%x, var4%R(3)%D(1,2)%x, var4%R(3)%D(2,2)%x) +deallocate(var4%R(3)%C%y, var4%R(3)%D(1,1)%y, var4%R(3)%D(2,1)%y, var4%R(3)%D(1,2)%y, var4%R(3)%D(2,2)%y) +deallocate(var4%R(3)%C%z, var4%R(3)%D(1,1)%z, var4%R(3)%D(2,1)%z, var4%R(3)%D(1,2)%z, var4%R(3)%D(2,2)%z) +deallocate(var4%R(3)%A, var4%R(3)%B, var4%R(3)%C, var4%R(3)%D) + + print *, "valid mapping, OK" +endif + +contains + subroutine foo(x, y) + type(t) :: x, y + intent(in) :: x + intent(inout) :: y + integer :: tmp_x(2,2), tmp_y(2,2), tmp_z(2,2), i, j + if (x%A /= 45) stop 1 + if (any (x%B /= [1,2,3])) stop 2 + if (x%C%x /= 6) stop 3 + if (x%C%y /= 5) stop 3 + if (x%C%z /= 4) stop 3 + + tmp_x = reshape([1, 4, 11, 14], [2,2]) + tmp_y = reshape([2, 5, 12, 15], [2,2]) + tmp_z = reshape([3, 6, 13, 16], [2,2]) + do j = 1, 2 + do i = 1, 2 + if (x%D(i,j)%x /= tmp_x(i,j)) stop 4 + if (x%D(i,j)%y /= tmp_y(i,j)) stop 4 + if (x%D(i,j)%z /= tmp_z(i,j)) stop 4 + end do + end do + + if (y%A /= 145) stop 5 + if (any (y%B /= [991,992,993])) stop 6 + if (y%C%x /= 996) stop 7 + if (y%C%y /= 995) stop 7 + if (y%C%z /= 994) stop 7 + tmp_x = reshape([199, 499, 1199, 1499], [2,2]) + tmp_y = reshape([299, 599, 1299, 1599], [2,2]) + tmp_z = reshape([399, 699, 1399, 1699], [2,2]) + do j = 1, 2 + do i = 1, 2 + if (y%D(i,j)%x /= tmp_x(i,j)) stop 8 + if (y%D(i,j)%y /= tmp_y(i,j)) stop 8 + if (y%D(i,j)%z /= tmp_z(i,j)) stop 8 + end do + end do + + y%A = x%A + y%B(:) = x%B + y%C%x = x%C%x + y%C%y = x%C%y + y%C%z = x%C%z + do j = 1, 2 + do i = 1, 2 + y%D(i,j)%x = x%D(i,j)%x + y%D(i,j)%y = x%D(i,j)%y + y%D(i,j)%z = x%D(i,j)%z + end do + end do + end +end diff --git a/libgomp/testsuite/libgomp.fortran/map-alloc-comp-7.f90 b/libgomp/testsuite/libgomp.fortran/map-alloc-comp-7.f90 new file mode 100644 index 0000000..1493c5f --- /dev/null +++ b/libgomp/testsuite/libgomp.fortran/map-alloc-comp-7.f90 @@ -0,0 +1,672 @@ +module m + implicit none (type, external) + type t + integer, allocatable :: arr(:,:) + integer :: var + integer, allocatable :: slr + end type t + +contains + + subroutine check_it (is_present, dummy_alloced, inner_alloc, & + scalar, array, a_scalar, a_array, & + l_scalar, l_array, la_scalar, la_array, & + opt_scalar, opt_array, a_opt_scalar, a_opt_array) + type(t), intent(inout) :: & + scalar, array(:,:), opt_scalar, opt_array(:,:), a_scalar, a_array(:,:), & + a_opt_scalar, a_opt_array(:,:), & + l_scalar, l_array(:,:), la_scalar, la_array(:,:) + optional :: opt_scalar, opt_array, a_opt_scalar, a_opt_array + allocatable :: a_scalar, a_array, a_opt_scalar, a_opt_array, la_scalar, la_array + logical, value :: is_present, dummy_alloced, inner_alloc + integer :: i, j, k, l + + ! CHECK VALUE + if (scalar%var /= 42) stop 1 + if (l_scalar%var /= 42) stop 1 + if (is_present) then + if (opt_scalar%var /= 42) stop 2 + end if + if (any (shape(array) /= [3,2])) stop 1 + if (any (shape(l_array) /= [3,2])) stop 1 + if (is_present) then + if (any (shape(opt_array) /= [3,2])) stop 1 + end if + do j = 1, 2 + do i = 1, 3 + if (array(i,j)%var /= i*97 + 100*41*j) stop 3 + if (l_array(i,j)%var /= i*97 + 100*41*j) stop 3 + if (is_present) then + if (opt_array(i,j)%var /= i*97 + 100*41*j) stop 4 + end if + end do + end do + + if (dummy_alloced) then + if (a_scalar%var /= 42) stop 1 + if (la_scalar%var /= 42) stop 1 + if (is_present) then + if (a_opt_scalar%var /= 42) stop 1 + end if + if (any (shape(a_array) /= [3,2])) stop 1 + if (any (shape(la_array) /= [3,2])) stop 1 + if (is_present) then + if (any (shape(a_opt_array) /= [3,2])) stop 1 + end if + do j = 1, 2 + do i = 1, 3 + if (a_array(i,j)%var /= i*97 + 100*41*j) stop 1 + if (la_array(i,j)%var /= i*97 + 100*41*j) stop 1 + if (is_present) then + if (a_opt_array(i,j)%var /= i*97 + 100*41*j) stop 1 + end if + end do + end do + else + if (allocated (a_scalar)) stop 1 + if (allocated (la_scalar)) stop 1 + if (allocated (a_array)) stop 1 + if (allocated (la_array)) stop 1 + if (is_present) then + if (allocated (a_opt_scalar)) stop 1 + if (allocated (a_opt_array)) stop 1 + end if + end if + + if (inner_alloc) then + if (scalar%slr /= 467) stop 5 + if (l_scalar%slr /= 467) stop 5 + if (a_scalar%slr /= 467) stop 6 + if (la_scalar%slr /= 467) stop 6 + if (is_present) then + if (opt_scalar%slr /= 467) stop 7 + if (a_opt_scalar%slr /= 467) stop 8 + end if + do j = 1, 2 + do i = 1, 3 + if (array(i,j)%slr /= (i*97 + 100*41*j) + 467) stop 9 + if (l_array(i,j)%slr /= (i*97 + 100*41*j) + 467) stop 9 + if (a_array(i,j)%slr /= (i*97 + 100*41*j) + 467) stop 10 + if (la_array(i,j)%slr /= (i*97 + 100*41*j) + 467) stop 10 + if (is_present) then + if (opt_array(i,j)%slr /= (i*97 + 100*41*j) + 467) stop 11 + if (a_opt_array(i,j)%slr /= (i*97 + 100*41*j) + 467) stop 12 + end if + end do + end do + + do l = 1, 5 + do k = 1, 4 + if (any (shape(scalar%arr) /= [4,5])) stop 1 + if (any (shape(l_scalar%arr) /= [4,5])) stop 1 + if (any (shape(a_scalar%arr) /= [4,5])) stop 1 + if (any (shape(la_scalar%arr) /= [4,5])) stop 1 + if (scalar%arr(k,l) /= (i*27 + 1000*11*j) + 467) stop 13 + if (l_scalar%arr(k,l) /= (i*27 + 1000*11*j) + 467) stop 13 + if (a_scalar%arr(k,l) /= (i*27 + 1000*11*j) + 467) stop 14 + if (la_scalar%arr(k,l) /= (i*27 + 1000*11*j) + 467) stop 14 + if (is_present) then + if (any (shape(opt_scalar%arr) /= [4,5])) stop 1 + if (any (shape(a_opt_scalar%arr) /= [4,5])) stop 1 + if (opt_scalar%arr(k,l) /= (i*27 + 1000*11*j) + 467) stop 15 + if (a_opt_scalar%arr(k,l) /= (i*27 + 1000*11*j) + 467) stop 16 + end if + end do + end do + do j = 1, 2 + do i = 1, 3 + if (any (shape(array(i,j)%arr) /= [i,j])) stop 1 + if (any (shape(l_array(i,j)%arr) /= [i,j])) stop 1 + if (any (shape(a_array(i,j)%arr) /= [i,j])) stop 1 + if (any (shape(la_array(i,j)%arr) /= [i,j])) stop 1 + if (is_present) then + if (any (shape(opt_array(i,j)%arr) /= [i,j])) stop 1 + if (any (shape(a_opt_array(i,j)%arr) /= [i,j])) stop 1 + endif + do l = 1, j + do k = 1, i + if (array(i,j)%arr(k,l) /= i*27 + 1000*11*j + 467 + 3*k +53*l) stop 17 + if (l_array(i,j)%arr(k,l) /= i*27 + 1000*11*j + 467 + 3*k +53*l) stop 17 + if (a_array(i,j)%arr(k,l) /= i*27 + 1000*11*j + 467 + 3*k +53*l) stop 18 + if (la_array(i,j)%arr(k,l) /= i*27 + 1000*11*j + 467 + 3*k +53*l) stop 18 + if (is_present) then + if (opt_array(i,j)%arr(k,l) /= i*27 + 1000*11*j + 467 + 3*k +53*l) stop 19 + if (a_opt_array(i,j)%arr(k,l) /= i*27 + 1000*11*j + 467 + 3*k +53*l) stop 20 + end if + end do + end do + end do + end do + else if (dummy_alloced) then + if (allocated (scalar%slr)) stop 1 + if (allocated (l_scalar%slr)) stop 1 + if (allocated (a_scalar%slr)) stop 1 + if (allocated (la_scalar%slr)) stop 1 + if (is_present) then + if (allocated (opt_scalar%slr)) stop 1 + if (allocated (a_opt_scalar%slr)) stop 1 + endif + if (allocated (scalar%arr)) stop 1 + if (allocated (l_scalar%arr)) stop 1 + if (allocated (a_scalar%arr)) stop 1 + if (allocated (la_scalar%arr)) stop 1 + if (is_present) then + if (allocated (opt_scalar%arr)) stop 1 + if (allocated (a_opt_scalar%arr)) stop 1 + endif + end if + + ! SET VALUE + scalar%var = 42 + 13 + l_scalar%var = 42 + 13 + if (is_present) then + opt_scalar%var = 42 + 13 + endif + do j = 1, 2 + do i = 1, 3 + array(i,j)%var = i*97 + 100*41*j + 13 + l_array(i,j)%var = i*97 + 100*41*j + 13 + if (is_present) then + opt_array(i,j)%var = i*97 + 100*41*j + 13 + end if + end do + end do + + if (dummy_alloced) then + a_scalar%var = 42 + 13 + la_scalar%var = 42 + 13 + if (is_present) then + a_opt_scalar%var = 42 + 13 + endif + do j = 1, 2 + do i = 1, 3 + a_array(i,j)%var = i*97 + 100*41*j + 13 + la_array(i,j)%var = i*97 + 100*41*j + 13 + if (is_present) then + a_opt_array(i,j)%var = i*97 + 100*41*j + 13 + endif + end do + end do + end if + + if (inner_alloc) then + scalar%slr = 467 + 13 + l_scalar%slr = 467 + 13 + a_scalar%slr = 467 + 13 + la_scalar%slr = 467 + 13 + if (is_present) then + opt_scalar%slr = 467 + 13 + a_opt_scalar%slr = 467 + 13 + end if + do j = 1, 2 + do i = 1, 3 + array(i,j)%slr = (i*97 + 100*41*j) + 467 + 13 + l_array(i,j)%slr = (i*97 + 100*41*j) + 467 + 13 + a_array(i,j)%slr = (i*97 + 100*41*j) + 467 + 13 + la_array(i,j)%slr = (i*97 + 100*41*j) + 467 + 13 + if (is_present) then + opt_array(i,j)%slr = (i*97 + 100*41*j) + 467 + 13 + a_opt_array(i,j)%slr = (i*97 + 100*41*j) + 467 + 13 + end if + end do + end do + + do l = 1, 5 + do k = 1, 4 + scalar%arr(k,l) = (i*27 + 1000*11*j) + 467 + 13 + l_scalar%arr(k,l) = (i*27 + 1000*11*j) + 467 + 13 + a_scalar%arr(k,l) = (i*27 + 1000*11*j) + 467 + 13 + la_scalar%arr(k,l) = (i*27 + 1000*11*j) + 467 + 13 + if (is_present) then + opt_scalar%arr(k,l) = (i*27 + 1000*11*j) + 467 + 13 + a_opt_scalar%arr(k,l) = (i*27 + 1000*11*j) + 467 + 13 + end if + end do + end do + do j = 1, 2 + do i = 1, 3 + do l = 1, j + do k = 1, i + array(i,j)%arr(k,l) = i*27 + 1000*11*j + 467 + 3*k +53*l + 13 + l_array(i,j)%arr(k,l) = i*27 + 1000*11*j + 467 + 3*k +53*l + 13 + a_array(i,j)%arr(k,l) = i*27 + 1000*11*j + 467 + 3*k +53*l + 13 + la_array(i,j)%arr(k,l) = i*27 + 1000*11*j + 467 + 3*k +53*l + 13 + if (is_present) then + opt_array(i,j)%arr(k,l) = i*27 + 1000*11*j + 467 + 3*k +53*l + 13 + a_opt_array(i,j)%arr(k,l) = i*27 + 1000*11*j + 467 + 3*k +53*l + 13 + end if + end do + end do + end do + end do + end if + + end subroutine + subroutine check_reset (is_present, dummy_alloced, inner_alloc, & + scalar, array, a_scalar, a_array, & + l_scalar, l_array, la_scalar, la_array, & + opt_scalar, opt_array, a_opt_scalar, a_opt_array) + type(t), intent(inout) :: & + scalar, array(:,:), opt_scalar, opt_array(:,:), a_scalar, a_array(:,:), & + a_opt_scalar, a_opt_array(:,:), & + l_scalar, l_array(:,:), la_scalar, la_array(:,:) + optional :: opt_scalar, opt_array, a_opt_scalar, a_opt_array + allocatable :: a_scalar, a_array, a_opt_scalar, a_opt_array, la_scalar, la_array + logical, value :: is_present, dummy_alloced, inner_alloc + integer :: i, j, k, l + + ! CHECK VALUE + if (scalar%var /= 42 + 13) stop 1 + if (l_scalar%var /= 42 + 13) stop 1 + if (is_present) then + if (opt_scalar%var /= 42 + 13) stop 2 + end if + if (any (shape(array) /= [3,2])) stop 1 + if (any (shape(l_array) /= [3,2])) stop 1 + if (is_present) then + if (any (shape(opt_array) /= [3,2])) stop 1 + end if + do j = 1, 2 + do i = 1, 3 + if (array(i,j)%var /= i*97 + 100*41*j + 13) stop 3 + if (l_array(i,j)%var /= i*97 + 100*41*j + 13) stop 3 + if (is_present) then + if (opt_array(i,j)%var /= i*97 + 100*41*j + 13) stop 4 + end if + end do + end do + + if (dummy_alloced) then + if (a_scalar%var /= 42 + 13) stop 1 + if (la_scalar%var /= 42 + 13) stop 1 + if (is_present) then + if (a_opt_scalar%var /= 42 + 13) stop 1 + end if + if (any (shape(a_array) /= [3,2])) stop 1 + if (any (shape(la_array) /= [3,2])) stop 1 + if (is_present) then + if (any (shape(a_opt_array) /= [3,2])) stop 1 + end if + do j = 1, 2 + do i = 1, 3 + if (a_array(i,j)%var /= i*97 + 100*41*j + 13) stop 1 + if (la_array(i,j)%var /= i*97 + 100*41*j + 13) stop 1 + if (is_present) then + if (a_opt_array(i,j)%var /= i*97 + 100*41*j + 13) stop 1 + end if + end do + end do + else + if (allocated (a_scalar)) stop 1 + if (allocated (la_scalar)) stop 1 + if (allocated (a_array)) stop 1 + if (allocated (la_array)) stop 1 + if (is_present) then + if (allocated (a_opt_scalar)) stop 1 + if (allocated (a_opt_array)) stop 1 + end if + end if + + if (inner_alloc) then + if (scalar%slr /= 467 + 13) stop 5 + if (l_scalar%slr /= 467 + 13) stop 5 + if (a_scalar%slr /= 467 + 13) stop 6 + if (la_scalar%slr /= 467 + 13) stop 6 + if (is_present) then + if (opt_scalar%slr /= 467 + 13) stop 7 + if (a_opt_scalar%slr /= 467 + 13) stop 8 + end if + do j = 1, 2 + do i = 1, 3 + if (array(i,j)%slr /= (i*97 + 100*41*j) + 467 + 13) stop 9 + if (l_array(i,j)%slr /= (i*97 + 100*41*j) + 467 + 13) stop 9 + if (a_array(i,j)%slr /= (i*97 + 100*41*j) + 467 + 13) stop 10 + if (la_array(i,j)%slr /= (i*97 + 100*41*j) + 467 + 13) stop 10 + if (is_present) then + if (opt_array(i,j)%slr /= (i*97 + 100*41*j) + 467 + 13) stop 11 + if (a_opt_array(i,j)%slr /= (i*97 + 100*41*j) + 467 + 13) stop 12 + end if + end do + end do + + do l = 1, 5 + do k = 1, 4 + if (any (shape(scalar%arr) /= [4,5])) stop 1 + if (any (shape(l_scalar%arr) /= [4,5])) stop 1 + if (any (shape(a_scalar%arr) /= [4,5])) stop 1 + if (any (shape(la_scalar%arr) /= [4,5])) stop 1 + if (scalar%arr(k,l) /= (i*27 + 1000*11*j) + 467 + 13) stop 13 + if (l_scalar%arr(k,l) /= (i*27 + 1000*11*j) + 467 + 13) stop 13 + if (a_scalar%arr(k,l) /= (i*27 + 1000*11*j) + 467 + 13) stop 14 + if (la_scalar%arr(k,l) /= (i*27 + 1000*11*j) + 467 + 13) stop 14 + if (is_present) then + if (any (shape(opt_scalar%arr) /= [4,5])) stop 1 + if (any (shape(a_opt_scalar%arr) /= [4,5])) stop 1 + if (opt_scalar%arr(k,l) /= (i*27 + 1000*11*j) + 467 + 13) stop 15 + if (a_opt_scalar%arr(k,l) /= (i*27 + 1000*11*j) + 467 + 13) stop 16 + end if + end do + end do + do j = 1, 2 + do i = 1, 3 + if (any (shape(array(i,j)%arr) /= [i,j])) stop 1 + if (any (shape(l_array(i,j)%arr) /= [i,j])) stop 1 + if (any (shape(a_array(i,j)%arr) /= [i,j])) stop 1 + if (any (shape(la_array(i,j)%arr) /= [i,j])) stop 1 + if (is_present) then + if (any (shape(opt_array(i,j)%arr) /= [i,j])) stop 1 + if (any (shape(a_opt_array(i,j)%arr) /= [i,j])) stop 1 + endif + do l = 1, j + do k = 1, i + if (array(i,j)%arr(k,l) /= i*27 + 1000*11*j + 467 + 3*k +53*l + 13) stop 17 + if (l_array(i,j)%arr(k,l) /= i*27 + 1000*11*j + 467 + 3*k +53*l + 13) stop 17 + if (a_array(i,j)%arr(k,l) /= i*27 + 1000*11*j + 467 + 3*k +53*l + 13) stop 18 + if (la_array(i,j)%arr(k,l) /= i*27 + 1000*11*j + 467 + 3*k +53*l + 13) stop 18 + if (is_present) then + if (opt_array(i,j)%arr(k,l) /= i*27 + 1000*11*j + 467 + 3*k +53*l + 13) stop 19 + if (a_opt_array(i,j)%arr(k,l) /= i*27 + 1000*11*j + 467 + 3*k +53*l + 13) stop 20 + end if + end do + end do + end do + end do + else if (dummy_alloced) then + if (allocated (scalar%slr)) stop 1 + if (allocated (l_scalar%slr)) stop 1 + if (allocated (a_scalar%slr)) stop 1 + if (allocated (la_scalar%slr)) stop 1 + if (is_present) then + if (allocated (opt_scalar%slr)) stop 1 + if (allocated (a_opt_scalar%slr)) stop 1 + endif + if (allocated (scalar%arr)) stop 1 + if (allocated (l_scalar%arr)) stop 1 + if (allocated (a_scalar%arr)) stop 1 + if (allocated (la_scalar%arr)) stop 1 + if (is_present) then + if (allocated (opt_scalar%arr)) stop 1 + if (allocated (a_opt_scalar%arr)) stop 1 + endif + end if + + ! (RE)SET VALUE + scalar%var = 42 + l_scalar%var = 42 + if (is_present) then + opt_scalar%var = 42 + endif + do j = 1, 2 + do i = 1, 3 + array(i,j)%var = i*97 + 100*41*j + l_array(i,j)%var = i*97 + 100*41*j + if (is_present) then + opt_array(i,j)%var = i*97 + 100*41*j + end if + end do + end do + + if (dummy_alloced) then + a_scalar%var = 42 + la_scalar%var = 42 + if (is_present) then + a_opt_scalar%var = 42 + endif + do j = 1, 2 + do i = 1, 3 + a_array(i,j)%var = i*97 + 100*41*j + la_array(i,j)%var = i*97 + 100*41*j + if (is_present) then + a_opt_array(i,j)%var = i*97 + 100*41*j + endif + end do + end do + end if + + if (inner_alloc) then + scalar%slr = 467 + l_scalar%slr = 467 + a_scalar%slr = 467 + la_scalar%slr = 467 + if (is_present) then + opt_scalar%slr = 467 + a_opt_scalar%slr = 467 + end if + do j = 1, 2 + do i = 1, 3 + array(i,j)%slr = (i*97 + 100*41*j) + 467 + l_array(i,j)%slr = (i*97 + 100*41*j) + 467 + a_array(i,j)%slr = (i*97 + 100*41*j) + 467 + la_array(i,j)%slr = (i*97 + 100*41*j) + 467 + if (is_present) then + opt_array(i,j)%slr = (i*97 + 100*41*j) + 467 + a_opt_array(i,j)%slr = (i*97 + 100*41*j) + 467 + end if + end do + end do + + do l = 1, 5 + do k = 1, 4 + scalar%arr(k,l) = (i*27 + 1000*11*j) + 467 + l_scalar%arr(k,l) = (i*27 + 1000*11*j) + 467 + a_scalar%arr(k,l) = (i*27 + 1000*11*j) + 467 + la_scalar%arr(k,l) = (i*27 + 1000*11*j) + 467 + if (is_present) then + opt_scalar%arr(k,l) = (i*27 + 1000*11*j) + 467 + a_opt_scalar%arr(k,l) = (i*27 + 1000*11*j) + 467 + end if + end do + end do + do j = 1, 2 + do i = 1, 3 + do l = 1, j + do k = 1, i + array(i,j)%arr(k,l) = i*27 + 1000*11*j + 467 + 3*k +53*l + l_array(i,j)%arr(k,l) = i*27 + 1000*11*j + 467 + 3*k +53*l + a_array(i,j)%arr(k,l) = i*27 + 1000*11*j + 467 + 3*k +53*l + la_array(i,j)%arr(k,l) = i*27 + 1000*11*j + 467 + 3*k +53*l + if (is_present) then + opt_array(i,j)%arr(k,l) = i*27 + 1000*11*j + 467 + 3*k +53*l + a_opt_array(i,j)%arr(k,l) = i*27 + 1000*11*j + 467 + 3*k +53*l + end if + end do + end do + end do + end do + end if + end subroutine + + subroutine test(scalar, array, a_scalar, a_array, opt_scalar, opt_array, & + a_opt_scalar, a_opt_array) + type(t) :: scalar, array(:,:), opt_scalar, opt_array(:,:), a_scalar, a_array(:,:) + type(t) :: a_opt_scalar, a_opt_array(:,:) + type(t) :: l_scalar, l_array(3,2), la_scalar, la_array(:,:) + allocatable :: a_scalar, a_array, a_opt_scalar, a_opt_array, la_scalar, la_array + optional :: opt_scalar, opt_array, a_opt_scalar, a_opt_array + + integer :: i, j, k, l + logical :: is_present, dummy_alloced, local_alloced, inner_alloc + is_present = present(opt_scalar) + dummy_alloced = allocated(a_scalar) + inner_alloc = allocated(scalar%slr) + + l_scalar%var = 42 + do j = 1, 2 + do i = 1, 3 + l_array(i,j)%var = i*97 + 100*41*j + end do + end do + + if (dummy_alloced) then + allocate(la_scalar, la_array(3,2)) + a_scalar%var = 42 + la_scalar%var = 42 + do j = 1, 2 + do i = 1, 3 + l_array(i,j)%var = i*97 + 100*41*j + la_array(i,j)%var = i*97 + 100*41*j + end do + end do + end if + + if (inner_alloc) then + l_scalar%slr = 467 + la_scalar%slr = 467 + do j = 1, 2 + do i = 1, 3 + l_array(i,j)%slr = (i*97 + 100*41*j) + 467 + la_array(i,j)%slr = (i*97 + 100*41*j) + 467 + end do + end do + + allocate(l_scalar%arr(4,5), la_scalar%arr(4,5)) + do l = 1, 5 + do k = 1, 4 + l_scalar%arr(k,l) = (i*27 + 1000*11*j) + 467 + la_scalar%arr(k,l) = (i*27 + 1000*11*j) + 467 + end do + end do + do j = 1, 2 + do i = 1, 3 + allocate(l_array(i,j)%arr(i,j), la_array(i,j)%arr(i,j)) + do l = 1, j + do k = 1, i + l_array(i,j)%arr(k,l) = i*27 + 1000*11*j + 467 + 3*k +53*l + la_array(i,j)%arr(k,l) = i*27 + 1000*11*j + 467 + 3*k +53*l + end do + end do + end do + end do + end if + + ! implicit mapping + !$omp target + if (is_present) then + call check_it (is_present, dummy_alloced, inner_alloc, & + scalar, array, a_scalar, a_array, & + l_scalar, l_array, la_scalar, la_array, & + opt_scalar, opt_array, a_opt_scalar, a_opt_array) + else + call check_it (is_present, dummy_alloced, inner_alloc, & + scalar, array, a_scalar, a_array, & + l_scalar, l_array, la_scalar, la_array) + end if + !$omp end target + + if (is_present) then + call check_reset (is_present, dummy_alloced, inner_alloc, & + scalar, array, a_scalar, a_array, & + l_scalar, l_array, la_scalar, la_array, & + opt_scalar, opt_array, a_opt_scalar, a_opt_array) + else + call check_reset (is_present, dummy_alloced, inner_alloc, & + scalar, array, a_scalar, a_array, & + l_scalar, l_array, la_scalar, la_array) + endif + + ! explicit mapping + !$omp target map(scalar, array, opt_scalar, opt_array, a_scalar, a_array) & + !$omp& map(a_opt_scalar, a_opt_array) & + !$omp& map(l_scalar, l_array, la_scalar, la_array) + if (is_present) then + call check_it (is_present, dummy_alloced, inner_alloc, & + scalar, array, a_scalar, a_array, & + l_scalar, l_array, la_scalar, la_array, & + opt_scalar, opt_array, a_opt_scalar, a_opt_array) + else + call check_it (is_present, dummy_alloced, inner_alloc, & + scalar, array, a_scalar, a_array, & + l_scalar, l_array, la_scalar, la_array) + endif + !$omp end target + + if (is_present) then + call check_reset (is_present, dummy_alloced, inner_alloc, & + scalar, array, a_scalar, a_array, & + l_scalar, l_array, la_scalar, la_array, & + opt_scalar, opt_array, a_opt_scalar, a_opt_array) + else + call check_reset (is_present, dummy_alloced, inner_alloc, & + scalar, array, a_scalar, a_array, & + l_scalar, l_array, la_scalar, la_array) + endif + end subroutine +end module + +program main + use m + implicit none (type, external) + type(t) :: scalar, array(3,2), opt_scalar, opt_array(3,2), a_scalar, a_array(:,:) + type(t) :: a_opt_scalar, a_opt_array(:,:) + allocatable :: a_scalar, a_array, a_opt_scalar, a_opt_array + integer :: i, j, k, l, n + + scalar%var = 42 + opt_scalar%var = 42 + do j = 1, 2 + do i = 1, 3 + array(i,j)%var = i*97 + 100*41*j + opt_array(i,j)%var = i*97 + 100*41*j + end do + end do + + ! unallocated + call test (scalar, array, a_scalar, a_array) + call test (scalar, array, a_scalar, a_array, opt_scalar, opt_array, a_opt_scalar, a_opt_array) + + ! allocated + allocate(a_scalar, a_opt_scalar, a_array(3,2), a_opt_array(3,2)) + a_scalar%var = 42 + a_opt_scalar%var = 42 + do j = 1, 2 + do i = 1, 3 + a_array(i,j)%var = i*97 + 100*41*j + a_opt_array(i,j)%var = i*97 + 100*41*j + end do + end do + + call test (scalar, array, a_scalar, a_array) + call test (scalar, array, a_scalar, a_array, opt_scalar, opt_array, a_opt_scalar, a_opt_array) + + ! comps allocated + scalar%slr = 467 + a_scalar%slr = 467 + opt_scalar%slr = 467 + a_opt_scalar%slr = 467 + do j = 1, 2 + do i = 1, 3 + array(i,j)%slr = (i*97 + 100*41*j) + 467 + a_array(i,j)%slr = (i*97 + 100*41*j) + 467 + opt_array(i,j)%slr = (i*97 + 100*41*j) + 467 + a_opt_array(i,j)%slr = (i*97 + 100*41*j) + 467 + end do + end do + + allocate(scalar%arr(4,5), a_scalar%arr(4,5), opt_scalar%arr(4,5), a_opt_scalar%arr(4,5)) + do l = 1, 5 + do k = 1, 4 + scalar%arr(k,l) = (i*27 + 1000*11*j) + 467 + a_scalar%arr(k,l) = (i*27 + 1000*11*j) + 467 + opt_scalar%arr(k,l) = (i*27 + 1000*11*j) + 467 + a_opt_scalar%arr(k,l) = (i*27 + 1000*11*j) + 467 + end do + end do + do j = 1, 2 + do i = 1, 3 + allocate(array(i,j)%arr(i,j), a_array(i,j)%arr(i,j), opt_array(i,j)%arr(i,j), a_opt_array(i,j)%arr(i,j)) + do l = 1, j + do k = 1, i + array(i,j)%arr(k,l) = i*27 + 1000*11*j + 467 + 3*k +53*l + a_array(i,j)%arr(k,l) = i*27 + 1000*11*j + 467 + 3*k +53*l + opt_array(i,j)%arr(k,l) = i*27 + 1000*11*j + 467 + 3*k +53*l + a_opt_array(i,j)%arr(k,l) = i*27 + 1000*11*j + 467 + 3*k +53*l + end do + end do + end do + end do + + call test (scalar, array, a_scalar, a_array) + call test (scalar, array, a_scalar, a_array, opt_scalar, opt_array, a_opt_scalar, a_opt_array) + + deallocate(a_scalar, a_opt_scalar, a_array, a_opt_array) +end diff --git a/libgomp/testsuite/libgomp.fortran/map-alloc-comp-8.f90 b/libgomp/testsuite/libgomp.fortran/map-alloc-comp-8.f90 new file mode 100644 index 0000000..f5a286e --- /dev/null +++ b/libgomp/testsuite/libgomp.fortran/map-alloc-comp-8.f90 @@ -0,0 +1,268 @@ +module m + implicit none (type, external) + type t + integer, allocatable :: A(:) + end type t + type t2 + type(t), allocatable :: vT + integer, allocatable :: x + end type t2 + +contains + + subroutine test_alloc() + type(t) :: var + type(t), allocatable :: var2 + + allocate(var2) + allocate(var%A(4), var2%A(5)) + + !$omp target enter data map(alloc: var, var2) + !$omp target + if (.not. allocated(Var2)) stop 1 + if (.not. allocated(Var%A)) stop 2 + if (.not. allocated(Var2%A)) stop 3 + if (lbound(var%A, 1) /= 1 .or. ubound(var%A, 1) /= 4) stop 4 + if (lbound(var2%A, 1) /= 1 .or. ubound(var2%A, 1) /= 5) stop 5 + var%A = [1,2,3,4] + var2%A = [11,22,33,44,55] + !$omp end target + !$omp target exit data map(from: var, var2) + + if (.not. allocated(Var2)) error stop + if (.not. allocated(Var%A)) error stop + if (.not. allocated(Var2%A)) error stop + if (lbound(var%A, 1) /= 1 .or. ubound(var%A, 1) /= 4) error stop + if (lbound(var2%A, 1) /= 1 .or. ubound(var2%A, 1) /= 5) error stop + if (any(var%A /= [1,2,3,4])) error stop + if (any(var2%A /= [11,22,33,44,55])) error stop + end subroutine test_alloc + + subroutine test2_alloc() + type(t2) :: var + type(t2), allocatable :: var2 + + allocate(var2) + allocate(var%x, var2%x) + + !$omp target enter data map(alloc: var, var2) + !$omp target + if (.not. allocated(Var2)) stop 6 + if (.not. allocated(Var%x)) stop 7 + if (.not. allocated(Var2%x)) stop 8 + var%x = 42 + var2%x = 43 + !$omp end target + !$omp target exit data map(from: var, var2) + + if (.not. allocated(Var2)) error stop + if (.not. allocated(Var%x)) error stop + if (.not. allocated(Var2%x)) error stop + if (var%x /= 42) error stop + if (var2%x /= 43) error stop + + allocate(var%vt, var2%vt) + allocate(var%vt%A(-1:3), var2%vt%A(0:4)) + + !$omp target enter data map(alloc: var, var2) + !$omp target + if (.not. allocated(Var2)) stop 11 + if (.not. allocated(Var%x)) stop 12 + if (.not. allocated(Var2%x)) stop 13 + if (.not. allocated(Var%vt)) stop 14 + if (.not. allocated(Var2%vt)) stop 15 + if (.not. allocated(Var%vt%a)) stop 16 + if (.not. allocated(Var2%vt%a)) stop 17 + var%x = 42 + var2%x = 43 + if (lbound(var%vt%A, 1) /= -1 .or. ubound(var%vt%A, 1) /= 3) stop 4 + if (lbound(var2%vt%A, 1) /= 0 .or. ubound(var2%vt%A, 1) /= 4) stop 5 + var%vt%A = [1,2,3,4,5] + var2%vt%A = [11,22,33,44,55] + !$omp end target + !$omp target exit data map(from: var, var2) + + if (.not. allocated(Var2)) error stop + if (.not. allocated(Var%x)) error stop + if (.not. allocated(Var2%x)) error stop + if (.not. allocated(Var%vt)) error stop + if (.not. allocated(Var2%vt)) error stop + if (.not. allocated(Var%vt%a)) error stop + if (.not. allocated(Var2%vt%a)) error stop + if (var%x /= 42) error stop + if (var2%x /= 43) error stop + if (lbound(var%vt%A, 1) /= -1 .or. ubound(var%vt%A, 1) /= 3) error stop + if (lbound(var2%vt%A, 1) /= 0 .or. ubound(var2%vt%A, 1) /= 4) error stop + if (any(var%vt%A /= [1,2,3,4,5])) error stop + if (any(var2%vt%A /= [11,22,33,44,55])) error stop + end subroutine test2_alloc + + + subroutine test_alloc_target() + type(t) :: var + type(t), allocatable :: var2 + + allocate(var2) + allocate(var%A(4), var2%A(5)) + + !$omp target map(alloc: var, var2) + if (.not. allocated(Var2)) stop 1 + if (.not. allocated(Var%A)) stop 2 + if (.not. allocated(Var2%A)) stop 3 + if (lbound(var%A, 1) /= 1 .or. ubound(var%A, 1) /= 4) stop 4 + if (lbound(var2%A, 1) /= 1 .or. ubound(var2%A, 1) /= 5) stop 5 + var%A = [1,2,3,4] + var2%A = [11,22,33,44,55] + !$omp end target + + if (.not. allocated(Var2)) error stop + if (.not. allocated(Var%A)) error stop + if (.not. allocated(Var2%A)) error stop + if (lbound(var%A, 1) /= 1 .or. ubound(var%A, 1) /= 4) error stop + if (lbound(var2%A, 1) /= 1 .or. ubound(var2%A, 1) /= 5) error stop + end subroutine test_alloc_target + + subroutine test2_alloc_target() + type(t2) :: var + type(t2), allocatable :: var2 + + allocate(var2) + allocate(var%x, var2%x) + + !$omp target map(alloc: var, var2) + if (.not. allocated(Var2)) stop 6 + if (.not. allocated(Var%x)) stop 7 + if (.not. allocated(Var2%x)) stop 8 + var%x = 42 + var2%x = 43 + !$omp end target + + if (.not. allocated(Var2)) error stop + if (.not. allocated(Var%x)) error stop + if (.not. allocated(Var2%x)) error stop + + allocate(var%vt, var2%vt) + allocate(var%vt%A(-1:3), var2%vt%A(0:4)) + + !$omp target map(alloc: var, var2) + if (.not. allocated(Var2)) stop 11 + if (.not. allocated(Var%x)) stop 12 + if (.not. allocated(Var2%x)) stop 13 + if (.not. allocated(Var%vt)) stop 14 + if (.not. allocated(Var2%vt)) stop 15 + if (.not. allocated(Var%vt%a)) stop 16 + if (.not. allocated(Var2%vt%a)) stop 17 + var%x = 42 + var2%x = 43 + if (lbound(var%vt%A, 1) /= -1 .or. ubound(var%vt%A, 1) /= 3) stop 4 + if (lbound(var2%vt%A, 1) /= 0 .or. ubound(var2%vt%A, 1) /= 4) stop 5 + var%vt%A = [1,2,3,4,5] + var2%vt%A = [11,22,33,44,55] + !$omp end target + + if (.not. allocated(Var2)) error stop + if (.not. allocated(Var%x)) error stop + if (.not. allocated(Var2%x)) error stop + if (.not. allocated(Var%vt)) error stop + if (.not. allocated(Var2%vt)) error stop + if (.not. allocated(Var%vt%a)) error stop + if (.not. allocated(Var2%vt%a)) error stop + if (lbound(var%vt%A, 1) /= -1 .or. ubound(var%vt%A, 1) /= 3) error stop + if (lbound(var2%vt%A, 1) /= 0 .or. ubound(var2%vt%A, 1) /= 4) error stop + end subroutine test2_alloc_target + + + + subroutine test_from() + type(t) :: var + type(t), allocatable :: var2 + + allocate(var2) + allocate(var%A(4), var2%A(5)) + + !$omp target map(from: var, var2) + if (.not. allocated(Var2)) stop 1 + if (.not. allocated(Var%A)) stop 2 + if (.not. allocated(Var2%A)) stop 3 + if (lbound(var%A, 1) /= 1 .or. ubound(var%A, 1) /= 4) stop 4 + if (lbound(var2%A, 1) /= 1 .or. ubound(var2%A, 1) /= 5) stop 5 + var%A = [1,2,3,4] + var2%A = [11,22,33,44,55] + !$omp end target + + if (.not. allocated(Var2)) error stop + if (.not. allocated(Var%A)) error stop + if (.not. allocated(Var2%A)) error stop + if (lbound(var%A, 1) /= 1 .or. ubound(var%A, 1) /= 4) error stop + if (lbound(var2%A, 1) /= 1 .or. ubound(var2%A, 1) /= 5) error stop + if (any(var%A /= [1,2,3,4])) error stop + if (any(var2%A /= [11,22,33,44,55])) error stop + end subroutine test_from + + subroutine test2_from() + type(t2) :: var + type(t2), allocatable :: var2 + + allocate(var2) + allocate(var%x, var2%x) + + !$omp target map(from: var, var2) + if (.not. allocated(Var2)) stop 6 + if (.not. allocated(Var%x)) stop 7 + if (.not. allocated(Var2%x)) stop 8 + var%x = 42 + var2%x = 43 + !$omp end target + + if (.not. allocated(Var2)) error stop + if (.not. allocated(Var%x)) error stop + if (.not. allocated(Var2%x)) error stop + if (var%x /= 42) error stop + if (var2%x /= 43) error stop + + allocate(var%vt, var2%vt) + allocate(var%vt%A(-1:3), var2%vt%A(0:4)) + + !$omp target map(from: var, var2) + if (.not. allocated(Var2)) stop 11 + if (.not. allocated(Var%x)) stop 12 + if (.not. allocated(Var2%x)) stop 13 + if (.not. allocated(Var%vt)) stop 14 + if (.not. allocated(Var2%vt)) stop 15 + if (.not. allocated(Var%vt%a)) stop 16 + if (.not. allocated(Var2%vt%a)) stop 17 + var%x = 42 + var2%x = 43 + if (lbound(var%vt%A, 1) /= -1 .or. ubound(var%vt%A, 1) /= 3) stop 4 + if (lbound(var2%vt%A, 1) /= 0 .or. ubound(var2%vt%A, 1) /= 4) stop 5 + var%vt%A = [1,2,3,4,5] + var2%vt%A = [11,22,33,44,55] + !$omp end target + + if (.not. allocated(Var2)) error stop + if (.not. allocated(Var%x)) error stop + if (.not. allocated(Var2%x)) error stop + if (.not. allocated(Var%vt)) error stop + if (.not. allocated(Var2%vt)) error stop + if (.not. allocated(Var%vt%a)) error stop + if (.not. allocated(Var2%vt%a)) error stop + if (var%x /= 42) error stop + if (var2%x /= 43) error stop + if (lbound(var%vt%A, 1) /= -1 .or. ubound(var%vt%A, 1) /= 3) error stop + if (lbound(var2%vt%A, 1) /= 0 .or. ubound(var2%vt%A, 1) /= 4) error stop + if (any(var%vt%A /= [1,2,3,4,5])) error stop + if (any(var2%vt%A /= [11,22,33,44,55])) error stop + end subroutine test2_from + +end module m + +use m + implicit none (type, external) + call test_alloc + call test2_alloc + call test_alloc_target + call test2_alloc_target + + call test_from + call test2_from +end diff --git a/libgomp/testsuite/libgomp.fortran/map-alloc-comp-9.f90 b/libgomp/testsuite/libgomp.fortran/map-alloc-comp-9.f90 new file mode 100644 index 0000000..3cec392 --- /dev/null +++ b/libgomp/testsuite/libgomp.fortran/map-alloc-comp-9.f90 @@ -0,0 +1,559 @@ +! Ensure that polymorphic mapping is diagnosed as undefined behavior +! Ensure that static access to polymorphic variables works + +subroutine test(case) +implicit none(type, external) +type t + integer :: x(4) +end type t + +type ta + integer, allocatable :: x(:) +end type ta + +type t2 + class(t), allocatable :: x + class(t), allocatable :: x2(:) +end type t2 + +type t3 + type(t2) :: y + type(t2) :: y2(2) +end type t3 + +type t4 + type(t3), allocatable :: y + type(t3), allocatable :: y2(:) +end type t4 + +integer, value :: case + +logical :: is_shared_mem + +! Mangle stack addresses +integer, volatile :: case_var(100*case) + +type(t), allocatable :: var1 +type(ta), allocatable :: var1a +class(t), allocatable :: var2 +type(t2), allocatable :: var3 +type(t4), allocatable :: var4 + +case_var(100) = 0 +!print *, 'case', case + +var1 = t([1,2,3,4]) +var1a = ta([-1,-2,-3,-4,-5]) + +var2 = t([11,22,33,44]) + +allocate(t2 :: var3) +allocate(t :: var3%x) +allocate(t :: var3%x2(2)) +var3%x%x = [111,222,333,444] +var3%x2(1)%x = 2*[111,222,333,444] +var3%x2(2)%x = 3*[111,222,333,444] + +allocate(t4 :: var4) +allocate(t3 :: var4%y) +allocate(t3 :: var4%y2(2)) +allocate(t :: var4%y%y%x) +allocate(t :: var4%y%y%x2(2)) +allocate(t :: var4%y2(1)%y%x) +allocate(t :: var4%y2(1)%y%x2(2)) +allocate(t :: var4%y2(2)%y%x) +allocate(t :: var4%y2(2)%y%x2(2)) +var4%y%y%x%x = -1 * [1111,2222,3333,4444] +var4%y%y%x2(1)%x = -2 * [1111,2222,3333,4444] +var4%y%y%x2(2)%x = -3 * [1111,2222,3333,4444] +var4%y2(1)%y%x%x = -4 * [1111,2222,3333,4444] +var4%y2(1)%y%x2(1)%x = -5 * [1111,2222,3333,4444] +var4%y2(1)%y%x2(2)%x = -6 * [1111,2222,3333,4444] +var4%y2(2)%y%x%x = -7 * [1111,2222,3333,4444] +var4%y2(2)%y%x2(1)%x = -8 * [1111,2222,3333,4444] +var4%y2(2)%y%x2(2)%x = -9 * [1111,2222,3333,4444] + +is_shared_mem = .false. +!$omp target map(to: is_shared_mem) + is_shared_mem = .true. +!$omp end target + +if (case == 1) then + ! implicit mapping + !$omp target + if (any (var1%x /= [1,2,3,4])) stop 1 + var1%x = 2 * var1%x + !$omp end target + + !$omp target + if (any (var1a%x /= [-1,-2,-3,-4])) stop 2 + var1a%x = 3 * var1a%x + !$omp end target + + !$omp target ! { dg-warning "Mapping of polymorphic list item 'var2' is unspecified behavior \\\[-Wopenmp\\\]" } + if (any (var2%x /= [11,22,33,44])) stop 3 + var2%x = 4 * var2%x + !$omp end target + + !$omp target ! { dg-warning "Mapping of polymorphic list item 'var3->x' is unspecified behavior \\\[-Wopenmp\\\]" } + if (any (var3%x%x /= [111,222,333,444])) stop 4 + var3%x%x = 5 * var3%x%x + if (is_shared_mem) then ! For stride data, this accesses the host's _vtab + if (any (var3%x2(1)%x /= 2*[111,222,333,444])) stop 4 + if (any (var3%x2(2)%x /= 3*[111,222,333,444])) stop 4 + var3%x2(1)%x = 5 * var3%x2(1)%x + var3%x2(2)%x = 5 * var3%x2(2)%x + end if + !$omp end target + + !$omp target ! { dg-warning "Mapping of polymorphic list item 'var4\.\[0-9\]+->y->y\.x' is unspecified behavior \\\[-Wopenmp\\\]" } + if (any (var4%y%y%x%x /= -1 * [1111,2222,3333,4444])) stop 5 + if (is_shared_mem) then ! For stride data, this accesses the host's _vtab + if (any (var4%y%y%x2(1)%x /= -2 * [1111,2222,3333,4444])) stop 5 + if (any (var4%y%y%x2(2)%x /= -3 * [1111,2222,3333,4444])) stop 5 + endif + if (any (var4%y2(1)%y%x%x /= -4 * [1111,2222,3333,4444])) stop 5 + if (is_shared_mem) then ! For stride data, this accesses the host's _vtab + if (any (var4%y2(1)%y%x2(1)%x /= -5 * [1111,2222,3333,4444])) stop 5 + if (any (var4%y2(1)%y%x2(2)%x /= -6 * [1111,2222,3333,4444])) stop 5 + endif + if (any (var4%y2(2)%y%x%x /= -7 * [1111,2222,3333,4444])) stop 5 + if (is_shared_mem) then ! For stride data, this accesses the host's _vtab + if (any (var4%y2(2)%y%x2(1)%x /= -8 * [1111,2222,3333,4444])) stop 5 + if (any (var4%y2(2)%y%x2(2)%x /= -9 * [1111,2222,3333,4444])) stop 5 + end if + var4%y%y%x%x = 6 * var4%y%y%x%x + if (is_shared_mem) then ! For stride data, this accesses the host's _vtab + var4%y%y%x2(1)%x = 6 * var4%y%y%x2(1)%x + var4%y%y%x2(2)%x = 6 * var4%y%y%x2(2)%x + endif + var4%y2(1)%y%x%x = 6 * var4%y2(1)%y%x%x + if (is_shared_mem) then ! For stride data, this accesses the host's _vtab + var4%y2(1)%y%x2(1)%x = 6 * var4%y2(1)%y%x2(1)%x + var4%y2(1)%y%x2(2)%x = 6 * var4%y2(1)%y%x2(2)%x + endif + var4%y2(2)%y%x%x = 6 * var4%y2(2)%y%x%x + if (is_shared_mem) then ! For stride data, this accesses the host's _vtab + var4%y2(2)%y%x2(1)%x = 6 * var4%y2(2)%y%x2(1)%x + var4%y2(2)%y%x2(2)%x = 6 * var4%y2(2)%y%x2(2)%x + endif + !$omp end target + +else if (case == 2) then + ! Use target with defaultmap(TO) + + !$omp target defaultmap(to : all) + if (any (var1%x /= [1,2,3,4])) stop 1 + var1%x = 2 * var1%x + !$omp end target + + !$omp target defaultmap(to : all) + if (any (var1a%x /= [-1,-2,-3,-4])) stop 2 + var1a%x = 3 * var1a%x + !$omp end target + + !$omp target defaultmap(to : all) ! { dg-warning "Mapping of polymorphic list item 'var2' is unspecified behavior \\\[-Wopenmp\\\]" } + if (any (var2%x /= [11,22,33,44])) stop 3 + var2%x = 4 * var2%x + !$omp end target + + !$omp target defaultmap(to : all) ! { dg-warning "Mapping of polymorphic list item 'var3->x' is unspecified behavior \\\[-Wopenmp\\\]" } + if (any (var3%x%x /= [111,222,333,444])) stop 4 + var3%x%x = 5 * var3%x%x + if (is_shared_mem) then ! For stride data, this accesses the host's _vtab + if (any (var3%x2(1)%x /= 2*[111,222,333,444])) stop 4 + if (any (var3%x2(2)%x /= 3*[111,222,333,444])) stop 4 + var3%x2(1)%x = 5 * var3%x2(1)%x + var3%x2(2)%x = 5 * var3%x2(2)%x + endif + !$omp end target + + !$omp target defaultmap(to : all) firstprivate(is_shared_mem) ! { dg-warning "Mapping of polymorphic list item 'var4\.\[0-9\]+->y->y\.x' is unspecified behavior \\\[-Wopenmp\\\]" } + if (any (var4%y%y%x%x /= -1 * [1111,2222,3333,4444])) stop 5 + if (is_shared_mem) then ! For stride data, this accesses the host's _vtab + if (any (var4%y%y%x2(1)%x /= -2 * [1111,2222,3333,4444])) stop 5 + if (any (var4%y%y%x2(2)%x /= -3 * [1111,2222,3333,4444])) stop 5 + endif + if (any (var4%y2(1)%y%x%x /= -4 * [1111,2222,3333,4444])) stop 5 + if (is_shared_mem) then ! For stride data, this accesses the host's _vtab + if (any (var4%y2(1)%y%x2(1)%x /= -5 * [1111,2222,3333,4444])) stop 5 + if (any (var4%y2(1)%y%x2(2)%x /= -6 * [1111,2222,3333,4444])) stop 5 + endif + if (any (var4%y2(2)%y%x%x /= -7 * [1111,2222,3333,4444])) stop 5 + if (is_shared_mem) then ! For stride data, this accesses the host's _vtab + if (any (var4%y2(2)%y%x2(1)%x /= -8 * [1111,2222,3333,4444])) stop 5 + if (any (var4%y2(2)%y%x2(2)%x /= -9 * [1111,2222,3333,4444])) stop 5 + endif + var4%y%y%x%x = 6 * var4%y%y%x%x + if (is_shared_mem) then ! For stride data, this accesses the host's _vtab + var4%y%y%x2(1)%x = 6 * var4%y%y%x2(1)%x + var4%y%y%x2(2)%x = 6 * var4%y%y%x2(2)%x + endif + var4%y2(1)%y%x%x = 6 * var4%y2(1)%y%x%x + if (is_shared_mem) then ! For stride data, this accesses the host's _vtab + var4%y2(1)%y%x2(1)%x = 6 * var4%y2(1)%y%x2(1)%x + var4%y2(1)%y%x2(2)%x = 6 * var4%y2(1)%y%x2(2)%x + endif + var4%y2(2)%y%x%x = 6 * var4%y2(2)%y%x%x + if (is_shared_mem) then ! For stride data, this accesses the host's _vtab + var4%y2(2)%y%x2(1)%x = 6 * var4%y2(2)%y%x2(1)%x + var4%y2(2)%y%x2(2)%x = 6 * var4%y2(2)%y%x2(2)%x + endif + !$omp end target + +else if (case == 3) then + ! Use target with map clause + + !$omp target map(tofrom: var1) + if (any (var1%x /= [1,2,3,4])) stop 1 + var1%x = 2 * var1%x + !$omp end target + + !$omp target map(tofrom: var1a) + if (any (var1a%x /= [-1,-2,-3,-4])) stop 2 + var1a%x = 3 * var1a%x + !$omp end target + + !$omp target map(tofrom: var2) ! { dg-warning "28: Mapping of polymorphic list item 'var2' is unspecified behavior \\\[-Wopenmp\\\]" } + if (any (var2%x /= [11,22,33,44])) stop 3 + var2%x = 4 * var2%x + !$omp end target + + !$omp target map(tofrom: var3) ! { dg-warning "28: Mapping of polymorphic list item 'var3->x' is unspecified behavior \\\[-Wopenmp\\\]" } + if (any (var3%x%x /= [111,222,333,444])) stop 4 + var3%x%x = 5 * var3%x%x + if (is_shared_mem) then ! For stride data, this accesses the host's _vtab + if (any (var3%x2(1)%x /= 2*[111,222,333,444])) stop 4 + if (any (var3%x2(2)%x /= 3*[111,222,333,444])) stop 4 + var3%x2(1)%x = 5 * var3%x2(1)%x + var3%x2(2)%x = 5 * var3%x2(2)%x + endif + !$omp end target + + !$omp target map(tofrom: var4) ! { dg-warning "28: Mapping of polymorphic list item 'var4\.\[0-9\]+->y->y\.x' is unspecified behavior \\\[-Wopenmp\\\]" } + if (any (var4%y%y%x%x /= -1 * [1111,2222,3333,4444])) stop 5 + if (is_shared_mem) then ! For stride data, this accesses the host's _vtab + if (any (var4%y%y%x2(1)%x /= -2 * [1111,2222,3333,4444])) stop 5 + if (any (var4%y%y%x2(2)%x /= -3 * [1111,2222,3333,4444])) stop 5 + end if + if (any (var4%y2(1)%y%x%x /= -4 * [1111,2222,3333,4444])) stop 5 + if (is_shared_mem) then ! For stride data, this accesses the host's _vtab + if (any (var4%y2(1)%y%x2(1)%x /= -5 * [1111,2222,3333,4444])) stop 5 + if (any (var4%y2(1)%y%x2(2)%x /= -6 * [1111,2222,3333,4444])) stop 5 + endif + if (any (var4%y2(2)%y%x%x /= -7 * [1111,2222,3333,4444])) stop 5 + if (is_shared_mem) then ! For stride data, this accesses the host's _vtab + if (any (var4%y2(2)%y%x2(1)%x /= -8 * [1111,2222,3333,4444])) stop 5 + if (any (var4%y2(2)%y%x2(2)%x /= -9 * [1111,2222,3333,4444])) stop 5 + endif + var4%y%y%x%x = 6 * var4%y%y%x%x + if (is_shared_mem) then ! For stride data, this accesses the host's _vtab + var4%y%y%x2(1)%x = 6 * var4%y%y%x2(1)%x + var4%y%y%x2(2)%x = 6 * var4%y%y%x2(2)%x + endif + var4%y2(1)%y%x%x = 6 * var4%y2(1)%y%x%x + if (is_shared_mem) then ! For stride data, this accesses the host's _vtab + var4%y2(1)%y%x2(1)%x = 6 * var4%y2(1)%y%x2(1)%x + var4%y2(1)%y%x2(2)%x = 6 * var4%y2(1)%y%x2(2)%x + endif + var4%y2(2)%y%x%x = 6 * var4%y2(2)%y%x%x + if (is_shared_mem) then ! For stride data, this accesses the host's _vtab + var4%y2(2)%y%x2(1)%x = 6 * var4%y2(2)%y%x2(1)%x + var4%y2(2)%y%x2(2)%x = 6 * var4%y2(2)%y%x2(2)%x + endif + !$omp end target + +else if (case == 4) then + ! Use target with map clause -- NOTE: This uses TO not TOFROM + + !$omp target map(to: var1) + if (any (var1%x /= [1,2,3,4])) stop 1 + var1%x = 2 * var1%x + !$omp end target + + !$omp target map(to: var1a) + if (any (var1a%x /= [-1,-2,-3,-4])) stop 2 + var1a%x = 3 * var1a%x + !$omp end target + + !$omp target map(to: var2) ! { dg-warning "24: Mapping of polymorphic list item 'var2' is unspecified behavior \\\[-Wopenmp\\\]" } + if (any (var2%x /= [11,22,33,44])) stop 3 + var2%x = 4 * var2%x + !$omp end target + + !$omp target map(to: var3) ! { dg-warning "24: Mapping of polymorphic list item 'var3->x' is unspecified behavior \\\[-Wopenmp\\\]" } + if (any (var3%x%x /= [111,222,333,444])) stop 4 + var3%x%x = 5 * var3%x%x + if (is_shared_mem) then ! For stride data, this accesses the host's _vtab + if (any (var3%x2(1)%x /= 2*[111,222,333,444])) stop 4 + if (any (var3%x2(2)%x /= 3*[111,222,333,444])) stop 4 + var3%x2(1)%x = 5 * var3%x2(1)%x + var3%x2(2)%x = 5 * var3%x2(2)%x + endif + !$omp end target + + !$omp target map(to: var4) ! { dg-warning "24: Mapping of polymorphic list item 'var4\.\[0-9\]+->y->y\.x' is unspecified behavior \\\[-Wopenmp\\\]" } + if (any (var4%y%y%x%x /= -1 * [1111,2222,3333,4444])) stop 5 + if (is_shared_mem) then ! For stride data, this accesses the host's _vtab + if (any (var4%y%y%x2(1)%x /= -2 * [1111,2222,3333,4444])) stop 5 + if (any (var4%y%y%x2(2)%x /= -3 * [1111,2222,3333,4444])) stop 5 + endif + if (any (var4%y2(1)%y%x%x /= -4 * [1111,2222,3333,4444])) stop 5 + if (is_shared_mem) then ! For stride data, this accesses the host's _vtab + if (any (var4%y2(1)%y%x2(1)%x /= -5 * [1111,2222,3333,4444])) stop 5 + if (any (var4%y2(1)%y%x2(2)%x /= -6 * [1111,2222,3333,4444])) stop 5 + endif + if (any (var4%y2(2)%y%x%x /= -7 * [1111,2222,3333,4444])) stop 5 + if (is_shared_mem) then ! For stride data, this accesses the host's _vtab + if (any (var4%y2(2)%y%x2(1)%x /= -8 * [1111,2222,3333,4444])) stop 5 + if (any (var4%y2(2)%y%x2(2)%x /= -9 * [1111,2222,3333,4444])) stop 5 + endif + var4%y%y%x%x = 6 * var4%y%y%x%x + if (is_shared_mem) then ! For stride data, this accesses the host's _vtab + var4%y%y%x2(1)%x = 6 * var4%y%y%x2(1)%x + var4%y%y%x2(2)%x = 6 * var4%y%y%x2(2)%x + endif + var4%y2(1)%y%x%x = 6 * var4%y2(1)%y%x%x + if (is_shared_mem) then ! For stride data, this accesses the host's _vtab + var4%y2(1)%y%x2(1)%x = 6 * var4%y2(1)%y%x2(1)%x + var4%y2(1)%y%x2(2)%x = 6 * var4%y2(1)%y%x2(2)%x + endif + var4%y2(2)%y%x%x = 6 * var4%y2(2)%y%x%x + if (is_shared_mem) then ! For stride data, this accesses the host's _vtab + var4%y2(2)%y%x2(1)%x = 6 * var4%y2(2)%y%x2(1)%x + var4%y2(2)%y%x2(2)%x = 6 * var4%y2(2)%y%x2(2)%x + endif + !$omp end target + +else if (case == 5) then + ! Use target enter/exit data + target with explicit map + !$omp target enter data map(to: var1) + !$omp target enter data map(to: var1a) + !$omp target enter data map(to: var2) ! { dg-warning "35: Mapping of polymorphic list item 'var2' is unspecified behavior \\\[-Wopenmp\\\]" } + !$omp target enter data map(to: var3) ! { dg-warning "35: Mapping of polymorphic list item 'var3->x' is unspecified behavior \\\[-Wopenmp\\\]" } + !$omp target enter data map(to: var4) ! { dg-warning "35: Mapping of polymorphic list item 'var4\.\[0-9\]+->y->y\.x' is unspecified behavior \\\[-Wopenmp\\\]" } + + !$omp target map(to: var1) + if (any (var1%x /= [1,2,3,4])) stop 1 + var1%x = 2 * var1%x + !$omp end target + + !$omp target map(to: var1a) + if (any (var1a%x /= [-1,-2,-3,-4])) stop 2 + var1a%x = 3 * var1a%x + !$omp end target + + !$omp target map(to: var2) ! { dg-warning "24: Mapping of polymorphic list item 'var2' is unspecified behavior \\\[-Wopenmp\\\]" } + if (any (var2%x /= [11,22,33,44])) stop 3 + var2%x = 4 * var2%x + !$omp end target + + !$omp target map(to: var3) ! { dg-warning "24: Mapping of polymorphic list item 'var3->x' is unspecified behavior \\\[-Wopenmp\\\]" } + if (any (var3%x%x /= [111,222,333,444])) stop 4 + var3%x%x = 5 * var3%x%x + if (is_shared_mem) then ! For stride data, this accesses the host's _vtab + if (any (var3%x2(1)%x /= 2*[111,222,333,444])) stop 4 + if (any (var3%x2(2)%x /= 3*[111,222,333,444])) stop 4 + var3%x2(1)%x = 5 * var3%x2(1)%x + var3%x2(2)%x = 5 * var3%x2(2)%x + endif + !$omp end target + + !$omp target map(to: var4) ! { dg-warning "24: Mapping of polymorphic list item 'var4\.\[0-9\]+->y->y\.x' is unspecified behavior \\\[-Wopenmp\\\]" } + if (any (var4%y%y%x%x /= -1 * [1111,2222,3333,4444])) stop 5 + if (is_shared_mem) then ! For stride data, this accesses the host's _vtab + if (any (var4%y%y%x2(1)%x /= -2 * [1111,2222,3333,4444])) stop 5 + if (any (var4%y%y%x2(2)%x /= -3 * [1111,2222,3333,4444])) stop 5 + endif + if (any (var4%y2(1)%y%x%x /= -4 * [1111,2222,3333,4444])) stop 5 + if (is_shared_mem) then ! For stride data, this accesses the host's _vtab + if (any (var4%y2(1)%y%x2(1)%x /= -5 * [1111,2222,3333,4444])) stop 5 + if (any (var4%y2(1)%y%x2(2)%x /= -6 * [1111,2222,3333,4444])) stop 5 + endif + if (any (var4%y2(2)%y%x%x /= -7 * [1111,2222,3333,4444])) stop 5 + if (is_shared_mem) then ! For stride data, this accesses the host's _vtab + if (any (var4%y2(2)%y%x2(1)%x /= -8 * [1111,2222,3333,4444])) stop 5 + if (any (var4%y2(2)%y%x2(2)%x /= -9 * [1111,2222,3333,4444])) stop 5 + endif + var4%y%y%x%x = 6 * var4%y%y%x%x + if (is_shared_mem) then ! For stride data, this accesses the host's _vtab + var4%y%y%x2(1)%x = 6 * var4%y%y%x2(1)%x + var4%y%y%x2(2)%x = 6 * var4%y%y%x2(2)%x + endif + var4%y2(1)%y%x%x = 6 * var4%y2(1)%y%x%x + if (is_shared_mem) then ! For stride data, this accesses the host's _vtab + var4%y2(1)%y%x2(1)%x = 6 * var4%y2(1)%y%x2(1)%x + var4%y2(1)%y%x2(2)%x = 6 * var4%y2(1)%y%x2(2)%x + endif + var4%y2(2)%y%x%x = 6 * var4%y2(2)%y%x%x + if (is_shared_mem) then ! For stride data, this accesses the host's _vtab + var4%y2(2)%y%x2(1)%x = 6 * var4%y2(2)%y%x2(1)%x + var4%y2(2)%y%x2(2)%x = 6 * var4%y2(2)%y%x2(2)%x + endif + !$omp end target + + !$omp target exit data map(from: var1) + !$omp target exit data map(from: var1a) + !$omp target exit data map(from: var2) ! { dg-warning "36: Mapping of polymorphic list item 'var2' is unspecified behavior \\\[-Wopenmp\\\]" } + !$omp target exit data map(from: var3) ! { dg-warning "36: Mapping of polymorphic list item 'var3->x' is unspecified behavior \\\[-Wopenmp\\\]" } + !$omp target exit data map(from: var4) ! { dg-warning "36: Mapping of polymorphic list item 'var4\.\[0-9\]+->y->y\.x' is unspecified behavior \\\[-Wopenmp\\\]" } + +else if (case == 6) then + ! Use target enter/exit data + target with implicit map + + !$omp target enter data map(to: var1) + !$omp target enter data map(to: var1a) + !$omp target enter data map(to: var2) ! { dg-warning "35: Mapping of polymorphic list item 'var2' is unspecified behavior \\\[-Wopenmp\\\]" } + !$omp target enter data map(to: var3) ! { dg-warning "35: Mapping of polymorphic list item 'var3->x' is unspecified behavior \\\[-Wopenmp\\\]" } + !$omp target enter data map(to: var4) ! { dg-warning "35: Mapping of polymorphic list item 'var4\.\[0-9\]+->y->y\.x' is unspecified behavior \\\[-Wopenmp\\\]" } + + !$omp target + if (any (var1%x /= [1,2,3,4])) stop 1 + var1%x = 2 * var1%x + !$omp end target + + !$omp target + if (any (var1a%x /= [-1,-2,-3,-4])) stop 2 + var1a%x = 3 * var1a%x + !$omp end target + + !$omp target ! { dg-warning "Mapping of polymorphic list item 'var2' is unspecified behavior \\\[-Wopenmp\\\]" } + if (any (var2%x /= [11,22,33,44])) stop 3 + var2%x = 4 * var2%x + !$omp end target + + !$omp target ! { dg-warning "Mapping of polymorphic list item 'var3->x' is unspecified behavior \\\[-Wopenmp\\\]" } + if (any (var3%x%x /= [111,222,333,444])) stop 4 + var3%x%x = 5 * var3%x%x + if (is_shared_mem) then ! For stride data, this accesses the host's _vtab + if (any (var3%x2(1)%x /= 2*[111,222,333,444])) stop 4 + if (any (var3%x2(2)%x /= 3*[111,222,333,444])) stop 4 + var3%x2(1)%x = 5 * var3%x2(1)%x + var3%x2(2)%x = 5 * var3%x2(2)%x + endif + !$omp end target + + !$omp target ! { dg-warning "Mapping of polymorphic list item 'var4\.\[0-9\]+->y->y\.x' is unspecified behavior \\\[-Wopenmp\\\]" } + if (any (var4%y%y%x%x /= -1 * [1111,2222,3333,4444])) stop 5 + if (is_shared_mem) then ! For stride data, this accesses the host's _vtab + if (any (var4%y%y%x2(1)%x /= -2 * [1111,2222,3333,4444])) stop 5 + if (any (var4%y%y%x2(2)%x /= -3 * [1111,2222,3333,4444])) stop 5 + endif + if (any (var4%y2(1)%y%x%x /= -4 * [1111,2222,3333,4444])) stop 5 + if (is_shared_mem) then ! For stride data, this accesses the host's _vtab + if (any (var4%y2(1)%y%x2(1)%x /= -5 * [1111,2222,3333,4444])) stop 5 + if (any (var4%y2(1)%y%x2(2)%x /= -6 * [1111,2222,3333,4444])) stop 5 + endif + if (any (var4%y2(2)%y%x%x /= -7 * [1111,2222,3333,4444])) stop 5 + if (is_shared_mem) then ! For stride data, this accesses the host's _vtab + if (any (var4%y2(2)%y%x2(1)%x /= -8 * [1111,2222,3333,4444])) stop 5 + if (any (var4%y2(2)%y%x2(2)%x /= -9 * [1111,2222,3333,4444])) stop 5 + endif + var4%y%y%x%x = 6 * var4%y%y%x%x + if (is_shared_mem) then ! For stride data, this accesses the host's _vtab + var4%y%y%x2(1)%x = 6 * var4%y%y%x2(1)%x + var4%y%y%x2(2)%x = 6 * var4%y%y%x2(2)%x + endif + var4%y2(1)%y%x%x = 6 * var4%y2(1)%y%x%x + if (is_shared_mem) then ! For stride data, this accesses the host's _vtab + var4%y2(1)%y%x2(1)%x = 6 * var4%y2(1)%y%x2(1)%x + var4%y2(1)%y%x2(2)%x = 6 * var4%y2(1)%y%x2(2)%x + endif + var4%y2(2)%y%x%x = 6 * var4%y2(2)%y%x%x + if (is_shared_mem) then ! For stride data, this accesses the host's _vtab + var4%y2(2)%y%x2(1)%x = 6 * var4%y2(2)%y%x2(1)%x + var4%y2(2)%y%x2(2)%x = 6 * var4%y2(2)%y%x2(2)%x + endif + !$omp end target + + !$omp target exit data map(from: var1) + !$omp target exit data map(from: var1a) + !$omp target exit data map(from: var2) ! { dg-warning "36: Mapping of polymorphic list item 'var2' is unspecified behavior \\\[-Wopenmp\\\]" } + !$omp target exit data map(from: var3) ! { dg-warning "36: Mapping of polymorphic list item 'var3->x' is unspecified behavior \\\[-Wopenmp\\\]" } + !$omp target exit data map(from: var4) ! { dg-warning "36: Mapping of polymorphic list item 'var4\.\[0-9\]+->y->y\.x' is unspecified behavior \\\[-Wopenmp\\\]" } + +else + error stop +end if + +if ((case /= 2 .and. case /= 4) .or. is_shared_mem) then + ! The target update should have been active, check for the updated values + if (any (var1%x /= 2 * [1,2,3,4])) stop 11 + if (any (var1a%x /= 3 * [-1,-2,-3,-4])) stop 22 + if (any (var2%x /= 4 * [11,22,33,44])) stop 33 + + if (any (var3%x%x /= 5 * [111,222,333,444])) stop 44 + if (is_shared_mem) then ! For stride data, this accesses the host's _vtab + if (any (var3%x2(1)%x /= 2 * 5 * [111,222,333,444])) stop 44 + if (any (var3%x2(2)%x /= 3 * 5 * [111,222,333,444])) stop 44 + endif + + if (any (var4%y%y%x%x /= -1 * 6 * [1111,2222,3333,4444])) stop 55 + if (is_shared_mem) then ! For stride data, this accesses the host's _vtab + if (any (var4%y%y%x2(1)%x /= -2 * 6 * [1111,2222,3333,4444])) stop 55 + if (any (var4%y%y%x2(2)%x /= -3 * 6 * [1111,2222,3333,4444])) stop 55 + endif + if (any (var4%y2(1)%y%x%x /= -4 * 6 * [1111,2222,3333,4444])) stop 55 + if (is_shared_mem) then ! For stride data, this accesses the host's _vtab + if (any (var4%y2(1)%y%x2(1)%x /= -5 * 6 * [1111,2222,3333,4444])) stop 55 + if (any (var4%y2(1)%y%x2(2)%x /= -6 * 6 * [1111,2222,3333,4444])) stop 55 + endif + if (any (var4%y2(2)%y%x%x /= -7 * 6 * [1111,2222,3333,4444])) stop 55 + if (is_shared_mem) then ! For stride data, this accesses the host's _vtab + if (any (var4%y2(2)%y%x2(1)%x /= -8 * 6 * [1111,2222,3333,4444])) stop 55 + if (any (var4%y2(2)%y%x2(2)%x /= -9 * 6 * [1111,2222,3333,4444])) stop 55 + endif +else + ! The old host values should still be there as 'to:' created a device copy + if (any (var1%x /= [1,2,3,4])) stop 12 + if (any (var1a%x /= [-1,-2,-3,-4])) stop 22 + if (any (var2%x /= [11,22,33,44])) stop 33 + + if (any (var3%x%x /= [111,222,333,444])) stop 44 + ! .not. is_shared_mem: + ! if (any (var3%x2(1)%x /= 2*[111,222,333,444])) stop 44 + ! if (any (var3%x2(2)%x /= 3*[111,222,333,444])) stop 44 + + if (any (var4%y%y%x%x /= -1 * [1111,2222,3333,4444])) stop 55 + if (any (var4%y%y%x2(1)%x /= -2 * [1111,2222,3333,4444])) stop 55 + if (any (var4%y%y%x2(2)%x /= -3 * [1111,2222,3333,4444])) stop 55 + if (any (var4%y2(1)%y%x%x /= -4 * [1111,2222,3333,4444])) stop 55 + ! .not. is_shared_mem: + !if (any (var4%y2(1)%y%x2(1)%x /= -5 * [1111,2222,3333,4444])) stop 55 + !if (any (var4%y2(1)%y%x2(2)%x /= -6 * [1111,2222,3333,4444])) stop 55 + if (any (var4%y2(2)%y%x%x /= -7 * [1111,2222,3333,4444])) stop 55 + ! .not. is_shared_mem: + !if (any (var4%y2(2)%y%x2(1)%x /= -8 * [1111,2222,3333,4444])) stop 55 + !if (any (var4%y2(2)%y%x2(2)%x /= -9 * [1111,2222,3333,4444])) stop 55 +end if +if (case_var(100) /= 0) stop 123 +end subroutine test + +program main + use omp_lib + implicit none(type, external) + interface + subroutine test(case) + integer, value :: case + end + end interface + integer :: dev + call run_it(omp_get_default_device()) + do dev = 0, omp_get_num_devices() + call run_it(dev) + end do + call run_it(omp_initial_device) +! print *, 'all done' +contains +subroutine run_it(dev) + integer, value :: dev +! print *, 'DEVICE', dev + call omp_set_default_device(dev) + call test(1) + call test(2) + call test(3) + call test(4) + call test(5) + call test(6) +end +end diff --git a/libgomp/testsuite/libgomp.oacc-c++/exceptions-bad_cast-1.C b/libgomp/testsuite/libgomp.oacc-c++/exceptions-bad_cast-1.C new file mode 100644 index 0000000..0545601 --- /dev/null +++ b/libgomp/testsuite/libgomp.oacc-c++/exceptions-bad_cast-1.C @@ -0,0 +1,54 @@ +/* 'std::bad_cast' exception in OpenACC compute region. */ + +/* { dg-require-effective-target exceptions } + { dg-additional-options -fexceptions } */ +/* { dg-additional-options -fdump-tree-optimized-raw } + { dg-additional-options -foffload-options=-fdump-tree-optimized-raw } */ + +/* See also '../libgomp.c++/target-exceptions-bad_cast-1.C'. */ + +/* See also '../../../gcc/testsuite/g++.target/gcn/exceptions-bad_cast-1.C', + '../../../gcc/testsuite/g++.target/nvptx/exceptions-bad_cast-1.C'. */ + +#include <iostream> + +struct C1 +{ + virtual void f() + {} +}; + +struct C2 : C1 +{ +}; + +int main() +{ + std::cerr << "CheCKpOInT\n"; +#pragma omp target +#pragma acc serial + /* { dg-bogus {using 'vector_length \(32\)', ignoring 1} {} { target openacc_nvidia_accel_selected xfail *-*-* } .-1 } */ + { + C1 c1; + [[maybe_unused]] + C2 &c2 = dynamic_cast<C2 &>(c1); + /* 'std::bad_cast' is thrown. */ + } +} + +/* { dg-output {CheCKpOInT[\r\n]+} } + + { dg-final { scan-tree-dump-times {gimple_call <__cxa_bad_cast, } 1 optimized } } + { dg-final { scan-offload-tree-dump-times {gimple_call <__cxa_bad_cast, } 1 optimized } } + For host execution, we print something like: + terminate called after throwing an instance of 'std::bad_cast' + what(): std::bad_cast + Aborted (core dumped) + { dg-output {.*std::bad_cast} { target openacc_host_selected } } + For GCN, nvptx offload execution, we don't print anything, but just 'abort'. + + TODO For GCN, nvptx offload execution, this currently doesn't 'abort' due to + the 'std::bad_cast' exception, but rather due to SIGSEGV in 'dynamic_cast'; + PR119692. + + { dg-shouldfail {'std::bad_cast' exception} } */ diff --git a/libgomp/testsuite/libgomp.oacc-c++/exceptions-bad_cast-2-offload-sorry-GCN.C b/libgomp/testsuite/libgomp.oacc-c++/exceptions-bad_cast-2-offload-sorry-GCN.C new file mode 100644 index 0000000..8260966 --- /dev/null +++ b/libgomp/testsuite/libgomp.oacc-c++/exceptions-bad_cast-2-offload-sorry-GCN.C @@ -0,0 +1,18 @@ +/* 'std::bad_cast' exception in OpenACC compute region, caught, '-foffload-options=-mno-fake-exceptions'. */ + +/* As this test case involves an expected offload compilation failure, we have to handle each offload target individually. + { dg-do link { target openacc_radeon_accel_selected } } */ +/* { dg-require-effective-target exceptions } + { dg-additional-options -fexceptions } */ +/* { dg-additional-options -foffload-options=-mno-fake-exceptions } */ +/* { dg-additional-options -fdump-tree-optimized-raw } + { dg-additional-options -foffload-options=-fdump-tree-optimized-raw } */ + +#include "exceptions-bad_cast-2.C" + +/* { dg-final { scan-tree-dump-times {gimple_call <__cxa_bad_cast, } 1 optimized } } + { dg-final { only_for_offload_target amdgcn-amdhsa scan-offload-tree-dump-times {gimple_call <__cxa_bad_cast, } 1 optimized } } + Given '-foffload-options=-mno-fake-exceptions', offload compilation fails: + { dg-regexp {[^\r\n]+: In function 'main[^']+':[\r\n]+(?:[^\r\n]+: sorry, unimplemented: exception handling not supported[\r\n]+)+} } + (Note, using 'dg-regexp' instead of 'dg-message', as the former runs before the auto-mark-UNSUPPORTED.) + { dg-excess-errors {'mkoffload' failure etc.} } */ diff --git a/libgomp/testsuite/libgomp.oacc-c++/exceptions-bad_cast-2-offload-sorry-nvptx.C b/libgomp/testsuite/libgomp.oacc-c++/exceptions-bad_cast-2-offload-sorry-nvptx.C new file mode 100644 index 0000000..86d3f6c --- /dev/null +++ b/libgomp/testsuite/libgomp.oacc-c++/exceptions-bad_cast-2-offload-sorry-nvptx.C @@ -0,0 +1,20 @@ +/* 'std::bad_cast' exception in OpenACC compute region, caught, '-foffload-options=-mno-fake-exceptions'. */ + +/* As this test case involves an expected offload compilation failure, we have to handle each offload target individually. + { dg-do link { target openacc_nvidia_accel_selected } } */ +/* { dg-require-effective-target exceptions } + { dg-additional-options -fexceptions } */ +/* { dg-additional-options -foffload-options=-mno-fake-exceptions } */ +/* { dg-additional-options -fdump-tree-optimized-raw } + { dg-additional-options -foffload-options=-fdump-tree-optimized-raw } */ + +#include "exceptions-bad_cast-2.C" + +/* { dg-bogus {using 'vector_length \(32\)', ignoring 1} {} { target openacc_nvidia_accel_selected xfail *-*-* } 0 } */ + +/* { dg-final { scan-tree-dump-times {gimple_call <__cxa_bad_cast, } 1 optimized } } + { dg-final { only_for_offload_target nvptx-none scan-offload-tree-dump-times {gimple_call <__cxa_bad_cast, } 1 optimized } } + Given '-foffload-options=-mno-fake-exceptions', offload compilation fails: + { dg-regexp {[^\r\n]+: In function 'main[^']+':[\r\n]+(?:[^\r\n]+: sorry, unimplemented: exception handling not supported[\r\n]+)+} } + (Note, using 'dg-regexp' instead of 'dg-message', as the former runs before the auto-mark-UNSUPPORTED.) + { dg-excess-errors {'mkoffload' failure etc.} } */ diff --git a/libgomp/testsuite/libgomp.oacc-c++/exceptions-bad_cast-2.C b/libgomp/testsuite/libgomp.oacc-c++/exceptions-bad_cast-2.C new file mode 100644 index 0000000..24399ef --- /dev/null +++ b/libgomp/testsuite/libgomp.oacc-c++/exceptions-bad_cast-2.C @@ -0,0 +1,60 @@ +/* 'std::bad_cast' exception in OpenACC compute region, caught. */ + +/* { dg-require-effective-target exceptions } + { dg-additional-options -fexceptions } */ +/* { dg-additional-options -fdump-tree-optimized-raw } + { dg-additional-options -foffload-options=-fdump-tree-optimized-raw } */ +/* { dg-bogus {_ZTISt8bad_cast} PR119734 { target openacc_nvidia_accel_selected xfail *-*-* } 0 } + { dg-excess-errors {'mkoffload' failure etc.} { xfail openacc_nvidia_accel_selected } } */ + +/* See also '../libgomp.c++/target-exceptions-bad_cast-2.C'. */ + +/* See also '../../../gcc/testsuite/g++.target/gcn/exceptions-bad_cast-2.C', + '../../../gcc/testsuite/g++.target/nvptx/exceptions-bad_cast-2.C'. */ + +#include <iostream> +#include <typeinfo> + +struct C1 +{ + virtual void f() + {} +}; + +struct C2 : C1 +{ +}; + +int main() +{ + std::cerr << "CheCKpOInT\n"; +#pragma omp target +#pragma acc serial + { + C1 c1; + try + { + [[maybe_unused]] + C2 &c2 = dynamic_cast<C2 &>(c1); + /* 'std::bad_cast' is thrown. */ + } + catch (const std::bad_cast &e) + { + __builtin_printf("caught '%s'\n", e.what()); + } + } +} + +/* { dg-output {CheCKpOInT[\r\n]+} } + + { dg-final { scan-tree-dump-times {gimple_call <__cxa_bad_cast, } 1 optimized } } + { dg-final { scan-offload-tree-dump-times {gimple_call <__cxa_bad_cast, } 1 optimized } } + { dg-output {.*caught 'std::bad_cast'[\r\n]+} { target openacc_host_selected } } + For GCN, nvptx offload execution, we don't print anything, but just 'abort'. + + TODO For GCN, nvptx offload execution, this currently doesn't 'abort' due to + the 'std::bad_cast' exception, but rather due to SIGSEGV in 'dynamic_cast'; + PR119692. + + For GCN, nvptx offload execution, there is no 'catch'ing; any exception is fatal. + { dg-shouldfail {'std::bad_cast' exception} { ! openacc_host_selected } } */ diff --git a/libgomp/testsuite/libgomp.oacc-c++/exceptions-bad_cast-3.C b/libgomp/testsuite/libgomp.oacc-c++/exceptions-bad_cast-3.C new file mode 100644 index 0000000..4fa419f --- /dev/null +++ b/libgomp/testsuite/libgomp.oacc-c++/exceptions-bad_cast-3.C @@ -0,0 +1,49 @@ +/* 'std::bad_cast' exception in OpenACC compute region, dead code. */ + +/* { dg-require-effective-target exceptions } + { dg-additional-options -fexceptions } */ +/* Wrong code for offloading execution. + { dg-skip-if PR119692 { ! openacc_host_selected } } + { dg-additional-options -fdump-tree-gimple } */ +/* { dg-additional-options -fdump-tree-optimized-raw } */ + +/* See also '../libgomp.c++/target-exceptions-bad_cast-3.C'. */ + +/* See also '../../../gcc/testsuite/g++.target/gcn/exceptions-bad_cast-3.C', + '../../../gcc/testsuite/g++.target/nvptx/exceptions-bad_cast-3.C'. */ + +/* For PR119692 workarounds. */ +#ifndef DEFAULT +# define DEFAULT +#endif + +struct C1 +{ + virtual void f() + {} +}; + +struct C2 : C1 +{ +}; + +int main() +{ +#pragma omp target DEFAULT +#pragma acc serial DEFAULT + { + C1 c1; + bool a = false; + asm volatile ("" : : "r" (&a) : "memory"); + if (a) + { + [[maybe_unused]] + C2 &c2 = dynamic_cast<C2 &>(c1); + /* 'std::bad_cast' is thrown. */ + } + } +} + +/* { dg-final { scan-tree-dump-not {(?n)#pragma omp target oacc_serial map\(tofrom:_ZTI2C2 \[len: [0-9]+\]\) map\(tofrom:_ZTI2C1 \[len: [0-9]+\]\) map\(tofrom:_ZTV2C1 \[len: [0-9]+\]\)$} gimple { xfail *-*-* } } } */ + +/* { dg-final { scan-tree-dump-times {gimple_call <__cxa_bad_cast, } 1 optimized } } */ diff --git a/libgomp/testsuite/libgomp.oacc-c++/exceptions-throw-1.C b/libgomp/testsuite/libgomp.oacc-c++/exceptions-throw-1.C new file mode 100644 index 0000000..f2ef751 --- /dev/null +++ b/libgomp/testsuite/libgomp.oacc-c++/exceptions-throw-1.C @@ -0,0 +1,46 @@ +/* 'throw' in OpenACC compute region. */ + +/* { dg-require-effective-target exceptions } + { dg-additional-options -fexceptions } */ +/* { dg-additional-options -fdump-tree-optimized-raw } + { dg-additional-options -foffload-options=-fdump-tree-optimized-raw } */ +/* { dg-bogus {Size expression must be absolute\.} PR119737 { target { openacc_radeon_accel_selected && __OPTIMIZE__ } xfail *-*-* } 0 } + { dg-ice PR119737 { openacc_radeon_accel_selected && __OPTIMIZE__ } } + { dg-excess-errors {'mkoffload' failure etc.} { xfail { openacc_radeon_accel_selected && __OPTIMIZE__ } } } */ + +/* See also '../libgomp.c++/target-exceptions-throw-1.C'. */ + +/* See also '../../../gcc/testsuite/g++.target/gcn/exceptions-throw-1.C', + '../../../gcc/testsuite/g++.target/nvptx/exceptions-throw-1.C'. */ + +#include <iostream> + +class MyException +{ +}; + +int main() +{ + std::cerr << "CheCKpOInT\n"; +#pragma omp target +#pragma acc serial + /* { dg-bogus {using 'vector_length \(32\)', ignoring 1} {} { target openacc_nvidia_accel_selected xfail *-*-* } .-1 } */ + { + MyException e1; + throw e1; + } +} + +/* { dg-output {CheCKpOInT[\r\n]+} } + + { dg-final { scan-tree-dump-times {gimple_call <__cxa_allocate_exception, } 1 optimized } } + { dg-final { scan-tree-dump-times {gimple_call <__cxa_throw, } 1 optimized } } + { dg-final { scan-offload-tree-dump-times {gimple_call <__cxa_allocate_exception, } 1 optimized } } + { dg-final { scan-offload-tree-dump-times {gimple_call <__cxa_throw, } 1 optimized } } + For host execution, we print something like: + terminate called after throwing an instance of 'MyException' + Aborted (core dumped) + { dg-output {.*MyException} { target openacc_host_selected } } + For GCN, nvptx offload execution, we don't print anything, but just 'abort'. + + { dg-shouldfail {'MyException' exception} } */ diff --git a/libgomp/testsuite/libgomp.oacc-c++/exceptions-throw-2-offload-sorry-GCN.C b/libgomp/testsuite/libgomp.oacc-c++/exceptions-throw-2-offload-sorry-GCN.C new file mode 100644 index 0000000..40be837 --- /dev/null +++ b/libgomp/testsuite/libgomp.oacc-c++/exceptions-throw-2-offload-sorry-GCN.C @@ -0,0 +1,20 @@ +/* 'throw' in OpenACC compute region, caught, '-foffload-options=-mno-fake-exceptions'. */ + +/* As this test case involves an expected offload compilation failure, we have to handle each offload target individually. + { dg-do link { target openacc_radeon_accel_selected } } */ +/* { dg-require-effective-target exceptions } + { dg-additional-options -fexceptions } */ +/* { dg-additional-options -foffload-options=-mno-fake-exceptions } */ +/* { dg-additional-options -fdump-tree-optimized-raw } + { dg-additional-options -foffload-options=-fdump-tree-optimized-raw } */ + +#include "exceptions-throw-2.C" + +/* { dg-final { scan-tree-dump-times {gimple_call <__cxa_allocate_exception, } 1 optimized } } + { dg-final { scan-tree-dump-times {gimple_call <__cxa_throw, } 1 optimized } } + { dg-final { only_for_offload_target amdgcn-amdhsa scan-offload-tree-dump-times {gimple_call <__cxa_allocate_exception, } 1 optimized } } + { dg-final { only_for_offload_target amdgcn-amdhsa scan-offload-tree-dump-times {gimple_call <__cxa_throw, } 1 optimized } } + Given '-foffload-options=-mno-fake-exceptions', offload compilation fails: + { dg-regexp {[^\r\n]+: In function 'main[^']+':[\r\n]+(?:[^\r\n]+: sorry, unimplemented: exception handling not supported[\r\n]+)+} } + (Note, using 'dg-regexp' instead of 'dg-message', as the former runs before the auto-mark-UNSUPPORTED.) + { dg-excess-errors {'mkoffload' failure etc.} } */ diff --git a/libgomp/testsuite/libgomp.oacc-c++/exceptions-throw-2-offload-sorry-nvptx.C b/libgomp/testsuite/libgomp.oacc-c++/exceptions-throw-2-offload-sorry-nvptx.C new file mode 100644 index 0000000..9461455 --- /dev/null +++ b/libgomp/testsuite/libgomp.oacc-c++/exceptions-throw-2-offload-sorry-nvptx.C @@ -0,0 +1,22 @@ +/* 'throw' in OpenACC compute region, caught, '-foffload-options=-mno-fake-exceptions'. */ + +/* As this test case involves an expected offload compilation failure, we have to handle each offload target individually. + { dg-do link { target openacc_nvidia_accel_selected } } */ +/* { dg-require-effective-target exceptions } + { dg-additional-options -fexceptions } */ +/* { dg-additional-options -foffload-options=-mno-fake-exceptions } */ +/* { dg-additional-options -fdump-tree-optimized-raw } + { dg-additional-options -foffload-options=-fdump-tree-optimized-raw } */ + +#include "exceptions-throw-2.C" + +/* { dg-bogus {using 'vector_length \(32\)', ignoring 1} {} { target openacc_nvidia_accel_selected xfail *-*-* } 0 } */ + +/* { dg-final { scan-tree-dump-times {gimple_call <__cxa_allocate_exception, } 1 optimized } } + { dg-final { scan-tree-dump-times {gimple_call <__cxa_throw, } 1 optimized } } + { dg-final { only_for_offload_target nvptx-none scan-offload-tree-dump-times {gimple_call <__cxa_allocate_exception, } 1 optimized } } + { dg-final { only_for_offload_target nvptx-none scan-offload-tree-dump-times {gimple_call <__cxa_throw, } 1 optimized } } + Given '-foffload-options=-mno-fake-exceptions', offload compilation fails: + { dg-regexp {[^\r\n]+: In function 'main[^']+':[\r\n]+(?:[^\r\n]+: sorry, unimplemented: exception handling not supported[\r\n]+)+} } + (Note, using 'dg-regexp' instead of 'dg-message', as the former runs before the auto-mark-UNSUPPORTED.) + { dg-excess-errors {'mkoffload' failure etc.} } */ diff --git a/libgomp/testsuite/libgomp.oacc-c++/exceptions-throw-2.C b/libgomp/testsuite/libgomp.oacc-c++/exceptions-throw-2.C new file mode 100644 index 0000000..f6dc970 --- /dev/null +++ b/libgomp/testsuite/libgomp.oacc-c++/exceptions-throw-2.C @@ -0,0 +1,55 @@ +/* 'throw' in OpenACC compute region, caught. */ + +/* { dg-require-effective-target exceptions } + { dg-additional-options -fexceptions } */ +/* { dg-additional-options -fdump-tree-optimized-raw } + { dg-additional-options -foffload-options=-fdump-tree-optimized-raw } */ +/* { dg-bogus {undefined symbol: typeinfo name for MyException} PR119806 { target { openacc_radeon_accel_selected && { ! __OPTIMIZE__ } } xfail *-*-* } 0 } + { dg-excess-errors {'mkoffload' failure etc.} { xfail { openacc_radeon_accel_selected && { ! __OPTIMIZE__ } } } } */ +/* { dg-bogus {Size expression must be absolute\.} PR119737 { target { openacc_radeon_accel_selected && __OPTIMIZE__ } xfail *-*-* } 0 } + { dg-ice PR119737 { openacc_radeon_accel_selected && __OPTIMIZE__ } } + { dg-excess-errors {'mkoffload' failures etc.} { xfail { openacc_radeon_accel_selected && __OPTIMIZE__ } } } */ +/* { dg-bogus {Initial value type mismatch} PR119806 { target { openacc_nvidia_accel_selected && { ! __OPTIMIZE__ } } xfail *-*-* } 0 } + { dg-excess-errors {'mkoffload' failure etc.} { xfail { openacc_nvidia_accel_selected && { ! __OPTIMIZE__ } } } } */ + +/* See also '../libgomp.c++/target-exceptions-throw-2.C'. */ + +/* See also '../../../gcc/testsuite/g++.target/gcn/exceptions-throw-2.C', + '../../../gcc/testsuite/g++.target/nvptx/exceptions-throw-2.C'. */ + +#include <iostream> + +class MyException +{ +}; + +int main() +{ + std::cerr << "CheCKpOInT\n"; +#pragma omp target +#pragma acc serial + /* { dg-bogus {using 'vector_length \(32\)', ignoring 1} {} { target openacc_nvidia_accel_selected xfail *-*-* } .-1 } */ + { + try + { + MyException e1; + throw e1; + } + catch (const MyException &e) + { + __builtin_printf("caught '%s'\n", "MyException"); + } + } +} + +/* { dg-output {CheCKpOInT[\r\n]+} } + + { dg-final { scan-tree-dump-times {gimple_call <__cxa_allocate_exception, } 1 optimized } } + { dg-final { scan-tree-dump-times {gimple_call <__cxa_throw, } 1 optimized } } + { dg-final { scan-offload-tree-dump-times {gimple_call <__cxa_allocate_exception, } 1 optimized } } + { dg-final { scan-offload-tree-dump-times {gimple_call <__cxa_throw, } 1 optimized } } + { dg-output {.*caught 'MyException'[\r\n]+} { target openacc_host_selected } } + For GCN, nvptx offload execution, we don't print anything, but just 'abort'. + + For GCN, nvptx offload execution, there is no 'catch'ing; any exception is fatal. + { dg-shouldfail {'MyException' exception} { ! openacc_host_selected } } */ diff --git a/libgomp/testsuite/libgomp.oacc-c++/exceptions-throw-3.C b/libgomp/testsuite/libgomp.oacc-c++/exceptions-throw-3.C new file mode 100644 index 0000000..74a62b3 --- /dev/null +++ b/libgomp/testsuite/libgomp.oacc-c++/exceptions-throw-3.C @@ -0,0 +1,43 @@ +/* 'throw' in OpenACC compute region, dead code. */ + +/* { dg-require-effective-target exceptions } + { dg-additional-options -fexceptions } */ +/* Wrong code for offloading execution. + { dg-skip-if PR119692 { ! openacc_host_selected } } + { dg-additional-options -fdump-tree-gimple } */ +/* { dg-additional-options -fdump-tree-optimized-raw } */ + +/* See also '../libgomp.c++/target-exceptions-throw-3.C'. */ + +/* See also '../../../gcc/testsuite/g++.target/gcn/exceptions-throw-3.C', + '../../../gcc/testsuite/g++.target/nvptx/exceptions-throw-3.C'. */ + +/* For PR119692 workarounds. */ +#ifndef DEFAULT +# define DEFAULT +#endif + +class MyException +{ +}; + +int main() +{ +#pragma omp target DEFAULT +#pragma acc serial DEFAULT + /* { dg-bogus {using 'vector_length \(32\)', ignoring 1} {} { target openacc_nvidia_accel_selected xfail *-*-* } .-1 } */ + { + bool a = false; + asm volatile ("" : : "r" (&a) : "memory"); + if (a) + { + MyException e1; + throw e1; + } + } +} + +/* { dg-final { scan-tree-dump-not {(?n)#pragma omp target oacc_serial map\(tofrom:_ZTI11MyException \[len: [0-9]+\]\)$} gimple { xfail *-*-* } } } */ + +/* { dg-final { scan-tree-dump-times {gimple_call <__cxa_allocate_exception, } 1 optimized } } + { dg-final { scan-tree-dump-times {gimple_call <__cxa_throw, } 1 optimized } } */ diff --git a/libgomp/testsuite/libgomp.oacc-c++/pr119692-1-1.C b/libgomp/testsuite/libgomp.oacc-c++/pr119692-1-1.C new file mode 100644 index 0000000..5c3e037 --- /dev/null +++ b/libgomp/testsuite/libgomp.oacc-c++/pr119692-1-1.C @@ -0,0 +1,42 @@ +/* PR119692 "C++ 'typeinfo', 'vtable' vs. OpenACC, OpenMP 'target' offloading" */ + +/* { dg-additional-options -UDEFAULT } + Wrong code for offloading execution. + { dg-skip-if PR119692 { ! openacc_host_selected } } */ +/* { dg-additional-options -fdump-tree-gimple } */ + +/* See also '../libgomp.c++/pr119692-1-1.C'. */ + +/* See also '../../../gcc/testsuite/g++.target/gcn/pr119692-1-1.C', + '../../../gcc/testsuite/g++.target/nvptx/pr119692-1-1.C'. */ + +#ifndef DEFAULT +# define DEFAULT +#endif + +struct C1 +{ + virtual void f() + {} +}; + +struct C2 : C1 +{ +}; + +int main() +{ +#pragma omp target DEFAULT +#pragma acc serial DEFAULT + /* { dg-bogus {using 'vector_length \(32\)', ignoring 1} {} { target openacc_nvidia_accel_selected xfail *-*-* } .-1 } */ + { + C1 c1; + C1 *c1p = &c1; + asm volatile ("" : : "r" (&c1p) : "memory"); + C2 *c2 = dynamic_cast<C2 *>(c1p); + if (c2) + __builtin_abort(); + } +} + +/* { dg-final { scan-tree-dump-not {(?n)#pragma omp target oacc_serial map\(tofrom:_ZTI2C2 \[len: [0-9]+\]\) map\(tofrom:_ZTI2C1 \[len: [0-9]+\]\) map\(tofrom:_ZTV2C1 \[len: [0-9]+\]\)$} gimple { xfail *-*-* } } } */ diff --git a/libgomp/testsuite/libgomp.oacc-c++/pr119692-1-2.C b/libgomp/testsuite/libgomp.oacc-c++/pr119692-1-2.C new file mode 100644 index 0000000..207b183 --- /dev/null +++ b/libgomp/testsuite/libgomp.oacc-c++/pr119692-1-2.C @@ -0,0 +1,12 @@ +/* PR119692 "C++ 'typeinfo', 'vtable' vs. OpenACC, OpenMP 'target' offloading" */ + +/* { dg-additional-options -DDEFAULT=default(none) } + Wrong code for offloading execution. + { dg-skip-if PR119692 { ! openacc_host_selected } } */ +/* { dg-additional-options -fdump-tree-gimple } */ + +#include "pr119692-1-1.C" + +/* { dg-bogus {using 'vector_length \(32\)', ignoring 1} {} { target openacc_nvidia_accel_selected xfail *-*-* } 0 } */ + +/* { dg-final { scan-tree-dump-not {(?n)#pragma omp target oacc_serial default\(none\) map\(tofrom:_ZTI2C2 \[len: [0-9]+\]\) map\(tofrom:_ZTI2C1 \[len: [0-9]+\]\) map\(tofrom:_ZTV2C1 \[len: [0-9]+\]\)$} gimple { xfail *-*-* } } } */ diff --git a/libgomp/testsuite/libgomp.oacc-c++/pr119692-1-3.C b/libgomp/testsuite/libgomp.oacc-c++/pr119692-1-3.C new file mode 100644 index 0000000..e9b44de --- /dev/null +++ b/libgomp/testsuite/libgomp.oacc-c++/pr119692-1-3.C @@ -0,0 +1,12 @@ +/* PR119692 "C++ 'typeinfo', 'vtable' vs. OpenACC, OpenMP 'target' offloading" */ + +/* { dg-additional-options -DDEFAULT=default(present) } + Wrong code for offloading execution. + { dg-xfail-run-if PR119692 { ! openacc_host_selected } } */ +/* { dg-additional-options -fdump-tree-gimple } */ + +#include "pr119692-1-1.C" + +/* { dg-bogus {using 'vector_length \(32\)', ignoring 1} {} { target openacc_nvidia_accel_selected xfail *-*-* } 0 } */ + +/* { dg-final { scan-tree-dump-not {(?n)#pragma omp target oacc_serial default\(present\) map\(force_present:_ZTI2C2 \[len: [0-9]+\]\) map\(force_present:_ZTI2C1 \[len: [0-9]+\]\) map\(force_present:_ZTV2C1 \[len: [0-9]+\]\)$} gimple { xfail *-*-* } } } */ diff --git a/libphobos/ChangeLog b/libphobos/ChangeLog index 4a8f6921..e97b427 100644 --- a/libphobos/ChangeLog +++ b/libphobos/ChangeLog @@ -1,3 +1,13 @@ +2025-04-12 Iain Buclaw <ibuclaw@gdcproject.org> + + PR d/119761 + * libdruntime/MERGE: Merge upstream druntime 09ed02ce56. + * libdruntime/Makefile.am (DRUNTIME_DISOURCES): Rename __builtins.di + to __importc_builtins.di. + * libdruntime/Makefile.in: Regenerate. + * libdruntime/__builtins.di: Move to... + * libdruntime/__importc_builtins.di: ...here. + 2025-04-11 Iain Buclaw <ibuclaw@gdcproject.org> * src/MERGE: Merge upstream phobos 40ffbb364. diff --git a/libphobos/libdruntime/MERGE b/libphobos/libdruntime/MERGE index 00c8518..840f8dd 100644 --- a/libphobos/libdruntime/MERGE +++ b/libphobos/libdruntime/MERGE @@ -1,4 +1,4 @@ -c6863be7206eef3c393726363a480baf0a0c6530 +09ed02ce56ea5bf3e59f21ee0390cd85eb8bfaa7 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/Makefile.am b/libphobos/libdruntime/Makefile.am index 9adb503..4098310 100644 --- a/libphobos/libdruntime/Makefile.am +++ b/libphobos/libdruntime/Makefile.am @@ -445,4 +445,4 @@ DRUNTIME_DSOURCES_WINDOWS = core/sys/windows/accctrl.d \ core/sys/windows/winuser.d core/sys/windows/winver.d \ core/sys/windows/wtsapi32.d core/sys/windows/wtypes.d -DRUNTIME_DISOURCES = __builtins.di __main.di +DRUNTIME_DISOURCES = __importc_builtins.di __main.di diff --git a/libphobos/libdruntime/Makefile.in b/libphobos/libdruntime/Makefile.in index 8f8072c..1c0fa54 100644 --- a/libphobos/libdruntime/Makefile.in +++ b/libphobos/libdruntime/Makefile.in @@ -1126,7 +1126,7 @@ DRUNTIME_DSOURCES_WINDOWS = core/sys/windows/accctrl.d \ core/sys/windows/winuser.d core/sys/windows/winver.d \ core/sys/windows/wtsapi32.d core/sys/windows/wtypes.d -DRUNTIME_DISOURCES = __builtins.di __main.di +DRUNTIME_DISOURCES = __importc_builtins.di __main.di all: all-am .SUFFIXES: diff --git a/libphobos/libdruntime/__builtins.di b/libphobos/libdruntime/__importc_builtins.di index b4fef09..9493962 100644 --- a/libphobos/libdruntime/__builtins.di +++ b/libphobos/libdruntime/__importc_builtins.di @@ -3,10 +3,10 @@ * The purpose is to make it unnecessary to hardwire them into the compiler. * As the leading double underscore suggests, this is for internal use only. * - * Copyright: Copyright Digital Mars 2022 + * Copyright: Copyright D Language Foundation 2022-2025 * License: $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: Walter Bright - * Source: $(DRUNTIMESRC __builtins.d) + * Source: $(DRUNTIMESRC __importc_builtins.di) */ @@ -86,6 +86,12 @@ version (DigitalMars) return core.bitop.bswap(value); } + uint __builtin__popcount()(ulong value) + { + import core.bitop; + return core.bitop._popcnt(value); + } + // Lazily imported on first use private alias c_long = imported!"core.stdc.config".c_long; diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index 65405a2..107b275 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,3 +1,213 @@ +2025-04-18 François Dumont <frs.dumont@gmail.com> + + * testsuite/util/debug/unordered_checks.h (fill_container): New helper method. + (use_erased_local_iterator, invalid_local_iterator_pre_increment) + (invalid_local_iterator_post_increment, invalid_local_iterator_compare) + (invalid_local_iterator_range): Use latter. + (fill_and_get_local_iterator): New, use fill_container. + (use_invalid_local_iterator): Use latter. + (invalid_local_iterator_arrow_operator): New test function. + (invalid_local_iterator_copy_instantiation): New test function. + (invalid_local_iterator_move_instantiation): New test function. + (invalid_local_iterator_copy_assignment): New test function. + (invalid_local_iterator_move_assignment): New test function. + (invalid_local_iterator_const_conversion): New test function. + * testsuite/23_containers/unordered_map/debug/invalid_local_iterator_arrow_operator_neg.cc: + New test case. + * testsuite/23_containers/unordered_map/debug/invalid_local_iterator_const_conversion_neg.cc: + New test case. + * testsuite/23_containers/unordered_map/debug/invalid_local_iterator_copy_assignment_neg.cc: + New test case. + * testsuite/23_containers/unordered_map/debug/invalid_local_iterator_copy_construction_neg.cc: + New test case. + * testsuite/23_containers/unordered_map/debug/invalid_local_iterator_move_assignment_neg.cc: + New test case. + * testsuite/23_containers/unordered_map/debug/invalid_local_iterator_move_construction_neg.cc: + New test case. + * testsuite/23_containers/unordered_map/debug/max_load_factor_neg.cc: Test unordered_map. + * testsuite/23_containers/unordered_multimap/debug/begin2_neg.cc: Test unordered_multimap. + * testsuite/23_containers/unordered_multimap/debug/bucket_size_neg.cc: Likewise. + * testsuite/23_containers/unordered_multimap/debug/cbegin_neg.cc: Likewise. + * testsuite/23_containers/unordered_multimap/debug/cend_neg.cc: Likewise. + * testsuite/23_containers/unordered_multimap/debug/end1_neg.cc: Likewise. + * testsuite/23_containers/unordered_multimap/debug/end2_neg.cc: Likewise. + * testsuite/23_containers/unordered_multimap/debug/invalid_local_iterator_arrow_operator_neg.cc: + New test case. + * testsuite/23_containers/unordered_multimap/debug/invalid_local_iterator_const_conversion_neg.cc: + New test case. + * testsuite/23_containers/unordered_multimap/debug/invalid_local_iterator_copy_assignment_neg.cc: + New test case. + * testsuite/23_containers/unordered_multimap/debug/invalid_local_iterator_copy_construction_neg.cc: + New test case. + * testsuite/23_containers/unordered_multimap/debug/invalid_local_iterator_move_assignment_neg.cc: + New test case. + * testsuite/23_containers/unordered_multimap/debug/invalid_local_iterator_move_construction_neg.cc: + New test case. + * testsuite/23_containers/unordered_multimap/debug/max_load_factor_neg.cc: + Test unordered_multimap. + * testsuite/23_containers/unordered_multiset/debug/invalid_local_iterator_arrow_operator_neg.cc: + New test case. + * testsuite/23_containers/unordered_multiset/debug/invalid_local_iterator_const_conversion_neg.cc: + New test case. + * testsuite/23_containers/unordered_multiset/debug/invalid_local_iterator_copy_assignment_neg.cc: + New test case. + * testsuite/23_containers/unordered_multiset/debug/invalid_local_iterator_copy_construction_neg.cc: + New test case. + * testsuite/23_containers/unordered_multiset/debug/invalid_local_iterator_move_assignment_neg.cc: + New test case. + * testsuite/23_containers/unordered_multiset/debug/invalid_local_iterator_move_construction_neg.cc: + New test case. + * testsuite/23_containers/unordered_set/debug/invalid_local_iterator_arrow_operator_neg.cc: + New test case. + * testsuite/23_containers/unordered_set/debug/invalid_local_iterator_const_conversion_neg.cc: + New test case. + * testsuite/23_containers/unordered_set/debug/invalid_local_iterator_copy_assignment_neg.cc: + New test case. + * testsuite/23_containers/unordered_set/debug/invalid_local_iterator_copy_construction_neg.cc: + New test case. + * testsuite/23_containers/unordered_set/debug/invalid_local_iterator_move_assignment_neg.cc: + New test case. + * testsuite/23_containers/unordered_set/debug/invalid_local_iterator_move_construction_neg.cc: + New test case. + +2025-04-18 Tomasz Kamiński <tkaminsk@redhat.com> + + * doc/xml/manual/appendix_contributing.xml: Add 'and functions'. + +2025-04-17 Jason Merrill <jason@redhat.com> + + * testsuite/20_util/tuple/element_access/get_neg.cc: Adjust + diagnostic. + +2025-04-17 Tomasz Kamiński <tkaminsk@redhat.com> + + PR libstdc++/119840 + * include/std/format (_M_parse_fill_and_align): Cast elements of + __not_fill to _CharT. + +2025-04-17 Jonathan Wakely <jwakely@redhat.com> + + * include/std/format (format_kind): Do not use 'not' + alternative token to make the primary template ill-formed. Use + the undeclared identifier __primary_template_not_defined and a + comment that will appear in diagnostics. + * testsuite/std/format/ranges/format_kind_neg.cc: New test. + +2025-04-17 Tomasz Kamiński <tkaminsk@redhat.com> + + PR libstdc++/109162 + * include/std/format (__format::__simply_formattable_range): Define. + (range_formatter::format): Do not instantiate _M_format for mutable + _Rg if const _Rg can be used. + +2025-04-16 Tomasz Kamiński <tkaminsk@redhat.com> + + PR libstdc++/109162 + * include/std/format (range_formatter::format): Format const range, + only if reference type is not changed. + * testsuite/std/format/ranges/formatter.cc: New tests. + +2025-04-16 Tomasz Kamiński <tkaminsk@redhat.com> + + PR libstdc++/109162 + * include/std/format (__formatter_int::_M_format_character_escaped) + (__formatter_str::format): Use __sink.out() to produce _Sink_iter. + (__format::__const_formattable_range): Moved closer to range_formatter. + (__format::__maybe_const_range): Use `__conditional_t` and moved closer + to range_formatter. + (__format::__format_padded, __format::maybe_const) + (__format::__indexed_formatter_storage, __format::__tuple_formatter) + (std::formatter<pair<_Fp, _Sp>, _CharT>>) + (std::formatter<tuple<_Tps...>, _CharT): Define. + (std::formatter<_Rg, _CharT>::format): Cast incoming range to + __format::__maybe_const_range<_Rg, _CharT>&. + (std::formatter<_Rg, _CharT>::_M_format): Extracted from format, + and use __format_padded. + (std::formatter<_Rg, _CharT>::_M_format_no_padding): Rename... + (std::formatter<_Rg, _CharT>::_M_format_elems): ...to this. + (std::formatter<_Rg, _CharT>::_M_format_with_padding): Extracted as + __format_padded. + * testsuite/util/testsuite_iterators.h (test_input_range_nocopy): + Define. + * testsuite/std/format/ranges/formatter.cc: Tests for `m` specifier. + * testsuite/std/format/ranges/sequence.cc: Tests for array and subrange. + * testsuite/std/format/ranges/map.cc: New test. + * testsuite/std/format/tuple.cc: New test. + +2025-04-15 Jonathan Wakely <jwakely@redhat.com> + + * include/std/ranges (__glibcxx_want_ranges_iota): Do not + define. + +2025-04-15 Jonathan Wakely <jwakely@redhat.com> + + * include/std/numeric (ranges): Only declare namespace for C++23 + and later. + (ranges::iota_result): Fix indentation. + * testsuite/17_intro/names.cc: Check ranges is not used as an + identifier before C++20. + +2025-04-15 Tomasz Kamiński <tkaminsk@redhat.com> + + PR libstdc++/109162 + * include/std/format (__format::__has_debug_format, _Pres_type::_Pres_seq) + (_Pres_type::_Pres_str, __format::__Stackbuf_size): Define. + (_Separators::_S_squares, _Separators::_S_parens, _Separators::_S_comma) + (_Separators::_S_colon): Define additional constants. + (_Spec::_M_parse_fill_and_align): Define overload accepting + list of excluded characters for fill, and forward existing overload. + (__formatter_str::_M_format_range): Define. + (__format::_Buf_sink) Use __Stackbuf_size for size of array. + (__format::__is_map_formattable, std::range_formatter) + (std::formatter<_Rg, _CharT>): Define. + * src/c++23/std.cc.in (std::format_kind, std::range_format) + (std::range_formatter): Export. + * testsuite/std/format/formatter/lwg3944.cc: Guarded tests with + __glibcxx_format_ranges. + * testsuite/std/format/formatter/requirements.cc: Adjusted for standard + behavior. + * testsuite/23_containers/vector/bool/format.cc: Test vector<bool> formatting. + * testsuite/std/format/ranges/format_kind.cc: New test. + * testsuite/std/format/ranges/formatter.cc: New test. + * testsuite/std/format/ranges/sequence.cc: New test. + * testsuite/std/format/ranges/string.cc: New test. + +2025-04-15 Jonathan Wakely <jwakely@redhat.com> + + PR libstdc++/119748 + * include/bits/basic_string.h (_S_copy_chars): Only optimize for + contiguous iterators that are convertible to const charT*. Use + explicit conversion to charT after dereferencing iterator. + (_S_copy_range): Likewise for contiguous ranges. + * include/bits/basic_string.tcc (_M_construct): Use explicit + conversion to charT after dereferencing iterator. + * include/bits/cow_string.h (_S_copy_chars): Likewise. + (basic_string(from_range_t, R&&, const Allocator&)): Likewise. + Only optimize for contiguous iterators that are convertible to + const charT*. + * testsuite/21_strings/basic_string/cons/char/119748.cc: New + test. + * testsuite/21_strings/basic_string/cons/wchar_t/119748.cc: + New test. + +2025-04-15 Jonathan Wakely <jwakely@redhat.com> + + * testsuite/util/testsuite_iterators.h (test_container): Define + array constructor for C++98 as well. + +2025-04-14 Jonathan Wakely <jwakely@redhat.com> + + PR libstdc++/21334 + * doc/xml/manual/using.xml: Document that container data race + avoidance rules do not apply to COW std::string. + * doc/html/*: Regenerate. + +2025-04-14 Tomasz Kamiński <tkaminsk@redhat.com> + + PR libstdc++/119725 + * testsuite/std/format/debug.cc: Updated dg-options. + * testsuite/std/format/debug_nonunicode.cc: Updated dg-options. + 2025-04-11 Jonathan Wakely <jwakely@redhat.com> * src/c++17/fast_float/LOCAL_PATCHES: Update. diff --git a/libstdc++-v3/doc/html/manual/using_concurrency.html b/libstdc++-v3/doc/html/manual/using_concurrency.html index d21f158..d570d3a 100644 --- a/libstdc++-v3/doc/html/manual/using_concurrency.html +++ b/libstdc++-v3/doc/html/manual/using_concurrency.html @@ -126,6 +126,16 @@ gcc version 4.1.2 20070925 (Red Hat 4.1.2-33) the container the iterator refers to (for example incrementing a list iterator must access the pointers between nodes, which are part of the container and so conflict with other accesses to the container). + </p><p> + The Copy-On-Write <code class="classname">std::string</code> implementation + used before GCC 5 (and with + <a class="link" href="using_dual_abi.html" title="Dual ABI">_GLIBCXX_USE_CXX11_ABI=0</a>) + is not a standard container and does not conform to the data race + avoidance rules described above. For the Copy-On-Write + <code class="classname">std::string</code>, non-const member functions such as + <code class="function">begin()</code> are considered to be modifying accesses + and so must not be used concurrently with any other accesses to the + same object. </p><p>Programs which follow the rules above will not encounter data races in library code, even when using library types which share state between distinct objects. In the example below the diff --git a/libstdc++-v3/doc/xml/manual/appendix_contributing.xml b/libstdc++-v3/doc/xml/manual/appendix_contributing.xml index ac607fc..b924545 100644 --- a/libstdc++-v3/doc/xml/manual/appendix_contributing.xml +++ b/libstdc++-v3/doc/xml/manual/appendix_contributing.xml @@ -895,7 +895,7 @@ indicate a place that may require attention for multi-thread safety. Examples: <code>_M_num_elements _M_initialize ()</code> - Static data members, constants, and enumerations: <literal>_S_.*</literal> + Static data and function members, constants, and enumerations: <literal>_S_.*</literal> Examples: <code>_S_max_elements _S_default_value</code> diff --git a/libstdc++-v3/doc/xml/manual/using.xml b/libstdc++-v3/doc/xml/manual/using.xml index 7ca3a3f..bf92c49 100644 --- a/libstdc++-v3/doc/xml/manual/using.xml +++ b/libstdc++-v3/doc/xml/manual/using.xml @@ -2069,6 +2069,18 @@ gcc version 4.1.2 20070925 (Red Hat 4.1.2-33) of the container and so conflict with other accesses to the container). </para> + <para> + The Copy-On-Write <classname>std::string</classname> implementation + used before GCC 5 (and with + <link linkend="manual.intro.using.abi">_GLIBCXX_USE_CXX11_ABI=0</link>) + is not a standard container and does not conform to the data race + avoidance rules described above. For the Copy-On-Write + <classname>std::string</classname>, non-const member functions such as + <function>begin()</function> are considered to be modifying accesses + and so must not be used concurrently with any other accesses to the + same object. + </para> + <para>Programs which follow the rules above will not encounter data races in library code, even when using library types which share state between distinct objects. In the example below the diff --git a/libstdc++-v3/include/bits/basic_string.h b/libstdc++-v3/include/bits/basic_string.h index 9c431c7..c90bd09 100644 --- a/libstdc++-v3/include/bits/basic_string.h +++ b/libstdc++-v3/include/bits/basic_string.h @@ -488,8 +488,11 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 is_same<_IterBase, const _CharT*>>::value) _S_copy(__p, std::__niter_base(__k1), __k2 - __k1); #if __cpp_lib_concepts - else if constexpr (contiguous_iterator<_Iterator> - && is_same_v<iter_value_t<_Iterator>, _CharT>) + else if constexpr (requires { + requires contiguous_iterator<_Iterator>; + { std::to_address(__k1) } + -> convertible_to<const _CharT*>; + }) { const auto __d = __k2 - __k1; (void) (__k1 + __d); // See P3349R1 @@ -499,7 +502,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 else #endif for (; __k1 != __k2; ++__k1, (void)++__p) - traits_type::assign(*__p, *__k1); // These types are off. + traits_type::assign(*__p, static_cast<_CharT>(*__k1)); } #pragma GCC diagnostic pop @@ -527,12 +530,19 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 static constexpr void _S_copy_range(pointer __p, _Rg&& __rg, size_type __n) { - if constexpr (ranges::contiguous_range<_Rg> - && is_same_v<ranges::range_value_t<_Rg>, _CharT>) + if constexpr (requires { + requires ranges::contiguous_range<_Rg>; + { ranges::data(std::forward<_Rg>(__rg)) } + -> convertible_to<const _CharT*>; + }) _S_copy(__p, ranges::data(std::forward<_Rg>(__rg)), __n); else - for (auto&& __e : __rg) - traits_type::assign(*__p++, std::forward<decltype(__e)>(__e)); + { + auto __first = ranges::begin(__rg); + const auto __last = ranges::end(__rg); + for (; __first != __last; ++__first) + traits_type::assign(*__p++, static_cast<_CharT>(*__first)); + } } #endif diff --git a/libstdc++-v3/include/bits/basic_string.tcc b/libstdc++-v3/include/bits/basic_string.tcc index 02230ac..bca55bc 100644 --- a/libstdc++-v3/include/bits/basic_string.tcc +++ b/libstdc++-v3/include/bits/basic_string.tcc @@ -210,7 +210,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _M_data(__another); _M_capacity(__capacity); } - traits_type::assign(_M_data()[__len++], *__beg); + traits_type::assign(_M_data()[__len++], + static_cast<_CharT>(*__beg)); ++__beg; } diff --git a/libstdc++-v3/include/bits/cow_string.h b/libstdc++-v3/include/bits/cow_string.h index b250397..f9df2be 100644 --- a/libstdc++-v3/include/bits/cow_string.h +++ b/libstdc++-v3/include/bits/cow_string.h @@ -423,7 +423,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _S_copy_chars(_CharT* __p, _Iterator __k1, _Iterator __k2) { for (; __k1 != __k2; ++__k1, (void)++__p) - traits_type::assign(*__p, *__k1); // These types are off. + traits_type::assign(*__p, static_cast<_CharT>(*__k1)); } static void @@ -656,12 +656,19 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION reserve(__n); pointer __p = _M_data(); - if constexpr (ranges::contiguous_range<_Rg> - && is_same_v<ranges::range_value_t<_Rg>, _CharT>) + if constexpr (requires { + requires ranges::contiguous_range<_Rg>; + { ranges::data(std::forward<_Rg>(__rg)) } + -> convertible_to<const _CharT*>; + }) _M_copy(__p, ranges::data(std::forward<_Rg>(__rg)), __n); else - for (auto&& __e : __rg) - traits_type::assign(*__p++, std::forward<decltype(__e)>(__e)); + { + auto __first = ranges::begin(__rg); + const auto __last = ranges::end(__rg); + for (; __first != __last; ++__first) + traits_type::assign(*__p++, static_cast<_CharT>(*__first)); + } _M_rep()->_M_set_length_and_sharable(__n); } else diff --git a/libstdc++-v3/include/std/format b/libstdc++-v3/include/std/format index 23f0097..e557e10 100644 --- a/libstdc++-v3/include/std/format +++ b/libstdc++-v3/include/std/format @@ -97,6 +97,10 @@ namespace __format #define _GLIBCXX_WIDEN_(C, S) ::std::__format::_Widen<C>(S, L##S) #define _GLIBCXX_WIDEN(S) _GLIBCXX_WIDEN_(_CharT, S) + // Size for stack located buffer + template<typename _CharT> + constexpr size_t __stackbuf_size = 32 * sizeof(void*) / sizeof(_CharT); + // Type-erased character sinks. template<typename _CharT> class _Sink; template<typename _CharT> class _Fixedbuf_sink; @@ -475,9 +479,10 @@ namespace __format _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_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. + _Pres_p = 0, _Pres_P, // For pointers. + _Pres_s = 0, // For strings, bool + _Pres_seq = 0, _Pres_str, // For ranges + _Pres_esc = 0xf, // For strings, charT and ranges }; enum _Align { @@ -544,42 +549,48 @@ namespace __format // pre: __first != __last constexpr iterator _M_parse_fill_and_align(iterator __first, iterator __last) noexcept + { return _M_parse_fill_and_align(__first, __last, "{"); } + + // pre: __first != __last + constexpr iterator + _M_parse_fill_and_align(iterator __first, iterator __last, string_view __not_fill) noexcept { - if (*__first != '{') + for (char __c : __not_fill) + if (*__first == static_cast<_CharT>(__c)) + return __first; + + using namespace __unicode; + if constexpr (__literal_encoding_is_unicode<_CharT>()) { - using namespace __unicode; - if constexpr (__literal_encoding_is_unicode<_CharT>()) - { - // Accept any UCS scalar value as fill character. - _Utf32_view<ranges::subrange<iterator>> __uv({__first, __last}); - if (!__uv.empty()) - { - auto __beg = __uv.begin(); - char32_t __c = *__beg++; - if (__is_scalar_value(__c)) - if (auto __next = __beg.base(); __next != __last) - if (_Align __align = _S_align(*__next)) - { - _M_fill = __c; - _M_align = __align; - return ++__next; - } - } - } - else if (__last - __first >= 2) - if (_Align __align = _S_align(__first[1])) - { - _M_fill = *__first; - _M_align = __align; - return __first + 2; - } + // Accept any UCS scalar value as fill character. + _Utf32_view<ranges::subrange<iterator>> __uv({__first, __last}); + if (!__uv.empty()) + { + auto __beg = __uv.begin(); + char32_t __c = *__beg++; + if (__is_scalar_value(__c)) + if (auto __next = __beg.base(); __next != __last) + if (_Align __align = _S_align(*__next)) + { + _M_fill = __c; + _M_align = __align; + return ++__next; + } + } + } + else if (__last - __first >= 2) + if (_Align __align = _S_align(__first[1])) + { + _M_fill = *__first; + _M_align = __align; + return __first + 2; + } - if (_Align __align = _S_align(__first[0])) - { - _M_fill = ' '; - _M_align = __align; - return __first + 1; - } + if (_Align __align = _S_align(__first[0])) + { + _M_fill = ' '; + _M_align = __align; + return __first + 1; } return __first; } @@ -934,11 +945,27 @@ namespace __format static consteval _Str_view _S_all() - { return _GLIBCXX_WIDEN("{}"); } + { return _GLIBCXX_WIDEN("[]{}(), : "); } static consteval - _Str_view _S_braces() + _Str_view _S_squares() { return _S_all().substr(0, 2); } + + static consteval + _Str_view _S_braces() + { return _S_all().substr(2, 2); } + + static consteval + _Str_view _S_parens() + { return _S_all().substr(4, 2); } + + static consteval + _Str_view _S_comma() + { return _S_all().substr(6, 2); } + + static consteval + _Str_view _S_colon() + { return _S_all().substr(8, 2); } }; template<typename _CharT> @@ -1231,6 +1258,13 @@ namespace __format template<__char _CharT> struct __formatter_str { + __formatter_str() = default; + + constexpr + __formatter_str(_Spec<_CharT> __spec) noexcept + : _M_spec(__spec) + { } + constexpr typename basic_format_parse_context<_CharT>::iterator parse(basic_format_parse_context<_CharT>& __pc) { @@ -1316,8 +1350,7 @@ namespace __format __fc, _M_spec); __format::_Str_sink<_CharT> __sink; - __format::_Sink_iter<_CharT> __out(__sink); - __format::__write_escaped(__out, __s, __term); + __format::__write_escaped(__sink.out(), __s, __term); basic_string_view<_CharT> __escaped(__sink.view().data(), __sink.view().size()); const size_t __escaped_width = _S_trunc(__escaped, __prec); @@ -1329,6 +1362,43 @@ namespace __format } #if __glibcxx_format_ranges // C++ >= 23 && HOSTED + template<ranges::input_range _Rg, typename _Out> + requires same_as<remove_cvref_t<ranges::range_reference_t<_Rg>>, _CharT> + typename basic_format_context<_Out, _CharT>::iterator + _M_format_range(_Rg&& __rg, basic_format_context<_Out, _CharT>& __fc) const + { + using _String = basic_string<_CharT>; + using _String_view = basic_string_view<_CharT>; + if constexpr (ranges::forward_range<_Rg> || ranges::sized_range<_Rg>) + { + const size_t __n(ranges::distance(__rg)); + if constexpr (ranges::contiguous_range<_Rg>) + return format(_String_view(ranges::data(__rg), __n), __fc); + else if (__n <= __format::__stackbuf_size<_CharT>) + { + _CharT __buf[__format::__stackbuf_size<_CharT>]; + ranges::copy(__rg, __buf); + return format(_String_view(__buf, __n), __fc); + } + else if constexpr (ranges::sized_range<_Rg>) + return format(_String(from_range, __rg), __fc); + else if constexpr (ranges::random_access_range<_Rg>) + { + ranges::iterator_t<_Rg> __first = ranges::begin(__rg); + ranges::subrange __sub(__first, __first + __n); + return format(_String(from_range, __sub), __fc); + } + else + { + // N.B. preserve the computed size + ranges::subrange __sub(__rg, __n); + return format(_String(from_range, __sub), __fc); + } + } + else + return format(_String(from_range, __rg), __fc); + } + constexpr void set_debug_format() noexcept { _M_spec._M_type = _Pres_esc; } @@ -1627,7 +1697,7 @@ namespace __format template<typename _Out> typename basic_format_context<_Out, _CharT>::iterator _M_format_character_escaped(_CharT __c, - basic_format_context<_Out, _CharT>& __fc) const + basic_format_context<_Out, _CharT>& __fc) const { using _Esc = _Escapes<_CharT>; constexpr auto __term = __format::_Term_char::_Tc_apos; @@ -1637,8 +1707,7 @@ namespace __format _CharT __buf[12]; __format::_Fixedbuf_sink<_CharT> __sink(__buf); - __format::_Sink_iter<_CharT> __out(__sink); - __format::__write_escaped(__out, __in, __term); + __format::__write_escaped(__sink.out(), __in, __term); const basic_string_view<_CharT> __escaped = __sink.view(); size_t __estimated_width; @@ -2931,7 +3000,7 @@ namespace __format }; /// @} -#if defined _GLIBCXX_USE_WCHAR_T && __cpp_lib_format_ranges +#if defined _GLIBCXX_USE_WCHAR_T && __glibcxx_format_ranges // _GLIBCXX_RESOLVE_LIB_DEFECTS // 3944. Formatters converting sequences of char to sequences of wchar_t @@ -2991,32 +3060,21 @@ namespace __format concept __formattable_impl = __parsable_with<_Tp, _Context> && __formattable_with<_Tp, _Context>; + template<typename _Formatter> + concept __has_debug_format = requires(_Formatter __f) + { + __f.set_debug_format(); + }; + } // namespace __format /// @endcond -// Concept std::formattable was introduced by P2286R8 "Formatting Ranges", -// but we can't guard it with __cpp_lib_format_ranges until we define that! -#if __cplusplus > 202002L +#if __glibcxx_format_ranges // C++ >= 23 && HOSTED // [format.formattable], concept formattable template<typename _Tp, typename _CharT> concept formattable = __format::__formattable_impl<remove_reference_t<_Tp>, _CharT>; -#endif - -#if __cpp_lib_format_ranges - /// @cond undocumented -namespace __format -{ - template<typename _Rg, typename _CharT> - concept __const_formattable_range - = ranges::input_range<const _Rg> - && formattable<ranges::range_reference_t<const _Rg>, _CharT>; - template<typename _Rg, typename _CharT> - using __maybe_const_range - = conditional_t<__const_formattable_range<_Rg, _CharT>, const _Rg, _Rg>; -} // namespace __format - /// @endcond #endif // format_ranges /// An iterator after the last character written, and the number of @@ -3246,7 +3304,7 @@ namespace __format class _Buf_sink : public _Sink<_CharT> { protected: - _CharT _M_buf[32 * sizeof(void*) / sizeof(_CharT)]; + _CharT _M_buf[__stackbuf_size<_CharT>]; [[__gnu__::__always_inline__]] constexpr @@ -5088,7 +5146,7 @@ namespace __format } #endif -#if __cpp_lib_format_ranges +#if __glibcxx_format_ranges // C++ >= 23 && HOSTED // [format.range], formatting of ranges // [format.range.fmtkind], variable template format_kind enum class range_format { @@ -5102,7 +5160,10 @@ namespace __format /// @cond undocumented template<typename _Rg> - constexpr auto format_kind = not defined(format_kind<_Rg>); + constexpr auto format_kind = + __primary_template_not_defined( + format_kind<_Rg> // you can specialize this for non-const input ranges + ); template<typename _Tp> consteval range_format @@ -5133,28 +5194,600 @@ namespace __format template<ranges::input_range _Rg> requires same_as<_Rg, remove_cvref_t<_Rg>> constexpr range_format format_kind<_Rg> = __fmt_kind<_Rg>(); - // [format.range.formatter], class template range_formatter - template<typename _Tp, typename _CharT = char> - requires same_as<remove_cvref_t<_Tp>, _Tp> && formattable<_Tp, _CharT> - class range_formatter; // TODO - /// @cond undocumented namespace __format { - // [format.range.fmtdef], class template range-default-formatter - template<range_format _Kind, ranges::input_range _Rg, typename _CharT> - struct __range_default_formatter; // TODO + template<typename _CharT, typename _Out, typename _Callback> + typename basic_format_context<_Out, _CharT>::iterator + __format_padded(basic_format_context<_Out, _CharT>& __fc, + const _Spec<_CharT>& __spec, + _Callback&& __call) + { + // This is required to implement formatting with padding, + // as we need to format to temporary buffer, using the same iterator. + static_assert(is_same_v<_Out, __format::_Sink_iter<_CharT>>); + + if (__spec._M_get_width(__fc) == 0) + return __call(__fc); + + struct _Restore_out + { + _Restore_out(basic_format_context<_Sink_iter<_CharT>, _CharT>& __fc) + : _M_ctx(std::addressof(__fc)), _M_out(__fc.out()) + { } + + void _M_trigger() + { + if (_M_ctx) + _M_ctx->advance_to(_M_out); + _M_ctx = nullptr; + } + + ~_Restore_out() + { _M_trigger(); } + + private: + basic_format_context<_Sink_iter<_CharT>, _CharT>* _M_ctx; + _Sink_iter<_CharT> _M_out; + }; + + _Restore_out __restore(__fc); + // TODO Consider double sinking, first buffer of width + // size and then original sink, if first buffer is overun + // we do not need to align + _Str_sink<_CharT> __buf; + __fc.advance_to(__buf.out()); + __call(__fc); + __restore._M_trigger(); + + basic_string_view<_CharT> __str(__buf.view()); + size_t __width; + if constexpr (__unicode::__literal_encoding_is_unicode<_CharT>()) + __width = __unicode::__field_width(__str); + else + __width = __str.size(); + + return __format::__write_padded_as_spec(__str, __width, __fc, __spec); + } + + template<typename _Rg, typename _CharT> + concept __const_formattable_range + = ranges::input_range<const _Rg> + && formattable<ranges::range_reference_t<const _Rg>, _CharT>; + + // _Rg& and const _Rg& are both formattable and use same formatter + // specialization for their references. + template<typename _Rg, typename _CharT> + concept __simply_formattable_range + = __const_formattable_range<_Rg, _CharT> + && same_as<remove_cvref_t<ranges::range_reference_t<_Rg>>, + remove_cvref_t<ranges::range_reference_t<const _Rg>>>; + + template<typename _Rg, typename _CharT> + using __maybe_const_range + = __conditional_t<__const_formattable_range<_Rg, _CharT>, const _Rg, _Rg>; + + template<typename _Tp, typename _CharT> + using __maybe_const + = __conditional_t<formattable<const _Tp, _CharT>, const _Tp, _Tp>; + + template<size_t _Pos, typename _Tp, typename _CharT> + struct __indexed_formatter_storage + { + constexpr void + _M_parse() + { + basic_format_parse_context<_CharT> __pc({}); + if (_M_formatter.parse(__pc) != __pc.end()) + __format::__failed_to_parse_format_spec(); + } + + template<typename _Out> + void + _M_format(__maybe_const<_Tp, _CharT>& __elem, + basic_format_context<_Out, _CharT>& __fc, + basic_string_view<_CharT> __sep) const + { + if constexpr (_Pos != 0) + __fc.advance_to(__format::__write(__fc.out(), __sep)); + __fc.advance_to(_M_formatter.format(__elem, __fc)); + } + + [[__gnu__::__always_inline__]] + constexpr void + set_debug_format() + { + if constexpr (__has_debug_format<formatter<_Tp, _CharT>>) + _M_formatter.set_debug_format(); + } + + private: + formatter<_Tp, _CharT> _M_formatter; + }; + + template<typename _CharT, typename... _Tps> + class __tuple_formatter + { + using _String_view = basic_string_view<_CharT>; + using _Seps = __format::_Separators<_CharT>; + + public: + constexpr void + set_separator(basic_string_view<_CharT> __sep) noexcept + { _M_sep = __sep; } + + constexpr void + set_brackets(basic_string_view<_CharT> __open, + basic_string_view<_CharT> __close) noexcept + { + _M_open = __open; + _M_close = __close; + } + + // We deviate from standard, that declares this as template accepting + // unconstrained ParseContext type, which seems unimplementable. + constexpr typename basic_format_parse_context<_CharT>::iterator + parse(basic_format_parse_context<_CharT>& __pc) + { + auto __first = __pc.begin(); + const auto __last = __pc.end(); + __format::_Spec<_CharT> __spec{}; + + auto __finished = [&] + { + if (__first != __last && *__first != '}') + return false; + + _M_spec = __spec; + _M_felems._M_parse(); + _M_felems.set_debug_format(); + return true; + }; + + if (__finished()) + return __first; + + __first = __spec._M_parse_fill_and_align(__first, __last, "{:"); + if (__finished()) + return __first; + + __first = __spec._M_parse_width(__first, __last, __pc); + if (__finished()) + return __first; + + if (*__first == 'n') + { + ++__first; + _M_open = _M_close = _String_view(); + } + else if (*__first == 'm') + { + ++__first; + if constexpr (sizeof...(_Tps) == 2) + { + _M_sep = _Seps::_S_colon(); + _M_open = _M_close = _String_view(); + } + else + __throw_format_error("format error: 'm' specifier requires range" + " of pair or tuple of two elements"); + } + + if (__finished()) + return __first; + + __format::__failed_to_parse_format_spec(); + } + + protected: + template<typename _Tuple, typename _Out, size_t... _Ids> + typename basic_format_context<_Out, _CharT>::iterator + _M_format(_Tuple& __tuple, index_sequence<_Ids...>, + basic_format_context<_Out, _CharT>& __fc) const + { return _M_format_elems(std::get<_Ids>(__tuple)..., __fc); } + + template<typename _Out> + typename basic_format_context<_Out, _CharT>::iterator + _M_format_elems(__maybe_const<_Tps, _CharT>&... __elems, + basic_format_context<_Out, _CharT>& __fc) const + { + return __format::__format_padded( + __fc, _M_spec, + [this, &__elems...](basic_format_context<_Out, _CharT>& __nfc) + { + __nfc.advance_to(__format::__write(__nfc.out(), _M_open)); + _M_felems._M_format(__elems..., __nfc, _M_sep); + return __format::__write(__nfc.out(), _M_close); + }); + } + + private: + template<size_t... _Ids> + struct __formatters_storage + : __indexed_formatter_storage<_Ids, _Tps, _CharT>... + { + template<size_t _Id, typename _Up> + using _Base = __indexed_formatter_storage<_Id, _Up, _CharT>; + + constexpr void + _M_parse() + { + (_Base<_Ids, _Tps>::_M_parse(), ...); + } + + template<typename _Out> + void + _M_format(__maybe_const<_Tps, _CharT>&... __elems, + basic_format_context<_Out, _CharT>& __fc, + _String_view __sep) const + { + (_Base<_Ids, _Tps>::_M_format(__elems, __fc, __sep), ...); + } + + constexpr void + set_debug_format() + { + (_Base<_Ids, _Tps>::set_debug_format(), ...); + } + }; + + template<size_t... _Ids> + static auto + _S_create_storage(index_sequence<_Ids...>) + -> __formatters_storage<_Ids...>; + using _Formatters + = decltype(_S_create_storage(index_sequence_for<_Tps...>())); + + _Spec<_CharT> _M_spec{}; + _String_view _M_open = _Seps::_S_parens().substr(0, 1); + _String_view _M_close = _Seps::_S_parens().substr(1, 1); + _String_view _M_sep = _Seps::_S_comma(); + _Formatters _M_felems; + }; + + template<typename _Tp> + concept __is_map_formattable + = __is_pair<_Tp> || (__is_tuple_v<_Tp> && tuple_size_v<_Tp> == 2); + } // namespace __format /// @endcond + // [format.tuple] Tuple formatter + template<__format::__char _CharT, formattable<_CharT> _Fp, + formattable<_CharT> _Sp> + struct formatter<pair<_Fp, _Sp>, _CharT> + : __format::__tuple_formatter<_CharT, remove_cvref_t<_Fp>, + remove_cvref_t<_Sp>> + { + private: + using __maybe_const_pair + = __conditional_t<formattable<const _Fp, _CharT> + && formattable<const _Sp, _CharT>, + const pair<_Fp, _Sp>, pair<_Fp, _Sp>>; + public: + // We deviate from standard, that declares this as template accepting + // unconstrained FormatContext type, which seems unimplementable. + template<typename _Out> + typename basic_format_context<_Out, _CharT>::iterator + format(__maybe_const_pair& __p, + basic_format_context<_Out, _CharT>& __fc) const + { return this->_M_format_elems(__p.first, __p.second, __fc); } + }; + + template<__format::__char _CharT, formattable<_CharT>... _Tps> + struct formatter<tuple<_Tps...>, _CharT> + : __format::__tuple_formatter<_CharT, remove_cvref_t<_Tps>...> + { + private: + using __maybe_const_tuple + = __conditional_t<(formattable<const _Tps, _CharT> && ...), + const tuple<_Tps...>, tuple<_Tps...>>; + public: + // We deviate from standard, that declares this as template accepting + // unconstrained FormatContext type, which seems unimplementable. + template<typename _Out> + typename basic_format_context<_Out, _CharT>::iterator + format(__maybe_const_tuple& __t, + basic_format_context<_Out, _CharT>& __fc) const + { return this->_M_format(__t, index_sequence_for<_Tps...>(), __fc); } + }; + + // [format.range.formatter], class template range_formatter + template<typename _Tp, __format::__char _CharT = char> + requires same_as<remove_cvref_t<_Tp>, _Tp> && formattable<_Tp, _CharT> + class range_formatter + { + using _String_view = basic_string_view<_CharT>; + using _Seps = __format::_Separators<_CharT>; + + public: + constexpr void + set_separator(basic_string_view<_CharT> __sep) noexcept + { _M_sep = __sep; } + + constexpr void + set_brackets(basic_string_view<_CharT> __open, + basic_string_view<_CharT> __close) noexcept + { + _M_open = __open; + _M_close = __close; + } + + constexpr formatter<_Tp, _CharT>& + underlying() noexcept + { return _M_fval; } + + constexpr const formatter<_Tp, _CharT>& + underlying() const noexcept + { return _M_fval; } + + // We deviate from standard, that declares this as template accepting + // unconstrained ParseContext type, which seems unimplementable. + constexpr typename basic_format_parse_context<_CharT>::iterator + parse(basic_format_parse_context<_CharT>& __pc) + { + auto __first = __pc.begin(); + const auto __last = __pc.end(); + __format::_Spec<_CharT> __spec{}; + bool __no_brace = false; + + auto __finished = [&] + { return __first == __last || *__first == '}'; }; + + auto __finalize = [&] + { + _M_spec = __spec; + return __first; + }; + + auto __parse_val = [&](_String_view __nfs = _String_view()) + { + basic_format_parse_context<_CharT> __npc(__nfs); + if (_M_fval.parse(__npc) != __npc.end()) + __format::__failed_to_parse_format_spec(); + if constexpr (__format::__has_debug_format<formatter<_Tp, _CharT>>) + _M_fval.set_debug_format(); + return __finalize(); + }; + + if (__finished()) + return __parse_val(); + + __first = __spec._M_parse_fill_and_align(__first, __last, "{:"); + if (__finished()) + return __parse_val(); + + __first = __spec._M_parse_width(__first, __last, __pc); + if (__finished()) + return __parse_val(); + + if (*__first == '?') + { + ++__first; + __spec._M_type = __format::_Pres_esc; + if (__finished() || *__first != 's') + __throw_format_error("format error: '?' is allowed only in" + " combination with 's'"); + } + + if (*__first == 's') + { + ++__first; + if constexpr (same_as<_Tp, _CharT>) + { + if (__spec._M_type != __format::_Pres_esc) + __spec._M_type = __format::_Pres_str; + if (__finished()) + return __finalize(); + __throw_format_error("format error: element format specifier" + " cannot be provided when 's' specifier is used"); + } + else + __throw_format_error("format error: 's' specifier requires" + " range of character types"); + } + + if (__finished()) + return __parse_val(); + + if (*__first == 'n') + { + ++__first; + _M_open = _M_close = _String_view(); + __no_brace = true; + } + + if (__finished()) + return __parse_val(); + + if (*__first == 'm') + { + _String_view __m(__first, 1); + ++__first; + if constexpr (__format::__is_map_formattable<_Tp>) + { + _M_sep = _Seps::_S_comma(); + if (!__no_brace) + { + _M_open = _Seps::_S_braces().substr(0, 1); + _M_close = _Seps::_S_braces().substr(1, 1); + } + if (__finished()) + return __parse_val(__m); + __throw_format_error("format error: element format specifier" + " cannot be provided when 'm' specifier is used"); + } + else + __throw_format_error("format error: 'm' specifier requires" + " range of pairs or tuples of two elements"); + } + + if (__finished()) + return __parse_val(); + + if (*__first == ':') + { + __pc.advance_to(++__first); + __first = _M_fval.parse(__pc); + } + + if (__finished()) + return __finalize(); + + __format::__failed_to_parse_format_spec(); + } + + // We deviate from standard, that declares this as template accepting + // unconstrained FormatContext type, which seems unimplementable. + template<ranges::input_range _Rg, typename _Out> + requires formattable<ranges::range_reference_t<_Rg>, _CharT> && + same_as<remove_cvref_t<ranges::range_reference_t<_Rg>>, _Tp> + typename basic_format_context<_Out, _CharT>::iterator + format(_Rg&& __rg, basic_format_context<_Out, _CharT>& __fc) const + { + using _Range = remove_reference_t<_Rg>; + if constexpr (__format::__simply_formattable_range<_Range, _CharT>) + return _M_format<const _Range>(__rg, __fc); + else + return _M_format(__rg, __fc); + } + + private: + template<ranges::input_range _Rg, typename _Out> + typename basic_format_context<_Out, _CharT>::iterator + _M_format(_Rg& __rg, basic_format_context<_Out, _CharT>& __fc) const + { + if constexpr (same_as<_Tp, _CharT>) + if (_M_spec._M_type == __format::_Pres_str + || _M_spec._M_type == __format::_Pres_esc) + { + __format::__formatter_str __fstr(_M_spec); + return __fstr._M_format_range(__rg, __fc); + } + return __format::__format_padded( + __fc, _M_spec, + [this, &__rg](basic_format_context<_Out, _CharT>& __nfc) + { return _M_format_elems(__rg, __nfc); }); + } + + + template<ranges::input_range _Rg, typename _Out> + typename basic_format_context<_Out, _CharT>::iterator + _M_format_elems(_Rg& __rg, + basic_format_context<_Out, _CharT>& __fc) const + { + auto __out = __format::__write(__fc.out(), _M_open); + + auto __first = ranges::begin(__rg); + auto const __last = ranges::end(__rg); + if (__first == __last) + return __format::__write(__out, _M_close); + + __fc.advance_to(__out); + __out = _M_fval.format(*__first, __fc); + for (++__first; __first != __last; ++__first) + { + __out = __format::__write(__out, _M_sep); + __fc.advance_to(__out); + __out = _M_fval.format(*__first, __fc); + } + + return __format::__write(__out, _M_close); + } + + __format::_Spec<_CharT> _M_spec{}; + _String_view _M_open = _Seps::_S_squares().substr(0, 1); + _String_view _M_close = _Seps::_S_squares().substr(1, 1); + _String_view _M_sep = _Seps::_S_comma(); + formatter<_Tp, _CharT> _M_fval; + }; + + // In standard this is shown as inheriting from specialization of + // exposition only specialization for range-default-formatter for + // each range_format. We opt for simpler implementation. // [format.range.fmtmap], [format.range.fmtset], [format.range.fmtstr], // specializations for maps, sets, and strings - template<ranges::input_range _Rg, typename _CharT> + template<ranges::input_range _Rg, __format::__char _CharT> requires (format_kind<_Rg> != range_format::disabled) && formattable<ranges::range_reference_t<_Rg>, _CharT> struct formatter<_Rg, _CharT> - : __format::__range_default_formatter<format_kind<_Rg>, _Rg, _CharT> - { }; + { + private: + static const bool _S_range_format_is_string = + (format_kind<_Rg> == range_format::string) + || (format_kind<_Rg> == range_format::debug_string); + using _Vt = remove_cvref_t< + ranges::range_reference_t< + __format::__maybe_const_range<_Rg, _CharT>>>; + + static consteval bool _S_is_correct() + { + if constexpr (_S_range_format_is_string) + static_assert(same_as<_Vt, _CharT>); + return true; + } + + static_assert(_S_is_correct()); + + public: + constexpr formatter() noexcept + { + using _Seps = __format::_Separators<_CharT>; + if constexpr (format_kind<_Rg> == range_format::map) + { + static_assert(__format::__is_map_formattable<_Vt>); + _M_under.set_brackets(_Seps::_S_braces().substr(0, 1), + _Seps::_S_braces().substr(1, 1)); + _M_under.underlying().set_brackets({}, {}); + _M_under.underlying().set_separator(_Seps::_S_colon()); + } + else if constexpr (format_kind<_Rg> == range_format::set) + _M_under.set_brackets(_Seps::_S_braces().substr(0, 1), + _Seps::_S_braces().substr(1, 1)); + } + + constexpr void + set_separator(basic_string_view<_CharT> __sep) noexcept + requires (!_S_range_format_is_string) + { _M_under.set_separator(__sep); } + + constexpr void + set_brackets(basic_string_view<_CharT> __open, + basic_string_view<_CharT> __close) noexcept + requires (!_S_range_format_is_string) + { _M_under.set_brackets(__open, __close); } + + // We deviate from standard, that declares this as template accepting + // unconstrained ParseContext type, which seems unimplementable. + constexpr typename basic_format_parse_context<_CharT>::iterator + parse(basic_format_parse_context<_CharT>& __pc) + { + auto __res = _M_under.parse(__pc); + if constexpr (format_kind<_Rg> == range_format::debug_string) + _M_under.set_debug_format(); + return __res; + } + + // We deviate from standard, that declares this as template accepting + // unconstrained FormatContext type, which seems unimplementable. + template<typename _Out> + typename basic_format_context<_Out, _CharT>::iterator + format(__format::__maybe_const_range<_Rg, _CharT>& __rg, + basic_format_context<_Out, _CharT>& __fc) const + { + if constexpr (_S_range_format_is_string) + return _M_under._M_format_range(__rg, __fc); + else + return _M_under.format(__rg, __fc); + } + + private: + using _Formatter_under + = __conditional_t<_S_range_format_is_string, + __format::__formatter_str<_CharT>, + range_formatter<_Vt, _CharT>>; + _Formatter_under _M_under; + }; #endif // C++23 formatting ranges #undef _GLIBCXX_WIDEN diff --git a/libstdc++-v3/include/std/numeric b/libstdc++-v3/include/std/numeric index 4d36fcd..490963e 100644 --- a/libstdc++-v3/include/std/numeric +++ b/libstdc++-v3/include/std/numeric @@ -732,12 +732,11 @@ namespace __detail /// @} group numeric_ops #endif // C++17 +#if __glibcxx_ranges_iota >= 202202L // C++ >= 23 namespace ranges { -#if __glibcxx_ranges_iota >= 202202L // C++ >= 23 - template<typename _Out, typename _Tp> - using iota_result = out_value_result<_Out, _Tp>; + using iota_result = out_value_result<_Out, _Tp>; struct __iota_fn { @@ -762,9 +761,8 @@ namespace ranges }; inline constexpr __iota_fn iota{}; - -#endif // __glibcxx_ranges_iota } // namespace ranges +#endif // __glibcxx_ranges_iota _GLIBCXX_END_NAMESPACE_VERSION } // namespace std diff --git a/libstdc++-v3/include/std/ranges b/libstdc++-v3/include/std/ranges index 7a339c5..9300c36 100644 --- a/libstdc++-v3/include/std/ranges +++ b/libstdc++-v3/include/std/ranges @@ -64,7 +64,6 @@ #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_join_with #define __glibcxx_want_ranges_repeat #define __glibcxx_want_ranges_slide diff --git a/libstdc++-v3/src/c++23/std.cc.in b/libstdc++-v3/src/c++23/std.cc.in index 12253b9..5e18ad7 100644 --- a/libstdc++-v3/src/c++23/std.cc.in +++ b/libstdc++-v3/src/c++23/std.cc.in @@ -1332,6 +1332,12 @@ export namespace std using std::wformat_context; using std::wformat_parse_context; using std::wformat_string; +// FIXME __cpp_lib_format_ranges +#ifdef __glibcxx_format_ranges + using std::format_kind; + using std::range_format; + using std::range_formatter; +#endif } // <forward_list> diff --git a/libstdc++-v3/testsuite/17_intro/names.cc b/libstdc++-v3/testsuite/17_intro/names.cc index 4458325..f67818d 100644 --- a/libstdc++-v3/testsuite/17_intro/names.cc +++ b/libstdc++-v3/testsuite/17_intro/names.cc @@ -142,6 +142,10 @@ #define try_emplace ( #endif +#if __cplusplus < 202002L +#define ranges ( +#endif + // These clash with newlib so don't use them. # define __lockable cannot be used as an identifier # define __null_sentinel cannot be used as an identifier diff --git a/libstdc++-v3/testsuite/20_util/tuple/element_access/get_neg.cc b/libstdc++-v3/testsuite/20_util/tuple/element_access/get_neg.cc index 48628a9..18d47d2 100644 --- a/libstdc++-v3/testsuite/20_util/tuple/element_access/get_neg.cc +++ b/libstdc++-v3/testsuite/20_util/tuple/element_access/get_neg.cc @@ -61,4 +61,4 @@ test03() // { dg-error "tuple index must be in range" "" { target *-*-* } 0 } // { dg-prune-output "no type named 'type' in .*_Nth_type" } -// { dg-prune-output "pack index is out of range" } +// { dg-prune-output "pack index '.' is out of range" } diff --git a/libstdc++-v3/testsuite/21_strings/basic_string/cons/char/119748.cc b/libstdc++-v3/testsuite/21_strings/basic_string/cons/char/119748.cc new file mode 100644 index 0000000..301ca5d --- /dev/null +++ b/libstdc++-v3/testsuite/21_strings/basic_string/cons/char/119748.cc @@ -0,0 +1,35 @@ +// { dg-do compile } + +// Bug 119748 +// string(InputIterator, InputIterator) rejects volatile charT* as iterator + +#ifndef TEST_CHAR_TYPE +#define TEST_CHAR_TYPE char +#endif + +#include <string> +#include <testsuite_iterators.h> + +typedef TEST_CHAR_TYPE C; + +volatile C vs[42] = {}; +std::basic_string<C> s(vs+0, vs+42); +#ifdef __cpp_lib_containers_ranges +std::basic_string<C> s2(std::from_range, vs); +#endif + +using namespace __gnu_test; + +test_container<volatile C, input_iterator_wrapper> input_cont(vs); +std::basic_string<C> s3(input_cont.begin(), input_cont.end()); + +test_container<volatile C, forward_iterator_wrapper> fwd_cont(vs); +std::basic_string<C> s4(fwd_cont.begin(), fwd_cont.end()); + +#ifdef __cpp_lib_containers_ranges +test_input_range<volatile C> input_range(vs); +std::basic_string<C> s5(std::from_range, input_range); + +test_forward_range<volatile C> fwd_range(vs); +std::basic_string<C> s6(std::from_range, fwd_range); +#endif diff --git a/libstdc++-v3/testsuite/21_strings/basic_string/cons/wchar_t/119748.cc b/libstdc++-v3/testsuite/21_strings/basic_string/cons/wchar_t/119748.cc new file mode 100644 index 0000000..7d3ba10 --- /dev/null +++ b/libstdc++-v3/testsuite/21_strings/basic_string/cons/wchar_t/119748.cc @@ -0,0 +1,7 @@ +// { dg-do compile } + +// Bug 119748 +// string(InputIterator, InputIterator) rejects volatile charT* as iterator + +#define TEST_CHAR_TYPE wchar_t +#include "../char/119748.cc" diff --git a/libstdc++-v3/testsuite/23_containers/unordered_map/debug/invalid_local_iterator_arrow_operator_neg.cc b/libstdc++-v3/testsuite/23_containers/unordered_map/debug/invalid_local_iterator_arrow_operator_neg.cc new file mode 100644 index 0000000..09870a7 --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/unordered_map/debug/invalid_local_iterator_arrow_operator_neg.cc @@ -0,0 +1,17 @@ +// { dg-do run { target c++11 xfail *-*-* } } +// { dg-require-debug-mode "" } + +#include <unordered_map> +#include <debug/unordered_checks.h> + +void test01() +{ + __gnu_test::invalid_local_iterator_arrow_operator + <std::unordered_map<int, int>>(); +} + +int main() +{ + test01(); + return 0; +} diff --git a/libstdc++-v3/testsuite/23_containers/unordered_map/debug/invalid_local_iterator_const_conversion_neg.cc b/libstdc++-v3/testsuite/23_containers/unordered_map/debug/invalid_local_iterator_const_conversion_neg.cc new file mode 100644 index 0000000..7bfe3a8 --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/unordered_map/debug/invalid_local_iterator_const_conversion_neg.cc @@ -0,0 +1,17 @@ +// { dg-do run { target c++11 xfail *-*-* } } +// { dg-require-debug-mode "" } + +#include <unordered_map> +#include <debug/unordered_checks.h> + +void test01() +{ + __gnu_test::invalid_local_iterator_const_conversion + <std::unordered_map<int, int>>(); +} + +int main() +{ + test01(); + return 0; +} diff --git a/libstdc++-v3/testsuite/23_containers/unordered_map/debug/invalid_local_iterator_copy_assignment_neg.cc b/libstdc++-v3/testsuite/23_containers/unordered_map/debug/invalid_local_iterator_copy_assignment_neg.cc new file mode 100644 index 0000000..d3b671b --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/unordered_map/debug/invalid_local_iterator_copy_assignment_neg.cc @@ -0,0 +1,17 @@ +// { dg-do run { target c++11 xfail *-*-* } } +// { dg-require-debug-mode "" } + +#include <unordered_map> +#include <debug/unordered_checks.h> + +void test01() +{ + __gnu_test::invalid_local_iterator_copy_assignment + <std::unordered_map<int, int>>(); +} + +int main() +{ + test01(); + return 0; +} diff --git a/libstdc++-v3/testsuite/23_containers/unordered_map/debug/invalid_local_iterator_copy_construction_neg.cc b/libstdc++-v3/testsuite/23_containers/unordered_map/debug/invalid_local_iterator_copy_construction_neg.cc new file mode 100644 index 0000000..d609671 --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/unordered_map/debug/invalid_local_iterator_copy_construction_neg.cc @@ -0,0 +1,17 @@ +// { dg-do run { target c++11 xfail *-*-* } } +// { dg-require-debug-mode "" } + +#include <unordered_map> +#include <debug/unordered_checks.h> + +void test01() +{ + __gnu_test::invalid_local_iterator_copy_construction + <std::unordered_map<int, int>>(); +} + +int main() +{ + test01(); + return 0; +} diff --git a/libstdc++-v3/testsuite/23_containers/unordered_map/debug/invalid_local_iterator_move_assignment_neg.cc b/libstdc++-v3/testsuite/23_containers/unordered_map/debug/invalid_local_iterator_move_assignment_neg.cc new file mode 100644 index 0000000..8d2ed6b --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/unordered_map/debug/invalid_local_iterator_move_assignment_neg.cc @@ -0,0 +1,17 @@ +// { dg-do run { target c++11 xfail *-*-* } } +// { dg-require-debug-mode "" } + +#include <unordered_map> +#include <debug/unordered_checks.h> + +void test01() +{ + __gnu_test::invalid_local_iterator_move_assignment + <std::unordered_map<int, int>>(); +} + +int main() +{ + test01(); + return 0; +} diff --git a/libstdc++-v3/testsuite/23_containers/unordered_map/debug/invalid_local_iterator_move_construction_neg.cc b/libstdc++-v3/testsuite/23_containers/unordered_map/debug/invalid_local_iterator_move_construction_neg.cc new file mode 100644 index 0000000..dd9b7dc --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/unordered_map/debug/invalid_local_iterator_move_construction_neg.cc @@ -0,0 +1,17 @@ +// { dg-do run { target c++11 xfail *-*-* } } +// { dg-require-debug-mode "" } + +#include <unordered_map> +#include <debug/unordered_checks.h> + +void test01() +{ + __gnu_test::invalid_local_iterator_move_construction + <std::unordered_map<int, int>>(); +} + +int main() +{ + test01(); + return 0; +} diff --git a/libstdc++-v3/testsuite/23_containers/unordered_map/debug/max_load_factor_neg.cc b/libstdc++-v3/testsuite/23_containers/unordered_map/debug/max_load_factor_neg.cc index 7fbc453..2596798 100644 --- a/libstdc++-v3/testsuite/23_containers/unordered_map/debug/max_load_factor_neg.cc +++ b/libstdc++-v3/testsuite/23_containers/unordered_map/debug/max_load_factor_neg.cc @@ -22,7 +22,7 @@ void test01() { - std::unordered_multimap<int, int> um; + std::unordered_map<int, int> um; um.max_load_factor(-1.0f); } diff --git a/libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/begin2_neg.cc b/libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/begin2_neg.cc index ff787cf..b2d67fb 100644 --- a/libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/begin2_neg.cc +++ b/libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/begin2_neg.cc @@ -22,8 +22,8 @@ void test01() { - std::unordered_map<int, int> um; - const std::unordered_map<int, int>& cum = um; + std::unordered_multimap<int, int> um; + const std::unordered_multimap<int, int>& cum = um; cum.begin(um.bucket_count()); } diff --git a/libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/bucket_size_neg.cc b/libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/bucket_size_neg.cc index b5ddb18..4d5cb84 100644 --- a/libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/bucket_size_neg.cc +++ b/libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/bucket_size_neg.cc @@ -22,7 +22,7 @@ void test01() { - std::unordered_map<int, int> um; + std::unordered_multimap<int, int> um; um.bucket_size(um.bucket_count()); } diff --git a/libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/cbegin_neg.cc b/libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/cbegin_neg.cc index 5ba1da5..654d409 100644 --- a/libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/cbegin_neg.cc +++ b/libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/cbegin_neg.cc @@ -22,7 +22,7 @@ void test01() { - std::unordered_map<int, int> um; + std::unordered_multimap<int, int> um; um.cbegin(um.bucket_count()); } diff --git a/libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/cend_neg.cc b/libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/cend_neg.cc index 031be37..f7149d4 100644 --- a/libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/cend_neg.cc +++ b/libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/cend_neg.cc @@ -22,7 +22,7 @@ void test01() { - std::unordered_map<int, int> um; + std::unordered_multimap<int, int> um; um.cend(um.bucket_count()); } diff --git a/libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/end1_neg.cc b/libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/end1_neg.cc index d412fcf..fd0f981 100644 --- a/libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/end1_neg.cc +++ b/libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/end1_neg.cc @@ -22,7 +22,7 @@ void test01() { - std::unordered_map<int, int> um; + std::unordered_multimap<int, int> um; um.end(um.bucket_count()); } diff --git a/libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/end2_neg.cc b/libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/end2_neg.cc index 0115351..0c3f86c 100644 --- a/libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/end2_neg.cc +++ b/libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/end2_neg.cc @@ -22,8 +22,8 @@ void test01() { - std::unordered_map<int, int> um; - const std::unordered_map<int, int>& cum = um; + std::unordered_multimap<int, int> um; + const std::unordered_multimap<int, int>& cum = um; cum.end(um.bucket_count()); } diff --git a/libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/invalid_local_iterator_arrow_operator_neg.cc b/libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/invalid_local_iterator_arrow_operator_neg.cc new file mode 100644 index 0000000..8b23020 --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/invalid_local_iterator_arrow_operator_neg.cc @@ -0,0 +1,17 @@ +// { dg-do run { target c++11 xfail *-*-* } } +// { dg-require-debug-mode "" } + +#include <unordered_map> +#include <debug/unordered_checks.h> + +void test01() +{ + __gnu_test::invalid_local_iterator_arrow_operator + <std::unordered_multimap<int, int>>(); +} + +int main() +{ + test01(); + return 0; +} diff --git a/libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/invalid_local_iterator_const_conversion_neg.cc b/libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/invalid_local_iterator_const_conversion_neg.cc new file mode 100644 index 0000000..62c0280 --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/invalid_local_iterator_const_conversion_neg.cc @@ -0,0 +1,17 @@ +// { dg-do run { target c++11 xfail *-*-* } } +// { dg-require-debug-mode "" } + +#include <unordered_map> +#include <debug/unordered_checks.h> + +void test01() +{ + __gnu_test::invalid_local_iterator_const_conversion + <std::unordered_multimap<int, int>>(); +} + +int main() +{ + test01(); + return 0; +} diff --git a/libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/invalid_local_iterator_copy_assignment_neg.cc b/libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/invalid_local_iterator_copy_assignment_neg.cc new file mode 100644 index 0000000..9ac5b35 --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/invalid_local_iterator_copy_assignment_neg.cc @@ -0,0 +1,17 @@ +// { dg-do run { target c++11 xfail *-*-* } } +// { dg-require-debug-mode "" } + +#include <unordered_map> +#include <debug/unordered_checks.h> + +void test01() +{ + __gnu_test::invalid_local_iterator_copy_assignment + <std::unordered_multimap<int, int>>(); +} + +int main() +{ + test01(); + return 0; +} diff --git a/libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/invalid_local_iterator_copy_construction_neg.cc b/libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/invalid_local_iterator_copy_construction_neg.cc new file mode 100644 index 0000000..4140272 --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/invalid_local_iterator_copy_construction_neg.cc @@ -0,0 +1,17 @@ +// { dg-do run { target c++11 xfail *-*-* } } +// { dg-require-debug-mode "" } + +#include <unordered_map> +#include <debug/unordered_checks.h> + +void test01() +{ + __gnu_test::invalid_local_iterator_copy_construction + <std::unordered_multimap<int, int>>(); +} + +int main() +{ + test01(); + return 0; +} diff --git a/libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/invalid_local_iterator_move_assignment_neg.cc b/libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/invalid_local_iterator_move_assignment_neg.cc new file mode 100644 index 0000000..32c847c --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/invalid_local_iterator_move_assignment_neg.cc @@ -0,0 +1,17 @@ +// { dg-do run { target c++11 xfail *-*-* } } +// { dg-require-debug-mode "" } + +#include <unordered_map> +#include <debug/unordered_checks.h> + +void test01() +{ + __gnu_test::invalid_local_iterator_move_assignment + <std::unordered_multimap<int, int>>(); +} + +int main() +{ + test01(); + return 0; +} diff --git a/libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/invalid_local_iterator_move_construction_neg.cc b/libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/invalid_local_iterator_move_construction_neg.cc new file mode 100644 index 0000000..124b9ec --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/invalid_local_iterator_move_construction_neg.cc @@ -0,0 +1,17 @@ +// { dg-do run { target c++11 xfail *-*-* } } +// { dg-require-debug-mode "" } + +#include <unordered_map> +#include <debug/unordered_checks.h> + +void test01() +{ + __gnu_test::invalid_local_iterator_move_construction + <std::unordered_multimap<int, int>>(); +} + +int main() +{ + test01(); + return 0; +} diff --git a/libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/max_load_factor_neg.cc b/libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/max_load_factor_neg.cc index 2596798..7fbc453 100644 --- a/libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/max_load_factor_neg.cc +++ b/libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/max_load_factor_neg.cc @@ -22,7 +22,7 @@ void test01() { - std::unordered_map<int, int> um; + std::unordered_multimap<int, int> um; um.max_load_factor(-1.0f); } diff --git a/libstdc++-v3/testsuite/23_containers/unordered_multiset/debug/invalid_local_iterator_arrow_operator_neg.cc b/libstdc++-v3/testsuite/23_containers/unordered_multiset/debug/invalid_local_iterator_arrow_operator_neg.cc new file mode 100644 index 0000000..1677b20 --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/unordered_multiset/debug/invalid_local_iterator_arrow_operator_neg.cc @@ -0,0 +1,17 @@ +// { dg-do run { target c++11 xfail *-*-* } } +// { dg-require-debug-mode "" } + +#include <unordered_set> +#include <debug/unordered_checks.h> + +void test01() +{ + __gnu_test::invalid_local_iterator_arrow_operator + <std::unordered_multiset<int>>(); +} + +int main() +{ + test01(); + return 0; +} diff --git a/libstdc++-v3/testsuite/23_containers/unordered_multiset/debug/invalid_local_iterator_const_conversion_neg.cc b/libstdc++-v3/testsuite/23_containers/unordered_multiset/debug/invalid_local_iterator_const_conversion_neg.cc new file mode 100644 index 0000000..0d64a41 --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/unordered_multiset/debug/invalid_local_iterator_const_conversion_neg.cc @@ -0,0 +1,17 @@ +// { dg-do run { target c++11 xfail *-*-* } } +// { dg-require-debug-mode "" } + +#include <unordered_set> +#include <debug/unordered_checks.h> + +void test01() +{ + __gnu_test::invalid_local_iterator_const_conversion + <std::unordered_multiset<int>>(); +} + +int main() +{ + test01(); + return 0; +} diff --git a/libstdc++-v3/testsuite/23_containers/unordered_multiset/debug/invalid_local_iterator_copy_assignment_neg.cc b/libstdc++-v3/testsuite/23_containers/unordered_multiset/debug/invalid_local_iterator_copy_assignment_neg.cc new file mode 100644 index 0000000..b0d7b9f --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/unordered_multiset/debug/invalid_local_iterator_copy_assignment_neg.cc @@ -0,0 +1,17 @@ +// { dg-do run { target c++11 xfail *-*-* } } +// { dg-require-debug-mode "" } + +#include <unordered_set> +#include <debug/unordered_checks.h> + +void test01() +{ + __gnu_test::invalid_local_iterator_copy_assignment + <std::unordered_multiset<int>>(); +} + +int main() +{ + test01(); + return 0; +} diff --git a/libstdc++-v3/testsuite/23_containers/unordered_multiset/debug/invalid_local_iterator_copy_construction_neg.cc b/libstdc++-v3/testsuite/23_containers/unordered_multiset/debug/invalid_local_iterator_copy_construction_neg.cc new file mode 100644 index 0000000..fa9c5ee --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/unordered_multiset/debug/invalid_local_iterator_copy_construction_neg.cc @@ -0,0 +1,17 @@ +// { dg-do run { target c++11 xfail *-*-* } } +// { dg-require-debug-mode "" } + +#include <unordered_set> +#include <debug/unordered_checks.h> + +void test01() +{ + __gnu_test::invalid_local_iterator_copy_construction + <std::unordered_multiset<int>>(); +} + +int main() +{ + test01(); + return 0; +} diff --git a/libstdc++-v3/testsuite/23_containers/unordered_multiset/debug/invalid_local_iterator_move_assignment_neg.cc b/libstdc++-v3/testsuite/23_containers/unordered_multiset/debug/invalid_local_iterator_move_assignment_neg.cc new file mode 100644 index 0000000..b25fedc --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/unordered_multiset/debug/invalid_local_iterator_move_assignment_neg.cc @@ -0,0 +1,17 @@ +// { dg-do run { target c++11 xfail *-*-* } } +// { dg-require-debug-mode "" } + +#include <unordered_set> +#include <debug/unordered_checks.h> + +void test01() +{ + __gnu_test::invalid_local_iterator_move_assignment + <std::unordered_multiset<int>>(); +} + +int main() +{ + test01(); + return 0; +} diff --git a/libstdc++-v3/testsuite/23_containers/unordered_multiset/debug/invalid_local_iterator_move_construction_neg.cc b/libstdc++-v3/testsuite/23_containers/unordered_multiset/debug/invalid_local_iterator_move_construction_neg.cc new file mode 100644 index 0000000..8b855b2 --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/unordered_multiset/debug/invalid_local_iterator_move_construction_neg.cc @@ -0,0 +1,17 @@ +// { dg-do run { target c++11 xfail *-*-* } } +// { dg-require-debug-mode "" } + +#include <unordered_set> +#include <debug/unordered_checks.h> + +void test01() +{ + __gnu_test::invalid_local_iterator_move_construction + <std::unordered_multiset<int>>(); +} + +int main() +{ + test01(); + return 0; +} diff --git a/libstdc++-v3/testsuite/23_containers/unordered_set/debug/invalid_local_iterator_arrow_operator_neg.cc b/libstdc++-v3/testsuite/23_containers/unordered_set/debug/invalid_local_iterator_arrow_operator_neg.cc new file mode 100644 index 0000000..f62ed6b --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/unordered_set/debug/invalid_local_iterator_arrow_operator_neg.cc @@ -0,0 +1,17 @@ +// { dg-do run { target c++11 xfail *-*-* } } +// { dg-require-debug-mode "" } + +#include <unordered_set> +#include <debug/unordered_checks.h> + +void test01() +{ + __gnu_test::invalid_local_iterator_arrow_operator + <std::unordered_set<int>>(); +} + +int main() +{ + test01(); + return 0; +} diff --git a/libstdc++-v3/testsuite/23_containers/unordered_set/debug/invalid_local_iterator_const_conversion_neg.cc b/libstdc++-v3/testsuite/23_containers/unordered_set/debug/invalid_local_iterator_const_conversion_neg.cc new file mode 100644 index 0000000..839f9ae --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/unordered_set/debug/invalid_local_iterator_const_conversion_neg.cc @@ -0,0 +1,17 @@ +// { dg-do run { target c++11 xfail *-*-* } } +// { dg-require-debug-mode "" } + +#include <unordered_set> +#include <debug/unordered_checks.h> + +void test01() +{ + __gnu_test::invalid_local_iterator_const_conversion + <std::unordered_set<int>>(); +} + +int main() +{ + test01(); + return 0; +} diff --git a/libstdc++-v3/testsuite/23_containers/unordered_set/debug/invalid_local_iterator_copy_assignment_neg.cc b/libstdc++-v3/testsuite/23_containers/unordered_set/debug/invalid_local_iterator_copy_assignment_neg.cc new file mode 100644 index 0000000..377019f --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/unordered_set/debug/invalid_local_iterator_copy_assignment_neg.cc @@ -0,0 +1,17 @@ +// { dg-do run { target c++11 xfail *-*-* } } +// { dg-require-debug-mode "" } + +#include <unordered_set> +#include <debug/unordered_checks.h> + +void test01() +{ + __gnu_test::invalid_local_iterator_copy_assignment + <std::unordered_set<int>>(); +} + +int main() +{ + test01(); + return 0; +} diff --git a/libstdc++-v3/testsuite/23_containers/unordered_set/debug/invalid_local_iterator_copy_construction_neg.cc b/libstdc++-v3/testsuite/23_containers/unordered_set/debug/invalid_local_iterator_copy_construction_neg.cc new file mode 100644 index 0000000..1f7e6dd --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/unordered_set/debug/invalid_local_iterator_copy_construction_neg.cc @@ -0,0 +1,17 @@ +// { dg-do run { target c++11 xfail *-*-* } } +// { dg-require-debug-mode "" } + +#include <unordered_set> +#include <debug/unordered_checks.h> + +void test01() +{ + __gnu_test::invalid_local_iterator_copy_construction + <std::unordered_set<int>>(); +} + +int main() +{ + test01(); + return 0; +} diff --git a/libstdc++-v3/testsuite/23_containers/unordered_set/debug/invalid_local_iterator_move_assignment_neg.cc b/libstdc++-v3/testsuite/23_containers/unordered_set/debug/invalid_local_iterator_move_assignment_neg.cc new file mode 100644 index 0000000..d16a154 --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/unordered_set/debug/invalid_local_iterator_move_assignment_neg.cc @@ -0,0 +1,17 @@ +// { dg-do run { target c++11 xfail *-*-* } } +// { dg-require-debug-mode "" } + +#include <unordered_set> +#include <debug/unordered_checks.h> + +void test01() +{ + __gnu_test::invalid_local_iterator_move_assignment + <std::unordered_set<int>>(); +} + +int main() +{ + test01(); + return 0; +} diff --git a/libstdc++-v3/testsuite/23_containers/unordered_set/debug/invalid_local_iterator_move_construction_neg.cc b/libstdc++-v3/testsuite/23_containers/unordered_set/debug/invalid_local_iterator_move_construction_neg.cc new file mode 100644 index 0000000..d878abf --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/unordered_set/debug/invalid_local_iterator_move_construction_neg.cc @@ -0,0 +1,17 @@ +// { dg-do run { target c++11 xfail *-*-* } } +// { dg-require-debug-mode "" } + +#include <unordered_set> +#include <debug/unordered_checks.h> + +void test01() +{ + __gnu_test::invalid_local_iterator_move_construction + <std::unordered_set<int>>(); +} + +int main() +{ + test01(); + return 0; +} diff --git a/libstdc++-v3/testsuite/23_containers/vector/bool/format.cc b/libstdc++-v3/testsuite/23_containers/vector/bool/format.cc index 2586225..eb24b66 100644 --- a/libstdc++-v3/testsuite/23_containers/vector/bool/format.cc +++ b/libstdc++-v3/testsuite/23_containers/vector/bool/format.cc @@ -56,6 +56,12 @@ test_output() res = std::format(WIDEN("{:=^#7X}"), v[1]); VERIFY( res == WIDEN("==0X0==") ); + + res = std::format(WIDEN("{}"), v); + VERIFY( res == WIDEN("[true, false]") ); + + res = std::format(WIDEN("{::d}"), v); + VERIFY( res == WIDEN("[1, 0]") ); } int main() diff --git a/libstdc++-v3/testsuite/std/format/debug.cc b/libstdc++-v3/testsuite/std/format/debug.cc index 07cd1e0..71bb7f4 100644 --- a/libstdc++-v3/testsuite/std/format/debug.cc +++ b/libstdc++-v3/testsuite/std/format/debug.cc @@ -1,4 +1,5 @@ -// { dg-options "-fexec-charset=UTF-8 -fwide-exec-charset=UTF-32LE -DUNICODE_ENC" } +// { dg-options "-fexec-charset=UTF-8 -fwide-exec-charset=UTF-32LE -DUNICODE_ENC" { target le } } +// { dg-options "-fexec-charset=UTF-8 -fwide-exec-charset=UTF-32BE -DUNICODE_ENC" { target be } } // { dg-do run { target c++23 } } // { dg-add-options no_pch } diff --git a/libstdc++-v3/testsuite/std/format/debug_nonunicode.cc b/libstdc++-v3/testsuite/std/format/debug_nonunicode.cc index 5c03171..2ac7e75 100644 --- a/libstdc++-v3/testsuite/std/format/debug_nonunicode.cc +++ b/libstdc++-v3/testsuite/std/format/debug_nonunicode.cc @@ -1,4 +1,4 @@ -// { dg-options "-fexec-charset=ISO8859-1 -fwide-exec-charset=UTF-32LE" } +// { dg-options "-fexec-charset=ISO8859-1" } // { dg-do run { target c++23 } } // { dg-add-options no_pch } diff --git a/libstdc++-v3/testsuite/std/format/formatter/lwg3944.cc b/libstdc++-v3/testsuite/std/format/formatter/lwg3944.cc index ff5f075..1f3edc9 100644 --- a/libstdc++-v3/testsuite/std/format/formatter/lwg3944.cc +++ b/libstdc++-v3/testsuite/std/format/formatter/lwg3944.cc @@ -4,6 +4,7 @@ // LWG 3944. Formatters converting sequences of char to sequences of wchar_t #include <format> +#include <vector> void test_lwg3944() { @@ -14,11 +15,10 @@ void test_lwg3944() std::format(L"{}",cstr); // { dg-error "here" } // Ill-formed in C++20 - // In C++23 they give L"['h', 'e', 'l', 'l', 'o']" std::format(L"{}", "hello"); // { dg-error "here" } std::format(L"{}", std::string_view("hello")); // { dg-error "here" } std::format(L"{}", std::string("hello")); // { dg-error "here" } -#ifdef __cpp_lib_format_ranges +#ifdef __glibcxx_format_ranges // LWG 3944 does not change this, it's still valid. std::format(L"{}", std::vector{'h', 'e', 'l', 'l', 'o'}); #endif diff --git a/libstdc++-v3/testsuite/std/format/formatter/requirements.cc b/libstdc++-v3/testsuite/std/format/formatter/requirements.cc index 416b9a8..1c9a0a5 100644 --- a/libstdc++-v3/testsuite/std/format/formatter/requirements.cc +++ b/libstdc++-v3/testsuite/std/format/formatter/requirements.cc @@ -70,12 +70,14 @@ test_specializations() // [format.formatter.spec] // LWG 3833. Remove specialization // template<size_t N> struct formatter<const charT[N], charT> - using Farr = std::format_context::formatter_type<const char[1]>; - static_assert( ! std::is_default_constructible_v<Farr> ); - static_assert( ! std::is_copy_constructible_v<Farr> ); - static_assert( ! std::is_move_constructible_v<Farr> ); - static_assert( ! std::is_copy_assignable_v<Farr> ); - static_assert( ! std::is_move_assignable_v<Farr> ); + // Formatter is only expected to be instantiated with only cv-unqual types + // and attempting to instantiate this specialization is ill-formed + // using Farr = std::format_context::formatter_type<const char[1]>; + // static_assert( ! std::is_default_constructible_v<Farr> ); + // static_assert( ! std::is_copy_constructible_v<Farr> ); + // static_assert( ! std::is_move_constructible_v<Farr> ); + // static_assert( ! std::is_copy_assignable_v<Farr> ); + // static_assert( ! std::is_move_assignable_v<Farr> ); } int main() diff --git a/libstdc++-v3/testsuite/std/format/ranges/format_kind.cc b/libstdc++-v3/testsuite/std/format/ranges/format_kind.cc new file mode 100644 index 0000000..14b9ff2 --- /dev/null +++ b/libstdc++-v3/testsuite/std/format/ranges/format_kind.cc @@ -0,0 +1,94 @@ +// { dg-do run { target c++23 } } + +#include <deque> +#include <flat_map> +#include <flat_set> +#include <format> +#include <list> +#include <map> +#include <set> +#include <testsuite_hooks.h> +#include <unordered_map> +#include <unordered_set> +#include <vector> + +static_assert( std::format_kind<std::vector<int>> == std::range_format::sequence ); +static_assert( std::format_kind<std::deque<int>> == std::range_format::sequence ); +static_assert( std::format_kind<std::list<int>> == std::range_format::sequence ); + +static_assert( std::format_kind<std::set<int>> == std::range_format::set ); +static_assert( std::format_kind<std::multiset<int>> == std::range_format::set ); +static_assert( std::format_kind<std::unordered_set<int>> == std::range_format::set ); +static_assert( std::format_kind<std::unordered_multiset<int>> == std::range_format::set ); +static_assert( std::format_kind<std::flat_set<int>> == std::range_format::set ); +static_assert( std::format_kind<std::flat_multiset<int>> == std::range_format::set ); + +static_assert( std::format_kind<std::map<int, int>> == std::range_format::map ); +static_assert( std::format_kind<std::multimap<int, int>> == std::range_format::map ); +static_assert( std::format_kind<std::unordered_map<int, int>> == std::range_format::map ); +static_assert( std::format_kind<std::unordered_multimap<int, int>> == std::range_format::map ); +static_assert( std::format_kind<std::flat_map<int, int>> == std::range_format::map ); +static_assert( std::format_kind<std::flat_multimap<int, int>> == std::range_format::map ); + +template<typename T> +struct MyVec : std::vector<T> +{}; + +static_assert( std::format_kind<MyVec<int>> == std::range_format::sequence ); + +template<typename T> +struct MySet : std::vector<T> +{ + using key_type = T; +}; + +static_assert( std::format_kind<MySet<int>> == std::range_format::set ); + +template<typename T> +struct MyMap : std::vector<T> +{ + using key_type = T; + using mapped_type = int; +}; + +static_assert( std::format_kind<MyMap<std::pair<int, int>>> == std::range_format::map ); +static_assert( std::format_kind<MyMap<std::tuple<int, int>>> == std::range_format::map ); +static_assert( std::format_kind<MyMap<int>> == std::range_format::set ); + +template<typename T, std::range_format rf> +struct CustFormat : std::vector<T> +{ + using std::vector<T>::vector; +}; + +template<typename T, std::range_format rf> +constexpr auto std::format_kind<CustFormat<T, rf>> = rf; + +void test_override() +{ + CustFormat<int, std::range_format::disabled> disabledf; + static_assert( !std::formattable<decltype(disabledf), char> ); + + CustFormat<int, std::range_format::sequence> seqf{1, 2, 3}; + VERIFY( std::format("{}", seqf) == "[1, 2, 3]" ); + + CustFormat<int, std::range_format::set> setf{1, 2, 3}; + VERIFY( std::format("{}", setf) == "{1, 2, 3}" ); + + // TODO test map once formatter for pair is implenented + + CustFormat<char, std::range_format::string> stringf{'a', 'b', 'c', 'd'}; + VERIFY( std::format("{}", stringf) == "abcd" ); + // Support precision as string do + VERIFY( std::format("{:.2}", stringf) == "ab" ); + + CustFormat<char, std::range_format::debug_string> debugf{'a', 'b', 'c', 'd'}; + VERIFY( std::format("{}", debugf) == R"("abcd")" ); + // Support precision as string do + VERIFY( std::format("{:.3}", debugf) == R"("ab)" ); +} + +int main() +{ + test_override(); +} diff --git a/libstdc++-v3/testsuite/std/format/ranges/format_kind_neg.cc b/libstdc++-v3/testsuite/std/format/ranges/format_kind_neg.cc new file mode 100644 index 0000000..bf8619d --- /dev/null +++ b/libstdc++-v3/testsuite/std/format/ranges/format_kind_neg.cc @@ -0,0 +1,13 @@ +// { dg-do compile { target c++23 } } + +// C++23 22.14.7.1 [format.range.fmtkind] p1: A program that instantiates +// the primary template of format_kind is ill-formed. + +#include <format> + +template<auto> struct Tester { }; + +Tester<std::format_kind<const int(&)[1]>> t; // { dg-error "here" } + +// { dg-error "use of 'std::format_kind" "" { target *-*-* } 0 } +// { dg-error "primary_template_not_defined" "" { target *-*-* } 0 } diff --git a/libstdc++-v3/testsuite/std/format/ranges/formatter.cc b/libstdc++-v3/testsuite/std/format/ranges/formatter.cc new file mode 100644 index 0000000..00ce9f6 --- /dev/null +++ b/libstdc++-v3/testsuite/std/format/ranges/formatter.cc @@ -0,0 +1,171 @@ +// { dg-do run { target c++23 } } + +#include <flat_map> +#include <format> +#include <testsuite_hooks.h> +#include <vector> + +#define WIDEN_(C, S) ::std::__format::_Widen<C>(S, L##S) +#define WIDEN(S) WIDEN_(_CharT, S) + +template<typename T, + template<typename, typename> class Formatter = std::range_formatter> +struct MyVector : std::vector<T> +{ + using std::vector<T>::vector; +}; + +template<typename T, + template<typename, typename> class Formatter, + typename CharT> +struct std::formatter<MyVector<T, Formatter>, CharT> +{ + constexpr formatter() noexcept + { + using _CharT = CharT; + _formatter.set_brackets(WIDEN("<"), WIDEN(">")); + _formatter.set_separator(WIDEN("; ")); + } + + constexpr std::basic_format_parse_context<CharT>::iterator + parse(std::basic_format_parse_context<CharT>& pc) + { return _formatter.parse(pc); } + + template<typename Out> + typename std::basic_format_context<Out, CharT>::iterator + format(const MyVector<T, Formatter>& mv, + std::basic_format_context<Out, CharT>& fc) const + { return _formatter.format(mv, fc); } + +private: + Formatter<T, CharT> _formatter; +}; + +template<typename _CharT, template<typename, typename> class Formatter> +void +test_default() +{ + MyVector<int, Formatter> vec{1, 2, 3}; + std::basic_string<_CharT> res; + + res = std::format(WIDEN("{}"), vec); + VERIFY( res == WIDEN("<1; 2; 3>") ); + res = std::format(WIDEN("{:}"), vec); + VERIFY( res == WIDEN("<1; 2; 3>") ); + res = std::format(WIDEN("{:n}"), vec); + VERIFY( res == WIDEN("1; 2; 3") ); + + res = std::format(WIDEN("{:3}"), vec); + VERIFY( res == WIDEN("<1; 2; 3>") ); + + res = std::format(WIDEN("{:10}"), vec); + VERIFY( res == WIDEN("<1; 2; 3> ") ); + + res = std::format(WIDEN("{:{}}"), vec, 10); + VERIFY( res == WIDEN("<1; 2; 3> ") ); + + res = std::format(WIDEN("{1:{0}}"), 10, vec); + VERIFY( res == WIDEN("<1; 2; 3> ") ); + + res = std::format(WIDEN("{:10n}"), vec); + VERIFY( res == WIDEN("1; 2; 3 ") ); + + res = std::format(WIDEN("{:*<11}"), vec); + VERIFY( res == WIDEN("<1; 2; 3>**") ); + + res = std::format(WIDEN("{:->12}"), vec); + VERIFY( res == WIDEN("---<1; 2; 3>") ); + + res = std::format(WIDEN("{:=^13}"), vec); + VERIFY( res == WIDEN("==<1; 2; 3>==") ); + + res = std::format(WIDEN("{:=^13n}"), vec); + VERIFY( res == WIDEN("===1; 2; 3===") ); + + res = std::format(WIDEN("{::#x}"), vec); + VERIFY( res == WIDEN("<0x1; 0x2; 0x3>") ); + + res = std::format(WIDEN("{:|^25n:#05x}"), vec); + VERIFY( res == WIDEN("|||0x001; 0x002; 0x003|||") ); + + // ':' is start of the format string for element + res = std::format(WIDEN("{::^+4}"), vec); + VERIFY( res == WIDEN("< +1 ; +2 ; +3 >") ); +} + +template<typename _CharT, template<typename, typename> class Formatter> +void +test_override() +{ + MyVector<_CharT, Formatter> vc{'a', 'b', 'c', 'd'}; + MyVector<std::pair<int, int>, Formatter> vp{{1, 11}, {2, 21}}; + std::basic_string<_CharT> res; + + res = std::format(WIDEN("{:s}"), vc); + VERIFY( res == WIDEN("abcd") ); + res = std::format(WIDEN("{:?s}"), vc); + VERIFY( res == WIDEN("\"abcd\"") ); + res = std::format(WIDEN("{:+^6s}"), vc); + VERIFY( res == WIDEN("+abcd+") ); + + res = std::format(WIDEN("{:m}"), vp); + VERIFY( res == WIDEN("{1: 11, 2: 21}") ); + res = std::format(WIDEN("{:=^20m}"), vp); + VERIFY( res == WIDEN("==={1: 11, 2: 21}===") ); +} + +template<template<typename, typename> class Formatter> +void test_outputs() +{ + test_default<char, Formatter>(); + test_default<wchar_t, Formatter>(); + test_override<char, Formatter>(); + test_override<wchar_t, Formatter>(); +} + +void +test_nested() +{ + MyVector<MyVector<int>> v + { + {1, 2}, + {11, 12} + }; + + std::string res = std::format("{}", v); + VERIFY( res == "<<1; 2>; <11; 12>>" ); + + res = std::format("{:+^18:n:02}", v); + VERIFY( res == "+<01; 02; 11; 12>+" ); +} + +struct MyFlatMap : std::flat_map<int, int> +{ + using std::flat_map<int, int>::flat_map; +}; + +template<typename CharT> +struct std::formatter<MyFlatMap, CharT> + // This cannot apply format BitVector const&, because formatted type would + // be std::pair<int const&, int const&>, and formatter for + // pair<int const&, int> cannot format it. + : std::range_formatter<MyFlatMap::reference> +{}; + +void test_const_ref_type_mismatch() +{ + MyFlatMap m{{1, 11}, {2, 22}}; + std::string res = std::format("{:m}", m); + VERIFY( res == "{1: 11, 2: 22}" ); +} + +template<typename T, typename CharT> +using VectorFormatter = std::formatter<std::vector<T>, CharT>; + +int main() +{ + test_outputs<std::range_formatter>(); + test_outputs<VectorFormatter>(); + test_nested(); + test_const_ref_type_mismatch(); +} diff --git a/libstdc++-v3/testsuite/std/format/ranges/map.cc b/libstdc++-v3/testsuite/std/format/ranges/map.cc new file mode 100644 index 0000000..34c5ed5 --- /dev/null +++ b/libstdc++-v3/testsuite/std/format/ranges/map.cc @@ -0,0 +1,209 @@ +// { dg-do run { target c++23 } } + +#include <flat_map> +#include <format> +#include <list> +#include <map> +#include <span> +#include <testsuite_hooks.h> +#include <testsuite_iterators.h> +#include <vector> + +struct NotFormattable +{ + friend auto operator<=>(NotFormattable, NotFormattable) = default; +}; + +static_assert( !std::formattable<std::map<int, NotFormattable>, char> ); +static_assert( !std::formattable<std::map<NotFormattable, int>, wchar_t> ); + +template<typename... Args> +bool +is_format_string_for(const char* str, Args&&... args) +{ + try { + (void) std::vformat(str, std::make_format_args(args...)); + return true; + } catch (const std::format_error&) { + return false; + } +} + +template<typename... Args> +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; + } +} + +template<typename Rg, typename CharT> +bool is_range_formatter_spec_for(CharT const* spec, Rg&& rg) +{ + using V = std::remove_cvref_t<std::ranges::range_reference_t<Rg>>; + std::range_formatter<V, CharT> fmt; + std::basic_format_parse_context<CharT> pc(spec); + try { + (void)fmt.parse(pc); + return true; + } catch (const std::format_error&) { + return false; + } +} + +#define WIDEN_(C, S) ::std::__format::_Widen<C>(S, L##S) +#define WIDEN(S) WIDEN_(_CharT, S) + +void +test_format_string() +{ + // only pair<T, U> amd tuple<T, U> value types are supported + VERIFY( !is_range_formatter_spec_for("m", std::vector<int>()) ); + VERIFY( !is_format_string_for("{:m}", std::vector<int>()) ); + VERIFY( !is_range_formatter_spec_for("m", std::vector<std::tuple<int, int, int>>()) ); + VERIFY( !is_format_string_for("{:m}", std::vector<std::tuple<int, int, int>>()) ); + + // invalid format stringss + VERIFY( !is_range_formatter_spec_for("?m", std::vector<std::pair<int, int>>()) ); + VERIFY( !is_format_string_for("{:?m}", std::vector<std::pair<int, int>>()) ); + VERIFY( !is_range_formatter_spec_for("m:", std::vector<std::pair<int, int>>()) ); + VERIFY( !is_format_string_for("{:m:}", std::vector<std::pair<int, int>>()) ); + + // precision is not supported + VERIFY( !is_range_formatter_spec_for(".10m", std::vector<std::pair<int, int>>()) ); + VERIFY( !is_format_string_for("{:.10m}", std::vector<std::pair<int, int>>()) ); + VERIFY( !is_format_string_for("{:.{}m}", std::vector<std::pair<int, int>>(), 10) ); + + // width needs to be integer type + VERIFY( !is_format_string_for("{:{}m}", std::vector<std::pair<int, int>>(), 1.0f) ); +} + +template<typename _CharT, typename Range> +void test_output(bool mapIsDefault) +{ + using Sv = std::basic_string_view<_CharT>; + using Pt = std::ranges::range_value_t<Range>; + using Ft = std::remove_cvref_t<std::tuple_element_t<0, Pt>>; + using St = std::remove_cvref_t<std::tuple_element_t<1, Pt>>; + auto makeRange = [](std::span<Pt> s) { + return Range(s.data(), s.data() + s.size()); + }; + + std::basic_string<_CharT> res; + size_t size = 0; + + Ft f1[]{1, 2, 3}; + St s1[]{11, 22, 33}; + Pt v1[]{{f1[0], s1[0]}, {f1[1], s1[1]}, {f1[2], s1[2]}}; + + res = std::format(WIDEN("{}"), makeRange(v1)); + if (mapIsDefault) + VERIFY( res == WIDEN("{1: 11, 2: 22, 3: 33}") ); + else + VERIFY( res == WIDEN("[(1, 11), (2, 22), (3, 33)]") ); + + res = std::format(WIDEN("{:m}"), makeRange(v1)); + VERIFY( res == WIDEN("{1: 11, 2: 22, 3: 33}") ); + res = std::format(WIDEN("{:nm}"), makeRange(v1)); + VERIFY( res == WIDEN("1: 11, 2: 22, 3: 33") ); + + res = std::format(WIDEN("{:3m}"), makeRange(v1)); + VERIFY( res == WIDEN("{1: 11, 2: 22, 3: 33}") ); + + res = std::format(WIDEN("{:25m}"), makeRange(v1)); + VERIFY( res == WIDEN("{1: 11, 2: 22, 3: 33} ") ); + + res = std::format(WIDEN("{:{}m}"), makeRange(v1), 25); + VERIFY( res == WIDEN("{1: 11, 2: 22, 3: 33} ") ); + + res = std::format(WIDEN("{1:{0}m}"), 25, makeRange(v1)); + VERIFY( res == WIDEN("{1: 11, 2: 22, 3: 33} ") ); + + res = std::format(WIDEN("{:25nm}"), makeRange(v1)); + VERIFY( res == WIDEN("1: 11, 2: 22, 3: 33 ") ); + + res = std::format(WIDEN("{:*<23m}"), makeRange(v1)); + VERIFY( res == WIDEN("{1: 11, 2: 22, 3: 33}**") ); + + res = std::format(WIDEN("{:->24m}"), makeRange(v1)); + VERIFY( res == WIDEN("---{1: 11, 2: 22, 3: 33}") ); + + res = std::format(WIDEN("{:=^25m}"), makeRange(v1)); + VERIFY( res == WIDEN("=={1: 11, 2: 22, 3: 33}==") ); + + res = std::format(WIDEN("{:=^25nm}"), makeRange(v1)); + VERIFY( res == WIDEN("===1: 11, 2: 22, 3: 33===") ); + + size = std::formatted_size(WIDEN("{:m}"), makeRange(v1)); + VERIFY( size == Sv(WIDEN("{1: 11, 2: 22, 3: 33}")).size() ); + + size = std::formatted_size(WIDEN("{:3m}"), makeRange(v1)); + VERIFY( size == Sv(WIDEN("{1: 11, 2: 22, 3: 33}")).size() ); + + size = std::formatted_size(WIDEN("{:25m}"), makeRange(v1)); + VERIFY( size == 25 ); +} + +template<class Range> +void test_output_c(bool mapIsDefault = false) +{ + test_output<char, Range>(mapIsDefault); + test_output<wchar_t, Range>(mapIsDefault); +} + +template<template<typename> class RangeT> +void test_output_pc() +{ + test_output_c<RangeT<std::pair<int, int>>>(); + test_output_c<RangeT<std::pair<const int, int>>>(); + test_output_c<RangeT<std::tuple<const int&, int&>>>(); +} + +void +test_outputs() +{ + using namespace __gnu_test; + test_output_c<std::map<int, int>>(true); + test_output_c<std::flat_map<int, int>>(true); + + test_output_pc<std::vector>(); + test_output_pc<std::list>(); + test_output_pc<std::span>(); + + test_output_pc<test_forward_range>(); + test_output_pc<test_input_range>(); + test_output_pc<test_input_range_nocopy>(); +} + +void +test_nested() +{ + std::vector<std::map<int, std::string>> vm{ + {{1, "one"}, {2, "two"}}, + {{1, "jeden"}, {2, "dwa"}}, + }; + std::string res; + + res = std::format("{}", vm); + VERIFY( res == R"([{1: "one", 2: "two"}, {1: "jeden", 2: "dwa"}])" ); + res = std::format("{:n:n}", vm); + VERIFY( res == R"(1: "one", 2: "two", 1: "jeden", 2: "dwa")" ); + + std::map<std::string, std::vector<std::string>> mv{ + {"english", {"zero", "one", "two"}}, + {"polish", {"zero", "jeden", "dwa"}}, + }; + res = std::format("{}", mv); + VERIFY( res == R"({"english": ["zero", "one", "two"], "polish": ["zero", "jeden", "dwa"]})" ); +} + +int main() +{ + test_format_string(); + test_outputs(); + test_nested(); +} diff --git a/libstdc++-v3/testsuite/std/format/ranges/sequence.cc b/libstdc++-v3/testsuite/std/format/ranges/sequence.cc new file mode 100644 index 0000000..61fc68e --- /dev/null +++ b/libstdc++-v3/testsuite/std/format/ranges/sequence.cc @@ -0,0 +1,206 @@ +// { dg-do run { target c++23 } } + +#include <array> +#include <format> +#include <list> +#include <ranges> +#include <span> +#include <testsuite_hooks.h> +#include <testsuite_iterators.h> +#include <vector> + +struct NotFormattable +{}; + +static_assert(!std::formattable<std::vector<NotFormattable>, char>); +static_assert(!std::formattable<std::span<NotFormattable>, wchar_t>); + +template<typename... Args> +bool +is_format_string_for(const char* str, Args&&... args) +{ + try { + (void) std::vformat(str, std::make_format_args(args...)); + return true; + } catch (const std::format_error&) { + return false; + } +} + +template<typename... Args> +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; + } +} + +template<typename Rg, typename CharT> +bool is_range_formatter_spec_for(CharT const* spec, Rg&& rg) +{ + using V = std::remove_cvref_t<std::ranges::range_reference_t<Rg>>; + std::range_formatter<V, CharT> fmt; + std::basic_format_parse_context<CharT> pc(spec); + try { + (void)fmt.parse(pc); + return true; + } catch (const std::format_error&) { + return false; + } +} + +void +test_format_string() +{ + // invalid format spec 'p' + VERIFY( !is_range_formatter_spec_for("p", std::vector<int>()) ); + VERIFY( !is_format_string_for("{:p}", std::vector<int>()) ); + VERIFY( !is_range_formatter_spec_for("np", std::vector<int>()) ); + VERIFY( !is_format_string_for("{:np}", std::vector<int>()) ); + + // width needs to be integer type + VERIFY( !is_format_string_for("{:{}}", std::vector<int>(), 1.0f) ); + + // element format needs to be valid + VERIFY( !is_range_formatter_spec_for(":p", std::vector<int>()) ); + VERIFY( !is_format_string_for("{::p}", std::vector<int>()) ); + VERIFY( !is_range_formatter_spec_for("n:p", std::vector<int>()) ); + VERIFY( !is_format_string_for("{:n:p}", std::vector<int>()) ); +} + +#define WIDEN_(C, S) ::std::__format::_Widen<C>(S, L##S) +#define WIDEN(S) WIDEN_(_CharT, S) + +template<typename _CharT, typename Range, typename Storage> +void test_output() +{ + using Sv = std::basic_string_view<_CharT>; + using T = std::ranges::range_value_t<Range>; + auto makeRange = [](Storage& s) -> Range { + if constexpr (std::is_same_v<std::remove_cvref_t<Range>, Storage>) + return s; + else + return Range(std::ranges::data(s), + std::ranges::data(s) + std::ranges::size(s)); + }; + + std::basic_string<_CharT> res; + size_t size = 0; + + Storage v1{1, 2, 3}; + res = std::format(WIDEN("{}"), makeRange(v1)); + VERIFY( res == WIDEN("[1, 2, 3]") ); + res = std::format(WIDEN("{:}"), makeRange(v1)); + VERIFY( res == WIDEN("[1, 2, 3]") ); + res = std::format(WIDEN("{:n}"), makeRange(v1)); + VERIFY( res == WIDEN("1, 2, 3") ); + + res = std::format(WIDEN("{:3}"), makeRange(v1)); + VERIFY( res == WIDEN("[1, 2, 3]") ); + + res = std::format(WIDEN("{:10}"), makeRange(v1)); + VERIFY( res == WIDEN("[1, 2, 3] ") ); + + res = std::format(WIDEN("{:{}}"), makeRange(v1), 10); + VERIFY( res == WIDEN("[1, 2, 3] ") ); + + res = std::format(WIDEN("{1:{0}}"), 10, makeRange(v1)); + VERIFY( res == WIDEN("[1, 2, 3] ") ); + + res = std::format(WIDEN("{:10n}"), makeRange(v1)); + VERIFY( res == WIDEN("1, 2, 3 ") ); + + res = std::format(WIDEN("{:*<11}"), makeRange(v1)); + VERIFY( res == WIDEN("[1, 2, 3]**") ); + + res = std::format(WIDEN("{:->12}"), makeRange(v1)); + VERIFY( res == WIDEN("---[1, 2, 3]") ); + + res = std::format(WIDEN("{:=^13}"), makeRange(v1)); + VERIFY( res == WIDEN("==[1, 2, 3]==") ); + + res = std::format(WIDEN("{:=^13n}"), makeRange(v1)); + VERIFY( res == WIDEN("===1, 2, 3===") ); + + res = std::format(WIDEN("{::#x}"), makeRange(v1)); + VERIFY( res == WIDEN("[0x1, 0x2, 0x3]") ); + + res = std::format(WIDEN("{:|^25n:#05x}"), makeRange(v1)); + VERIFY( res == WIDEN("|||0x001, 0x002, 0x003|||") ); + + // ':' is start of the format string for element + res = std::format(WIDEN("{::^+04}"), makeRange(v1)); + VERIFY( res == WIDEN("[ +1 , +2 , +3 ]") ); + + size = std::formatted_size(WIDEN("{:}"), makeRange(v1)); + VERIFY( size == Sv(WIDEN("[1, 2, 3]")).size() ); + + size = std::formatted_size(WIDEN("{:3}"), makeRange(v1)); + VERIFY( size == Sv(WIDEN("[1, 2, 3]")).size() ); + + size = std::formatted_size(WIDEN("{:10}"), makeRange(v1)); + VERIFY( size == 10 ); + + size = std::formatted_size(WIDEN("{:|^25n:#05x}"), makeRange(v1)); + VERIFY( size == 25 ); +} + +template<typename Cont> +void test_output_cont() +{ + test_output<char, Cont&, Cont>(); + test_output<wchar_t, Cont const&, Cont>(); +} + +template<typename View> +void test_output_view() +{ + test_output<char, View, int[3]>(); + test_output<wchar_t, View, int[3]>(); +} + +void +test_outputs() +{ + using namespace __gnu_test; + test_output_cont<std::vector<int>>(); + test_output_cont<std::list<int>>(); + test_output_cont<std::array<int, 3>>(); + + test_output_view<std::span<int>>(); + test_output_view<std::ranges::subrange<int*>>(); + test_output_view<test_forward_range<int>>(); + test_output_view<test_input_range<int>>(); + test_output_view<test_input_range_nocopy<int>>(); + + test_output_view<std::span<const int>>(); + test_output_view<std::ranges::subrange<const int*>>(); + test_output_view<test_forward_range<const int>>(); +} + +void +test_nested() +{ + std::vector<std::vector<int>> v + { + {1, 2}, + {11, 12} + }; + + std::string res = std::format("{}", v); + VERIFY( res == "[[1, 2], [11, 12]]" ); + + res = std::format("{:+^18:n:02}", v); + VERIFY( res == "+[01, 02, 11, 12]+" ); +} + +int main() +{ + test_format_string(); + test_outputs(); + test_nested(); +} diff --git a/libstdc++-v3/testsuite/std/format/ranges/string.cc b/libstdc++-v3/testsuite/std/format/ranges/string.cc new file mode 100644 index 0000000..7f59f59 --- /dev/null +++ b/libstdc++-v3/testsuite/std/format/ranges/string.cc @@ -0,0 +1,226 @@ +// { dg-do run { target c++23 } } + +#include <format> +#include <span> +#include <testsuite_hooks.h> +#include <testsuite_iterators.h> +#include <vector> + +template<typename... Args> +bool +is_format_string_for(const char* str, Args&&... args) +{ + try { + (void) std::vformat(str, std::make_format_args(args...)); + return true; + } catch (const std::format_error&) { + return false; + } +} + +template<typename... Args> +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; + } +} + +template<typename Rg, typename CharT> +bool is_range_formatter_spec_for(CharT const* spec, Rg&& rg) +{ + using V = std::remove_cvref_t<std::ranges::range_reference_t<Rg>>; + std::range_formatter<V, CharT> fmt; + std::basic_format_parse_context<CharT> pc(spec); + try { + (void)fmt.parse(pc); + return true; + } catch (const std::format_error&) { + return false; + } +} + +#define WIDEN_(C, S) ::std::__format::_Widen<C>(S, L##S) +#define WIDEN(S) WIDEN_(_CharT, S) + +void +test_format_string() +{ + // only CharT value types are supported + VERIFY( !is_range_formatter_spec_for(L"s", std::vector<char>()) ); + VERIFY( !is_format_string_for(L"{:s}", std::vector<char>()) ); + VERIFY( !is_range_formatter_spec_for(L"s", std::vector<char>()) ); + VERIFY( !is_format_string_for(L"{:s}", std::vector<char>()) ); + VERIFY( !is_range_formatter_spec_for("s", std::vector<int>()) ); + VERIFY( !is_format_string_for("{:s}", std::vector<int>()) ); + + // invalid format stringss + VERIFY( !is_range_formatter_spec_for("?", std::vector<char>()) ); + VERIFY( !is_format_string_for("{:?}", std::vector<char>()) ); + VERIFY( !is_range_formatter_spec_for("ns", std::vector<char>()) ); + VERIFY( !is_format_string_for("{:ns}", std::vector<char>()) ); + VERIFY( !is_range_formatter_spec_for("s:", std::vector<char>()) ); + VERIFY( !is_format_string_for("{:s:}", std::vector<char>()) ); + + // precision is not supported, even for s + VERIFY( !is_range_formatter_spec_for(".10s", std::vector<char>()) ); + VERIFY( !is_format_string_for("{:.10s}", std::vector<char>()) ); + VERIFY( !is_format_string_for("{:.{}s}", std::vector<char>(), 10) ); + + // width needs to be integer type + VERIFY( !is_format_string_for("{:{}s}", std::vector<char>(), 1.0f) ); +} + +template<typename Range> +void test_output() +{ + using _CharT = std::ranges::range_value_t<Range>; + auto makeRange = [](std::basic_string<_CharT>& s) { + return Range(s.data(), s.data() + s.size()); + }; + std::basic_string<_CharT> res; + size_t size = 0; + + std::basic_string<_CharT> s1 = WIDEN("abcd"); + res = std::format(WIDEN("{}"), makeRange(s1)); + VERIFY( res == WIDEN("['a', 'b', 'c', 'd']") ); + + res = std::format(WIDEN("{::}"), makeRange(s1)); + VERIFY( res == WIDEN("[a, b, c, d]") ); + + res = std::format(WIDEN("{:s}"), makeRange(s1)); + VERIFY( res == WIDEN("abcd") ); + + res = std::format(WIDEN("{:?s}"), makeRange(s1)); + VERIFY( res == WIDEN(R"("abcd")") ); + + res = std::format(WIDEN("{:3s}"), makeRange(s1)); + VERIFY( res == WIDEN("abcd") ); + + res = std::format(WIDEN("{:7s}"), makeRange(s1)); + VERIFY( res == WIDEN("abcd ") ); + + res = std::format(WIDEN("{:{}s}"), makeRange(s1), 7); + VERIFY( res == WIDEN("abcd ") ); + + res = std::format(WIDEN("{1:{0}s}"), 7, makeRange(s1)); + VERIFY( res == WIDEN("abcd ") ); + + res = std::format(WIDEN("{:*>6s}"), makeRange(s1)); + VERIFY( res == WIDEN("**abcd") ); + + res = std::format(WIDEN("{:-<5s}"), makeRange(s1)); + VERIFY( res == WIDEN("abcd-") ); + + res = std::format(WIDEN("{:=^8s}"), makeRange(s1)); + VERIFY( res == WIDEN("==abcd==") ); + + std::basic_string<_CharT> s2(512, static_cast<_CharT>('a')); + res = std::format(WIDEN("{:=^8s}"), makeRange(s2)); + VERIFY( res == s2 ); + + size = std::formatted_size(WIDEN("{:s}"), makeRange(s1)); + VERIFY( size == 4 ); + + size = std::formatted_size(WIDEN("{:3s}"), makeRange(s1)); + VERIFY( size == 4 ); + + size = std::formatted_size(WIDEN("{:7s}"), makeRange(s1)); + VERIFY( size == 7 ); + + size = std::formatted_size(WIDEN("{:s}"), makeRange(s2)); + VERIFY( size == 512 ); +} + +template<typename CharT> +struct cstr_view +{ + cstr_view() = default; + explicit cstr_view(CharT* f, CharT* l) + : ptr(f) + { VERIFY(!*l); } + + struct sentinel + { + friend constexpr + bool operator==(CharT const* ptr, sentinel) noexcept + { return !*ptr; } + }; + + constexpr + CharT* begin() const noexcept + { return ptr; }; + static constexpr + sentinel end() noexcept + { return {}; } + +private: + CharT* ptr = ""; +}; + +template<typename CharT> +void +test_outputs() +{ + using namespace __gnu_test; + test_output<std::vector<CharT>>(); + test_output<std::span<CharT>>(); + test_output<cstr_view<CharT>>(); + + test_output<test_forward_range<CharT>>(); + test_output<test_forward_sized_range<CharT>>(); + + test_output<test_input_range<CharT>>(); + test_output<test_input_sized_range<CharT>>(); + + test_output<test_range_nocopy<CharT, input_iterator_wrapper_nocopy>>(); + test_output<test_sized_range<CharT, input_iterator_wrapper_nocopy>>(); + + test_output<std::span<const CharT>>(); + test_output<cstr_view<const CharT>>(); + test_output<test_forward_range<const CharT>>(); + + static_assert(!std::formattable<std::span<volatile CharT>, CharT>); + static_assert(!std::formattable<std::span<const volatile CharT>, CharT>); +} + +void +test_nested() +{ + std::string_view s1 = "str1"; + std::string_view s2 = "str2"; + + std::vector<std::string> vs; + vs.emplace_back(s1); + vs.emplace_back(s2); + + VERIFY( std::format("{}", vs) == R"(["str1", "str2"])" ); + VERIFY( std::format("{:}", vs) == R"(["str1", "str2"])" ); + VERIFY( std::format("{::?}", vs) == R"(["str1", "str2"])" ); + VERIFY( std::format("{::}", vs) == R"([str1, str2])" ); + + std::vector<std::vector<char>> vv; + vv.emplace_back(s1.begin(), s1.end()); + vv.emplace_back(s2.begin(), s2.end()); + std::string_view escaped = R"([['s', 't', 'r', '1'], ['s', 't', 'r', '2']])"; + + VERIFY( std::format("{}", vv) == escaped ); + VERIFY( std::format("{:}", vv) == escaped ); + VERIFY( std::format("{::}", vv) == escaped ); + VERIFY( std::format("{:::?}", vv) == escaped ); + VERIFY( std::format("{:::}", vv) == R"([[s, t, r, 1], [s, t, r, 2]])" ); + VERIFY( std::format("{::s}", vv) == R"([str1, str2])" ); + VERIFY( std::format("{::?s}", vv) == R"(["str1", "str2"])" ); +} + +int main() +{ + test_format_string(); + test_outputs<char>(); + test_outputs<wchar_t>(); + test_nested(); +} diff --git a/libstdc++-v3/testsuite/std/format/tuple.cc b/libstdc++-v3/testsuite/std/format/tuple.cc new file mode 100644 index 0000000..62f9d29 --- /dev/null +++ b/libstdc++-v3/testsuite/std/format/tuple.cc @@ -0,0 +1,259 @@ +// { dg-do run { target c++23 } } + +#include <format> +#include <string> +#include <testsuite_hooks.h> +#include <tuple> +#include <utility> + +struct NotFormattable +{}; + +static_assert( !std::formattable<std::pair<int, NotFormattable>, char> ); +static_assert( !std::formattable<std::tuple<int, NotFormattable, int>, wchar_t> ); + +template<typename... Args> +bool +is_format_string_for(const char* str, Args&&... args) +{ + try { + (void) std::vformat(str, std::make_format_args(args...)); + return true; + } catch (const std::format_error&) { + return false; + } +} + +template<typename... Args> +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; + } +} + +#define WIDEN_(C, S) ::std::__format::_Widen<C>(S, L##S) +#define WIDEN(S) WIDEN_(_CharT, S) + +void +test_format_string() +{ + // invalid format stringss + VERIFY( !is_format_string_for("{:p}", std::tuple<>()) ); + VERIFY( !is_format_string_for("{:nm}", std::tuple<>()) ); + + // 'm' is only valid for 2 elemenst + VERIFY( !is_format_string_for("{:m}", std::tuple<>()) ); + VERIFY( !is_format_string_for("{:m}", std::tuple<int, int, int>()) ); + + // element specifier is not supported + VERIFY( !is_format_string_for("{::}", std::tuple<>()) ); + + // precision is not supported + VERIFY( !is_format_string_for("{:.10}", std::tuple<>()) ); + + // width needs to be integer type + VERIFY( !is_format_string_for("{:{}}", std::tuple<>(), 1.0f) ); +} + +template<typename _CharT> +void test_multi() +{ + using Sv = std::basic_string_view<_CharT>; + using Str = std::basic_string<_CharT>; + + std::basic_string<_CharT> res; + std::size_t size = 0; + std::tuple<int, Str, float> t1(1, WIDEN("test"), 2.1); + + res = std::format(WIDEN("{}"), t1); + VERIFY( res == WIDEN(R"((1, "test", 2.1))") ); + res = std::format(WIDEN("{:}"), t1); + VERIFY( res == WIDEN(R"((1, "test", 2.1))") ); + res = std::format(WIDEN("{:n}"), t1); + VERIFY( res == WIDEN(R"(1, "test", 2.1)") ); + + res = std::format(WIDEN("{:3}"), t1); + VERIFY( res == WIDEN(R"((1, "test", 2.1))") ); + + res = std::format(WIDEN("{:20}"), t1); + VERIFY( res == WIDEN(R"((1, "test", 2.1) )") ); + + res = std::format(WIDEN("{:{}}"), t1, 20); + VERIFY( res == WIDEN(R"((1, "test", 2.1) )") ); + + res = std::format(WIDEN("{1:{0}}"), 20, t1); + VERIFY( res == WIDEN(R"((1, "test", 2.1) )") ); + + res = std::format(WIDEN("{:^>17}"), t1); + VERIFY( res == WIDEN(R"(^(1, "test", 2.1))") ); + + res = std::format(WIDEN("{:$<18}"), t1); + VERIFY( res == WIDEN(R"((1, "test", 2.1)$$)") ); + + res = std::format(WIDEN("{:+^19}"), t1); + VERIFY( res == WIDEN(R"(+(1, "test", 2.1)++)") ); + + res = std::format(WIDEN("{:|^19n}"), t1); + VERIFY( res == WIDEN(R"(||1, "test", 2.1|||)") ); + + size = std::formatted_size(WIDEN("{}"), t1); + VERIFY( size == Sv(WIDEN(R"((1, "test", 2.1))")).size() ); + + size = std::formatted_size(WIDEN("{:3}"), t1); + VERIFY( size == Sv(WIDEN(R"((1, "test", 2.1))")).size() ); + + size = std::formatted_size(WIDEN("{:20}"), t1); + VERIFY( size == 20 ); + + std::tuple<int&, Str&, float&> t2 = t1; + res = std::format(WIDEN("{}"), t2); + VERIFY( res == WIDEN(R"((1, "test", 2.1))") ); + + std::tuple<int, int, int, int> t3(1, 2, 3, 4); + res = std::format(WIDEN("{}"), t3); + VERIFY( res == WIDEN(R"((1, 2, 3, 4))") ); + +} + +template<typename _CharT, typename Tuple> +void test_empty() +{ + std::basic_string<_CharT> res; + + Tuple e1; + res = std::format(WIDEN("{}"), e1); + VERIFY( res == WIDEN(R"(())") ); + + res = std::format(WIDEN("{:}"), e1); + VERIFY( res == WIDEN(R"(())") ); + + res = std::format(WIDEN("{:n}"), e1); + VERIFY( res == WIDEN(R"()") ); + + res = std::format(WIDEN("{:^>6}"), e1); + VERIFY( res == WIDEN(R"(^^^^())") ); +} + +template<typename _CharT, typename Pair> +void test_pair() +{ + using Ft = std::remove_cvref_t<std::tuple_element_t<0, Pair>>; + using St = std::remove_cvref_t<std::tuple_element_t<1, Pair>>; + + std::basic_string<_CharT> res; + + Ft f1 = 1; + St s1 = WIDEN("abc"); + Pair p1(f1, s1); + + res = std::format(WIDEN("{}"), p1); + VERIFY( res == WIDEN(R"((1, "abc"))") ); + + res = std::format(WIDEN("{:}"), p1); + VERIFY( res == WIDEN(R"((1, "abc"))") ); + + res = std::format(WIDEN("{:m}"), p1); + VERIFY( res == WIDEN(R"(1: "abc")") ); + + res = std::format(WIDEN("{:|^12m}"), p1); + VERIFY( res == WIDEN(R"(||1: "abc"||)") ); +} + +template<typename CharT, template<typename, typename> class PairT> +void test_pair_e() +{ + test_pair<CharT, PairT<int, std::basic_string<CharT>>>(); + test_pair<CharT, PairT<int, const CharT*>>(); + test_pair<CharT, PairT<const int, std::basic_string<CharT>>>(); + test_pair<CharT, PairT<int&, std::basic_string<CharT>&>>(); + test_pair<CharT, PairT<const int&, const std::basic_string<CharT>&>>(); +} + +template<typename Pair> +struct MyPair : Pair +{ + using Pair::Pair; +}; + +template<typename Pair, typename CharT> +struct std::formatter<MyPair<Pair>, CharT> +{ + constexpr formatter() noexcept + { + using _CharT = CharT; + _formatter.set_brackets(WIDEN("<"), WIDEN(">")); + _formatter.set_separator(WIDEN("; ")); + } + + constexpr std::basic_format_parse_context<CharT>::iterator + parse(std::basic_format_parse_context<CharT>& pc) + { return _formatter.parse(pc); } + + template<typename Out> + typename std::basic_format_context<Out, CharT>::iterator + format(const MyPair<Pair>& mp, + std::basic_format_context<Out, CharT>& fc) const + { return _formatter.format(mp, fc); } + +private: + std::formatter<Pair, CharT> _formatter; +}; + +template<typename _CharT, template<typename, typename> class PairT> +void test_custom() +{ + std::basic_string<_CharT> res; + MyPair<PairT<int, const _CharT*>> c1(1, WIDEN("abc")); + + res = std::format(WIDEN("{}"), c1); + VERIFY( res == WIDEN(R"(<1; "abc">)") ); + + res = std::format(WIDEN("{:}"), c1); + VERIFY( res == WIDEN(R"(<1; "abc">)") ); + + res = std::format(WIDEN("{:n}"), c1); + VERIFY( res == WIDEN(R"(1; "abc")") ); + + res = std::format(WIDEN("{:m}"), c1); + VERIFY( res == WIDEN(R"(1: "abc")") ); + + res = std::format(WIDEN("{:|^14}"), c1); + VERIFY( res == WIDEN(R"(||<1; "abc">||)") ); +} + +template<typename CharT> +void test_outputs() +{ + test_multi<CharT>(); + test_empty<CharT, std::tuple<>>(); + test_pair_e<CharT, std::pair>(); + test_pair_e<CharT, std::tuple>(); + test_custom<CharT, std::pair>(); + test_custom<CharT, std::tuple>(); +} + +void test_nested() +{ + std::string res; + std::tuple<std::tuple<>, std::pair<int, std::string>> tt{{}, {1, "abc"}}; + + res = std::format("{}", tt); + VERIFY( res == R"(((), (1, "abc")))" ); + res = std::format("{:n}", tt); + VERIFY( res == R"((), (1, "abc"))" ); + res = std::format("{:m}", tt); + VERIFY( res == R"((): (1, "abc"))" ); +} + +int main() +{ + test_format_string(); + test_outputs<char>(); + test_outputs<wchar_t>(); + test_nested(); +} diff --git a/libstdc++-v3/testsuite/util/debug/unordered_checks.h b/libstdc++-v3/testsuite/util/debug/unordered_checks.h index d01ee82..785aeb4 100644 --- a/libstdc++-v3/testsuite/util/debug/unordered_checks.h +++ b/libstdc++-v3/testsuite/util/debug/unordered_checks.h @@ -65,28 +65,36 @@ namespace __gnu_test template<typename _Tp> struct KeyExtractor { - static _Tp get_key(const _Tp& val) + static const _Tp& get_key(const _Tp& val) { return val; } }; template<typename _Tp1, typename _Tp2> - struct KeyExtractor<std::pair<const _Tp1, _Tp2>> + struct KeyExtractor<std::pair<_Tp1, _Tp2>> { - static _Tp1 get_key(const std::pair<const _Tp1, _Tp2>& val) + static const _Tp1& get_key(const std::pair<_Tp1, _Tp2>& val) { return val.first; } }; template<typename _Tp> - void use_erased_local_iterator() + void fill_container(_Tp& c) { typedef _Tp cont_type; typedef typename cont_type::value_type cont_val_type; typedef typename CopyableValueType<cont_val_type>::value_type val_type; generate_unique<val_type> gu; - cont_type c; for (size_t i = 0; i != 5; ++i) c.insert(gu.build()); + } + + template<typename _Tp> + void use_erased_local_iterator() + { + typedef _Tp cont_type; + typedef typename cont_type::value_type cont_val_type; + cont_type c; + fill_container(c); typename cont_type::local_iterator it, end; for (size_t i = 0; i != c.bucket_count(); ++i) @@ -96,22 +104,18 @@ namespace __gnu_test if (it != end) break; } - typename cont_type::key_type key = KeyExtractor<cont_val_type>::get_key(*it); + + const auto& key = KeyExtractor<cont_val_type>::get_key(*it); c.erase(key); VERIFY( it != end ); } template<typename _Tp> - void use_invalid_local_iterator() + typename _Tp::local_iterator + fill_and_get_local_iterator(_Tp& c) { typedef _Tp cont_type; - typedef typename cont_type::value_type cont_val_type; - typedef typename CopyableValueType<cont_val_type>::value_type val_type; - generate_unique<val_type> gu; - - cont_type c; - for (size_t i = 0; i != 5; ++i) - c.insert(gu.build()); + fill_container(c); typename cont_type::local_iterator it; for (size_t i = 0; i != c.bucket_count(); ++i) @@ -120,22 +124,107 @@ namespace __gnu_test if (it != c.end(i)) break; } - cont_val_type val = *it; + + return it; + } + + template<typename _Tp> + void use_invalid_local_iterator() + { + typedef _Tp cont_type; + cont_type c; + auto it = fill_and_get_local_iterator(c); + + const auto& val = *it; c.clear(); VERIFY( *it == val ); } template<typename _Tp> - void invalid_local_iterator_pre_increment() + void invalid_local_iterator_arrow_operator() { typedef _Tp cont_type; - typedef typename cont_type::value_type cont_val_type; - typedef typename CopyableValueType<cont_val_type>::value_type val_type; - generate_unique<val_type> gu; + cont_type c; + auto it = fill_and_get_local_iterator(c); + + const auto& val = *it; + c.clear(); + VERIFY( *it.operator->() == val ); + } + template<typename _Tp> + void invalid_local_iterator_copy_construction() + { + typedef _Tp cont_type; cont_type c; - for (size_t i = 0; i != 5; ++i) - c.insert(gu.build()); + auto it = fill_and_get_local_iterator(c); + + const auto& val = *it; + c.clear(); + typename cont_type::local_iterator lit(it); + VERIFY( *lit == val ); + } + + template<typename _Tp> + void invalid_local_iterator_move_construction() + { + typedef _Tp cont_type; + cont_type c; + auto it = fill_and_get_local_iterator(c); + + const auto& val = *it; + c.clear(); + typename cont_type::local_iterator lit(std::move(it)); + VERIFY( *lit == val ); + } + + template<typename _Tp> + void invalid_local_iterator_copy_assignment() + { + typedef _Tp cont_type; + cont_type c; + auto it = fill_and_get_local_iterator(c); + + const auto& val = *it; + c.clear(); + typename cont_type::local_iterator lit; + lit = it; + VERIFY( *lit == val ); + } + + template<typename _Tp> + void invalid_local_iterator_move_assignment() + { + typedef _Tp cont_type; + cont_type c; + auto it = fill_and_get_local_iterator(c); + + const auto& val = *it; + c.clear(); + typename cont_type::local_iterator lit; + lit = std::move(it); + VERIFY( *lit == val ); + } + + template<typename _Tp> + void invalid_local_iterator_const_conversion() + { + typedef _Tp cont_type; + cont_type c; + auto it = fill_and_get_local_iterator(c); + + const auto& val = *it; + c.clear(); + typename cont_type::const_local_iterator clit(it); + VERIFY( *clit == val ); + } + + template<typename _Tp> + void invalid_local_iterator_pre_increment() + { + typedef _Tp cont_type; + cont_type c; + fill_container(c); auto lit = c.begin(0); for (size_t i = 0; i != 6; ++i) @@ -146,13 +235,8 @@ namespace __gnu_test void invalid_local_iterator_post_increment() { typedef _Tp cont_type; - typedef typename cont_type::value_type cont_val_type; - typedef typename CopyableValueType<cont_val_type>::value_type val_type; - generate_unique<val_type> gu; - cont_type c; - for (size_t i = 0; i != 5; ++i) - c.insert(gu.build()); + fill_container(c); auto lit = c.begin(0); for (size_t i = 0; i != 6; ++i) @@ -163,13 +247,8 @@ namespace __gnu_test void invalid_local_iterator_compare() { typedef _Tp cont_type; - typedef typename cont_type::value_type cont_val_type; - typedef typename CopyableValueType<cont_val_type>::value_type val_type; - generate_unique<val_type> gu; - cont_type c; - for (size_t i = 0; i != 5; ++i) - c.insert(gu.build()); + fill_container(c); typename cont_type::local_iterator it1, it2; size_t i; @@ -194,13 +273,8 @@ namespace __gnu_test void invalid_local_iterator_range() { typedef _Tp cont_type; - typedef typename cont_type::value_type cont_val_type; - typedef typename CopyableValueType<cont_val_type>::value_type val_type; - generate_unique<val_type> gu; - cont_type c; - for (size_t i = 0; i != 5; ++i) - c.insert(gu.build()); + fill_container(c); typename cont_type::local_iterator it, end; for (size_t i = 0; i != c.bucket_count(); ++i) diff --git a/libstdc++-v3/testsuite/util/testsuite_iterators.h b/libstdc++-v3/testsuite/util/testsuite_iterators.h index 0df6dcc..74a8739 100644 --- a/libstdc++-v3/testsuite/util/testsuite_iterators.h +++ b/libstdc++-v3/testsuite/util/testsuite_iterators.h @@ -610,12 +610,10 @@ namespace __gnu_test test_container(T* _first, T* _last) : bounds(_first, _last) { } -#if __cplusplus >= 201103L template<std::size_t N> explicit - test_container(T (&arr)[N]) : test_container(arr, arr+N) + test_container(T (&arr)[N]) : bounds(arr, arr+N) { } -#endif ItType<T> it(int pos) @@ -894,6 +892,9 @@ namespace __gnu_test using test_input_range = test_range<T, input_iterator_wrapper>; template<typename T> + using test_input_range_nocopy + = test_range_nocopy<T, input_iterator_wrapper_nocopy>; + template<typename T> using test_output_range = test_range<T, output_iterator_wrapper>; diff --git a/maintainer-scripts/ChangeLog b/maintainer-scripts/ChangeLog index d08a03b..3c33199 100644 --- a/maintainer-scripts/ChangeLog +++ b/maintainer-scripts/ChangeLog @@ -1,3 +1,8 @@ +2025-04-17 Jakub Jelinek <jakub@redhat.com> + + * crontab: Snapshots from trunk are now GCC 16 related. + Add GCC 15 snapshots from the respective branch. + 2025-04-07 Jakub Jelinek <jakub@redhat.com> PR web/119227 diff --git a/maintainer-scripts/crontab b/maintainer-scripts/crontab index 7bb7362..c880d7d 100644 --- a/maintainer-scripts/crontab +++ b/maintainer-scripts/crontab @@ -1,7 +1,8 @@ 16 0 * * * sh /home/gccadmin/scripts/update_version_git 50 0 * * * sh /home/gccadmin/scripts/update_web_docs_git 55 0 * * * sh /home/gccadmin/scripts/update_web_docs_libstdcxx_git -32 22 * * 4 sh /home/gccadmin/scripts/gcc_release -s 12:releases/gcc-12 -l -d /sourceware/snapshot-tmp/gcc all -32 22 * * 5 sh /home/gccadmin/scripts/gcc_release -s 13:releases/gcc-13 -l -d /sourceware/snapshot-tmp/gcc all -32 22 * * 6 sh /home/gccadmin/scripts/gcc_release -s 14:releases/gcc-14 -l -d /sourceware/snapshot-tmp/gcc all -32 22 * * 7 sh /home/gccadmin/scripts/gcc_release -s 15:master -l -d /sourceware/snapshot-tmp/gcc all +32 22 * * 3 sh /home/gccadmin/scripts/gcc_release -s 12:releases/gcc-12 -l -d /sourceware/snapshot-tmp/gcc all +32 22 * * 4 sh /home/gccadmin/scripts/gcc_release -s 13:releases/gcc-13 -l -d /sourceware/snapshot-tmp/gcc all +32 22 * * 5 sh /home/gccadmin/scripts/gcc_release -s 14:releases/gcc-14 -l -d /sourceware/snapshot-tmp/gcc all +32 22 * * 6 sh /home/gccadmin/scripts/gcc_release -s 15:releases/gcc-15 -l -d /sourceware/snapshot-tmp/gcc all +32 22 * * 7 sh /home/gccadmin/scripts/gcc_release -s 16:master -l -d /sourceware/snapshot-tmp/gcc all |