diff options
author | Martin Liska <mliska@suse.cz> | 2021-08-18 15:50:28 +0200 |
---|---|---|
committer | Martin Liska <mliska@suse.cz> | 2021-08-18 15:50:28 +0200 |
commit | 60ae041aae40e239fda5fbf6f4c4ec047ce50962 (patch) | |
tree | 3705119982c7fe7577a66fc0bdf6539e0694e243 /gcc | |
parent | 7d5bfcbfd3f9074e48e78b82c60d9b5aca5011a0 (diff) | |
parent | f74433e70ae94a3b5291e45fea488b1cfdee4a34 (diff) | |
download | gcc-60ae041aae40e239fda5fbf6f4c4ec047ce50962.zip gcc-60ae041aae40e239fda5fbf6f4c4ec047ce50962.tar.gz gcc-60ae041aae40e239fda5fbf6f4c4ec047ce50962.tar.bz2 |
Merge branch 'master' into devel/sphinx
Diffstat (limited to 'gcc')
328 files changed, 16875 insertions, 3125 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index e2ffd84..b26f256 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,929 @@ +2021-08-17 Andrew MacLeod <amacleod@redhat.com> + + * gimple-range-gori.cc (gori_compute::gori_compute): Enable tracing. + (gori_compute::compute_operand_range): Add tracing. + (gori_compute::logical_combine): Ditto. + (gori_compute::compute_logical_operands): Ditto. + (gori_compute::compute_operand1_range): Ditto. + (gori_compute::compute_operand2_range): Ditto. + (gori_compute::outgoing_edge_range_p): Ditto. + * gimple-range-gori.h (class gori_compute): Add range_tracer. + +2021-08-17 Andrew MacLeod <amacleod@redhat.com> + + * flag-types.h (enum evrp_mode): Adjust evrp-mode values. + * gimple-range-cache.cc (DEBUG_RANGE_CACHE): Relocate from. + * gimple-range-trace.h (DEBUG_RANGE_CACHE): Here. + * params.opt (--param=evrp-mode): Adjust options. + +2021-08-17 Andrew MacLeod <amacleod@redhat.com> + + * Makefile.in (OBJS): Add gimple-range-trace.o. + * gimple-range-cache.h (enable_new_values): Remove unused prototype. + * gimple-range-fold.cc: Adjust headers. + * gimple-range-trace.cc: New. + * gimple-range-trace.h: New. + * gimple-range.cc (gimple_ranger::gimple_ranger): Enable tracer. + (gimple_ranger::range_of_expr): Add tracing. + (gimple_ranger::range_on_entry): Ditto. + (gimple_ranger::range_on_exit): Ditto. + (gimple_ranger::range_on_edge): Ditto. + (gimple_ranger::fold_range_internal): Ditto. + (gimple_ranger::dump_bb): Do not calculate edge range twice. + (trace_ranger::*): Remove. + (enable_ranger): Never create a trace_ranger. + (debug_seed_ranger): Move to gimple-range-trace.cc. + (dump_ranger): Ditto. + (debug_ranger): Ditto. + * gimple-range.h: Include gimple-range-trace.h. + (range_on_entry, range_on_exit): No longer virtual. + (class trace_ranger): Remove. + (DEBUG_RANGE_CACHE): Move to gimple-range-trace.h. + +2021-08-17 Martin Sebor <msebor@redhat.com> + + PR middle-end/101854 + * builtins.c (expand_builtin_alloca): Move warning code to check_alloca + in gimple-ssa-warn-access.cc. + * calls.c (alloc_max_size): Move code to check_alloca. + (get_size_range): Move to pointer-query.cc. + (maybe_warn_alloc_args_overflow): Move to gimple-ssa-warn-access.cc. + (get_attr_nonstring_decl): Move to tree.c. + (fntype_argno_type): Move to gimple-ssa-warn-access.cc. + (append_attrname): Same. + (maybe_warn_rdwr_sizes): Same. + (initialize_argument_information): Move code to + gimple-ssa-warn-access.cc. + * calls.h (maybe_warn_alloc_args_overflow): Move to + gimple-ssa-warn-access.h. + (get_attr_nonstring_decl): Move to tree.h. + (maybe_warn_nonstring_arg): Move to gimple-ssa-warn-access.h. + (enum size_range_flags): Move to pointer-query.h. + (get_size_range): Same. + * gimple-ssa-warn-access.cc (has_location): Remove unused overload + to avoid Clang -Wunused-function. + (get_size_range): Declare static. + (maybe_emit_free_warning): Rename... + (maybe_check_dealloc_call): ...to this for consistency. + (class pass_waccess): Add members. + (pass_waccess::~pass_waccess): Defined. + (alloc_max_size): Move here from calls.c. + (maybe_warn_alloc_args_overflow): Same. + (check_alloca): New function. + (check_alloc_size_call): New function. + (check_strncat): Handle another warning flag. + (pass_waccess::check_builtin): Handle alloca. + (fntype_argno_type): Move here from calls.c. + (append_attrname): Same. + (maybe_warn_rdwr_sizes): Same. + (pass_waccess::check_call): Define. + (check_nonstring_args): New function. + (pass_waccess::check): Call new member functions. + (pass_waccess::execute): Enable ranger. + * gimple-ssa-warn-access.h (get_size_range): Move here from calls.h. + (maybe_warn_nonstring_arg): Same. + * gimple-ssa-warn-restrict.c: Remove #include. + * pointer-query.cc (get_size_range): Move here from calls.c. + * pointer-query.h (enum size_range_flags): Same. + (get_size_range): Same. + * tree.c (get_attr_nonstring_decl): Move here from calls.c. + * tree.h (get_attr_nonstring_decl): Move here from calls.h. + +2021-08-17 Thomas Schwinge <thomas@codesourcery.com> + + * ggc.h (ggc_collect): Add 'force_collect' parameter. + * ggc-page.c (ggc_collect): Use that one instead of global + 'ggc_force_collect'. Adjust all users. + * doc/gty.texi (Invoking the garbage collector): Update. + * ggc-internal.h (ggc_force_collect): Remove. + * ggc-common.c (ggc_force_collect): Likewise. + * selftest.h (forcibly_ggc_collect): Remove. + * ggc-tests.c (selftest::forcibly_ggc_collect): Likewise. + * read-rtl-function.c (test_loading_labels): Adjust. + * selftest-run-tests.c (run_tests): Likewise. + +2021-08-17 Iain Sandoe <iain@sandoe.co.uk> + + * config/darwin.c (darwin_file_end): Reset and reclaim the + section names table at the end of compile. + +2021-08-17 Iain Sandoe <iain@sandoe.co.uk> + + PR target/100340 + * config.in: Regenerate. + * config/i386/darwin.h (EXTRA_ASM_OPTS): New + (ASM_SPEC): Pass options to disable branch shortening where + needed. + * configure: Regenerate. + * configure.ac: Detect versions of 'as' that support the + optimisation which has the bug. + +2021-08-17 Richard Biener <rguenther@suse.de> + + * optabs-query.c (supports_vec_gather_load_p): Also check + for masked optabs. + (supports_vec_scatter_store_p): Likewise. + * tree-vect-data-refs.c (vect_gather_scatter_fn_p): Fall + back to masked variants if non-masked are not supported. + * tree-vect-patterns.c (vect_recog_gather_scatter_pattern): + When we need to use masked gather/scatter but do not have + a mask set up a constant true one. + * tree-vect-stmts.c (vect_check_scalar_mask): Also allow + non-SSA_NAME masks. + +2021-08-17 Roger Sayle <roger@nextmovesoftware.com> + + * tree-ssa-ccp.c (bit_value_binop) [MINUS_EXPR]: Use same + algorithm as PLUS_EXPR to improve subtraction bit bounds. + [POINTER_DIFF_EXPR]: Treat as synonymous with MINUS_EXPR. + +2021-08-17 Roger Sayle <roger@nextmovesoftware.com> + + * tree-ssa-ccp.c (bit_value_mult_const): New helper function to + calculate the mask-value pair result of a multiplication by an + unsigned constant. + (bit_value_binop) [MULT_EXPR]: Call it from here for + multiplications by (sparse) non-negative constants. + +2021-08-17 Christophe Lyon <christophe.lyon@foss.st.com> + + PR target/100896 + * config.gcc (gcc_cv_initfini_array): Leave undefined for + uclinuxfdpiceabi targets. + +2021-08-17 Alexandre Oliva <oliva@adacore.com> + + * tree-inline.c (maybe_move_debug_stmts_to_successors): Don't + reverse debug stmts. + +2021-08-17 Alexandre Oliva <oliva@adacore.com> + + * tree-cfg.c (dump_function_to_file): Use fun, not cfun. + +2021-08-17 Jonathan Wright <jonathan.wright@arm.com> + + * config/aarch64/arm_neon.h (__LD4_LANE_FUNC): Delete. + (__LD4Q_LANE_FUNC): Likewise. + (vld4_lane_u8): Define without macro. + (vld4_lane_u16): Likewise. + (vld4_lane_u32): Likewise. + (vld4_lane_u64): Likewise. + (vld4_lane_s8): Likewise. + (vld4_lane_s16): Likewise. + (vld4_lane_s32): Likewise. + (vld4_lane_s64): Likewise. + (vld4_lane_f16): Likewise. + (vld4_lane_f32): Likewise. + (vld4_lane_f64): Likewise. + (vld4_lane_p8): Likewise. + (vld4_lane_p16): Likewise. + (vld4_lane_p64): Likewise. + (vld4q_lane_u8): Likewise. + (vld4q_lane_u16): Likewise. + (vld4q_lane_u32): Likewise. + (vld4q_lane_u64): Likewise. + (vld4q_lane_s8): Likewise. + (vld4q_lane_s16): Likewise. + (vld4q_lane_s32): Likewise. + (vld4q_lane_s64): Likewise. + (vld4q_lane_f16): Likewise. + (vld4q_lane_f32): Likewise. + (vld4q_lane_f64): Likewise. + (vld4q_lane_p8): Likewise. + (vld4q_lane_p16): Likewise. + (vld4q_lane_p64): Likewise. + (vld4_lane_bf16): Likewise. + (vld4q_lane_bf16): Likewise. + +2021-08-17 Jonathan Wright <jonathan.wright@arm.com> + + * config/aarch64/arm_neon.h (__LD3_LANE_FUNC): Delete. + (__LD3Q_LANE_FUNC): Delete. + (vld3_lane_u8): Define without macro. + (vld3_lane_u16): Likewise. + (vld3_lane_u32): Likewise. + (vld3_lane_u64): Likewise. + (vld3_lane_s8): Likewise. + (vld3_lane_s16): Likewise. + (vld3_lane_s32): Likewise. + (vld3_lane_s64): Likewise. + (vld3_lane_f16): Likewise. + (vld3_lane_f32): Likewise. + (vld3_lane_f64): Likewise. + (vld3_lane_p8): Likewise. + (vld3_lane_p16): Likewise. + (vld3_lane_p64): Likewise. + (vld3q_lane_u8): Likewise. + (vld3q_lane_u16): Likewise. + (vld3q_lane_u32): Likewise. + (vld3q_lane_u64): Likewise. + (vld3q_lane_s8): Likewise. + (vld3q_lane_s16): Likewise. + (vld3q_lane_s32): Likewise. + (vld3q_lane_s64): Likewise. + (vld3q_lane_f16): Likewise. + (vld3q_lane_f32): Likewise. + (vld3q_lane_f64): Likewise. + (vld3q_lane_p8): Likewise. + (vld3q_lane_p16): Likewise. + (vld3q_lane_p64): Likewise. + (vld3_lane_bf16): Likewise. + (vld3q_lane_bf16): Likewise. + +2021-08-17 Jonathan Wright <jonathan.wright@arm.com> + + * config/aarch64/arm_neon.h (__LD2_LANE_FUNC): Delete. + (__LD2Q_LANE_FUNC): Likewise. + (vld2_lane_u8): Define without macro. + (vld2_lane_u16): Likewise. + (vld2_lane_u32): Likewise. + (vld2_lane_u64): Likewise. + (vld2_lane_s8): Likewise. + (vld2_lane_s16): Likewise. + (vld2_lane_s32): Likewise. + (vld2_lane_s64): Likewise. + (vld2_lane_f16): Likewise. + (vld2_lane_f32): Likewise. + (vld2_lane_f64): Likewise. + (vld2_lane_p8): Likewise. + (vld2_lane_p16): Likewise. + (vld2_lane_p64): Likewise. + (vld2q_lane_u8): Likewise. + (vld2q_lane_u16): Likewise. + (vld2q_lane_u32): Likewise. + (vld2q_lane_u64): Likewise. + (vld2q_lane_s8): Likewise. + (vld2q_lane_s16): Likewise. + (vld2q_lane_s32): Likewise. + (vld2q_lane_s64): Likewise. + (vld2q_lane_f16): Likewise. + (vld2q_lane_f32): Likewise. + (vld2q_lane_f64): Likewise. + (vld2q_lane_p8): Likewise. + (vld2q_lane_p16): Likewise. + (vld2q_lane_p64): Likewise. + (vld2_lane_bf16): Likewise. + (vld2q_lane_bf16): Likewise. + +2021-08-17 Maxim Kuvyrkov <maxim.kuvyrkov@linaro.org> + + * haifa-sched.c (advance_one_cycle): Output more context-synchronization + lines for diff. + +2021-08-17 Maxim Kuvyrkov <maxim.kuvyrkov@linaro.org> + + * haifa-sched.c (enum rfs_decision, rfs_str): Add RFS_AUTOPREF. + (rank_for_schedule): Use it. + +2021-08-17 Maxim Kuvyrkov <maxim.kuvyrkov@linaro.org> + + PR rtl-optimization/91598 + * haifa-sched.c (autopref_rank_for_schedule): Prioritize "irrelevant" + insns after memory reads and before memory writes. + +2021-08-17 Alistair_Lee <alistair.lee@arm.com> + + * rtl.h (CONST_VECTOR_P): New macro. + * config/aarch64/aarch64.c (aarch64_get_sve_pred_bits): Use RTL + code testing macros. + (aarch64_ptrue_all_mode): Likewise. + (aarch64_expand_mov_immediate): Likewise. + (aarch64_const_vec_all_in_range_p): Likewise. + (aarch64_rtx_costs): Likewise. + (aarch64_legitimate_constant_p): Likewise. + (aarch64_simd_valid_immediate): Likewise. + (aarch64_simd_make_constant): Likewise. + (aarch64_convert_mult_to_shift): Likewise. + (aarch64_expand_sve_vec_perm): Likewise. + (aarch64_vec_fpconst_pow_of_2): Likewise. + +2021-08-17 Andrew MacLeod <amacleod@redhat.com> + + PR tree-optimization/101938 + * range-op.cc (operator_abs::op1_range): Special case + -TYPE_MIN_VALUE for flag_wrapv. + +2021-08-17 Kewen Lin <linkw@linux.ibm.com> + + * tree-vect-slp.c (vectorizable_bb_reduc_epilogue): Add the cost for + value extraction. + +2021-08-17 Jakub Jelinek <jakub@redhat.com> + + * tree.def (OMP_SCOPE): New tree code. + * tree.h (OMP_SCOPE_BODY, OMP_SCOPE_CLAUSES): Define. + * tree-nested.c (convert_nonlocal_reference_stmt, + convert_local_reference_stmt, convert_gimple_call): Handle + GIMPLE_OMP_SCOPE. + * tree-pretty-print.c (dump_generic_node): Handle OMP_SCOPE. + * gimple.def (GIMPLE_OMP_SCOPE): New gimple code. + * gimple.c (gimple_build_omp_scope): New function. + (gimple_copy): Handle GIMPLE_OMP_SCOPE. + * gimple.h (gimple_build_omp_scope): Declare. + (gimple_has_substatements): Handle GIMPLE_OMP_SCOPE. + (gimple_omp_scope_clauses, gimple_omp_scope_clauses_ptr, + gimple_omp_scope_set_clauses): New inline functions. + (CASE_GIMPLE_OMP): Add GIMPLE_OMP_SCOPE. + * gimple-pretty-print.c (dump_gimple_omp_scope): New function. + (pp_gimple_stmt_1): Handle GIMPLE_OMP_SCOPE. + * gimple-walk.c (walk_gimple_stmt): Likewise. + * gimple-low.c (lower_stmt): Likewise. + * gimplify.c (is_gimple_stmt): Handle OMP_MASTER. + (gimplify_scan_omp_clauses): For task reductions, handle OMP_SCOPE + like ORT_WORKSHARE constructs. Adjust diagnostics for %<scope%> + allowing task reductions. Reject inscan reductions on scope. + (omp_find_stores_stmt): Handle GIMPLE_OMP_SCOPE. + (gimplify_omp_workshare, gimplify_expr): Handle OMP_SCOPE. + * tree-inline.c (remap_gimple_stmt): Handle GIMPLE_OMP_SCOPE. + (estimate_num_insns): Likewise. + * omp-low.c (build_outer_var_ref): Look through GIMPLE_OMP_SCOPE + contexts if var isn't privatized there. + (check_omp_nesting_restrictions): Handle GIMPLE_OMP_SCOPE. + (scan_omp_1_stmt): Likewise. + (maybe_add_implicit_barrier_cancel): Look through outer + scope constructs. + (lower_omp_scope): New function. + (lower_omp_task_reductions): Handle OMP_SCOPE. + (lower_omp_1): Handle GIMPLE_OMP_SCOPE. + (diagnose_sb_1, diagnose_sb_2): Likewise. + * omp-expand.c (expand_omp_single): Support also GIMPLE_OMP_SCOPE. + (expand_omp): Handle GIMPLE_OMP_SCOPE. + (omp_make_gimple_edges): Likewise. + * omp-builtins.def (BUILT_IN_GOMP_SCOPE_START): New built-in. + +2021-08-17 Richard Biener <rguenther@suse.de> + + PR tree-optimization/101925 + * tree-ssa-sccvn.c (copy_reference_ops_from_ref): Set + reverse on COMPONENT_REF and ARRAY_REF according to + what reverse_storage_order_for_component_p does. + (vn_reference_eq): Compare reversed on reference ops. + (reverse_storage_order_for_component_p): New overload. + (vn_reference_lookup_3): Check reverse_storage_order_for_component_p + on the reference looked up. + +2021-08-17 Jeff Law <jlaw@localhost.localdomain> + + * config/h8300/h8300.c (shift_alg_si): Avoid loops for most SImode + shifts on the H8/S. + (h8300_option_override): Use loops on H8/S more often when optimizing + for size. + (get_shift_alg): Handle new "special" cases on H8/S. Simplify + accordingly. Handle various arithmetic right shifts with special + sequences that we couldn't handle before. + +2021-08-16 Jeff Law <jlaw@localhost.localdomain> + + * config.gcc (rl78-*-elf*): Do not include dbxelf.h. + +2021-08-16 Sebastian Huber <sebastian.huber@embedded-brains.de> + + * config/sparc/rtemself.h (SPARC_GCOV_TYPE_SIZE): Define. + * config/sparc/sparc.c (sparc_gcov_type_size): New. + (TARGET_GCOV_TYPE_SIZE): Redefine if SPARC_GCOV_TYPE_SIZE is defined. + * coverage.c (get_gcov_type): Use targetm.gcov_type_size(). + * doc/tm.texi (TARGET_GCOV_TYPE_SIZE): Add hook under "Misc". + * doc/tm.texi.in: Regenerate. + * target.def (gcov_type_size): New target hook. + * targhooks.c (default_gcov_type_size): New. + * targhooks.h (default_gcov_type_size): Declare. + * tree-profile.c (gimple_gen_edge_profiler): Use precision of + gcov_type_node. + (gimple_gen_time_profiler): Likewise. + +2021-08-16 Eric Botcazou <ebotcazou@gcc.gnu.org> + + * dwarf2out.c (add_scalar_info): Deal with DW_AT_data_bit_offset. + +2021-08-16 Tobias Burnus <tobias@codesourcery.com> + + PR middle-end/101931 + * omp-low.c (omp_runtime_api_call): Update for routines + added in the meanwhile. + +2021-08-16 Martin Liska <mliska@suse.cz> + + PR tree-optimization/100393 + * tree-switch-conversion.c (group_cluster::dump): Use + get_comparison_count. + (jump_table_cluster::find_jump_tables): Pre-compute number of + comparisons and then decrement it. Cache also max_ratio. + (jump_table_cluster::can_be_handled): Change signature. + * tree-switch-conversion.h (get_comparison_count): New. + +2021-08-16 Eric Botcazou <ebotcazou@gcc.gnu.org> + + * dwarf2out.c (add_data_member_location_attribute): Use GNAT + encodings only when -fgnat-encodings=all is specified. + (add_bound_info): Likewise. + (add_byte_size_attribute): Likewise. + (gen_member_die): Likewise. + +2021-08-16 Thomas Schwinge <thomas@codesourcery.com> + + * omp-oacc-neuter-broadcast.cc + (execute_omp_oacc_neuter_broadcast): Plug 'par' memory leak. + +2021-08-16 Thomas Schwinge <thomas@codesourcery.com> + + * omp-oacc-neuter-broadcast.cc + (execute_omp_oacc_neuter_broadcast): Clarify memory management for + 'prop_set'. + +2021-08-16 Thomas Schwinge <thomas@codesourcery.com> + + * omp-oacc-neuter-broadcast.cc (field_map): Move variable into... + (execute_omp_oacc_neuter_broadcast): ... here. + (install_var_field, build_receiver_ref, build_sender_ref): Take + 'field_map_t *' parameter. Adjust all users. + (worker_single_copy, neuter_worker_single): Take a + 'record_field_map_t *' parameter. Adjust all users. + +2021-08-16 liuhongt <hongtao.liu@intel.com> + + PR target/101930 + * config/i386/i386.md (ldexp<mode>3): Force operands[1] to + reg. + +2021-08-16 Martin Liska <mliska@suse.cz> + + PR ipa/101726 + * multiple_target.c (create_dispatcher_calls): Make default + function local only if it is a definition. + +2021-08-16 Martin Liska <mliska@suse.cz> + + PR ipa/100600 + * ipa-icf-gimple.c (func_checker::compare_ssa_name): Do not + consider equal SSA_NAMEs when one is a param. + +2021-08-16 liuhongt <hongtao.liu@intel.com> + + PR target/101846 + * config/i386/i386-expand.c (ix86_expand_vec_perm_vpermt2): + Support vpermi2b for V32QI/V16QImode. + (ix86_extract_perm_from_pool_constant): New function. + (ix86_expand_vec_one_operand_perm_avx512): Support + vpermw/vpermb under TARGET_AVX512BW/TARGET_AVX512VBMI. + (expand_vec_perm_1): Adjust comments for upper. + * config/i386/i386-protos.h (ix86_extract_perm_from_pool_constant): + New declare. + * config/i386/predicates.md (permvar_truncate_operand): New predicate. + (pshufb_truncv4siv4hi_operand): Ditto. + (pshufb_truncv8hiv8qi_operand): Ditto. + * config/i386/sse.md (*avx512bw_permvar_truncv16siv16hi_1): + New pre_reload define_insn_and_split. + (*avx512f_permvar_truncv8siv8hi_1): Ditto. + (*avx512f_vpermvar_truncv8div8si_1): Ditto. + (*avx512f_permvar_truncv32hiv32qi_1): Ditto. + (*avx512f_permvar_truncv16hiv16qi_1): Ditto. + (*avx512f_permvar_truncv4div4si_1): Ditto. + (*avx512f_pshufb_truncv8hiv8qi_1): Ditto. + (*avx512f_pshufb_truncv4siv4hi_1): Ditto. + (*avx512f_pshufd_truncv2div2si_1): Ditto. + +2021-08-16 Kito Cheng <kito.cheng@sifive.com> + + * config/riscv/multilib-generator: Support code model option for + multi-lib. + * doc/install.texi: Add document of new option for + --with-multilib-generator. + +2021-08-15 Clément Chigot <clement.chigot@atos.net> + + * config/rs6000/rs6000.c (xcoff_tls_exec_model_detected): New. + (rs6000_legitimize_tls_address_aix): Use it. + (rs6000_xcoff_file_end): Add ".ref __tls_get_addr" when + xcoff_tls_exec_model_detected is true. + +2021-08-15 Jeff Law <jlaw@localhost.localdomain> + + * config/h8300/h8300.c (shift_alg_si): Retune H8/300H shifts + to allow a bit more code growth, saving many dozens of cycles. + (h8300_option_override): Adjus shift_alg_si if optimizing for + code size. + (get_shift_alg): Use special + inline shifts for residuals + in more cases. + +2021-08-14 Stafford Horne <shorne@gmail.com> + + PR target/99783 + * config/or1k/or1k-opts.h: New file. + * config/or1k/or1k.c (or1k_legitimize_address_1, print_reloc): + Support generating gotha relocations if -mcmodel=large is + specified. + * config/or1k/or1k.h (TARGET_CMODEL_SMALL, TARGET_CMODEL_LARGE): + New macros. + * config/or1k/or1k.opt (mcmodel=): New option. + * doc/invoke.texi (OpenRISC Options): Document mcmodel. + +2021-08-14 Martin Sebor <msebor@redhat.com> + + PR middle-end/101791 + * gimple-ssa-warn-access.cc (new_delete_mismatch_p): Use new argument + to valid_new_delete_pair_p. + * tree.c (valid_new_delete_pair_p): Add argument. + * tree.h (valid_new_delete_pair_p): Same. + +2021-08-14 Jakub Jelinek <jakub@redhat.com> + + PR target/101896 + * config/i386/i386-expand.c (expand_vec_perm_broadcast_1) + <case E_V64QImode>: For this mode assert + !TARGET_AVX512BW || d->perm[0] rather than !TARGET_AVX2 || d->perm[0]. + +2021-08-13 Michael Meissner <meissner@linux.ibm.com> + + PR target/99921 + * config/rs6000/altivec.md (xxeval): Use register_predicate + instead of altivec_register_predicate. + +2021-08-13 Martin Sebor <msebor@redhat.com> + + PR middle-end/101734 + * tree-ssa-uninit.c (maybe_warn_read_write_only): New function. + (maybe_warn_operand): Call it. + +2021-08-13 Martin Liska <mliska@suse.cz> + + PR ipa/101354 + * attribs.c (decl_attributes): Make naked functions "noipa" + functions. + +2021-08-13 Martin Liska <mliska@suse.cz> + + PR ipa/101261 + * symtab.c (symtab_node::noninterposable_alias): Do not create + local aliases for target_clone functions as the clonning pass + rejects aliases. + +2021-08-13 Martin Liska <mliska@suse.cz> + + * opts.c (LIVE_PATCHING_OPTION): Define. + (control_options_for_live_patching): Use it in error messages. + +2021-08-13 Jan Hubicka <hubicka@ucw.cz> + + * ipa-modref.c (dump_eaf_flags): Dump EAF_NOREAD. + (implicit_const_eaf_flags, implicit_pure_eaf_flags, + ignore_stores_eaf_flags): New constants. + (remove_useless_eaf_flags): New function. + (eaf_flags_useful_p): Use it. + (deref_flags): Add EAF_NOT_RETURNED if flag is unused; + handle EAF_NOREAD. + (modref_lattice::init): Add EAF_NOREAD. + (modref_lattice::add_escape_point): Do not reacord escape point if + result is unused. + (modref_lattice::merge): EAF_NOESCAPE implies EAF_NODIRECTESCAPE; + use remove_useless_eaf_flags. + (modref_lattice::merge_deref): Use ignore_stores_eaf_flags. + (modref_lattice::merge_direct_load): Add EAF_NOREAD + (analyze_ssa_name_flags): Fix handling EAF_NOT_RETURNED + (analyze_parms): Use remove_useless_eaf_flags. + (ipa_merge_modref_summary_after_inlining): Use ignore_stores_eaf_flags. + (modref_merge_call_site_flags): Add caller and ecf_flags parameter; + use remove_useless_eaf_flags. + (modref_propagate_flags_in_scc): Update. + * ipa-modref.h: Turn eaf_flags_t back to char. + * tree-core.h (EAF_NOT_RETURNED): Fix. + (EAF_NOREAD): New constant + * tree-ssa-alias.c: (ref_maybe_used_by_call_p_1): Check for + EAF_NOREAD. + * tree-ssa-structalias.c (handle_rhs_call): Handle new flags. + (handle_pure_call): Likewise. + +2021-08-12 Jakub Jelinek <jakub@redhat.com> + + * tree.def (OMP_MASKED): New tree code. + * tree-core.h (enum omp_clause_code): Add OMP_CLAUSE_FILTER. + * tree.h (OMP_MASKED_BODY, OMP_MASKED_CLAUSES, OMP_MASKED_COMBINED, + OMP_CLAUSE_FILTER_EXPR): Define. + * tree.c (omp_clause_num_ops): Add OMP_CLAUSE_FILTER entry. + (omp_clause_code_name): Likewise. + (walk_tree_1): Handle OMP_CLAUSE_FILTER. + * tree-nested.c (convert_nonlocal_omp_clauses, + convert_local_omp_clauses): Handle OMP_CLAUSE_FILTER. + (convert_nonlocal_reference_stmt, convert_local_reference_stmt, + convert_gimple_call): Handle GIMPLE_OMP_MASTER. + * tree-pretty-print.c (dump_omp_clause): Handle OMP_CLAUSE_FILTER. + (dump_generic_node): Handle OMP_MASTER. + * gimple.def (GIMPLE_OMP_MASKED): New gimple code. + * gimple.c (gimple_build_omp_masked): New function. + (gimple_copy): Handle GIMPLE_OMP_MASKED. + * gimple.h (gimple_build_omp_masked): Declare. + (gimple_has_substatements): Handle GIMPLE_OMP_MASKED. + (gimple_omp_masked_clauses, gimple_omp_masked_clauses_ptr, + gimple_omp_masked_set_clauses): New inline functions. + (CASE_GIMPLE_OMP): Add GIMPLE_OMP_MASKED. + * gimple-pretty-print.c (dump_gimple_omp_masked): New function. + (pp_gimple_stmt_1): Handle GIMPLE_OMP_MASKED. + * gimple-walk.c (walk_gimple_stmt): Likewise. + * gimple-low.c (lower_stmt): Likewise. + * gimplify.c (is_gimple_stmt): Handle OMP_MASTER. + (gimplify_scan_omp_clauses): Handle OMP_CLAUSE_FILTER. For clauses + that take one expression rather than decl or constant, force + gimplification of that into a SSA_NAME or temporary unless min + invariant. + (gimplify_adjust_omp_clauses): Handle OMP_CLAUSE_FILTER. + (gimplify_expr): Handle OMP_MASKED. + * tree-inline.c (remap_gimple_stmt): Handle GIMPLE_OMP_MASKED. + (estimate_num_insns): Likewise. + * omp-low.c (scan_sharing_clauses): Handle OMP_CLAUSE_FILTER. + (check_omp_nesting_restrictions): Handle GIMPLE_OMP_MASKED. Adjust + diagnostics for existence of masked construct. + (scan_omp_1_stmt, lower_omp_master, lower_omp_1, diagnose_sb_1, + diagnose_sb_2): Handle GIMPLE_OMP_MASKED. + * omp-expand.c (expand_omp_synch, expand_omp, omp_make_gimple_edges): + Likewise. + +2021-08-12 UroÅ¡ Bizjak <ubizjak@gmail.com> + + PR target/98309 + * config/i386/i386.md (avx512f_scalef<mode>2): New insn pattern. + (ldexp<mode>3): Use avx512f_scalef<mode>2. + (UNSPEC_SCALEF): Move from ... + * config/i386/sse.md (UNSPEC_SCALEF): ... here. + +2021-08-12 Jan Hubicka <hubicka@ucw.cz> + + * ipa-split.c (consider_split): Fix condition testing void functions. + +2021-08-12 Aldy Hernandez <aldyh@redhat.com> + + * doc/invoke.texi: Remove docs for threader-mode param. + * flag-types.h (enum threader_mode): Remove. + * params.opt: Remove threader-mode param. + * tree-ssa-threadbackward.c (class back_threader): Remove + path_is_unreachable_p. + Make find_paths private. + Add maybe_thread and thread_through_all_blocks. + Remove reference marker for m_registry. + Remove reference marker for m_profit. + (back_threader::back_threader): Adjust for registry and profit not + being references. + (dump_path): Move down. + (debug): Move down. + (class thread_jumps): Remove. + (class back_threader_registry): Remove m_all_paths. + Remove destructor. + (thread_jumps::thread_through_all_blocks): Move to back_threader + class. + (fsm_find_thread_path): Remove + (back_threader::maybe_thread): New. + (back_threader::thread_through_all_blocks): Move from + thread_jumps. + (back_threader_registry::back_threader_registry): Remove + m_all_paths. + (back_threader_registry::~back_threader_registry): Remove. + (thread_jumps::find_taken_edge): Remove. + (thread_jumps::check_subpath_and_update_thread_path): Remove. + (thread_jumps::maybe_register_path): Remove. + (thread_jumps::handle_phi): Remove. + (handle_assignment_p): Remove. + (thread_jumps::handle_assignment): Remove. + (thread_jumps::fsm_find_control_statement_thread_paths): Remove. + (thread_jumps::find_jump_threads_backwards): Remove. + (thread_jumps::find_jump_threads_backwards_with_ranger): Remove. + (try_thread_blocks): Rename find_jump_threads_backwards to + maybe_thread. + (pass_early_thread_jumps::execute): Same. + +2021-08-12 Tobias Burnus <tobias@codesourcery.com> + + * tree-core.h (omp_clause_proc_bind_kind): Add + OMP_CLAUSE_PROC_BIND_PRIMARY. + * tree-pretty-print.c (dump_omp_clause): Add TODO comment to + change 'master' to 'primary' in proc_bind for OpenMP 5.1. + +2021-08-12 Claudiu Zissulescu <claziss@synopsys.com> + + * common/config/arc/arc-common.c (arc_option_init_struct): Remove + fno-common reference. + * config/arc/arc.c (arc_override_options): Remove overriding of + flag_no_common. + +2021-08-12 Jakub Jelinek <jakub@redhat.com> + + PR target/101860 + * config/i386/i386-expand.c (ix86_expand_vec_one_operand_perm_avx512): + If d->testing_p, return true after performing checks instead of + actually expanding the insn. + (expand_vec_perm_broadcast_1): Handle V32HImode - assert + !TARGET_AVX512BW and return false. + +2021-08-12 Eric Botcazou <ebotcazou@gcc.gnu.org> + + * configure.ac (PE linker --disable-dynamicbase support): New check. + * configure: Regenerate. + * config.in: Likewise. + * config/i386/mingw32.h (LINK_SPEC_DISABLE_DYNAMICBASE): New define. + (LINK_SPEC): Use it. + * config/i386/mingw-w64.h (LINK_SPEC_DISABLE_DYNAMICBASE): Likewise. + (LINK_SPEC): Likewise. + +2021-08-12 liuhongt <hongtao.liu@intel.com> + + PR target/101846 + * config/i386/sse.md (*avx2_zero_extendv16qiv16hi2_2): New + post_reload define_insn_and_split. + (*avx512bw_zero_extendv32qiv32hi2_2): Ditto. + (*sse4_1_zero_extendv8qiv8hi2_4): Ditto. + (*avx512f_zero_extendv16hiv16si2_2): Ditto. + (*avx2_zero_extendv8hiv8si2_2): Ditto. + (*sse4_1_zero_extendv4hiv4si2_4): Ditto. + (*avx512f_zero_extendv8siv8di2_2): Ditto. + (*avx2_zero_extendv4siv4di2_2): Ditto. + (*sse4_1_zero_extendv2siv2di2_4): Ditto. + (VI248_256, VI248_512, VI148_512, VI148_256, VI148_128): New + mode iterator. + +2021-08-11 Bill Schmidt <wschmidt@linux.ibm.com> + + * config/rs6000/rs6000-builtin-new.def: Add always, power5, and + power6 stanzas. + +2021-08-11 Bill Schmidt <wschmidt@linux.ibm.com> + + * config/rs6000/rs6000-builtin-new.def: Add vsx stanza. + +2021-08-11 Bill Schmidt <wschmidt@linux.ibm.com> + + * config/rs6000/rs6000-builtin-new.def: Finish altivec stanza. + * config/rs6000/rs6000-call.c (rs6000_init_builtins): Move + initialization of pcvoid_type_node here... + (altivec_init_builtins): ...from here. + * config/rs6000/rs6000.h (rs6000_builtin_type_index): Add + RS6000_BTI_const_ptr_void. + (pcvoid_type_node): New macro. + +2021-08-11 Richard Biener <rguenther@suse.de> + + PR target/101877 + * tree-ssa-forwprop.c (pass_forwprop::execute): Do not decompose + hard-register accesses. + +2021-08-11 Richard Biener <rguenther@suse.de> + + * tree-ssa-operands.c (operands_scanner::get_expr_operands): + Do not look at COMPONENT_REF FIELD_DECLs TREE_THIS_VOLATILE + to determine has_volatile_ops. + +2021-08-11 Eric Botcazou <ebotcazou@gcc.gnu.org> + + * cfgexpand.c (expand_used_vars): Reuse attribs local variable. + +2021-08-11 Jan Hubicka <hubicka@ucw.cz> + Alexandre Oliva <oliva@adacore.com> + + * ipa-modref.c (modref_lattice::dump): Fix escape_point's min_flags + dumping. + (modref_lattice::merge_deref): Fix handling of indirect scape points. + (update_escape_summary_1): Likewise. + (update_escape_summary): Likewise. + (ipa_merge_modref_summary_after_inlining): Likewise. + +2021-08-11 Richard Biener <rguenther@suse.de> + + PR middle-end/101858 + * fold-const.c (fold_binary_loc): Guard simplification + of X < (cast) (1 << Y) to integer types. + +2021-08-11 Richard Biener <rguenther@suse.de> + + PR tree-optimization/101861 + * tree-vect-stmts.c (vectorizable_load): Fix error in + previous change with regard to gather vectorization. + +2021-08-11 prathamesh.kulkarni <prathamesh.kulkarni@linaro.org> + + PR target/66791 + * config/arm/arm_neon.h (vdup_n_s8): Replace call to builtin + with constructor. + (vdup_n_s16): Likewise. + (vdup_n_s32): Likewise. + (vdup_n_s64): Likewise. + (vdup_n_u8): Likewise. + (vdup_n_u16): Likewise. + (vdup_n_u32): Likewise. + (vdup_n_u64): Likewise. + (vdup_n_p8): Likewise. + (vdup_n_p16): Likewise. + (vdup_n_p64): Likewise. + (vdup_n_f16): Likewise. + (vdup_n_f32): Likewise. + (vdupq_n_s8): Likewise. + (vdupq_n_s16): Likewise. + (vdupq_n_s32): Likewise. + (vdupq_n_s64): Likewise. + (vdupq_n_u8): Likewise. + (vdupq_n_u16): Likewise. + (vdupq_n_u32): Likewise. + (vdupq_n_u64): Likewise. + (vdupq_n_p8): Likewise. + (vdupq_n_p16): Likewise. + (vdupq_n_p64): Likewise. + (vdupq_n_f16): Likewise. + (vdupq_n_f32): Likewise. + (vmov_n_s8): Replace call to builtin with call to corresponding + vdup_n intrinsic. + (vmov_n_s16): Likewise. + (vmov_n_s32): Likewise. + (vmov_n_s64): Likewise. + (vmov_n_u8): Likewise. + (vmov_n_u16): Likewise. + (vmov_n_u32): Likewise. + (vmov_n_u64): Likewise. + (vmov_n_p8): Likewise. + (vmov_n_p16): Likewise. + (vmov_n_f16): Likewise. + (vmov_n_f32): Likewise. + (vmovq_n_s8): Likewise. + (vmovq_n_s16): Likewise. + (vmovq_n_s32): Likewise. + (vmovq_n_s64): Likewise. + (vmovq_n_u8): Likewise. + (vmovq_n_u16): Likewise. + (vmovq_n_u32): Likewise. + (vmovq_n_u64): Likewise. + (vmovq_n_p8): Likewise. + (vmovq_n_p16): Likewise. + (vmovq_n_f16): Likewise. + (vmovq_n_f32): Likewise. + * config/arm/arm_neon_builtins.def: Remove entries for vdup_n. + +2021-08-11 liuhongt <hongtao.liu@intel.com> + + PR target/98309 + * config/i386/i386.md (ldexp<mode>3): Extend to vscalefs[sd] + when TARGET_AVX512F and TARGET_SSE_MATH. + +2021-08-10 Jakub Jelinek <jakub@redhat.com> + + PR target/80355 + * config/i386/i386-expand.c (expand_vec_perm_even_odd): Return false + for V32HImode if !TARGET_AVX512BW. + (ix86_vectorize_vec_perm_const) <case E_V32HImode, case E_V64QImode>: + If !TARGET_AVX512BW and TARGET_AVX512F and d.testing_p, don't fail + early, but actually check the permutation. + +2021-08-10 Richard Biener <rguenther@suse.de> + + PR tree-optimization/101809 + * tree-vect-stmts.c (get_load_store_type): Allow emulated + gathers with offset vector nunits being a constant multiple + of the data vector nunits. + (vect_get_gather_scatter_ops): Use the appropriate nunits + for the offset vector defs. + (vectorizable_store): Adjust call to + vect_get_gather_scatter_ops. + (vectorizable_load): Likewise. Handle the case of less + offset vectors than data vectors. + +2021-08-10 Jakub Jelinek <jakub@redhat.com> + + PR target/80355 + * config/i386/sse.md (*avx512f_shuf_<shuffletype>64x2_1<mask_name>_1, + *avx512f_shuf_<shuffletype>32x4_1<mask_name>_1): New define_insn + patterns. + +2021-08-10 Richard Biener <rguenther@suse.de> + + PR tree-optimization/101801 + PR tree-optimization/101819 + * tree-vectorizer.h (vect_emulated_vector_p): Declare. + * tree-vect-loop.c (vect_emulated_vector_p): New function. + (vectorizable_reduction): Re-instantiate a check for emulated + operations. + * tree-vect-stmts.c (vectorizable_shift): Likewise. + (vectorizable_operation): Likewise. Cost emulated vector + operations according to the scalar sequence synthesized by + vector lowering. + +2021-08-10 Richard Biener <rguenther@suse.de> + + PR middle-end/101824 + * tree-nested.c (get_frame_field): Mark the COMPONENT_REF as + volatile in case the variable was. + +2021-08-10 H.J. Lu <hjl.tools@gmail.com> + + PR target/101804 + * config/i386/constraints.md (BC): Document for integer SSE + constant all bits set operand. + (BF): New constraint for const floating-point all bits set + vectors. + * config/i386/i386.c (standard_sse_constant_p): Likewise. + (standard_sse_constant_opcode): Likewise. + * config/i386/sse.md (sseconstm1): New mode attribute. + (mov<mode>_internal): Replace BC with <sseconstm1>. + +2021-08-10 liuhongt <hongtao.liu@intel.com> + + * config/i386/sse.md (cond_<insn><mode>): New expander. + (VI248_AVX512VLBW): New mode iterator. + * config/i386/predicates.md + (nonimmediate_or_const_vec_dup_operand): New predicate. + 2021-08-09 Andrew MacLeod <amacleod@redhat.com> PR tree-optimization/101741 diff --git a/gcc/DATESTAMP b/gcc/DATESTAMP index 7eb9baf..70b09db 100644 --- a/gcc/DATESTAMP +++ b/gcc/DATESTAMP @@ -1 +1 @@ -20210810 +20210818 diff --git a/gcc/Makefile.in b/gcc/Makefile.in index 6653e9e..9714fca 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -1406,6 +1406,7 @@ OBJS = \ gimple-range-edge.o \ gimple-range-fold.o \ gimple-range-gori.o \ + gimple-range-trace.o \ gimple-ssa-backprop.o \ gimple-ssa-evrp.o \ gimple-ssa-evrp-analyze.o \ diff --git a/gcc/ada/ChangeLog b/gcc/ada/ChangeLog index 254b562..8e19ca4 100644 --- a/gcc/ada/ChangeLog +++ b/gcc/ada/ChangeLog @@ -1,3 +1,10 @@ +2021-08-11 Bernd Edlinger <bernd.edlinger@hotmail.de> + + PR debug/101598 + * gcc-interface/trans.c (Subprogram_Body_to_gnu): Set the + DECL_SOURCE_LOCATION of DECL_IGNORED_P gnu_subprog_decl to + UNKNOWN_LOCATION. + 2021-07-25 Arnaud Charlet <charlet@adacore.com> * libgnat/s-osprim__x32.adb: Add missing with clause. diff --git a/gcc/ada/gcc-interface/decl.c b/gcc/ada/gcc-interface/decl.c index 4b6479b..5cedb74 100644 --- a/gcc/ada/gcc-interface/decl.c +++ b/gcc/ada/gcc-interface/decl.c @@ -1998,10 +1998,10 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, bool definition) so we use an intermediate step for standard DWARF. */ if (debug_info_p) { - if (gnat_encodings == DWARF_GNAT_ENCODINGS_ALL) - add_parallel_type (gnu_type, DECL_PARALLEL_TYPE (t)); - else + if (gnat_encodings != DWARF_GNAT_ENCODINGS_ALL) SET_TYPE_DEBUG_TYPE (gnu_type, gnu_field_type); + else if (DECL_PARALLEL_TYPE (t)) + add_parallel_type (gnu_type, DECL_PARALLEL_TYPE (t)); } } diff --git a/gcc/ada/gcc-interface/trans.c b/gcc/ada/gcc-interface/trans.c index f61183d..3df56aa 100644 --- a/gcc/ada/gcc-interface/trans.c +++ b/gcc/ada/gcc-interface/trans.c @@ -3885,7 +3885,9 @@ Subprogram_Body_to_gnu (Node_Id gnat_node) } /* Set the line number in the decl to correspond to that of the body. */ - if (!Sloc_to_locus (Sloc (gnat_node), &locus, false, gnu_subprog_decl)) + if (DECL_IGNORED_P (gnu_subprog_decl)) + locus = UNKNOWN_LOCATION; + else if (!Sloc_to_locus (Sloc (gnat_node), &locus, false, gnu_subprog_decl)) locus = input_location; DECL_SOURCE_LOCATION (gnu_subprog_decl) = locus; diff --git a/gcc/attribs.c b/gcc/attribs.c index afa485e..0d22c20 100644 --- a/gcc/attribs.c +++ b/gcc/attribs.c @@ -517,14 +517,9 @@ decl_attributes (tree *node, tree attributes, int flags, if (TREE_CODE (*node) == FUNCTION_DECL && attributes && lookup_attribute ("naked", attributes) != NULL - && lookup_attribute_spec (get_identifier ("naked"))) - { - if (lookup_attribute ("noinline", attributes) == NULL) - attributes = tree_cons (get_identifier ("noinline"), NULL, attributes); - - if (lookup_attribute ("noclone", attributes) == NULL) - attributes = tree_cons (get_identifier ("noclone"), NULL, attributes); - } + && lookup_attribute_spec (get_identifier ("naked")) + && lookup_attribute ("noipa", attributes) == NULL) + attributes = tree_cons (get_identifier ("noipa"), NULL, attributes); /* A "noipa" function attribute implies "noinline", "noclone" and "no_icf" for those targets that support it. */ diff --git a/gcc/builtins.c b/gcc/builtins.c index d2be807f..9954862 100644 --- a/gcc/builtins.c +++ b/gcc/builtins.c @@ -43,7 +43,7 @@ along with GCC; see the file COPYING3. If not see #include "alias.h" #include "fold-const.h" #include "fold-const-call.h" -#include "gimple-ssa-warn-restrict.h" +#include "gimple-ssa-warn-access.h" #include "stor-layout.h" #include "calls.h" #include "varasm.h" @@ -81,7 +81,6 @@ along with GCC; see the file COPYING3. If not see #include "demangle.h" #include "gimple-range.h" #include "pointer-query.h" -#include "gimple-ssa-warn-access.h" struct target_builtins default_target_builtins; #if SWITCHABLE_TARGET @@ -4896,25 +4895,6 @@ expand_builtin_alloca (tree exp) if (!valid_arglist) return NULL_RTX; - if ((alloca_for_var - && warn_vla_limit >= HOST_WIDE_INT_MAX - && warn_alloc_size_limit < warn_vla_limit) - || (!alloca_for_var - && warn_alloca_limit >= HOST_WIDE_INT_MAX - && warn_alloc_size_limit < warn_alloca_limit - )) - { - /* -Walloca-larger-than and -Wvla-larger-than settings of - less than HOST_WIDE_INT_MAX override the more general - -Walloc-size-larger-than so unless either of the former - options is smaller than the last one (wchich would imply - that the call was already checked), check the alloca - arguments for overflow. */ - tree args[] = { CALL_EXPR_ARG (exp, 0), NULL_TREE }; - int idx[] = { 0, -1 }; - maybe_warn_alloc_args_overflow (fndecl, exp, args, idx); - } - /* Compute the argument. */ op0 = expand_normal (CALL_EXPR_ARG (exp, 0)); diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog index 7306b36..5595994 100644 --- a/gcc/c-family/ChangeLog +++ b/gcc/c-family/ChangeLog @@ -1,3 +1,36 @@ +2021-08-17 Jakub Jelinek <jakub@redhat.com> + + PR c++/101539 + * c-common.h (enum rid): Add RID_IS_LAYOUT_COMPATIBLE. + * c-common.c (c_common_reswords): Add __is_layout_compatible. + +2021-08-17 Matt Jacobson <mhjacobson@me.com> + + * c-opts.c (c_common_post_options): Default to + flag_objc_sjlj_exceptions = 1 only when flag_objc_abi < 2. + +2021-08-17 Jakub Jelinek <jakub@redhat.com> + + * c-pragma.h (enum pragma_kind): Add PRAGMA_OMP_SCOPE. + * c-pragma.c (omp_pragmas): Add scope construct. + * c-omp.c (omp_directives): Uncomment scope directive entry. + +2021-08-16 Sebastian Huber <sebastian.huber@embedded-brains.de> + + * c-cppbuiltin.c (c_cpp_builtins): Define + __LIBGCC_GCOV_TYPE_SIZE if flag_building_libgcc is true. + +2021-08-12 Jakub Jelinek <jakub@redhat.com> + + * c-pragma.h (enum pragma_kind): Add PRAGMA_OMP_MASKED. + (enum pragma_omp_clause): Add PRAGMA_OMP_CLAUSE_FILTER. + * c-pragma.c (omp_pragmas_simd): Add masked construct. + * c-common.h (enum c_omp_clause_split): Add C_OMP_CLAUSE_SPLIT_MASKED + enumerator. + (c_finish_omp_masked): Declare. + * c-omp.c (c_finish_omp_masked): New function. + (c_omp_split_clauses): Handle combined masked constructs. + 2021-07-30 Jakub Jelinek <jakub@redhat.com> PR c++/101539 diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c index 00ac3c5..017e415 100644 --- a/gcc/c-family/c-common.c +++ b/gcc/c-family/c-common.c @@ -420,6 +420,7 @@ const struct c_common_resword c_common_reswords[] = { "__is_empty", RID_IS_EMPTY, D_CXXONLY }, { "__is_enum", RID_IS_ENUM, D_CXXONLY }, { "__is_final", RID_IS_FINAL, D_CXXONLY }, + { "__is_layout_compatible", RID_IS_LAYOUT_COMPATIBLE, D_CXXONLY }, { "__is_literal_type", RID_IS_LITERAL_TYPE, D_CXXONLY }, { "__is_pointer_interconvertible_base_of", RID_IS_POINTER_INTERCONVERTIBLE_BASE_OF, D_CXXONLY }, diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h index 65d8c1c..d66bf15 100644 --- a/gcc/c-family/c-common.h +++ b/gcc/c-family/c-common.h @@ -173,7 +173,8 @@ enum rid RID_IS_ABSTRACT, RID_IS_AGGREGATE, RID_IS_BASE_OF, RID_IS_CLASS, RID_IS_EMPTY, RID_IS_ENUM, - RID_IS_FINAL, RID_IS_LITERAL_TYPE, + RID_IS_FINAL, RID_IS_LAYOUT_COMPATIBLE, + RID_IS_LITERAL_TYPE, RID_IS_POINTER_INTERCONVERTIBLE_BASE_OF, RID_IS_POD, RID_IS_POLYMORPHIC, RID_IS_SAME_AS, @@ -1201,7 +1202,8 @@ enum c_omp_clause_split C_OMP_CLAUSE_SPLIT_COUNT, C_OMP_CLAUSE_SPLIT_SECTIONS = C_OMP_CLAUSE_SPLIT_FOR, C_OMP_CLAUSE_SPLIT_TASKLOOP = C_OMP_CLAUSE_SPLIT_FOR, - C_OMP_CLAUSE_SPLIT_LOOP = C_OMP_CLAUSE_SPLIT_FOR + C_OMP_CLAUSE_SPLIT_LOOP = C_OMP_CLAUSE_SPLIT_FOR, + C_OMP_CLAUSE_SPLIT_MASKED = C_OMP_CLAUSE_SPLIT_DISTRIBUTE }; enum c_omp_region_type @@ -1215,6 +1217,7 @@ enum c_omp_region_type }; extern tree c_finish_omp_master (location_t, tree); +extern tree c_finish_omp_masked (location_t, tree, tree); extern tree c_finish_omp_taskgroup (location_t, tree, tree); extern tree c_finish_omp_critical (location_t, tree, tree, tree); extern tree c_finish_omp_ordered (location_t, tree, tree); diff --git a/gcc/c-family/c-cppbuiltin.c b/gcc/c-family/c-cppbuiltin.c index f79f939..3fa62bc 100644 --- a/gcc/c-family/c-cppbuiltin.c +++ b/gcc/c-family/c-cppbuiltin.c @@ -1450,6 +1450,8 @@ c_cpp_builtins (cpp_reader *pfile) /* For libgcov. */ builtin_define_with_int_value ("__LIBGCC_VTABLE_USES_DESCRIPTORS__", TARGET_VTABLE_USES_DESCRIPTORS); + builtin_define_with_int_value ("__LIBGCC_GCOV_TYPE_SIZE", + targetm.gcov_type_size()); } /* For use in assembly language. */ diff --git a/gcc/c-family/c-omp.c b/gcc/c-family/c-omp.c index e70974d..d4e98bf 100644 --- a/gcc/c-family/c-omp.c +++ b/gcc/c-family/c-omp.c @@ -86,6 +86,20 @@ c_finish_omp_master (location_t loc, tree stmt) return t; } +/* Complete a #pragma omp masked construct. BODY is the structured-block + that follows the pragma. LOC is the location of the #pragma. */ + +tree +c_finish_omp_masked (location_t loc, tree body, tree clauses) +{ + tree stmt = make_node (OMP_MASKED); + TREE_TYPE (stmt) = void_type_node; + OMP_MASKED_BODY (stmt) = body; + OMP_MASKED_CLAUSES (stmt) = clauses; + SET_EXPR_LOCATION (stmt, loc); + return add_stmt (stmt); +} + /* Complete a #pragma omp taskgroup construct. BODY is the structured-block that follows the pragma. LOC is the location of the #pragma. */ @@ -1542,11 +1556,16 @@ c_oacc_split_loop_clauses (tree clauses, tree *not_loop_clauses, #pragma omp distribute parallel for simd #pragma omp distribute simd #pragma omp for simd + #pragma omp masked taskloop + #pragma omp masked taskloop simd #pragma omp master taskloop #pragma omp master taskloop simd #pragma omp parallel for #pragma omp parallel for simd #pragma omp parallel loop + #pragma omp parallel masked + #pragma omp parallel masked taskloop + #pragma omp parallel masked taskloop simd #pragma omp parallel master #pragma omp parallel master taskloop #pragma omp parallel master taskloop simd @@ -1651,6 +1670,9 @@ c_omp_split_clauses (location_t loc, enum tree_code code, case OMP_CLAUSE_BIND: s = C_OMP_CLAUSE_SPLIT_LOOP; break; + case OMP_CLAUSE_FILTER: + s = C_OMP_CLAUSE_SPLIT_MASKED; + break; /* Duplicate this to all of taskloop, distribute, for, simd and loop. */ case OMP_CLAUSE_COLLAPSE: @@ -1700,10 +1722,10 @@ c_omp_split_clauses (location_t loc, enum tree_code code, else s = C_OMP_CLAUSE_SPLIT_DISTRIBUTE; break; - /* Private clause is supported on all constructs but master, - it is enough to put it on the innermost one other than master. For - #pragma omp {for,sections} put it on parallel though, - as that's what we did for OpenMP 3.1. */ + /* Private clause is supported on all constructs but master/masked, + it is enough to put it on the innermost one other than + master/masked. For #pragma omp {for,sections} put it on parallel + though, as that's what we did for OpenMP 3.1. */ case OMP_CLAUSE_PRIVATE: switch (code) { @@ -1713,14 +1735,15 @@ c_omp_split_clauses (location_t loc, enum tree_code code, case OMP_DISTRIBUTE: s = C_OMP_CLAUSE_SPLIT_DISTRIBUTE; break; case OMP_TEAMS: s = C_OMP_CLAUSE_SPLIT_TEAMS; break; case OMP_MASTER: s = C_OMP_CLAUSE_SPLIT_PARALLEL; break; + case OMP_MASKED: s = C_OMP_CLAUSE_SPLIT_PARALLEL; break; case OMP_TASKLOOP: s = C_OMP_CLAUSE_SPLIT_TASKLOOP; break; case OMP_LOOP: s = C_OMP_CLAUSE_SPLIT_LOOP; break; default: gcc_unreachable (); } break; /* Firstprivate clause is supported on all constructs but - simd, master and loop. Put it on the outermost of those and - duplicate on teams and parallel. */ + simd, master, masked and loop. Put it on the outermost of those + and duplicate on teams and parallel. */ case OMP_CLAUSE_FIRSTPRIVATE: if ((mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_MAP)) != 0) @@ -1773,7 +1796,7 @@ c_omp_split_clauses (location_t loc, enum tree_code code, else if ((mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOGROUP)) != 0) /* This must be - #pragma omp parallel master taskloop{, simd}. */ + #pragma omp parallel mas{ked,ter} taskloop{, simd}. */ s = C_OMP_CLAUSE_SPLIT_TASKLOOP; else /* This must be @@ -1805,9 +1828,10 @@ c_omp_split_clauses (location_t loc, enum tree_code code, else if ((mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOGROUP)) != 0) { - /* This must be #pragma omp {,{,parallel }master }taskloop simd + /* This must be + #pragma omp {,{,parallel }mas{ked,ter} }taskloop simd or - #pragma omp {,parallel }master taskloop. */ + #pragma omp {,parallel }mas{ked,ter} taskloop. */ gcc_assert (code == OMP_SIMD || code == OMP_TASKLOOP); s = C_OMP_CLAUSE_SPLIT_TASKLOOP; } @@ -2044,7 +2068,8 @@ c_omp_split_clauses (location_t loc, enum tree_code code, } else if (code == OMP_SECTIONS || code == OMP_PARALLEL - || code == OMP_MASTER) + || code == OMP_MASTER + || code == OMP_MASKED) s = C_OMP_CLAUSE_SPLIT_PARALLEL; else if (code == OMP_TASKLOOP) s = C_OMP_CLAUSE_SPLIT_TASKLOOP; @@ -2455,7 +2480,8 @@ c_omp_split_clauses (location_t loc, enum tree_code code, gcc_assert (cclauses[C_OMP_CLAUSE_SPLIT_TARGET] == NULL_TREE); if ((mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NUM_TEAMS)) == 0) gcc_assert (cclauses[C_OMP_CLAUSE_SPLIT_TEAMS] == NULL_TREE); - if ((mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DIST_SCHEDULE)) == 0) + if ((mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DIST_SCHEDULE)) == 0 + && (mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FILTER)) == 0) gcc_assert (cclauses[C_OMP_CLAUSE_SPLIT_DISTRIBUTE] == NULL_TREE); if ((mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NUM_THREADS)) == 0) gcc_assert (cclauses[C_OMP_CLAUSE_SPLIT_PARALLEL] == NULL_TREE); @@ -2975,14 +3001,14 @@ static const struct c_omp_directive omp_directives[] = { C_OMP_DIR_STANDALONE, false }, */ { "loop", nullptr, nullptr, PRAGMA_OMP_LOOP, C_OMP_DIR_CONSTRUCT, true }, - /* { "masked", nullptr, nullptr, PRAGMA_OMP_MASKED, - C_OMP_DIR_CONSTRUCT, true }, */ + { "masked", nullptr, nullptr, PRAGMA_OMP_MASKED, + C_OMP_DIR_CONSTRUCT, true }, { "master", nullptr, nullptr, PRAGMA_OMP_MASTER, C_OMP_DIR_CONSTRUCT, true }, /* { "metadirective", nullptr, nullptr, PRAGMA_OMP_METADIRECTIVE, C_OMP_DIR_???, ??? }, */ - /* { "nothing", nullptr, nullptr, PRAGMA_OMP_NOTHING, - C_OMP_DIR_UTILITY, false }, */ + { "nothing", nullptr, nullptr, PRAGMA_OMP_NOTHING, + C_OMP_DIR_UTILITY, false }, /* ordered with depend clause is C_OMP_DIR_STANDALONE. */ { "ordered", nullptr, nullptr, PRAGMA_OMP_ORDERED, C_OMP_DIR_CONSTRUCT, true }, @@ -2992,8 +3018,8 @@ static const struct c_omp_directive omp_directives[] = { C_OMP_DIR_INFORMATIONAL, false }, { "scan", nullptr, nullptr, PRAGMA_OMP_SCAN, C_OMP_DIR_CONSTRUCT, true }, - /* { "scope", nullptr, nullptr, PRAGMA_OMP_SCOPE, - C_OMP_DIR_CONSTRUCT, false }, */ + { "scope", nullptr, nullptr, PRAGMA_OMP_SCOPE, + C_OMP_DIR_CONSTRUCT, false }, { "section", nullptr, nullptr, PRAGMA_OMP_SECTION, C_OMP_DIR_CONSTRUCT, false }, { "sections", nullptr, nullptr, PRAGMA_OMP_SECTIONS, diff --git a/gcc/c-family/c-opts.c b/gcc/c-family/c-opts.c index 1c4e832c..373af0c 100644 --- a/gcc/c-family/c-opts.c +++ b/gcc/c-family/c-opts.c @@ -852,9 +852,9 @@ c_common_post_options (const char **pfilename) else if (!flag_gnu89_inline && !flag_isoc99) error ("%<-fno-gnu89-inline%> is only supported in GNU99 or C99 mode"); - /* Default to ObjC sjlj exception handling if NeXT runtime. */ + /* Default to ObjC sjlj exception handling if NeXT runtime < v2. */ if (flag_objc_sjlj_exceptions < 0) - flag_objc_sjlj_exceptions = flag_next_runtime; + flag_objc_sjlj_exceptions = (flag_next_runtime && flag_objc_abi < 2); if (flag_objc_exceptions && !flag_objc_sjlj_exceptions) flag_exceptions = 1; diff --git a/gcc/c-family/c-pragma.c b/gcc/c-family/c-pragma.c index f46b5b9..238309d 100644 --- a/gcc/c-family/c-pragma.c +++ b/gcc/c-family/c-pragma.c @@ -1328,7 +1328,9 @@ static const struct omp_pragma_def omp_pragmas[] = { { "depobj", PRAGMA_OMP_DEPOBJ }, { "end", PRAGMA_OMP_END_DECLARE_TARGET }, { "flush", PRAGMA_OMP_FLUSH }, + { "nothing", PRAGMA_OMP_NOTHING }, { "requires", PRAGMA_OMP_REQUIRES }, + { "scope", PRAGMA_OMP_SCOPE }, { "section", PRAGMA_OMP_SECTION }, { "sections", PRAGMA_OMP_SECTIONS }, { "single", PRAGMA_OMP_SINGLE }, @@ -1343,6 +1345,7 @@ static const struct omp_pragma_def omp_pragmas_simd[] = { { "distribute", PRAGMA_OMP_DISTRIBUTE }, { "for", PRAGMA_OMP_FOR }, { "loop", PRAGMA_OMP_LOOP }, + { "masked", PRAGMA_OMP_MASKED }, { "master", PRAGMA_OMP_MASTER }, { "ordered", PRAGMA_OMP_ORDERED }, { "parallel", PRAGMA_OMP_PARALLEL }, diff --git a/gcc/c-family/c-pragma.h b/gcc/c-family/c-pragma.h index abd6667..dc9e8a6 100644 --- a/gcc/c-family/c-pragma.h +++ b/gcc/c-family/c-pragma.h @@ -57,11 +57,14 @@ enum pragma_kind { PRAGMA_OMP_FLUSH, PRAGMA_OMP_FOR, PRAGMA_OMP_LOOP, + PRAGMA_OMP_NOTHING, + PRAGMA_OMP_MASKED, PRAGMA_OMP_MASTER, PRAGMA_OMP_ORDERED, PRAGMA_OMP_PARALLEL, PRAGMA_OMP_REQUIRES, PRAGMA_OMP_SCAN, + PRAGMA_OMP_SCOPE, PRAGMA_OMP_SECTION, PRAGMA_OMP_SECTIONS, PRAGMA_OMP_SIMD, @@ -104,6 +107,7 @@ enum pragma_omp_clause { PRAGMA_OMP_CLAUSE_DEVICE, PRAGMA_OMP_CLAUSE_DEVICE_TYPE, PRAGMA_OMP_CLAUSE_DIST_SCHEDULE, + PRAGMA_OMP_CLAUSE_FILTER, PRAGMA_OMP_CLAUSE_FINAL, PRAGMA_OMP_CLAUSE_FIRSTPRIVATE, PRAGMA_OMP_CLAUSE_FOR, diff --git a/gcc/c/ChangeLog b/gcc/c/ChangeLog index 6f15b0f..caeac5b 100644 --- a/gcc/c/ChangeLog +++ b/gcc/c/ChangeLog @@ -1,3 +1,38 @@ +2021-08-17 Jakub Jelinek <jakub@redhat.com> + + * c-parser.c (OMP_SCOPE_CLAUSE_MASK): Define. + (c_parser_omp_scope): New function. + (c_parser_omp_construct): Handle PRAGMA_OMP_SCOPE. + +2021-08-12 Jakub Jelinek <jakub@redhat.com> + + * c-parser.c (c_parser_omp_clause_name): Parse filter clause name. + (c_parser_omp_clause_filter): New function. + (c_parser_omp_all_clauses): Handle PRAGMA_OMP_CLAUSE_FILTER. + (OMP_MASKED_CLAUSE_MASK): Define. + (c_parser_omp_masked): New function. + (c_parser_omp_parallel): Handle parallel masked. + (c_parser_omp_construct): Handle PRAGMA_OMP_MASKED. + * c-typeck.c (c_finish_omp_clauses): Handle OMP_CLAUSE_FILTER. + +2021-08-12 Martin Uecker <muecker@gwdg.de> + + PR c/101838 + PR c/29970 + * c-typeck.c (c_expr_sizeof_type): Evaluate + size expressions for structs of variable size. + +2021-08-12 Tobias Burnus <tobias@codesourcery.com> + + * c-parser.c (c_parser_omp_clause_proc_bind): Accept + 'primary' as alias for 'master'. + +2021-08-10 Martin Uecker <muecker@gwdg.de> + + PR c/29970 + * c-typeck.c (c_expr_sizeof_expr): Evaluate + size expressions for structs of variable size. + 2021-08-06 Tamar Christina <tamar.christina@arm.com> * c-decl.c (c_simulate_enum_decl): Pass vec<> by pointer. diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c index d24bfdb..d5f51b1 100644 --- a/gcc/c/c-parser.c +++ b/gcc/c/c-parser.c @@ -1578,14 +1578,15 @@ static tree c_parser_omp_for_loop (location_t, c_parser *, enum tree_code, static void c_parser_omp_taskwait (c_parser *); static void c_parser_omp_taskyield (c_parser *); static void c_parser_omp_cancel (c_parser *); +static void c_parser_omp_nothing (c_parser *); enum pragma_context { pragma_external, pragma_struct, pragma_param, pragma_stmt, pragma_compound }; static bool c_parser_pragma (c_parser *, enum pragma_context, bool *); -static void c_parser_omp_cancellation_point (c_parser *, enum pragma_context); +static bool c_parser_omp_cancellation_point (c_parser *, enum pragma_context); static bool c_parser_omp_target (c_parser *, enum pragma_context, bool *); static void c_parser_omp_end_declare_target (c_parser *); -static void c_parser_omp_declare (c_parser *, enum pragma_context); +static bool c_parser_omp_declare (c_parser *, enum pragma_context); static void c_parser_omp_requires (c_parser *); static bool c_parser_omp_ordered (c_parser *, enum pragma_context, bool *); static void c_parser_oacc_routine (c_parser *, enum pragma_context); @@ -6100,6 +6101,7 @@ c_parser_statement_after_labels (c_parser *parser, bool *if_p, if (c_parser_peek_token (parser)->type != CPP_OPEN_BRACE) add_debug_begin_stmt (loc); + restart: switch (c_parser_peek_token (parser)->type) { case CPP_OPEN_BRACE: @@ -6246,7 +6248,8 @@ c_parser_statement_after_labels (c_parser *parser, bool *if_p, c_parser_consume_token (parser); break; case CPP_PRAGMA: - c_parser_pragma (parser, pragma_stmt, if_p); + if (!c_parser_pragma (parser, pragma_stmt, if_p)) + goto restart; break; default: expr_stmt: @@ -12346,7 +12349,7 @@ c_parser_pragma (c_parser *parser, enum pragma_context context, bool *if_p) "%<#pragma %s%> may only be used in compound " "statements", construct); c_parser_skip_until_found (parser, CPP_PRAGMA_EOL, NULL); - return false; + return true; } goto bad_stmt; } @@ -12437,8 +12440,7 @@ c_parser_pragma (c_parser *parser, enum pragma_context context, bool *if_p) return false; case PRAGMA_OMP_CANCELLATION_POINT: - c_parser_omp_cancellation_point (parser, context); - return false; + return c_parser_omp_cancellation_point (parser, context); case PRAGMA_OMP_THREADPRIVATE: c_parser_omp_threadprivate (parser); @@ -12466,8 +12468,7 @@ c_parser_pragma (c_parser *parser, enum pragma_context context, bool *if_p) return false; case PRAGMA_OMP_DECLARE: - c_parser_omp_declare (parser, context); - return false; + return c_parser_omp_declare (parser, context); case PRAGMA_OMP_REQUIRES: if (context != pragma_external) @@ -12480,6 +12481,10 @@ c_parser_pragma (c_parser *parser, enum pragma_context context, bool *if_p) c_parser_omp_requires (parser); return false; + case PRAGMA_OMP_NOTHING: + c_parser_omp_nothing (parser); + return false; + case PRAGMA_OMP_ORDERED: return c_parser_omp_ordered (parser, context, if_p); @@ -12505,7 +12510,7 @@ c_parser_pragma (c_parser *parser, enum pragma_context context, bool *if_p) else c_parser_do_statement (parser, ivdep, unroll); } - return false; + return true; case PRAGMA_UNROLL: { @@ -12529,7 +12534,7 @@ c_parser_pragma (c_parser *parser, enum pragma_context context, bool *if_p) else c_parser_do_statement (parser, ivdep, unroll); } - return false; + return true; case PRAGMA_GCC_PCH_PREPROCESS: c_parser_error (parser, "%<#pragma GCC pch_preprocess%> must be first"); @@ -12696,7 +12701,9 @@ c_parser_omp_clause_name (c_parser *parser) result = PRAGMA_OMP_CLAUSE_DIST_SCHEDULE; break; case 'f': - if (!strcmp ("final", p)) + if (!strcmp ("filter", p)) + result = PRAGMA_OMP_CLAUSE_FILTER; + else if (!strcmp ("final", p)) result = PRAGMA_OMP_CLAUSE_FINAL; else if (!strcmp ("finalize", p)) result = PRAGMA_OACC_CLAUSE_FINALIZE; @@ -13948,6 +13955,38 @@ c_parser_omp_clause_hint (c_parser *parser, tree list) return list; } +/* OpenMP 5.1: + filter ( integer-expression ) */ + +static tree +c_parser_omp_clause_filter (c_parser *parser, tree list) +{ + location_t hint_loc = c_parser_peek_token (parser)->location; + matching_parens parens; + if (parens.require_open (parser)) + { + location_t expr_loc = c_parser_peek_token (parser)->location; + c_expr expr = c_parser_expr_no_commas (parser, NULL); + expr = convert_lvalue_to_rvalue (expr_loc, expr, false, true); + tree c, t = expr.value; + t = c_fully_fold (t, false, NULL); + if (!INTEGRAL_TYPE_P (TREE_TYPE (t))) + { + c_parser_error (parser, "expected integer expression"); + return list; + } + parens.skip_until_found_close (parser); + check_no_duplicate_clause (list, OMP_CLAUSE_FILTER, "filter"); + + c = build_omp_clause (hint_loc, OMP_CLAUSE_FILTER); + OMP_CLAUSE_FILTER_EXPR (c) = t; + OMP_CLAUSE_CHAIN (c) = list; + list = c; + } + + return list; +} + /* OpenMP 4.5: defaultmap ( tofrom : scalar ) @@ -15959,7 +15998,8 @@ c_parser_omp_clause_dist_schedule (c_parser *parser, tree list) proc_bind ( proc-bind-kind ) proc-bind-kind: - master | close | spread */ + primary | master | close | spread + where OpenMP 5.1 added 'primary' and deprecated the alias 'master'. */ static tree c_parser_omp_clause_proc_bind (c_parser *parser, tree list) @@ -15975,7 +16015,9 @@ c_parser_omp_clause_proc_bind (c_parser *parser, tree list) if (c_parser_next_token_is (parser, CPP_NAME)) { const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); - if (strcmp ("master", p) == 0) + if (strcmp ("primary", p) == 0) + kind = OMP_CLAUSE_PROC_BIND_PRIMARY; + else if (strcmp ("master", p) == 0) kind = OMP_CLAUSE_PROC_BIND_MASTER; else if (strcmp ("close", p) == 0) kind = OMP_CLAUSE_PROC_BIND_CLOSE; @@ -16407,6 +16449,10 @@ c_parser_omp_all_clauses (c_parser *parser, omp_clause_mask mask, clauses = c_parser_omp_clause_detach (parser, clauses); c_name = "detach"; break; + case PRAGMA_OMP_CLAUSE_FILTER: + clauses = c_parser_omp_clause_filter (parser, clauses); + c_name = "filter"; + break; case PRAGMA_OMP_CLAUSE_FIRSTPRIVATE: clauses = c_parser_omp_clause_firstprivate (parser, clauses); c_name = "firstprivate"; @@ -18972,6 +19018,70 @@ c_parser_omp_master (location_t loc, c_parser *parser, if_p)); } +/* OpenMP 5.1: + # pragma omp masked masked-clauses new-line + structured-block + + LOC is the location of the #pragma token. +*/ + +#define OMP_MASKED_CLAUSE_MASK \ + (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FILTER) + +static tree +c_parser_omp_masked (location_t loc, c_parser *parser, + char *p_name, omp_clause_mask mask, tree *cclauses, + bool *if_p) +{ + tree block, clauses, ret; + + strcat (p_name, " masked"); + mask |= OMP_MASKED_CLAUSE_MASK; + + if (c_parser_next_token_is (parser, CPP_NAME)) + { + const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); + + if (strcmp (p, "taskloop") == 0) + { + tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT]; + if (cclauses == NULL) + cclauses = cclauses_buf; + + c_parser_consume_token (parser); + if (!flag_openmp) /* flag_openmp_simd */ + return c_parser_omp_taskloop (loc, parser, p_name, mask, cclauses, + if_p); + block = c_begin_compound_stmt (true); + ret = c_parser_omp_taskloop (loc, parser, p_name, mask, cclauses, + if_p); + block = c_end_compound_stmt (loc, block, true); + if (ret == NULL_TREE) + return ret; + ret = c_finish_omp_masked (loc, block, + cclauses[C_OMP_CLAUSE_SPLIT_MASKED]); + OMP_MASKED_COMBINED (ret) = 1; + return ret; + } + } + if (!flag_openmp) /* flag_openmp_simd */ + { + c_parser_skip_to_pragma_eol (parser, false); + return NULL_TREE; + } + + clauses = c_parser_omp_all_clauses (parser, mask, p_name, cclauses == NULL); + if (cclauses) + { + omp_split_clauses (loc, OMP_MASKED, mask, clauses, cclauses); + clauses = cclauses[C_OMP_CLAUSE_SPLIT_MASKED]; + } + + return c_finish_omp_masked (loc, c_parser_omp_structured_block (parser, + if_p), + clauses); +} + /* OpenMP 2.5: # pragma omp ordered new-line structured-block @@ -19020,7 +19130,7 @@ c_parser_omp_ordered (c_parser *parser, enum pragma_context context, "%<#pragma omp ordered%> with %<depend%> clause may " "only be used in compound statements"); c_parser_skip_to_pragma_eol (parser, false); - return false; + return true; } tree clauses @@ -19234,7 +19344,36 @@ c_parser_omp_parallel (location_t loc, c_parser *parser, else if (c_parser_next_token_is (parser, CPP_NAME)) { const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); - if (cclauses == NULL && strcmp (p, "master") == 0) + if (cclauses == NULL && strcmp (p, "masked") == 0) + { + tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT]; + cclauses = cclauses_buf; + + c_parser_consume_token (parser); + if (!flag_openmp) /* flag_openmp_simd */ + return c_parser_omp_masked (loc, parser, p_name, mask, cclauses, + if_p); + block = c_begin_omp_parallel (); + tree ret = c_parser_omp_masked (loc, parser, p_name, mask, cclauses, + if_p); + stmt = c_finish_omp_parallel (loc, + cclauses[C_OMP_CLAUSE_SPLIT_PARALLEL], + block); + if (ret == NULL) + return ret; + /* masked does have just filter clause, but during gimplification + isn't represented by a gimplification omp context, so for + #pragma omp parallel masked don't set OMP_PARALLEL_COMBINED, + so that + #pragma omp parallel masked + #pragma omp taskloop simd lastprivate (x) + isn't confused with + #pragma omp parallel masked taskloop simd lastprivate (x) */ + if (OMP_MASKED_COMBINED (ret)) + OMP_PARALLEL_COMBINED (stmt) = 1; + return stmt; + } + else if (cclauses == NULL && strcmp (p, "master") == 0) { tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT]; cclauses = cclauses_buf; @@ -19354,6 +19493,33 @@ c_parser_omp_single (location_t loc, c_parser *parser, bool *if_p) return add_stmt (stmt); } +/* OpenMP 5.1: + # pragma omp scope scope-clause[optseq] new-line + structured-block + + LOC is the location of the #pragma. +*/ + +#define OMP_SCOPE_CLAUSE_MASK \ + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_REDUCTION) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT)) + +static tree +c_parser_omp_scope (location_t loc, c_parser *parser, bool *if_p) +{ + tree stmt = make_node (OMP_SCOPE); + SET_EXPR_LOCATION (stmt, loc); + TREE_TYPE (stmt) = void_type_node; + + OMP_SCOPE_CLAUSES (stmt) + = c_parser_omp_all_clauses (parser, OMP_SCOPE_CLAUSE_MASK, + "#pragma omp scope"); + OMP_SCOPE_BODY (stmt) = c_parser_omp_structured_block (parser, if_p); + + return add_stmt (stmt); +} + /* OpenMP 3.0: # pragma omp task task-clause[optseq] new-line @@ -19494,7 +19660,7 @@ c_parser_omp_cancel (c_parser *parser) | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SECTIONS) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_TASKGROUP)) -static void +static bool c_parser_omp_cancellation_point (c_parser *parser, enum pragma_context context) { location_t loc = c_parser_peek_token (parser)->location; @@ -19515,7 +19681,7 @@ c_parser_omp_cancellation_point (c_parser *parser, enum pragma_context context) { c_parser_error (parser, "expected %<point%>"); c_parser_skip_to_pragma_eol (parser); - return; + return false; } if (context != pragma_compound) @@ -19527,7 +19693,7 @@ c_parser_omp_cancellation_point (c_parser *parser, enum pragma_context context) else c_parser_error (parser, "expected declaration specifiers"); c_parser_skip_to_pragma_eol (parser, false); - return; + return true; } clauses @@ -19535,6 +19701,7 @@ c_parser_omp_cancellation_point (c_parser *parser, enum pragma_context context) "#pragma omp cancellation point"); c_finish_omp_cancellation_point (loc, clauses); + return true; } /* OpenMP 4.0: @@ -19820,7 +19987,7 @@ c_parser_omp_target_update (location_t loc, c_parser *parser, error_at (loc, "%<#pragma %s%> may only be used in compound statements", "omp target update"); c_parser_skip_to_pragma_eol (parser, false); - return false; + return true; } tree clauses @@ -19853,7 +20020,7 @@ c_parser_omp_target_update (location_t loc, c_parser *parser, | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEPEND) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT)) -static tree +static bool c_parser_omp_target_enter_data (location_t loc, c_parser *parser, enum pragma_context context) { @@ -19871,7 +20038,7 @@ c_parser_omp_target_enter_data (location_t loc, c_parser *parser, { c_parser_error (parser, "expected %<data%>"); c_parser_skip_to_pragma_eol (parser); - return NULL_TREE; + return false; } if (context == pragma_stmt) @@ -19879,7 +20046,7 @@ c_parser_omp_target_enter_data (location_t loc, c_parser *parser, error_at (loc, "%<#pragma %s%> may only be used in compound statements", "omp target enter data"); c_parser_skip_to_pragma_eol (parser, false); - return NULL_TREE; + return true; } tree clauses @@ -19918,7 +20085,7 @@ c_parser_omp_target_enter_data (location_t loc, c_parser *parser, error_at (loc, "%<#pragma omp target enter data%> must contain at least " "one %<map%> clause"); - return NULL_TREE; + return true; } tree stmt = make_node (OMP_TARGET_ENTER_DATA); @@ -19926,7 +20093,7 @@ c_parser_omp_target_enter_data (location_t loc, c_parser *parser, OMP_TARGET_ENTER_DATA_CLAUSES (stmt) = clauses; SET_EXPR_LOCATION (stmt, loc); add_stmt (stmt); - return stmt; + return true; } /* OpenMP 4.5: @@ -19939,7 +20106,7 @@ c_parser_omp_target_enter_data (location_t loc, c_parser *parser, | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEPEND) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT)) -static tree +static bool c_parser_omp_target_exit_data (location_t loc, c_parser *parser, enum pragma_context context) { @@ -19957,7 +20124,7 @@ c_parser_omp_target_exit_data (location_t loc, c_parser *parser, { c_parser_error (parser, "expected %<data%>"); c_parser_skip_to_pragma_eol (parser); - return NULL_TREE; + return false; } if (context == pragma_stmt) @@ -19965,7 +20132,7 @@ c_parser_omp_target_exit_data (location_t loc, c_parser *parser, error_at (loc, "%<#pragma %s%> may only be used in compound statements", "omp target exit data"); c_parser_skip_to_pragma_eol (parser, false); - return NULL_TREE; + return true; } tree clauses @@ -20006,7 +20173,7 @@ c_parser_omp_target_exit_data (location_t loc, c_parser *parser, error_at (loc, "%<#pragma omp target exit data%> must contain at least one " "%<map%> clause"); - return NULL_TREE; + return true; } tree stmt = make_node (OMP_TARGET_EXIT_DATA); @@ -20014,7 +20181,7 @@ c_parser_omp_target_exit_data (location_t loc, c_parser *parser, OMP_TARGET_EXIT_DATA_CLAUSES (stmt) = clauses; SET_EXPR_LOCATION (stmt, loc); add_stmt (stmt); - return stmt; + return true; } /* OpenMP 4.0: @@ -20172,14 +20339,12 @@ c_parser_omp_target (c_parser *parser, enum pragma_context context, bool *if_p) else if (strcmp (p, "enter") == 0) { c_parser_consume_token (parser); - c_parser_omp_target_enter_data (loc, parser, context); - return false; + return c_parser_omp_target_enter_data (loc, parser, context); } else if (strcmp (p, "exit") == 0) { c_parser_consume_token (parser); - c_parser_omp_target_exit_data (loc, parser, context); - return false; + return c_parser_omp_target_exit_data (loc, parser, context); } else if (strcmp (p, "update") == 0) { @@ -21438,7 +21603,7 @@ c_parser_omp_declare_reduction (c_parser *parser, enum pragma_context context) OpenMP 5.0 #pragma omp declare variant (identifier) match (context-selector) */ -static void +static bool c_parser_omp_declare (c_parser *parser, enum pragma_context context) { c_parser_consume_pragma (parser); @@ -21450,37 +21615,38 @@ c_parser_omp_declare (c_parser *parser, enum pragma_context context) /* c_parser_consume_token (parser); done in c_parser_omp_declare_simd. */ c_parser_omp_declare_simd (parser, context); - return; + return true; } if (strcmp (p, "reduction") == 0) { c_parser_consume_token (parser); c_parser_omp_declare_reduction (parser, context); - return; + return false; } if (!flag_openmp) /* flag_openmp_simd */ { c_parser_skip_to_pragma_eol (parser, false); - return; + return false; } if (strcmp (p, "target") == 0) { c_parser_consume_token (parser); c_parser_omp_declare_target (parser); - return; + return false; } if (strcmp (p, "variant") == 0) { /* c_parser_consume_token (parser); done in c_parser_omp_declare_simd. */ c_parser_omp_declare_simd (parser, context); - return; + return true; } } c_parser_error (parser, "expected %<simd%>, %<reduction%>, " "%<target%> or %<variant%>"); c_parser_skip_to_pragma_eol (parser); + return false; } /* OpenMP 5.0 @@ -21747,6 +21913,16 @@ c_parser_omp_taskloop (location_t loc, c_parser *parser, return ret; } +/* OpenMP 5.1 + #pragma omp nothing new-line */ + +static void +c_parser_omp_nothing (c_parser *parser) +{ + c_parser_consume_pragma (parser); + c_parser_skip_to_pragma_eol (parser); +} + /* Main entry point to parsing most OpenMP pragmas. */ static void @@ -21812,6 +21988,10 @@ c_parser_omp_construct (c_parser *parser, bool *if_p) strcpy (p_name, "#pragma omp"); stmt = c_parser_omp_loop (loc, parser, p_name, mask, NULL, if_p); break; + case PRAGMA_OMP_MASKED: + strcpy (p_name, "#pragma omp"); + stmt = c_parser_omp_masked (loc, parser, p_name, mask, NULL, if_p); + break; case PRAGMA_OMP_MASTER: strcpy (p_name, "#pragma omp"); stmt = c_parser_omp_master (loc, parser, p_name, mask, NULL, if_p); @@ -21820,6 +22000,9 @@ c_parser_omp_construct (c_parser *parser, bool *if_p) strcpy (p_name, "#pragma omp"); stmt = c_parser_omp_parallel (loc, parser, p_name, mask, NULL, if_p); break; + case PRAGMA_OMP_SCOPE: + stmt = c_parser_omp_scope (loc, parser, if_p); + break; case PRAGMA_OMP_SECTIONS: strcpy (p_name, "#pragma omp"); stmt = c_parser_omp_sections (loc, parser, p_name, mask, NULL); diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c index c5bf337..0c07af61 100644 --- a/gcc/c/c-typeck.c +++ b/gcc/c/c-typeck.c @@ -3022,8 +3022,14 @@ c_expr_sizeof_type (location_t loc, struct c_type_name *t) c_last_sizeof_loc = loc; ret.original_code = SIZEOF_EXPR; ret.original_type = NULL; + if (type == error_mark_node) + { + ret.value = error_mark_node; + ret.original_code = ERROR_MARK; + } + else if ((type_expr || TREE_CODE (ret.value) == INTEGER_CST) - && c_vla_type_p (type)) + && C_TYPE_VARIABLE_SIZE (type)) { /* If the type is a [*] array, it is a VLA but is represented as having a size of zero. In such a case we must ensure that @@ -15152,6 +15158,7 @@ c_finish_omp_clauses (tree clauses, enum c_omp_region_type ort) case OMP_CLAUSE_THREADS: case OMP_CLAUSE_SIMD: case OMP_CLAUSE_HINT: + case OMP_CLAUSE_FILTER: case OMP_CLAUSE_DEFAULTMAP: case OMP_CLAUSE_BIND: case OMP_CLAUSE_NUM_GANGS: diff --git a/gcc/calls.c b/gcc/calls.c index fcb0d6d..e50d3fc 100644 --- a/gcc/calls.c +++ b/gcc/calls.c @@ -17,7 +17,6 @@ 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 INCLUDE_STRING #include "config.h" #include "system.h" #include "coretypes.h" @@ -50,7 +49,6 @@ along with GCC; see the file COPYING3. If not see #include "rtl-iter.h" #include "tree-vrp.h" #include "tree-ssanames.h" -#include "tree-ssa-strlen.h" #include "intl.h" #include "stringpool.h" #include "hash-map.h" @@ -60,8 +58,6 @@ along with GCC; see the file COPYING3. If not see #include "gimple-fold.h" #include "attr-fnspec.h" #include "value-query.h" -#include "pointer-query.h" -#include "gimple-ssa-warn-access.h" #include "tree-pretty-print.h" /* Like PREFERRED_STACK_BOUNDARY but in units of bytes, not bits. */ @@ -1223,397 +1219,6 @@ store_unaligned_arguments_into_pseudos (struct arg_data *args, int num_actuals) } } -/* The limit set by -Walloc-larger-than=. */ -static GTY(()) tree alloc_object_size_limit; - -/* Initialize ALLOC_OBJECT_SIZE_LIMIT based on the -Walloc-size-larger-than= - setting if the option is specified, or to the maximum object size if it - is not. Return the initialized value. */ - -static tree -alloc_max_size (void) -{ - if (alloc_object_size_limit) - return alloc_object_size_limit; - - HOST_WIDE_INT limit = warn_alloc_size_limit; - if (limit == HOST_WIDE_INT_MAX) - limit = tree_to_shwi (TYPE_MAX_VALUE (ptrdiff_type_node)); - - alloc_object_size_limit = build_int_cst (size_type_node, limit); - - return alloc_object_size_limit; -} - -/* Return true when EXP's range can be determined and set RANGE[] to it - after adjusting it if necessary to make EXP a represents a valid size - of object, or a valid size argument to an allocation function declared - with attribute alloc_size (whose argument may be signed), or to a string - manipulation function like memset. - When ALLOW_ZERO is set in FLAGS, allow returning a range of [0, 0] for - a size in an anti-range [1, N] where N > PTRDIFF_MAX. A zero range is - a (nearly) invalid argument to allocation functions like malloc but it - is a valid argument to functions like memset. - When USE_LARGEST is set in FLAGS set RANGE to the largest valid subrange - in a multi-range, otherwise to the smallest valid subrange. */ - -bool -get_size_range (range_query *query, tree exp, gimple *stmt, tree range[2], - int flags /* = 0 */) -{ - if (!exp) - return false; - - if (tree_fits_uhwi_p (exp)) - { - /* EXP is a constant. */ - range[0] = range[1] = exp; - return true; - } - - tree exptype = TREE_TYPE (exp); - bool integral = INTEGRAL_TYPE_P (exptype); - - wide_int min, max; - enum value_range_kind range_type; - - if (!query) - query = get_global_range_query (); - - if (integral) - { - value_range vr; - - query->range_of_expr (vr, exp, stmt); - - if (vr.undefined_p ()) - vr.set_varying (TREE_TYPE (exp)); - range_type = vr.kind (); - min = wi::to_wide (vr.min ()); - max = wi::to_wide (vr.max ()); - } - else - range_type = VR_VARYING; - - if (range_type == VR_VARYING) - { - if (integral) - { - /* Use the full range of the type of the expression when - no value range information is available. */ - range[0] = TYPE_MIN_VALUE (exptype); - range[1] = TYPE_MAX_VALUE (exptype); - return true; - } - - range[0] = NULL_TREE; - range[1] = NULL_TREE; - return false; - } - - unsigned expprec = TYPE_PRECISION (exptype); - - bool signed_p = !TYPE_UNSIGNED (exptype); - - if (range_type == VR_ANTI_RANGE) - { - if (signed_p) - { - if (wi::les_p (max, 0)) - { - /* EXP is not in a strictly negative range. That means - it must be in some (not necessarily strictly) positive - range which includes zero. Since in signed to unsigned - conversions negative values end up converted to large - positive values, and otherwise they are not valid sizes, - the resulting range is in both cases [0, TYPE_MAX]. */ - min = wi::zero (expprec); - max = wi::to_wide (TYPE_MAX_VALUE (exptype)); - } - else if (wi::les_p (min - 1, 0)) - { - /* EXP is not in a negative-positive range. That means EXP - is either negative, or greater than max. Since negative - sizes are invalid make the range [MAX + 1, TYPE_MAX]. */ - min = max + 1; - max = wi::to_wide (TYPE_MAX_VALUE (exptype)); - } - else - { - max = min - 1; - min = wi::zero (expprec); - } - } - else - { - wide_int maxsize = wi::to_wide (max_object_size ()); - min = wide_int::from (min, maxsize.get_precision (), UNSIGNED); - max = wide_int::from (max, maxsize.get_precision (), UNSIGNED); - if (wi::eq_p (0, min - 1)) - { - /* EXP is unsigned and not in the range [1, MAX]. That means - it's either zero or greater than MAX. Even though 0 would - normally be detected by -Walloc-zero, unless ALLOW_ZERO - is set, set the range to [MAX, TYPE_MAX] so that when MAX - is greater than the limit the whole range is diagnosed. */ - wide_int maxsize = wi::to_wide (max_object_size ()); - if (flags & SR_ALLOW_ZERO) - { - if (wi::leu_p (maxsize, max + 1) - || !(flags & SR_USE_LARGEST)) - min = max = wi::zero (expprec); - else - { - min = max + 1; - max = wi::to_wide (TYPE_MAX_VALUE (exptype)); - } - } - else - { - min = max + 1; - max = wi::to_wide (TYPE_MAX_VALUE (exptype)); - } - } - else if ((flags & SR_USE_LARGEST) - && wi::ltu_p (max + 1, maxsize)) - { - /* When USE_LARGEST is set and the larger of the two subranges - is a valid size, use it... */ - min = max + 1; - max = maxsize; - } - else - { - /* ...otherwise use the smaller subrange. */ - max = min - 1; - min = wi::zero (expprec); - } - } - } - - range[0] = wide_int_to_tree (exptype, min); - range[1] = wide_int_to_tree (exptype, max); - - return true; -} - -bool -get_size_range (tree exp, tree range[2], int flags /* = 0 */) -{ - return get_size_range (/*query=*/NULL, exp, /*stmt=*/NULL, range, flags); -} - -/* Diagnose a call EXP to function FN decorated with attribute alloc_size - whose argument numbers given by IDX with values given by ARGS exceed - the maximum object size or cause an unsigned oveflow (wrapping) when - multiplied. FN is null when EXP is a call via a function pointer. - When ARGS[0] is null the function does nothing. ARGS[1] may be null - for functions like malloc, and non-null for those like calloc that - are decorated with a two-argument attribute alloc_size. */ - -void -maybe_warn_alloc_args_overflow (tree fn, tree exp, tree args[2], int idx[2]) -{ - /* The range each of the (up to) two arguments is known to be in. */ - tree argrange[2][2] = { { NULL_TREE, NULL_TREE }, { NULL_TREE, NULL_TREE } }; - - /* Maximum object size set by -Walloc-size-larger-than= or SIZE_MAX / 2. */ - tree maxobjsize = alloc_max_size (); - - location_t loc = EXPR_LOCATION (exp); - - tree fntype = fn ? TREE_TYPE (fn) : TREE_TYPE (TREE_TYPE (exp)); - bool warned = false; - - /* Validate each argument individually. */ - for (unsigned i = 0; i != 2 && args[i]; ++i) - { - if (TREE_CODE (args[i]) == INTEGER_CST) - { - argrange[i][0] = args[i]; - argrange[i][1] = args[i]; - - if (tree_int_cst_lt (args[i], integer_zero_node)) - { - warned = warning_at (loc, OPT_Walloc_size_larger_than_, - "argument %i value %qE is negative", - idx[i] + 1, args[i]); - } - else if (integer_zerop (args[i])) - { - /* Avoid issuing -Walloc-zero for allocation functions other - than __builtin_alloca that are declared with attribute - returns_nonnull because there's no portability risk. This - avoids warning for such calls to libiberty's xmalloc and - friends. - Also avoid issuing the warning for calls to function named - "alloca". */ - if (fn && fndecl_built_in_p (fn, BUILT_IN_ALLOCA) - ? IDENTIFIER_LENGTH (DECL_NAME (fn)) != 6 - : !lookup_attribute ("returns_nonnull", - TYPE_ATTRIBUTES (fntype))) - warned = warning_at (loc, OPT_Walloc_zero, - "argument %i value is zero", - idx[i] + 1); - } - else if (tree_int_cst_lt (maxobjsize, args[i])) - { - /* G++ emits calls to ::operator new[](SIZE_MAX) in C++98 - mode and with -fno-exceptions as a way to indicate array - size overflow. There's no good way to detect C++98 here - so avoid diagnosing these calls for all C++ modes. */ - if (i == 0 - && fn - && !args[1] - && lang_GNU_CXX () - && DECL_IS_OPERATOR_NEW_P (fn) - && integer_all_onesp (args[i])) - continue; - - warned = warning_at (loc, OPT_Walloc_size_larger_than_, - "argument %i value %qE exceeds " - "maximum object size %E", - idx[i] + 1, args[i], maxobjsize); - } - } - else if (TREE_CODE (args[i]) == SSA_NAME - && get_size_range (args[i], argrange[i])) - { - /* Verify that the argument's range is not negative (including - upper bound of zero). */ - if (tree_int_cst_lt (argrange[i][0], integer_zero_node) - && tree_int_cst_le (argrange[i][1], integer_zero_node)) - { - warned = warning_at (loc, OPT_Walloc_size_larger_than_, - "argument %i range [%E, %E] is negative", - idx[i] + 1, - argrange[i][0], argrange[i][1]); - } - else if (tree_int_cst_lt (maxobjsize, argrange[i][0])) - { - warned = warning_at (loc, OPT_Walloc_size_larger_than_, - "argument %i range [%E, %E] exceeds " - "maximum object size %E", - idx[i] + 1, - argrange[i][0], argrange[i][1], - maxobjsize); - } - } - } - - if (!argrange[0]) - return; - - /* For a two-argument alloc_size, validate the product of the two - arguments if both of their values or ranges are known. */ - if (!warned && tree_fits_uhwi_p (argrange[0][0]) - && argrange[1][0] && tree_fits_uhwi_p (argrange[1][0]) - && !integer_onep (argrange[0][0]) - && !integer_onep (argrange[1][0])) - { - /* Check for overflow in the product of a function decorated with - attribute alloc_size (X, Y). */ - unsigned szprec = TYPE_PRECISION (size_type_node); - wide_int x = wi::to_wide (argrange[0][0], szprec); - wide_int y = wi::to_wide (argrange[1][0], szprec); - - wi::overflow_type vflow; - wide_int prod = wi::umul (x, y, &vflow); - - if (vflow) - warned = warning_at (loc, OPT_Walloc_size_larger_than_, - "product %<%E * %E%> of arguments %i and %i " - "exceeds %<SIZE_MAX%>", - argrange[0][0], argrange[1][0], - idx[0] + 1, idx[1] + 1); - else if (wi::ltu_p (wi::to_wide (maxobjsize, szprec), prod)) - warned = warning_at (loc, OPT_Walloc_size_larger_than_, - "product %<%E * %E%> of arguments %i and %i " - "exceeds maximum object size %E", - argrange[0][0], argrange[1][0], - idx[0] + 1, idx[1] + 1, - maxobjsize); - - if (warned) - { - /* Print the full range of each of the two arguments to make - it clear when it is, in fact, in a range and not constant. */ - if (argrange[0][0] != argrange [0][1]) - inform (loc, "argument %i in the range [%E, %E]", - idx[0] + 1, argrange[0][0], argrange[0][1]); - if (argrange[1][0] != argrange [1][1]) - inform (loc, "argument %i in the range [%E, %E]", - idx[1] + 1, argrange[1][0], argrange[1][1]); - } - } - - if (warned && fn) - { - location_t fnloc = DECL_SOURCE_LOCATION (fn); - - if (DECL_IS_UNDECLARED_BUILTIN (fn)) - inform (loc, - "in a call to built-in allocation function %qD", fn); - else - inform (fnloc, - "in a call to allocation function %qD declared here", fn); - } -} - -/* If EXPR refers to a character array or pointer declared attribute - nonstring return a decl for that array or pointer and set *REF to - the referenced enclosing object or pointer. Otherwise returns - null. */ - -tree -get_attr_nonstring_decl (tree expr, tree *ref) -{ - tree decl = expr; - tree var = NULL_TREE; - if (TREE_CODE (decl) == SSA_NAME) - { - gimple *def = SSA_NAME_DEF_STMT (decl); - - if (is_gimple_assign (def)) - { - tree_code code = gimple_assign_rhs_code (def); - if (code == ADDR_EXPR - || code == COMPONENT_REF - || code == VAR_DECL) - decl = gimple_assign_rhs1 (def); - } - else - var = SSA_NAME_VAR (decl); - } - - if (TREE_CODE (decl) == ADDR_EXPR) - decl = TREE_OPERAND (decl, 0); - - /* To simplify calling code, store the referenced DECL regardless of - the attribute determined below, but avoid storing the SSA_NAME_VAR - obtained above (it's not useful for dataflow purposes). */ - if (ref) - *ref = decl; - - /* Use the SSA_NAME_VAR that was determined above to see if it's - declared nonstring. Otherwise drill down into the referenced - DECL. */ - if (var) - decl = var; - else if (TREE_CODE (decl) == ARRAY_REF) - decl = TREE_OPERAND (decl, 0); - else if (TREE_CODE (decl) == COMPONENT_REF) - decl = TREE_OPERAND (decl, 1); - else if (TREE_CODE (decl) == MEM_REF) - return get_attr_nonstring_decl (TREE_OPERAND (decl, 0), ref); - - if (DECL_P (decl) - && lookup_attribute ("nonstring", DECL_ATTRIBUTES (decl))) - return decl; - - return NULL_TREE; -} - /* Issue an error if CALL_EXPR was flagged as requiring tall-call optimization. */ @@ -1627,310 +1232,6 @@ maybe_complain_about_tail_call (tree call_expr, const char *reason) error_at (EXPR_LOCATION (call_expr), "cannot tail-call: %s", reason); } -/* Returns the type of the argument ARGNO to function with type FNTYPE - or null when the typoe cannot be determined or no such argument exists. */ - -static tree -fntype_argno_type (tree fntype, unsigned argno) -{ - if (!prototype_p (fntype)) - return NULL_TREE; - - tree argtype; - function_args_iterator it; - FOREACH_FUNCTION_ARGS (fntype, argtype, it) - if (argno-- == 0) - return argtype; - - return NULL_TREE; -} - -/* Helper to append the "human readable" attribute access specification - described by ACCESS to the array ATTRSTR with size STRSIZE. Used in - diagnostics. */ - -static inline void -append_attrname (const std::pair<int, attr_access> &access, - char *attrstr, size_t strsize) -{ - if (access.second.internal_p) - return; - - tree str = access.second.to_external_string (); - gcc_assert (strsize >= (size_t) TREE_STRING_LENGTH (str)); - strcpy (attrstr, TREE_STRING_POINTER (str)); -} - -/* Iterate over attribute access read-only, read-write, and write-only - arguments and diagnose past-the-end accesses and related problems - in the function call EXP. */ - -static void -maybe_warn_rdwr_sizes (rdwr_map *rwm, tree fndecl, tree fntype, tree exp) -{ - auto_diagnostic_group adg; - - /* Set if a warning has been issued for any argument (used to decide - whether to emit an informational note at the end). */ - opt_code opt_warned = N_OPTS; - - /* A string describing the attributes that the warnings issued by this - function apply to. Used to print one informational note per function - call, rather than one per warning. That reduces clutter. */ - char attrstr[80]; - attrstr[0] = 0; - - for (rdwr_map::iterator it = rwm->begin (); it != rwm->end (); ++it) - { - std::pair<int, attr_access> access = *it; - - /* Get the function call arguments corresponding to the attribute's - positional arguments. When both arguments have been specified - there will be two entries in *RWM, one for each. They are - cross-referenced by their respective argument numbers in - ACCESS.PTRARG and ACCESS.SIZARG. */ - const int ptridx = access.second.ptrarg; - const int sizidx = access.second.sizarg; - - gcc_assert (ptridx != -1); - gcc_assert (access.first == ptridx || access.first == sizidx); - - /* The pointer is set to null for the entry corresponding to - the size argument. Skip it. It's handled when the entry - corresponding to the pointer argument comes up. */ - if (!access.second.ptr) - continue; - - tree ptrtype = fntype_argno_type (fntype, ptridx); - tree argtype = TREE_TYPE (ptrtype); - - /* The size of the access by the call. */ - tree access_size; - if (sizidx == -1) - { - /* If only the pointer attribute operand was specified and - not size, set SIZE to the greater of MINSIZE or size of - one element of the pointed to type to detect smaller - objects (null pointers are diagnosed in this case only - if the pointer is also declared with attribute nonnull. */ - if (access.second.minsize - && access.second.minsize != HOST_WIDE_INT_M1U) - access_size = build_int_cstu (sizetype, access.second.minsize); - else - access_size = size_one_node; - } - else - access_size = rwm->get (sizidx)->size; - - /* Format the value or range to avoid an explosion of messages. */ - char sizstr[80]; - tree sizrng[2] = { size_zero_node, build_all_ones_cst (sizetype) }; - if (get_size_range (access_size, sizrng, true)) - { - char *s0 = print_generic_expr_to_str (sizrng[0]); - if (tree_int_cst_equal (sizrng[0], sizrng[1])) - { - gcc_checking_assert (strlen (s0) < sizeof sizstr); - strcpy (sizstr, s0); - } - else - { - char *s1 = print_generic_expr_to_str (sizrng[1]); - gcc_checking_assert (strlen (s0) + strlen (s1) - < sizeof sizstr - 4); - sprintf (sizstr, "[%s, %s]", s0, s1); - free (s1); - } - free (s0); - } - else - *sizstr = '\0'; - - /* Set if a warning has been issued for the current argument. */ - opt_code arg_warned = no_warning; - location_t loc = EXPR_LOCATION (exp); - tree ptr = access.second.ptr; - if (*sizstr - && tree_int_cst_sgn (sizrng[0]) < 0 - && tree_int_cst_sgn (sizrng[1]) < 0) - { - /* Warn about negative sizes. */ - if (access.second.internal_p) - { - const std::string argtypestr - = access.second.array_as_string (ptrtype); - - if (warning_at (loc, OPT_Wstringop_overflow_, - "bound argument %i value %s is " - "negative for a variable length array " - "argument %i of type %s", - sizidx + 1, sizstr, - ptridx + 1, argtypestr.c_str ())) - arg_warned = OPT_Wstringop_overflow_; - } - else if (warning_at (loc, OPT_Wstringop_overflow_, - "argument %i value %s is negative", - sizidx + 1, sizstr)) - arg_warned = OPT_Wstringop_overflow_; - - if (arg_warned != no_warning) - { - append_attrname (access, attrstr, sizeof attrstr); - /* Remember a warning has been issued and avoid warning - again below for the same attribute. */ - opt_warned = arg_warned; - continue; - } - } - - if (tree_int_cst_sgn (sizrng[0]) >= 0) - { - if (COMPLETE_TYPE_P (argtype)) - { - /* Multiply ACCESS_SIZE by the size of the type the pointer - argument points to. If it's incomplete the size is used - as is. */ - if (tree argsize = TYPE_SIZE_UNIT (argtype)) - if (TREE_CODE (argsize) == INTEGER_CST) - { - const int prec = TYPE_PRECISION (sizetype); - wide_int minsize = wi::to_wide (sizrng[0], prec); - minsize *= wi::to_wide (argsize, prec); - access_size = wide_int_to_tree (sizetype, minsize); - } - } - } - else - access_size = NULL_TREE; - - if (integer_zerop (ptr)) - { - if (sizidx >= 0 && tree_int_cst_sgn (sizrng[0]) > 0) - { - /* Warn about null pointers with positive sizes. This is - different from also declaring the pointer argument with - attribute nonnull when the function accepts null pointers - only when the corresponding size is zero. */ - if (access.second.internal_p) - { - const std::string argtypestr - = access.second.array_as_string (ptrtype); - - if (warning_at (loc, OPT_Wnonnull, - "argument %i of variable length " - "array %s is null but " - "the corresponding bound argument " - "%i value is %s", - ptridx + 1, argtypestr.c_str (), - sizidx + 1, sizstr)) - arg_warned = OPT_Wnonnull; - } - else if (warning_at (loc, OPT_Wnonnull, - "argument %i is null but " - "the corresponding size argument " - "%i value is %s", - ptridx + 1, sizidx + 1, sizstr)) - arg_warned = OPT_Wnonnull; - } - else if (access_size && access.second.static_p) - { - /* Warn about null pointers for [static N] array arguments - but do not warn for ordinary (i.e., nonstatic) arrays. */ - if (warning_at (loc, OPT_Wnonnull, - "argument %i to %<%T[static %E]%> " - "is null where non-null expected", - ptridx + 1, argtype, access_size)) - arg_warned = OPT_Wnonnull; - } - - if (arg_warned != no_warning) - { - append_attrname (access, attrstr, sizeof attrstr); - /* Remember a warning has been issued and avoid warning - again below for the same attribute. */ - opt_warned = OPT_Wnonnull; - continue; - } - } - - access_data data (ptr, access.second.mode, NULL_TREE, false, - NULL_TREE, false); - access_ref* const pobj = (access.second.mode == access_write_only - ? &data.dst : &data.src); - tree objsize = compute_objsize (ptr, 1, pobj); - - /* The size of the destination or source object. */ - tree dstsize = NULL_TREE, srcsize = NULL_TREE; - if (access.second.mode == access_read_only - || access.second.mode == access_none) - { - /* For a read-only argument there is no destination. For - no access, set the source as well and differentiate via - the access flag below. */ - srcsize = objsize; - if (access.second.mode == access_read_only - || access.second.mode == access_none) - { - /* For a read-only attribute there is no destination so - clear OBJSIZE. This emits "reading N bytes" kind of - diagnostics instead of the "writing N bytes" kind, - unless MODE is none. */ - objsize = NULL_TREE; - } - } - else - dstsize = objsize; - - /* Clear the no-warning bit in case it was set by check_access - in a prior iteration so that accesses via different arguments - are diagnosed. */ - suppress_warning (exp, OPT_Wstringop_overflow_, false); - access_mode mode = data.mode; - if (mode == access_deferred) - mode = TYPE_READONLY (argtype) ? access_read_only : access_read_write; - check_access (exp, access_size, /*maxread=*/ NULL_TREE, srcsize, - dstsize, mode, &data); - - if (warning_suppressed_p (exp, OPT_Wstringop_overflow_)) - opt_warned = OPT_Wstringop_overflow_; - if (opt_warned != N_OPTS) - { - if (access.second.internal_p) - inform (loc, "referencing argument %u of type %qT", - ptridx + 1, ptrtype); - else - /* If check_access issued a warning above, append the relevant - attribute to the string. */ - append_attrname (access, attrstr, sizeof attrstr); - } - } - - if (*attrstr) - { - if (fndecl) - inform (DECL_SOURCE_LOCATION (fndecl), - "in a call to function %qD declared with attribute %qs", - fndecl, attrstr); - else - inform (EXPR_LOCATION (fndecl), - "in a call with type %qT and attribute %qs", - fntype, attrstr); - } - else if (opt_warned != N_OPTS) - { - if (fndecl) - inform (DECL_SOURCE_LOCATION (fndecl), - "in a call to function %qD", fndecl); - else - inform (EXPR_LOCATION (fndecl), - "in a call with type %qT", fntype); - } - - /* Set the bit in case if was cleared and not set above. */ - if (opt_warned != N_OPTS) - suppress_warning (exp, opt_warned); -} - /* Fill in ARGS_SIZE and ARGS array based on the parameters found in CALL_EXPR EXP. @@ -2030,27 +1331,6 @@ initialize_argument_information (int num_actuals ATTRIBUTE_UNUSED, bitmap_obstack_release (NULL); - tree fntypeattrs = TYPE_ATTRIBUTES (fntype); - /* Extract attribute alloc_size from the type of the called expression - (which could be a function or a function pointer) and if set, store - the indices of the corresponding arguments in ALLOC_IDX, and then - the actual argument(s) at those indices in ALLOC_ARGS. */ - int alloc_idx[2] = { -1, -1 }; - if (tree alloc_size = lookup_attribute ("alloc_size", fntypeattrs)) - { - tree args = TREE_VALUE (alloc_size); - alloc_idx[0] = TREE_INT_CST_LOW (TREE_VALUE (args)) - 1; - if (TREE_CHAIN (args)) - alloc_idx[1] = TREE_INT_CST_LOW (TREE_VALUE (TREE_CHAIN (args))) - 1; - } - - /* Array for up to the two attribute alloc_size arguments. */ - tree alloc_args[] = { NULL_TREE, NULL_TREE }; - - /* Map of attribute accewss specifications for function arguments. */ - rdwr_map rdwr_idx; - init_attr_rdwr_indices (&rdwr_idx, fntypeattrs); - /* I counts args in order (to be) pushed; ARGPOS counts in order written. */ for (argpos = 0; argpos < num_actuals; i--, argpos++) { @@ -2283,44 +1563,7 @@ initialize_argument_information (int num_actuals ATTRIBUTE_UNUSED, does pass the promoted mode. */ arg.mode = TYPE_MODE (type); targetm.calls.function_arg_advance (args_so_far, arg); - - /* Store argument values for functions decorated with attribute - alloc_size. */ - if (argpos == alloc_idx[0]) - alloc_args[0] = args[i].tree_value; - else if (argpos == alloc_idx[1]) - alloc_args[1] = args[i].tree_value; - - /* Save the actual argument that corresponds to the access attribute - operand for later processing. */ - if (attr_access *access = rdwr_idx.get (argpos)) - { - if (POINTER_TYPE_P (type)) - { - access->ptr = args[i].tree_value; - // A nonnull ACCESS->SIZE contains VLA bounds. */ - } - else - { - access->size = args[i].tree_value; - gcc_assert (access->ptr == NULL_TREE); - } - } - } - - if (alloc_args[0]) - { - /* Check the arguments of functions decorated with attribute - alloc_size. */ - maybe_warn_alloc_args_overflow (fndecl, exp, alloc_args, alloc_idx); } - - /* Detect passing non-string arguments to functions expecting - nul-terminated strings. */ - maybe_warn_nonstring_arg (fndecl, exp); - - /* Check attribute access arguments. */ - maybe_warn_rdwr_sizes (&rdwr_idx, fndecl, fntype, exp); } /* Update ARGS_SIZE to contain the total size for the argument block. @@ -6020,6 +5263,3 @@ cxx17_empty_base_field_p (const_tree field) && RECORD_OR_UNION_TYPE_P (TREE_TYPE (field)) && !lookup_attribute ("no_unique_address", DECL_ATTRIBUTES (field))); } - -/* Tell the garbage collector about GTY markers in this source file. */ -#include "gt-calls.h" diff --git a/gcc/calls.h b/gcc/calls.h index 4a018f6..9a98f5d 100644 --- a/gcc/calls.h +++ b/gcc/calls.h @@ -130,21 +130,8 @@ extern bool apply_pass_by_reference_rules (CUMULATIVE_ARGS *, function_arg_info &); extern bool reference_callee_copied (CUMULATIVE_ARGS *, const function_arg_info &); -extern void maybe_warn_alloc_args_overflow (tree, tree, tree[2], int[2]); -extern tree get_attr_nonstring_decl (tree, tree * = NULL); -extern bool maybe_warn_nonstring_arg (tree, tree); extern void maybe_complain_about_tail_call (tree, const char *); -enum size_range_flags - { - /* Set to consider zero a valid range. */ - SR_ALLOW_ZERO = 1, - /* Set to use the largest subrange of a set of ranges as opposed - to the smallest. */ - SR_USE_LARGEST = 2 - }; -extern bool get_size_range (tree, tree[2], int = 0); -extern bool get_size_range (class range_query *, tree, gimple *, - tree[2], int = 0); + extern rtx rtx_for_static_chain (const_tree, bool); extern bool cxx17_empty_base_field_p (const_tree); diff --git a/gcc/cfgexpand.c b/gcc/cfgexpand.c index 8183280..03260b0 100644 --- a/gcc/cfgexpand.c +++ b/gcc/cfgexpand.c @@ -2294,22 +2294,19 @@ expand_used_vars (bitmap forced_stack_vars) if (gen_stack_protect_signal || cfun->calls_alloca || has_protected_decls - || lookup_attribute ("stack_protect", - DECL_ATTRIBUTES (current_function_decl))) + || lookup_attribute ("stack_protect", attribs)) create_stack_guard (); break; case SPCT_FLAG_DEFAULT: if (cfun->calls_alloca || has_protected_decls - || lookup_attribute ("stack_protect", - DECL_ATTRIBUTES (current_function_decl))) + || lookup_attribute ("stack_protect", attribs)) create_stack_guard (); break; case SPCT_FLAG_EXPLICIT: - if (lookup_attribute ("stack_protect", - DECL_ATTRIBUTES (current_function_decl))) + if (lookup_attribute ("stack_protect", attribs)) create_stack_guard (); break; diff --git a/gcc/common/config/arc/arc-common.c b/gcc/common/config/arc/arc-common.c index 6a11902..3b36d09 100644 --- a/gcc/common/config/arc/arc-common.c +++ b/gcc/common/config/arc/arc-common.c @@ -30,10 +30,8 @@ along with GCC; see the file COPYING3. If not see #include "flags.h" static void -arc_option_init_struct (struct gcc_options *opts) +arc_option_init_struct (struct gcc_options *opts ATTRIBUTE_UNUSED) { - opts->x_flag_no_common = 255; /* Mark as not user-initialized. */ - /* Which cpu we're compiling for (ARC600, ARC601, ARC700, ARCv2). */ arc_cpu = PROCESSOR_NONE; } diff --git a/gcc/config.gcc b/gcc/config.gcc index 93e2b32..d9bfbfd 100644 --- a/gcc/config.gcc +++ b/gcc/config.gcc @@ -851,8 +851,14 @@ case ${target} in tmake_file="${tmake_file} t-glibc" target_has_targetcm=yes target_has_targetdm=yes - # Linux targets always support .init_array. - gcc_cv_initfini_array=yes + case $target in + *-*-*uclibc* | *-*-uclinuxfdpiceabi) + ;; + *) + # Linux targets always support .init_array. + gcc_cv_initfini_array=yes + ;; + esac ;; *-*-netbsd*) tm_p_file="${tm_p_file} netbsd-protos.h" @@ -3126,7 +3132,7 @@ rs6000-ibm-aix[789].* | powerpc-ibm-aix[789].*) default_use_cxa_atexit=yes ;; rl78-*-elf*) - tm_file="dbxelf.h elfos.h newlib-stdint.h ${tm_file}" + tm_file="elfos.h newlib-stdint.h ${tm_file}" target_has_targetm_common=no c_target_objs="rl78-c.o" cxx_target_objs="rl78-c.o" diff --git a/gcc/config.in b/gcc/config.in index affaff2..d8a810b 100644 --- a/gcc/config.in +++ b/gcc/config.in @@ -616,6 +616,13 @@ #endif +/* Define if your Mac OS X assembler supports -mllvm -x86-pad-for-align=false. + */ +#ifndef USED_FOR_TARGET +#undef HAVE_AS_MLLVM_X86_PAD_FOR_ALIGN +#endif + + /* Define if your Mac OS X assembler supports the -mmacos-version-min option. */ #ifndef USED_FOR_TARGET @@ -1695,6 +1702,12 @@ #endif +/* Define if the PE linker supports --disable-dynamicbase option. */ +#ifndef USED_FOR_TARGET +#undef HAVE_LD_PE_DISABLE_DYNAMICBASE +#endif + + /* Define if your linker supports PIE option. */ #ifndef USED_FOR_TARGET #undef HAVE_LD_PIE diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c index 4cd4b03..3213585 100644 --- a/gcc/config/aarch64/aarch64.c +++ b/gcc/config/aarch64/aarch64.c @@ -4174,7 +4174,7 @@ aarch64_force_temporary (machine_mode mode, rtx x, rtx value) static bool aarch64_get_sve_pred_bits (rtx_vector_builder &builder, rtx x) { - if (GET_CODE (x) != CONST_VECTOR) + if (!CONST_VECTOR_P (x)) return false; unsigned int factor = vector_element_size (GET_MODE_NUNITS (VNx16BImode), @@ -4230,7 +4230,7 @@ opt_machine_mode aarch64_ptrue_all_mode (rtx x) { gcc_assert (GET_MODE (x) == VNx16BImode); - if (GET_CODE (x) != CONST_VECTOR + if (!CONST_VECTOR_P (x) || !CONST_VECTOR_DUPLICATE_P (x) || !CONST_INT_P (CONST_VECTOR_ENCODED_ELT (x, 0)) || INTVAL (CONST_VECTOR_ENCODED_ELT (x, 0)) == 0) @@ -5930,7 +5930,7 @@ aarch64_expand_mov_immediate (rtx dest, rtx imm) return; } - if (GET_CODE (imm) == CONST_VECTOR && aarch64_sve_data_mode_p (mode)) + if (CONST_VECTOR_P (imm) && aarch64_sve_data_mode_p (mode)) if (rtx res = aarch64_expand_sve_const_vector (dest, imm)) { if (dest != res) @@ -10634,7 +10634,7 @@ aarch64_const_vec_all_in_range_p (rtx vec, HOST_WIDE_INT minval, HOST_WIDE_INT maxval) { - if (GET_CODE (vec) != CONST_VECTOR + if (!CONST_VECTOR_P (vec) || GET_MODE_CLASS (GET_MODE (vec)) != MODE_VECTOR_INT) return false; @@ -12771,7 +12771,7 @@ aarch64_rtx_costs (rtx x, machine_mode mode, int outer ATTRIBUTE_UNUSED, case SIGN_EXTRACT: /* Bit-field insertion. Strip any redundant widening of the RHS to meet the width of the target. */ - if (GET_CODE (op1) == SUBREG) + if (SUBREG_P (op1)) op1 = SUBREG_REG (op1); if ((GET_CODE (op1) == ZERO_EXTEND || GET_CODE (op1) == SIGN_EXTEND) @@ -13044,7 +13044,7 @@ aarch64_rtx_costs (rtx x, machine_mode mode, int outer ATTRIBUTE_UNUSED, But the integer MINUS logic expects the shift/extend operation in op1. */ if (! (REG_P (op0) - || (GET_CODE (op0) == SUBREG && REG_P (SUBREG_REG (op0))))) + || (SUBREG_P (op0) && REG_P (SUBREG_REG (op0))))) { op0 = XEXP (x, 1); op1 = XEXP (x, 0); @@ -18239,7 +18239,7 @@ aarch64_legitimate_constant_p (machine_mode mode, rtx x) /* Otherwise, accept any CONST_VECTOR that, if all else fails, can at least be forced to memory and loaded from there. */ - if (GET_CODE (x) == CONST_VECTOR) + if (CONST_VECTOR_P (x)) return !targetm.cannot_force_const_mem (mode, x); /* Do not allow vector struct mode constants for Advanced SIMD. @@ -20044,7 +20044,7 @@ aarch64_simd_valid_immediate (rtx op, simd_immediate_info *info, scalar_mode elt_mode = GET_MODE_INNER (mode); rtx base, step; unsigned int n_elts; - if (GET_CODE (op) == CONST_VECTOR + if (CONST_VECTOR_P (op) && CONST_VECTOR_DUPLICATE_P (op)) n_elts = CONST_VECTOR_NPATTERNS (op); else if ((vec_flags & VEC_SVE_DATA) @@ -20066,7 +20066,7 @@ aarch64_simd_valid_immediate (rtx op, simd_immediate_info *info, } return true; } - else if (GET_CODE (op) == CONST_VECTOR + else if (CONST_VECTOR_P (op) && CONST_VECTOR_NUNITS (op).is_constant (&n_elts)) /* N_ELTS set above. */; else @@ -20666,7 +20666,7 @@ aarch64_simd_make_constant (rtx vals) int n_const = 0; int i; - if (GET_CODE (vals) == CONST_VECTOR) + if (CONST_VECTOR_P (vals)) const_vec = vals; else if (GET_CODE (vals) == PARALLEL) { @@ -21207,7 +21207,7 @@ aarch64_sve_expand_vector_init (rtx target, rtx vals) static rtx aarch64_convert_mult_to_shift (rtx value, rtx_code &code) { - if (GET_CODE (value) != CONST_VECTOR) + if (!CONST_VECTOR_P (value)) return NULL_RTX; rtx_vector_builder builder; @@ -22371,7 +22371,7 @@ aarch64_expand_sve_vec_perm (rtx target, rtx op0, rtx op1, rtx sel) rtx sel_reg = force_reg (sel_mode, sel); /* Check if the sel only references the first values vector. */ - if (GET_CODE (sel) == CONST_VECTOR + if (CONST_VECTOR_P (sel) && aarch64_const_vec_all_in_range_p (sel, 0, nunits - 1)) { emit_unspec2 (target, UNSPEC_TBL, op0, sel_reg); @@ -22393,7 +22393,7 @@ aarch64_expand_sve_vec_perm (rtx target, rtx op0, rtx op1, rtx sel) rtx res0 = gen_reg_rtx (data_mode); rtx res1 = gen_reg_rtx (data_mode); rtx neg_num_elems = aarch64_simd_gen_const_vector_dup (sel_mode, -nunits); - if (GET_CODE (sel) != CONST_VECTOR + if (!CONST_VECTOR_P (sel) || !aarch64_const_vec_all_in_range_p (sel, 0, 2 * nunits - 1)) { rtx max_sel = aarch64_simd_gen_const_vector_dup (sel_mode, @@ -24925,7 +24925,7 @@ int aarch64_vec_fpconst_pow_of_2 (rtx x) { int nelts; - if (GET_CODE (x) != CONST_VECTOR + if (!CONST_VECTOR_P (x) || !CONST_VECTOR_NUNITS (x).is_constant (&nelts)) return -1; diff --git a/gcc/config/aarch64/arm_neon.h b/gcc/config/aarch64/arm_neon.h index 390cf9a..d8b2970 100644 --- a/gcc/config/aarch64/arm_neon.h +++ b/gcc/config/aarch64/arm_neon.h @@ -19882,296 +19882,1569 @@ vld4q_dup_p64 (const poly64_t * __a) /* vld2_lane */ -#define __LD2_LANE_FUNC(intype, vectype, largetype, ptrtype, mode, \ - qmode, ptrmode, funcsuffix, signedtype) \ -__extension__ extern __inline intype \ -__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) \ -vld2_lane_##funcsuffix (const ptrtype * __ptr, intype __b, const int __c) \ -{ \ - __builtin_aarch64_simd_oi __o; \ - largetype __temp; \ - __temp.val[0] = \ - vcombine_##funcsuffix (__b.val[0], vcreate_##funcsuffix (0)); \ - __temp.val[1] = \ - vcombine_##funcsuffix (__b.val[1], vcreate_##funcsuffix (0)); \ - __o = __builtin_aarch64_set_qregoi##qmode (__o, \ - (signedtype) __temp.val[0], \ - 0); \ - __o = __builtin_aarch64_set_qregoi##qmode (__o, \ - (signedtype) __temp.val[1], \ - 1); \ - __o = __builtin_aarch64_ld2_lane##mode ( \ - (__builtin_aarch64_simd_##ptrmode *) __ptr, __o, __c); \ - __b.val[0] = (vectype) __builtin_aarch64_get_dregoidi (__o, 0); \ - __b.val[1] = (vectype) __builtin_aarch64_get_dregoidi (__o, 1); \ - return __b; \ -} - -__LD2_LANE_FUNC (float16x4x2_t, float16x4_t, float16x8x2_t, float16_t, v4hf, - v8hf, hf, f16, float16x8_t) -__LD2_LANE_FUNC (float32x2x2_t, float32x2_t, float32x4x2_t, float32_t, v2sf, v4sf, - sf, f32, float32x4_t) -__LD2_LANE_FUNC (float64x1x2_t, float64x1_t, float64x2x2_t, float64_t, df, v2df, - df, f64, float64x2_t) -__LD2_LANE_FUNC (poly8x8x2_t, poly8x8_t, poly8x16x2_t, poly8_t, v8qi, v16qi, qi, p8, - int8x16_t) -__LD2_LANE_FUNC (poly16x4x2_t, poly16x4_t, poly16x8x2_t, poly16_t, v4hi, v8hi, hi, - p16, int16x8_t) -__LD2_LANE_FUNC (poly64x1x2_t, poly64x1_t, poly64x2x2_t, poly64_t, di, - v2di_ssps, di, p64, poly64x2_t) -__LD2_LANE_FUNC (int8x8x2_t, int8x8_t, int8x16x2_t, int8_t, v8qi, v16qi, qi, s8, - int8x16_t) -__LD2_LANE_FUNC (int16x4x2_t, int16x4_t, int16x8x2_t, int16_t, v4hi, v8hi, hi, s16, - int16x8_t) -__LD2_LANE_FUNC (int32x2x2_t, int32x2_t, int32x4x2_t, int32_t, v2si, v4si, si, s32, - int32x4_t) -__LD2_LANE_FUNC (int64x1x2_t, int64x1_t, int64x2x2_t, int64_t, di, v2di, di, s64, - int64x2_t) -__LD2_LANE_FUNC (uint8x8x2_t, uint8x8_t, uint8x16x2_t, uint8_t, v8qi, v16qi, qi, u8, - int8x16_t) -__LD2_LANE_FUNC (uint16x4x2_t, uint16x4_t, uint16x8x2_t, uint16_t, v4hi, v8hi, hi, - u16, int16x8_t) -__LD2_LANE_FUNC (uint32x2x2_t, uint32x2_t, uint32x4x2_t, uint32_t, v2si, v4si, si, - u32, int32x4_t) -__LD2_LANE_FUNC (uint64x1x2_t, uint64x1_t, uint64x2x2_t, uint64_t, di, v2di, di, - u64, int64x2_t) +__extension__ extern __inline uint8x8x2_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld2_lane_u8 (const uint8_t * __ptr, uint8x8x2_t __b, const int __c) +{ + __builtin_aarch64_simd_oi __o; + uint8x16x2_t __temp; + __temp.val[0] = vcombine_u8 (__b.val[0], vcreate_u8 (0)); + __temp.val[1] = vcombine_u8 (__b.val[1], vcreate_u8 (0)); + __o = __builtin_aarch64_set_qregoiv16qi (__o, (int8x16_t) __temp.val[0], 0); + __o = __builtin_aarch64_set_qregoiv16qi (__o, (int8x16_t) __temp.val[1], 1); + __o = __builtin_aarch64_ld2_lanev8qi ( + (__builtin_aarch64_simd_qi *) __ptr, __o, __c); + __b.val[0] = (uint8x8_t) __builtin_aarch64_get_dregoidi (__o, 0); + __b.val[1] = (uint8x8_t) __builtin_aarch64_get_dregoidi (__o, 1); + return __b; +} + +__extension__ extern __inline uint16x4x2_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld2_lane_u16 (const uint16_t * __ptr, uint16x4x2_t __b, const int __c) +{ + __builtin_aarch64_simd_oi __o; + uint16x8x2_t __temp; + __temp.val[0] = vcombine_u16 (__b.val[0], vcreate_u16 (0)); + __temp.val[1] = vcombine_u16 (__b.val[1], vcreate_u16 (0)); + __o = __builtin_aarch64_set_qregoiv8hi (__o, (int16x8_t) __temp.val[0], 0); + __o = __builtin_aarch64_set_qregoiv8hi (__o, (int16x8_t) __temp.val[1], 1); + __o = __builtin_aarch64_ld2_lanev4hi ( + (__builtin_aarch64_simd_hi *) __ptr, __o, __c); + __b.val[0] = (uint16x4_t) __builtin_aarch64_get_dregoidi (__o, 0); + __b.val[1] = (uint16x4_t) __builtin_aarch64_get_dregoidi (__o, 1); + return __b; +} + +__extension__ extern __inline uint32x2x2_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld2_lane_u32 (const uint32_t * __ptr, uint32x2x2_t __b, const int __c) +{ + __builtin_aarch64_simd_oi __o; + uint32x4x2_t __temp; + __temp.val[0] = vcombine_u32 (__b.val[0], vcreate_u32 (0)); + __temp.val[1] = vcombine_u32 (__b.val[1], vcreate_u32 (0)); + __o = __builtin_aarch64_set_qregoiv4si (__o, (int32x4_t) __temp.val[0], 0); + __o = __builtin_aarch64_set_qregoiv4si (__o, (int32x4_t) __temp.val[1], 1); + __o = __builtin_aarch64_ld2_lanev2si ( + (__builtin_aarch64_simd_si *) __ptr, __o, __c); + __b.val[0] = (uint32x2_t) __builtin_aarch64_get_dregoidi (__o, 0); + __b.val[1] = (uint32x2_t) __builtin_aarch64_get_dregoidi (__o, 1); + return __b; +} + +__extension__ extern __inline uint64x1x2_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld2_lane_u64 (const uint64_t * __ptr, uint64x1x2_t __b, const int __c) +{ + __builtin_aarch64_simd_oi __o; + uint64x2x2_t __temp; + __temp.val[0] = vcombine_u64 (__b.val[0], vcreate_u64 (0)); + __temp.val[1] = vcombine_u64 (__b.val[1], vcreate_u64 (0)); + __o = __builtin_aarch64_set_qregoiv2di (__o, (int64x2_t) __temp.val[0], 0); + __o = __builtin_aarch64_set_qregoiv2di (__o, (int64x2_t) __temp.val[1], 1); + __o = __builtin_aarch64_ld2_lanedi ( + (__builtin_aarch64_simd_di *) __ptr, __o, __c); + __b.val[0] = (uint64x1_t) __builtin_aarch64_get_dregoidi (__o, 0); + __b.val[1] = (uint64x1_t) __builtin_aarch64_get_dregoidi (__o, 1); + return __b; +} + +__extension__ extern __inline int8x8x2_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld2_lane_s8 (const int8_t * __ptr, int8x8x2_t __b, const int __c) +{ + __builtin_aarch64_simd_oi __o; + int8x16x2_t __temp; + __temp.val[0] = vcombine_s8 (__b.val[0], vcreate_s8 (0)); + __temp.val[1] = vcombine_s8 (__b.val[1], vcreate_s8 (0)); + __o = __builtin_aarch64_set_qregoiv16qi (__o, (int8x16_t) __temp.val[0], 0); + __o = __builtin_aarch64_set_qregoiv16qi (__o, (int8x16_t) __temp.val[1], 1); + __o = __builtin_aarch64_ld2_lanev8qi ( + (__builtin_aarch64_simd_qi *) __ptr, __o, __c); + __b.val[0] = (int8x8_t) __builtin_aarch64_get_dregoidi (__o, 0); + __b.val[1] = (int8x8_t) __builtin_aarch64_get_dregoidi (__o, 1); + return __b; +} + +__extension__ extern __inline int16x4x2_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld2_lane_s16 (const int16_t * __ptr, int16x4x2_t __b, const int __c) +{ + __builtin_aarch64_simd_oi __o; + int16x8x2_t __temp; + __temp.val[0] = vcombine_s16 (__b.val[0], vcreate_s16 (0)); + __temp.val[1] = vcombine_s16 (__b.val[1], vcreate_s16 (0)); + __o = __builtin_aarch64_set_qregoiv8hi (__o, (int16x8_t) __temp.val[0], 0); + __o = __builtin_aarch64_set_qregoiv8hi (__o, (int16x8_t) __temp.val[1], 1); + __o = __builtin_aarch64_ld2_lanev4hi ( + (__builtin_aarch64_simd_hi *) __ptr, __o, __c); + __b.val[0] = (int16x4_t) __builtin_aarch64_get_dregoidi (__o, 0); + __b.val[1] = (int16x4_t) __builtin_aarch64_get_dregoidi (__o, 1); + return __b; +} + +__extension__ extern __inline int32x2x2_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld2_lane_s32 (const int32_t * __ptr, int32x2x2_t __b, const int __c) +{ + __builtin_aarch64_simd_oi __o; + int32x4x2_t __temp; + __temp.val[0] = vcombine_s32 (__b.val[0], vcreate_s32 (0)); + __temp.val[1] = vcombine_s32 (__b.val[1], vcreate_s32 (0)); + __o = __builtin_aarch64_set_qregoiv4si (__o, (int32x4_t) __temp.val[0], 0); + __o = __builtin_aarch64_set_qregoiv4si (__o, (int32x4_t) __temp.val[1], 1); + __o = __builtin_aarch64_ld2_lanev2si ( + (__builtin_aarch64_simd_si *) __ptr, __o, __c); + __b.val[0] = (int32x2_t) __builtin_aarch64_get_dregoidi (__o, 0); + __b.val[1] = (int32x2_t) __builtin_aarch64_get_dregoidi (__o, 1); + return __b; +} + +__extension__ extern __inline int64x1x2_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld2_lane_s64 (const int64_t * __ptr, int64x1x2_t __b, const int __c) +{ + __builtin_aarch64_simd_oi __o; + int64x2x2_t __temp; + __temp.val[0] = vcombine_s64 (__b.val[0], vcreate_s64 (0)); + __temp.val[1] = vcombine_s64 (__b.val[1], vcreate_s64 (0)); + __o = __builtin_aarch64_set_qregoiv2di (__o, (int64x2_t) __temp.val[0], 0); + __o = __builtin_aarch64_set_qregoiv2di (__o, (int64x2_t) __temp.val[1], 1); + __o = __builtin_aarch64_ld2_lanedi ( + (__builtin_aarch64_simd_di *) __ptr, __o, __c); + __b.val[0] = (int64x1_t) __builtin_aarch64_get_dregoidi (__o, 0); + __b.val[1] = (int64x1_t) __builtin_aarch64_get_dregoidi (__o, 1); + return __b; +} + +__extension__ extern __inline float16x4x2_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld2_lane_f16 (const float16_t * __ptr, float16x4x2_t __b, const int __c) +{ + __builtin_aarch64_simd_oi __o; + float16x8x2_t __temp; + __temp.val[0] = vcombine_f16 (__b.val[0], vcreate_f16 (0)); + __temp.val[1] = vcombine_f16 (__b.val[1], vcreate_f16 (0)); + __o = __builtin_aarch64_set_qregoiv8hf (__o, (float16x8_t) __temp.val[0], 0); + __o = __builtin_aarch64_set_qregoiv8hf (__o, (float16x8_t) __temp.val[1], 1); + __o = __builtin_aarch64_ld2_lanev4hf ( + (__builtin_aarch64_simd_hf *) __ptr, __o, __c); + __b.val[0] = (float16x4_t) __builtin_aarch64_get_dregoidi (__o, 0); + __b.val[1] = (float16x4_t) __builtin_aarch64_get_dregoidi (__o, 1); + return __b; +} + +__extension__ extern __inline float32x2x2_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld2_lane_f32 (const float32_t * __ptr, float32x2x2_t __b, const int __c) +{ + __builtin_aarch64_simd_oi __o; + float32x4x2_t __temp; + __temp.val[0] = vcombine_f32 (__b.val[0], vcreate_f32 (0)); + __temp.val[1] = vcombine_f32 (__b.val[1], vcreate_f32 (0)); + __o = __builtin_aarch64_set_qregoiv4sf (__o, (float32x4_t) __temp.val[0], 0); + __o = __builtin_aarch64_set_qregoiv4sf (__o, (float32x4_t) __temp.val[1], 1); + __o = __builtin_aarch64_ld2_lanev2sf ( + (__builtin_aarch64_simd_sf *) __ptr, __o, __c); + __b.val[0] = (float32x2_t) __builtin_aarch64_get_dregoidi (__o, 0); + __b.val[1] = (float32x2_t) __builtin_aarch64_get_dregoidi (__o, 1); + return __b; +} + +__extension__ extern __inline float64x1x2_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld2_lane_f64 (const float64_t * __ptr, float64x1x2_t __b, const int __c) +{ + __builtin_aarch64_simd_oi __o; + float64x2x2_t __temp; + __temp.val[0] = vcombine_f64 (__b.val[0], vcreate_f64 (0)); + __temp.val[1] = vcombine_f64 (__b.val[1], vcreate_f64 (0)); + __o = __builtin_aarch64_set_qregoiv2df (__o, (float64x2_t) __temp.val[0], 0); + __o = __builtin_aarch64_set_qregoiv2df (__o, (float64x2_t) __temp.val[1], 1); + __o = __builtin_aarch64_ld2_lanedf ( + (__builtin_aarch64_simd_df *) __ptr, __o, __c); + __b.val[0] = (float64x1_t) __builtin_aarch64_get_dregoidi (__o, 0); + __b.val[1] = (float64x1_t) __builtin_aarch64_get_dregoidi (__o, 1); + return __b; +} + +__extension__ extern __inline poly8x8x2_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld2_lane_p8 (const poly8_t * __ptr, poly8x8x2_t __b, const int __c) +{ + __builtin_aarch64_simd_oi __o; + poly8x16x2_t __temp; + __temp.val[0] = vcombine_p8 (__b.val[0], vcreate_p8 (0)); + __temp.val[1] = vcombine_p8 (__b.val[1], vcreate_p8 (0)); + __o = __builtin_aarch64_set_qregoiv16qi (__o, (int8x16_t) __temp.val[0], 0); + __o = __builtin_aarch64_set_qregoiv16qi (__o, (int8x16_t) __temp.val[1], 1); + __o = __builtin_aarch64_ld2_lanev8qi ( + (__builtin_aarch64_simd_qi *) __ptr, __o, __c); + __b.val[0] = (poly8x8_t) __builtin_aarch64_get_dregoidi (__o, 0); + __b.val[1] = (poly8x8_t) __builtin_aarch64_get_dregoidi (__o, 1); + return __b; +} + +__extension__ extern __inline poly16x4x2_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld2_lane_p16 (const poly16_t * __ptr, poly16x4x2_t __b, const int __c) +{ + __builtin_aarch64_simd_oi __o; + poly16x8x2_t __temp; + __temp.val[0] = vcombine_p16 (__b.val[0], vcreate_p16 (0)); + __temp.val[1] = vcombine_p16 (__b.val[1], vcreate_p16 (0)); + __o = __builtin_aarch64_set_qregoiv8hi (__o, (int16x8_t) __temp.val[0], 0); + __o = __builtin_aarch64_set_qregoiv8hi (__o, (int16x8_t) __temp.val[1], 1); + __o = __builtin_aarch64_ld2_lanev4hi ( + (__builtin_aarch64_simd_hi *) __ptr, __o, __c); + __b.val[0] = (poly16x4_t) __builtin_aarch64_get_dregoidi (__o, 0); + __b.val[1] = (poly16x4_t) __builtin_aarch64_get_dregoidi (__o, 1); + return __b; +} + +__extension__ extern __inline poly64x1x2_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld2_lane_p64 (const poly64_t * __ptr, poly64x1x2_t __b, const int __c) +{ + __builtin_aarch64_simd_oi __o; + poly64x2x2_t __temp; + __temp.val[0] = vcombine_p64 (__b.val[0], vcreate_p64 (0)); + __temp.val[1] = vcombine_p64 (__b.val[1], vcreate_p64 (0)); + __o = __builtin_aarch64_set_qregoiv2di (__o, (int64x2_t) __temp.val[0], 0); + __o = __builtin_aarch64_set_qregoiv2di (__o, (int64x2_t) __temp.val[1], 1); + __o = __builtin_aarch64_ld2_lanedi ( + (__builtin_aarch64_simd_di *) __ptr, __o, __c); + __b.val[0] = (poly64x1_t) __builtin_aarch64_get_dregoidi (__o, 0); + __b.val[1] = (poly64x1_t) __builtin_aarch64_get_dregoidi (__o, 1); + return __b; +} /* vld2q_lane */ -#define __LD2Q_LANE_FUNC(intype, vtype, ptrtype, mode, ptrmode, funcsuffix) \ -__extension__ extern __inline intype \ -__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) \ -vld2q_lane_##funcsuffix (const ptrtype * __ptr, intype __b, const int __c) \ -{ \ - __builtin_aarch64_simd_oi __o; \ - intype ret; \ - __o = __builtin_aarch64_set_qregoiv4si (__o, (int32x4_t) __b.val[0], 0); \ - __o = __builtin_aarch64_set_qregoiv4si (__o, (int32x4_t) __b.val[1], 1); \ - __o = __builtin_aarch64_ld2_lane##mode ( \ - (__builtin_aarch64_simd_##ptrmode *) __ptr, __o, __c); \ - ret.val[0] = (vtype) __builtin_aarch64_get_qregoiv4si (__o, 0); \ - ret.val[1] = (vtype) __builtin_aarch64_get_qregoiv4si (__o, 1); \ - return ret; \ -} - -__LD2Q_LANE_FUNC (float16x8x2_t, float16x8_t, float16_t, v8hf, hf, f16) -__LD2Q_LANE_FUNC (float32x4x2_t, float32x4_t, float32_t, v4sf, sf, f32) -__LD2Q_LANE_FUNC (float64x2x2_t, float64x2_t, float64_t, v2df, df, f64) -__LD2Q_LANE_FUNC (poly8x16x2_t, poly8x16_t, poly8_t, v16qi, qi, p8) -__LD2Q_LANE_FUNC (poly16x8x2_t, poly16x8_t, poly16_t, v8hi, hi, p16) -__LD2Q_LANE_FUNC (poly64x2x2_t, poly64x2_t, poly64_t, v2di, di, p64) -__LD2Q_LANE_FUNC (int8x16x2_t, int8x16_t, int8_t, v16qi, qi, s8) -__LD2Q_LANE_FUNC (int16x8x2_t, int16x8_t, int16_t, v8hi, hi, s16) -__LD2Q_LANE_FUNC (int32x4x2_t, int32x4_t, int32_t, v4si, si, s32) -__LD2Q_LANE_FUNC (int64x2x2_t, int64x2_t, int64_t, v2di, di, s64) -__LD2Q_LANE_FUNC (uint8x16x2_t, uint8x16_t, uint8_t, v16qi, qi, u8) -__LD2Q_LANE_FUNC (uint16x8x2_t, uint16x8_t, uint16_t, v8hi, hi, u16) -__LD2Q_LANE_FUNC (uint32x4x2_t, uint32x4_t, uint32_t, v4si, si, u32) -__LD2Q_LANE_FUNC (uint64x2x2_t, uint64x2_t, uint64_t, v2di, di, u64) +__extension__ extern __inline uint8x16x2_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld2q_lane_u8 (const uint8_t * __ptr, uint8x16x2_t __b, const int __c) +{ + __builtin_aarch64_simd_oi __o; + uint8x16x2_t ret; + __o = __builtin_aarch64_set_qregoiv4si (__o, (int32x4_t) __b.val[0], 0); + __o = __builtin_aarch64_set_qregoiv4si (__o, (int32x4_t) __b.val[1], 1); + __o = __builtin_aarch64_ld2_lanev16qi ( + (__builtin_aarch64_simd_qi *) __ptr, __o, __c); + ret.val[0] = (uint8x16_t) __builtin_aarch64_get_qregoiv4si (__o, 0); + ret.val[1] = (uint8x16_t) __builtin_aarch64_get_qregoiv4si (__o, 1); + return ret; +} + +__extension__ extern __inline uint16x8x2_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld2q_lane_u16 (const uint16_t * __ptr, uint16x8x2_t __b, const int __c) +{ + __builtin_aarch64_simd_oi __o; + uint16x8x2_t ret; + __o = __builtin_aarch64_set_qregoiv4si (__o, (int32x4_t) __b.val[0], 0); + __o = __builtin_aarch64_set_qregoiv4si (__o, (int32x4_t) __b.val[1], 1); + __o = __builtin_aarch64_ld2_lanev8hi ( + (__builtin_aarch64_simd_hi *) __ptr, __o, __c); + ret.val[0] = (uint16x8_t) __builtin_aarch64_get_qregoiv4si (__o, 0); + ret.val[1] = (uint16x8_t) __builtin_aarch64_get_qregoiv4si (__o, 1); + return ret; +} + +__extension__ extern __inline uint32x4x2_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld2q_lane_u32 (const uint32_t * __ptr, uint32x4x2_t __b, const int __c) +{ + __builtin_aarch64_simd_oi __o; + uint32x4x2_t ret; + __o = __builtin_aarch64_set_qregoiv4si (__o, (int32x4_t) __b.val[0], 0); + __o = __builtin_aarch64_set_qregoiv4si (__o, (int32x4_t) __b.val[1], 1); + __o = __builtin_aarch64_ld2_lanev4si ( + (__builtin_aarch64_simd_si *) __ptr, __o, __c); + ret.val[0] = (uint32x4_t) __builtin_aarch64_get_qregoiv4si (__o, 0); + ret.val[1] = (uint32x4_t) __builtin_aarch64_get_qregoiv4si (__o, 1); + return ret; +} + +__extension__ extern __inline uint64x2x2_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld2q_lane_u64 (const uint64_t * __ptr, uint64x2x2_t __b, const int __c) +{ + __builtin_aarch64_simd_oi __o; + uint64x2x2_t ret; + __o = __builtin_aarch64_set_qregoiv4si (__o, (int32x4_t) __b.val[0], 0); + __o = __builtin_aarch64_set_qregoiv4si (__o, (int32x4_t) __b.val[1], 1); + __o = __builtin_aarch64_ld2_lanev2di ( + (__builtin_aarch64_simd_di *) __ptr, __o, __c); + ret.val[0] = (uint64x2_t) __builtin_aarch64_get_qregoiv4si (__o, 0); + ret.val[1] = (uint64x2_t) __builtin_aarch64_get_qregoiv4si (__o, 1); + return ret; +} + +__extension__ extern __inline int8x16x2_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld2q_lane_s8 (const int8_t * __ptr, int8x16x2_t __b, const int __c) +{ + __builtin_aarch64_simd_oi __o; + int8x16x2_t ret; + __o = __builtin_aarch64_set_qregoiv4si (__o, (int32x4_t) __b.val[0], 0); + __o = __builtin_aarch64_set_qregoiv4si (__o, (int32x4_t) __b.val[1], 1); + __o = __builtin_aarch64_ld2_lanev16qi ( + (__builtin_aarch64_simd_qi *) __ptr, __o, __c); + ret.val[0] = (int8x16_t) __builtin_aarch64_get_qregoiv4si (__o, 0); + ret.val[1] = (int8x16_t) __builtin_aarch64_get_qregoiv4si (__o, 1); + return ret; +} + +__extension__ extern __inline int16x8x2_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld2q_lane_s16 (const int16_t * __ptr, int16x8x2_t __b, const int __c) +{ + __builtin_aarch64_simd_oi __o; + int16x8x2_t ret; + __o = __builtin_aarch64_set_qregoiv4si (__o, (int32x4_t) __b.val[0], 0); + __o = __builtin_aarch64_set_qregoiv4si (__o, (int32x4_t) __b.val[1], 1); + __o = __builtin_aarch64_ld2_lanev8hi ( + (__builtin_aarch64_simd_hi *) __ptr, __o, __c); + ret.val[0] = (int16x8_t) __builtin_aarch64_get_qregoiv4si (__o, 0); + ret.val[1] = (int16x8_t) __builtin_aarch64_get_qregoiv4si (__o, 1); + return ret; +} + +__extension__ extern __inline int32x4x2_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld2q_lane_s32 (const int32_t * __ptr, int32x4x2_t __b, const int __c) +{ + __builtin_aarch64_simd_oi __o; + int32x4x2_t ret; + __o = __builtin_aarch64_set_qregoiv4si (__o, __b.val[0], 0); + __o = __builtin_aarch64_set_qregoiv4si (__o, __b.val[1], 1); + __o = __builtin_aarch64_ld2_lanev4si ( + (__builtin_aarch64_simd_si *) __ptr, __o, __c); + ret.val[0] = __builtin_aarch64_get_qregoiv4si (__o, 0); + ret.val[1] = __builtin_aarch64_get_qregoiv4si (__o, 1); + return ret; +} + +__extension__ extern __inline int64x2x2_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld2q_lane_s64 (const int64_t * __ptr, int64x2x2_t __b, const int __c) +{ + __builtin_aarch64_simd_oi __o; + int64x2x2_t ret; + __o = __builtin_aarch64_set_qregoiv4si (__o, (int32x4_t) __b.val[0], 0); + __o = __builtin_aarch64_set_qregoiv4si (__o, (int32x4_t) __b.val[1], 1); + __o = __builtin_aarch64_ld2_lanev2di ( + (__builtin_aarch64_simd_di *) __ptr, __o, __c); + ret.val[0] = (int64x2_t) __builtin_aarch64_get_qregoiv4si (__o, 0); + ret.val[1] = (int64x2_t) __builtin_aarch64_get_qregoiv4si (__o, 1); + return ret; +} + +__extension__ extern __inline float16x8x2_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld2q_lane_f16 (const float16_t * __ptr, float16x8x2_t __b, const int __c) +{ + __builtin_aarch64_simd_oi __o; + float16x8x2_t ret; + __o = __builtin_aarch64_set_qregoiv4si (__o, (int32x4_t) __b.val[0], 0); + __o = __builtin_aarch64_set_qregoiv4si (__o, (int32x4_t) __b.val[1], 1); + __o = __builtin_aarch64_ld2_lanev8hf ( + (__builtin_aarch64_simd_hf *) __ptr, __o, __c); + ret.val[0] = (float16x8_t) __builtin_aarch64_get_qregoiv4si (__o, 0); + ret.val[1] = (float16x8_t) __builtin_aarch64_get_qregoiv4si (__o, 1); + return ret; +} + +__extension__ extern __inline float32x4x2_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld2q_lane_f32 (const float32_t * __ptr, float32x4x2_t __b, const int __c) +{ + __builtin_aarch64_simd_oi __o; + float32x4x2_t ret; + __o = __builtin_aarch64_set_qregoiv4si (__o, (int32x4_t) __b.val[0], 0); + __o = __builtin_aarch64_set_qregoiv4si (__o, (int32x4_t) __b.val[1], 1); + __o = __builtin_aarch64_ld2_lanev4sf ( + (__builtin_aarch64_simd_sf *) __ptr, __o, __c); + ret.val[0] = (float32x4_t) __builtin_aarch64_get_qregoiv4si (__o, 0); + ret.val[1] = (float32x4_t) __builtin_aarch64_get_qregoiv4si (__o, 1); + return ret; +} + +__extension__ extern __inline float64x2x2_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld2q_lane_f64 (const float64_t * __ptr, float64x2x2_t __b, const int __c) +{ + __builtin_aarch64_simd_oi __o; + float64x2x2_t ret; + __o = __builtin_aarch64_set_qregoiv4si (__o, (int32x4_t) __b.val[0], 0); + __o = __builtin_aarch64_set_qregoiv4si (__o, (int32x4_t) __b.val[1], 1); + __o = __builtin_aarch64_ld2_lanev2df ( + (__builtin_aarch64_simd_df *) __ptr, __o, __c); + ret.val[0] = (float64x2_t) __builtin_aarch64_get_qregoiv4si (__o, 0); + ret.val[1] = (float64x2_t) __builtin_aarch64_get_qregoiv4si (__o, 1); + return ret; +} + +__extension__ extern __inline poly8x16x2_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld2q_lane_p8 (const poly8_t * __ptr, poly8x16x2_t __b, const int __c) +{ + __builtin_aarch64_simd_oi __o; + poly8x16x2_t ret; + __o = __builtin_aarch64_set_qregoiv4si (__o, (int32x4_t) __b.val[0], 0); + __o = __builtin_aarch64_set_qregoiv4si (__o, (int32x4_t) __b.val[1], 1); + __o = __builtin_aarch64_ld2_lanev16qi ( + (__builtin_aarch64_simd_qi *) __ptr, __o, __c); + ret.val[0] = (poly8x16_t) __builtin_aarch64_get_qregoiv4si (__o, 0); + ret.val[1] = (poly8x16_t) __builtin_aarch64_get_qregoiv4si (__o, 1); + return ret; +} + +__extension__ extern __inline poly16x8x2_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld2q_lane_p16 (const poly16_t * __ptr, poly16x8x2_t __b, const int __c) +{ + __builtin_aarch64_simd_oi __o; + poly16x8x2_t ret; + __o = __builtin_aarch64_set_qregoiv4si (__o, (int32x4_t) __b.val[0], 0); + __o = __builtin_aarch64_set_qregoiv4si (__o, (int32x4_t) __b.val[1], 1); + __o = __builtin_aarch64_ld2_lanev8hi ( + (__builtin_aarch64_simd_hi *) __ptr, __o, __c); + ret.val[0] = (poly16x8_t) __builtin_aarch64_get_qregoiv4si (__o, 0); + ret.val[1] = (poly16x8_t) __builtin_aarch64_get_qregoiv4si (__o, 1); + return ret; +} + +__extension__ extern __inline poly64x2x2_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld2q_lane_p64 (const poly64_t * __ptr, poly64x2x2_t __b, const int __c) +{ + __builtin_aarch64_simd_oi __o; + poly64x2x2_t ret; + __o = __builtin_aarch64_set_qregoiv4si (__o, (int32x4_t) __b.val[0], 0); + __o = __builtin_aarch64_set_qregoiv4si (__o, (int32x4_t) __b.val[1], 1); + __o = __builtin_aarch64_ld2_lanev2di ( + (__builtin_aarch64_simd_di *) __ptr, __o, __c); + ret.val[0] = (poly64x2_t) __builtin_aarch64_get_qregoiv4si (__o, 0); + ret.val[1] = (poly64x2_t) __builtin_aarch64_get_qregoiv4si (__o, 1); + return ret; +} /* vld3_lane */ -#define __LD3_LANE_FUNC(intype, vectype, largetype, ptrtype, mode, \ - qmode, ptrmode, funcsuffix, signedtype) \ -__extension__ extern __inline intype \ -__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) \ -vld3_lane_##funcsuffix (const ptrtype * __ptr, intype __b, const int __c) \ -{ \ - __builtin_aarch64_simd_ci __o; \ - largetype __temp; \ - __temp.val[0] = \ - vcombine_##funcsuffix (__b.val[0], vcreate_##funcsuffix (0)); \ - __temp.val[1] = \ - vcombine_##funcsuffix (__b.val[1], vcreate_##funcsuffix (0)); \ - __temp.val[2] = \ - vcombine_##funcsuffix (__b.val[2], vcreate_##funcsuffix (0)); \ - __o = __builtin_aarch64_set_qregci##qmode (__o, \ - (signedtype) __temp.val[0], \ - 0); \ - __o = __builtin_aarch64_set_qregci##qmode (__o, \ - (signedtype) __temp.val[1], \ - 1); \ - __o = __builtin_aarch64_set_qregci##qmode (__o, \ - (signedtype) __temp.val[2], \ - 2); \ - __o = __builtin_aarch64_ld3_lane##mode ( \ - (__builtin_aarch64_simd_##ptrmode *) __ptr, __o, __c); \ - __b.val[0] = (vectype) __builtin_aarch64_get_dregcidi (__o, 0); \ - __b.val[1] = (vectype) __builtin_aarch64_get_dregcidi (__o, 1); \ - __b.val[2] = (vectype) __builtin_aarch64_get_dregcidi (__o, 2); \ - return __b; \ -} - -__LD3_LANE_FUNC (float16x4x3_t, float16x4_t, float16x8x3_t, float16_t, v4hf, - v8hf, hf, f16, float16x8_t) -__LD3_LANE_FUNC (float32x2x3_t, float32x2_t, float32x4x3_t, float32_t, v2sf, v4sf, - sf, f32, float32x4_t) -__LD3_LANE_FUNC (float64x1x3_t, float64x1_t, float64x2x3_t, float64_t, df, v2df, - df, f64, float64x2_t) -__LD3_LANE_FUNC (poly8x8x3_t, poly8x8_t, poly8x16x3_t, poly8_t, v8qi, v16qi, qi, p8, - int8x16_t) -__LD3_LANE_FUNC (poly16x4x3_t, poly16x4_t, poly16x8x3_t, poly16_t, v4hi, v8hi, hi, - p16, int16x8_t) -__LD3_LANE_FUNC (poly64x1x3_t, poly64x1_t, poly64x2x3_t, poly64_t, di, - v2di_ssps, di, p64, poly64x2_t) -__LD3_LANE_FUNC (int8x8x3_t, int8x8_t, int8x16x3_t, int8_t, v8qi, v16qi, qi, s8, - int8x16_t) -__LD3_LANE_FUNC (int16x4x3_t, int16x4_t, int16x8x3_t, int16_t, v4hi, v8hi, hi, s16, - int16x8_t) -__LD3_LANE_FUNC (int32x2x3_t, int32x2_t, int32x4x3_t, int32_t, v2si, v4si, si, s32, - int32x4_t) -__LD3_LANE_FUNC (int64x1x3_t, int64x1_t, int64x2x3_t, int64_t, di, v2di, di, s64, - int64x2_t) -__LD3_LANE_FUNC (uint8x8x3_t, uint8x8_t, uint8x16x3_t, uint8_t, v8qi, v16qi, qi, u8, - int8x16_t) -__LD3_LANE_FUNC (uint16x4x3_t, uint16x4_t, uint16x8x3_t, uint16_t, v4hi, v8hi, hi, - u16, int16x8_t) -__LD3_LANE_FUNC (uint32x2x3_t, uint32x2_t, uint32x4x3_t, uint32_t, v2si, v4si, si, - u32, int32x4_t) -__LD3_LANE_FUNC (uint64x1x3_t, uint64x1_t, uint64x2x3_t, uint64_t, di, v2di, di, - u64, int64x2_t) +__extension__ extern __inline uint8x8x3_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld3_lane_u8 (const uint8_t * __ptr, uint8x8x3_t __b, const int __c) +{ + __builtin_aarch64_simd_ci __o; + uint8x16x3_t __temp; + __temp.val[0] = vcombine_u8 (__b.val[0], vcreate_u8 (0)); + __temp.val[1] = vcombine_u8 (__b.val[1], vcreate_u8 (0)); + __temp.val[2] = vcombine_u8 (__b.val[2], vcreate_u8 (0)); + __o = __builtin_aarch64_set_qregciv16qi (__o, (int8x16_t) __temp.val[0], 0); + __o = __builtin_aarch64_set_qregciv16qi (__o, (int8x16_t) __temp.val[1], 1); + __o = __builtin_aarch64_set_qregciv16qi (__o, (int8x16_t) __temp.val[2], 2); + __o = __builtin_aarch64_ld3_lanev8qi ( + (__builtin_aarch64_simd_qi *) __ptr, __o, __c); + __b.val[0] = (uint8x8_t) __builtin_aarch64_get_dregcidi (__o, 0); + __b.val[1] = (uint8x8_t) __builtin_aarch64_get_dregcidi (__o, 1); + __b.val[2] = (uint8x8_t) __builtin_aarch64_get_dregcidi (__o, 2); + return __b; +} + +__extension__ extern __inline uint16x4x3_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld3_lane_u16 (const uint16_t * __ptr, uint16x4x3_t __b, const int __c) +{ + __builtin_aarch64_simd_ci __o; + uint16x8x3_t __temp; + __temp.val[0] = vcombine_u16 (__b.val[0], vcreate_u16 (0)); + __temp.val[1] = vcombine_u16 (__b.val[1], vcreate_u16 (0)); + __temp.val[2] = vcombine_u16 (__b.val[2], vcreate_u16 (0)); + __o = __builtin_aarch64_set_qregciv8hi (__o, (int16x8_t) __temp.val[0], 0); + __o = __builtin_aarch64_set_qregciv8hi (__o, (int16x8_t) __temp.val[1], 1); + __o = __builtin_aarch64_set_qregciv8hi (__o, (int16x8_t) __temp.val[2], 2); + __o = __builtin_aarch64_ld3_lanev4hi ( + (__builtin_aarch64_simd_hi *) __ptr, __o, __c); + __b.val[0] = (uint16x4_t) __builtin_aarch64_get_dregcidi (__o, 0); + __b.val[1] = (uint16x4_t) __builtin_aarch64_get_dregcidi (__o, 1); + __b.val[2] = (uint16x4_t) __builtin_aarch64_get_dregcidi (__o, 2); + return __b; +} + +__extension__ extern __inline uint32x2x3_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld3_lane_u32 (const uint32_t * __ptr, uint32x2x3_t __b, const int __c) +{ + __builtin_aarch64_simd_ci __o; + uint32x4x3_t __temp; + __temp.val[0] = vcombine_u32 (__b.val[0], vcreate_u32 (0)); + __temp.val[1] = vcombine_u32 (__b.val[1], vcreate_u32 (0)); + __temp.val[2] = vcombine_u32 (__b.val[2], vcreate_u32 (0)); + __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) __temp.val[0], 0); + __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) __temp.val[1], 1); + __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) __temp.val[2], 2); + __o = __builtin_aarch64_ld3_lanev2si ( + (__builtin_aarch64_simd_si *) __ptr, __o, __c); + __b.val[0] = (uint32x2_t) __builtin_aarch64_get_dregcidi (__o, 0); + __b.val[1] = (uint32x2_t) __builtin_aarch64_get_dregcidi (__o, 1); + __b.val[2] = (uint32x2_t) __builtin_aarch64_get_dregcidi (__o, 2); + return __b; +} + +__extension__ extern __inline uint64x1x3_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld3_lane_u64 (const uint64_t * __ptr, uint64x1x3_t __b, const int __c) +{ + __builtin_aarch64_simd_ci __o; + uint64x2x3_t __temp; + __temp.val[0] = vcombine_u64 (__b.val[0], vcreate_u64 (0)); + __temp.val[1] = vcombine_u64 (__b.val[1], vcreate_u64 (0)); + __temp.val[2] = vcombine_u64 (__b.val[2], vcreate_u64 (0)); + __o = __builtin_aarch64_set_qregciv2di (__o, (int64x2_t) __temp.val[0], 0); + __o = __builtin_aarch64_set_qregciv2di (__o, (int64x2_t) __temp.val[1], 1); + __o = __builtin_aarch64_set_qregciv2di (__o, (int64x2_t) __temp.val[2], 2); + __o = __builtin_aarch64_ld3_lanedi ( + (__builtin_aarch64_simd_di *) __ptr, __o, __c); + __b.val[0] = (uint64x1_t) __builtin_aarch64_get_dregcidi (__o, 0); + __b.val[1] = (uint64x1_t) __builtin_aarch64_get_dregcidi (__o, 1); + __b.val[2] = (uint64x1_t) __builtin_aarch64_get_dregcidi (__o, 2); + return __b; +} + +__extension__ extern __inline int8x8x3_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld3_lane_s8 (const int8_t * __ptr, int8x8x3_t __b, const int __c) +{ + __builtin_aarch64_simd_ci __o; + int8x16x3_t __temp; + __temp.val[0] = vcombine_s8 (__b.val[0], vcreate_s8 (0)); + __temp.val[1] = vcombine_s8 (__b.val[1], vcreate_s8 (0)); + __temp.val[2] = vcombine_s8 (__b.val[2], vcreate_s8 (0)); + __o = __builtin_aarch64_set_qregciv16qi (__o, (int8x16_t) __temp.val[0], 0); + __o = __builtin_aarch64_set_qregciv16qi (__o, (int8x16_t) __temp.val[1], 1); + __o = __builtin_aarch64_set_qregciv16qi (__o, (int8x16_t) __temp.val[2], 2); + __o = __builtin_aarch64_ld3_lanev8qi ( + (__builtin_aarch64_simd_qi *) __ptr, __o, __c); + __b.val[0] = (int8x8_t) __builtin_aarch64_get_dregcidi (__o, 0); + __b.val[1] = (int8x8_t) __builtin_aarch64_get_dregcidi (__o, 1); + __b.val[2] = (int8x8_t) __builtin_aarch64_get_dregcidi (__o, 2); + return __b; +} + +__extension__ extern __inline int16x4x3_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld3_lane_s16 (const int16_t * __ptr, int16x4x3_t __b, const int __c) +{ + __builtin_aarch64_simd_ci __o; + int16x8x3_t __temp; + __temp.val[0] = vcombine_s16 (__b.val[0], vcreate_s16 (0)); + __temp.val[1] = vcombine_s16 (__b.val[1], vcreate_s16 (0)); + __temp.val[2] = vcombine_s16 (__b.val[2], vcreate_s16 (0)); + __o = __builtin_aarch64_set_qregciv8hi (__o, (int16x8_t) __temp.val[0], 0); + __o = __builtin_aarch64_set_qregciv8hi (__o, (int16x8_t) __temp.val[1], 1); + __o = __builtin_aarch64_set_qregciv8hi (__o, (int16x8_t) __temp.val[2], 2); + __o = __builtin_aarch64_ld3_lanev4hi ( + (__builtin_aarch64_simd_hi *) __ptr, __o, __c); + __b.val[0] = (int16x4_t) __builtin_aarch64_get_dregcidi (__o, 0); + __b.val[1] = (int16x4_t) __builtin_aarch64_get_dregcidi (__o, 1); + __b.val[2] = (int16x4_t) __builtin_aarch64_get_dregcidi (__o, 2); + return __b; +} + +__extension__ extern __inline int32x2x3_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld3_lane_s32 (const int32_t * __ptr, int32x2x3_t __b, const int __c) +{ + __builtin_aarch64_simd_ci __o; + int32x4x3_t __temp; + __temp.val[0] = vcombine_s32 (__b.val[0], vcreate_s32 (0)); + __temp.val[1] = vcombine_s32 (__b.val[1], vcreate_s32 (0)); + __temp.val[2] = vcombine_s32 (__b.val[2], vcreate_s32 (0)); + __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) __temp.val[0], 0); + __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) __temp.val[1], 1); + __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) __temp.val[2], 2); + __o = __builtin_aarch64_ld3_lanev2si ( + (__builtin_aarch64_simd_si *) __ptr, __o, __c); + __b.val[0] = (int32x2_t) __builtin_aarch64_get_dregcidi (__o, 0); + __b.val[1] = (int32x2_t) __builtin_aarch64_get_dregcidi (__o, 1); + __b.val[2] = (int32x2_t) __builtin_aarch64_get_dregcidi (__o, 2); + return __b; +} + +__extension__ extern __inline int64x1x3_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld3_lane_s64 (const int64_t * __ptr, int64x1x3_t __b, const int __c) +{ + __builtin_aarch64_simd_ci __o; + int64x2x3_t __temp; + __temp.val[0] = vcombine_s64 (__b.val[0], vcreate_s64 (0)); + __temp.val[1] = vcombine_s64 (__b.val[1], vcreate_s64 (0)); + __temp.val[2] = vcombine_s64 (__b.val[2], vcreate_s64 (0)); + __o = __builtin_aarch64_set_qregciv2di (__o, (int64x2_t) __temp.val[0], 0); + __o = __builtin_aarch64_set_qregciv2di (__o, (int64x2_t) __temp.val[1], 1); + __o = __builtin_aarch64_set_qregciv2di (__o, (int64x2_t) __temp.val[2], 2); + __o = __builtin_aarch64_ld3_lanedi ( + (__builtin_aarch64_simd_di *) __ptr, __o, __c); + __b.val[0] = (int64x1_t) __builtin_aarch64_get_dregcidi (__o, 0); + __b.val[1] = (int64x1_t) __builtin_aarch64_get_dregcidi (__o, 1); + __b.val[2] = (int64x1_t) __builtin_aarch64_get_dregcidi (__o, 2); + return __b; +} + +__extension__ extern __inline float16x4x3_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld3_lane_f16 (const float16_t * __ptr, float16x4x3_t __b, const int __c) +{ + __builtin_aarch64_simd_ci __o; + float16x8x3_t __temp; + __temp.val[0] = vcombine_f16 (__b.val[0], vcreate_f16 (0)); + __temp.val[1] = vcombine_f16 (__b.val[1], vcreate_f16 (0)); + __temp.val[2] = vcombine_f16 (__b.val[2], vcreate_f16 (0)); + __o = __builtin_aarch64_set_qregciv8hf (__o, (float16x8_t) __temp.val[0], 0); + __o = __builtin_aarch64_set_qregciv8hf (__o, (float16x8_t) __temp.val[1], 1); + __o = __builtin_aarch64_set_qregciv8hf (__o, (float16x8_t) __temp.val[2], 2); + __o = __builtin_aarch64_ld3_lanev4hf ( + (__builtin_aarch64_simd_hf *) __ptr, __o, __c); + __b.val[0] = (float16x4_t) __builtin_aarch64_get_dregcidi (__o, 0); + __b.val[1] = (float16x4_t) __builtin_aarch64_get_dregcidi (__o, 1); + __b.val[2] = (float16x4_t) __builtin_aarch64_get_dregcidi (__o, 2); + return __b; +} + +__extension__ extern __inline float32x2x3_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld3_lane_f32 (const float32_t * __ptr, float32x2x3_t __b, const int __c) +{ + __builtin_aarch64_simd_ci __o; + float32x4x3_t __temp; + __temp.val[0] = vcombine_f32 (__b.val[0], vcreate_f32 (0)); + __temp.val[1] = vcombine_f32 (__b.val[1], vcreate_f32 (0)); + __temp.val[2] = vcombine_f32 (__b.val[2], vcreate_f32 (0)); + __o = __builtin_aarch64_set_qregciv4sf (__o, (float32x4_t) __temp.val[0], 0); + __o = __builtin_aarch64_set_qregciv4sf (__o, (float32x4_t) __temp.val[1], 1); + __o = __builtin_aarch64_set_qregciv4sf (__o, (float32x4_t) __temp.val[2], 2); + __o = __builtin_aarch64_ld3_lanev2sf ( + (__builtin_aarch64_simd_sf *) __ptr, __o, __c); + __b.val[0] = (float32x2_t) __builtin_aarch64_get_dregcidi (__o, 0); + __b.val[1] = (float32x2_t) __builtin_aarch64_get_dregcidi (__o, 1); + __b.val[2] = (float32x2_t) __builtin_aarch64_get_dregcidi (__o, 2); + return __b; +} + +__extension__ extern __inline float64x1x3_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld3_lane_f64 (const float64_t * __ptr, float64x1x3_t __b, const int __c) +{ + __builtin_aarch64_simd_ci __o; + float64x2x3_t __temp; + __temp.val[0] = vcombine_f64 (__b.val[0], vcreate_f64 (0)); + __temp.val[1] = vcombine_f64 (__b.val[1], vcreate_f64 (0)); + __temp.val[2] = vcombine_f64 (__b.val[2], vcreate_f64 (0)); + __o = __builtin_aarch64_set_qregciv2df (__o, (float64x2_t) __temp.val[0], 0); + __o = __builtin_aarch64_set_qregciv2df (__o, (float64x2_t) __temp.val[1], 1); + __o = __builtin_aarch64_set_qregciv2df (__o, (float64x2_t) __temp.val[2], 2); + __o = __builtin_aarch64_ld3_lanedi ( + (__builtin_aarch64_simd_di *) __ptr, __o, __c); + __b.val[0] = (float64x1_t) __builtin_aarch64_get_dregcidi (__o, 0); + __b.val[1] = (float64x1_t) __builtin_aarch64_get_dregcidi (__o, 1); + __b.val[2] = (float64x1_t) __builtin_aarch64_get_dregcidi (__o, 2); + return __b; +} + +__extension__ extern __inline poly8x8x3_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld3_lane_p8 (const poly8_t * __ptr, poly8x8x3_t __b, const int __c) +{ + __builtin_aarch64_simd_ci __o; + poly8x16x3_t __temp; + __temp.val[0] = vcombine_p8 (__b.val[0], vcreate_p8 (0)); + __temp.val[1] = vcombine_p8 (__b.val[1], vcreate_p8 (0)); + __temp.val[2] = vcombine_p8 (__b.val[2], vcreate_p8 (0)); + __o = __builtin_aarch64_set_qregciv16qi (__o, (int8x16_t) __temp.val[0], 0); + __o = __builtin_aarch64_set_qregciv16qi (__o, (int8x16_t) __temp.val[1], 1); + __o = __builtin_aarch64_set_qregciv16qi (__o, (int8x16_t) __temp.val[2], 2); + __o = __builtin_aarch64_ld3_lanev8qi ( + (__builtin_aarch64_simd_qi *) __ptr, __o, __c); + __b.val[0] = (poly8x8_t) __builtin_aarch64_get_dregcidi (__o, 0); + __b.val[1] = (poly8x8_t) __builtin_aarch64_get_dregcidi (__o, 1); + __b.val[2] = (poly8x8_t) __builtin_aarch64_get_dregcidi (__o, 2); + return __b; +} + +__extension__ extern __inline poly16x4x3_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld3_lane_p16 (const poly16_t * __ptr, poly16x4x3_t __b, const int __c) +{ + __builtin_aarch64_simd_ci __o; + poly16x8x3_t __temp; + __temp.val[0] = vcombine_p16 (__b.val[0], vcreate_p16 (0)); + __temp.val[1] = vcombine_p16 (__b.val[1], vcreate_p16 (0)); + __temp.val[2] = vcombine_p16 (__b.val[2], vcreate_p16 (0)); + __o = __builtin_aarch64_set_qregciv8hi (__o, (int16x8_t) __temp.val[0], 0); + __o = __builtin_aarch64_set_qregciv8hi (__o, (int16x8_t) __temp.val[1], 1); + __o = __builtin_aarch64_set_qregciv8hi (__o, (int16x8_t) __temp.val[2], 2); + __o = __builtin_aarch64_ld3_lanev4hi ( + (__builtin_aarch64_simd_hi *) __ptr, __o, __c); + __b.val[0] = (poly16x4_t) __builtin_aarch64_get_dregcidi (__o, 0); + __b.val[1] = (poly16x4_t) __builtin_aarch64_get_dregcidi (__o, 1); + __b.val[2] = (poly16x4_t) __builtin_aarch64_get_dregcidi (__o, 2); + return __b; +} + +__extension__ extern __inline poly64x1x3_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld3_lane_p64 (const poly64_t * __ptr, poly64x1x3_t __b, const int __c) +{ + __builtin_aarch64_simd_ci __o; + poly64x2x3_t __temp; + __temp.val[0] = vcombine_p64 (__b.val[0], vcreate_p64 (0)); + __temp.val[1] = vcombine_p64 (__b.val[1], vcreate_p64 (0)); + __temp.val[2] = vcombine_p64 (__b.val[2], vcreate_p64 (0)); + __o = __builtin_aarch64_set_qregciv2di (__o, (int64x2_t) __temp.val[0], 0); + __o = __builtin_aarch64_set_qregciv2di (__o, (int64x2_t) __temp.val[1], 1); + __o = __builtin_aarch64_set_qregciv2di (__o, (int64x2_t) __temp.val[2], 2); + __o = __builtin_aarch64_ld3_lanedi ( + (__builtin_aarch64_simd_di *) __ptr, __o, __c); + __b.val[0] = (poly64x1_t) __builtin_aarch64_get_dregcidi (__o, 0); + __b.val[1] = (poly64x1_t) __builtin_aarch64_get_dregcidi (__o, 1); + __b.val[2] = (poly64x1_t) __builtin_aarch64_get_dregcidi (__o, 2); + return __b; +} /* vld3q_lane */ -#define __LD3Q_LANE_FUNC(intype, vtype, ptrtype, mode, ptrmode, funcsuffix) \ -__extension__ extern __inline intype \ -__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) \ -vld3q_lane_##funcsuffix (const ptrtype * __ptr, intype __b, const int __c) \ -{ \ - __builtin_aarch64_simd_ci __o; \ - intype ret; \ - __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) __b.val[0], 0); \ - __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) __b.val[1], 1); \ - __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) __b.val[2], 2); \ - __o = __builtin_aarch64_ld3_lane##mode ( \ - (__builtin_aarch64_simd_##ptrmode *) __ptr, __o, __c); \ - ret.val[0] = (vtype) __builtin_aarch64_get_qregciv4si (__o, 0); \ - ret.val[1] = (vtype) __builtin_aarch64_get_qregciv4si (__o, 1); \ - ret.val[2] = (vtype) __builtin_aarch64_get_qregciv4si (__o, 2); \ - return ret; \ -} - -__LD3Q_LANE_FUNC (float16x8x3_t, float16x8_t, float16_t, v8hf, hf, f16) -__LD3Q_LANE_FUNC (float32x4x3_t, float32x4_t, float32_t, v4sf, sf, f32) -__LD3Q_LANE_FUNC (float64x2x3_t, float64x2_t, float64_t, v2df, df, f64) -__LD3Q_LANE_FUNC (poly8x16x3_t, poly8x16_t, poly8_t, v16qi, qi, p8) -__LD3Q_LANE_FUNC (poly16x8x3_t, poly16x8_t, poly16_t, v8hi, hi, p16) -__LD3Q_LANE_FUNC (poly64x2x3_t, poly64x2_t, poly64_t, v2di, di, p64) -__LD3Q_LANE_FUNC (int8x16x3_t, int8x16_t, int8_t, v16qi, qi, s8) -__LD3Q_LANE_FUNC (int16x8x3_t, int16x8_t, int16_t, v8hi, hi, s16) -__LD3Q_LANE_FUNC (int32x4x3_t, int32x4_t, int32_t, v4si, si, s32) -__LD3Q_LANE_FUNC (int64x2x3_t, int64x2_t, int64_t, v2di, di, s64) -__LD3Q_LANE_FUNC (uint8x16x3_t, uint8x16_t, uint8_t, v16qi, qi, u8) -__LD3Q_LANE_FUNC (uint16x8x3_t, uint16x8_t, uint16_t, v8hi, hi, u16) -__LD3Q_LANE_FUNC (uint32x4x3_t, uint32x4_t, uint32_t, v4si, si, u32) -__LD3Q_LANE_FUNC (uint64x2x3_t, uint64x2_t, uint64_t, v2di, di, u64) +__extension__ extern __inline uint8x16x3_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld3q_lane_u8 (const uint8_t * __ptr, uint8x16x3_t __b, const int __c) +{ + __builtin_aarch64_simd_ci __o; + uint8x16x3_t ret; + __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) __b.val[0], 0); + __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) __b.val[1], 1); + __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) __b.val[2], 2); + __o = __builtin_aarch64_ld3_lanev16qi ( + (__builtin_aarch64_simd_qi *) __ptr, __o, __c); + ret.val[0] = (uint8x16_t) __builtin_aarch64_get_qregciv4si (__o, 0); + ret.val[1] = (uint8x16_t) __builtin_aarch64_get_qregciv4si (__o, 1); + ret.val[2] = (uint8x16_t) __builtin_aarch64_get_qregciv4si (__o, 2); + return ret; +} + +__extension__ extern __inline uint16x8x3_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld3q_lane_u16 (const uint16_t * __ptr, uint16x8x3_t __b, const int __c) +{ + __builtin_aarch64_simd_ci __o; + uint16x8x3_t ret; + __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) __b.val[0], 0); + __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) __b.val[1], 1); + __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) __b.val[2], 2); + __o = __builtin_aarch64_ld3_lanev8hi ( + (__builtin_aarch64_simd_hi *) __ptr, __o, __c); + ret.val[0] = (uint16x8_t) __builtin_aarch64_get_qregciv4si (__o, 0); + ret.val[1] = (uint16x8_t) __builtin_aarch64_get_qregciv4si (__o, 1); + ret.val[2] = (uint16x8_t) __builtin_aarch64_get_qregciv4si (__o, 2); + return ret; +} + +__extension__ extern __inline uint32x4x3_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld3q_lane_u32 (const uint32_t * __ptr, uint32x4x3_t __b, const int __c) +{ + __builtin_aarch64_simd_ci __o; + uint32x4x3_t ret; + __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) __b.val[0], 0); + __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) __b.val[1], 1); + __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) __b.val[2], 2); + __o = __builtin_aarch64_ld3_lanev4si ( + (__builtin_aarch64_simd_si *) __ptr, __o, __c); + ret.val[0] = (uint32x4_t) __builtin_aarch64_get_qregciv4si (__o, 0); + ret.val[1] = (uint32x4_t) __builtin_aarch64_get_qregciv4si (__o, 1); + ret.val[2] = (uint32x4_t) __builtin_aarch64_get_qregciv4si (__o, 2); + return ret; +} + +__extension__ extern __inline uint64x2x3_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld3q_lane_u64 (const uint64_t * __ptr, uint64x2x3_t __b, const int __c) +{ + __builtin_aarch64_simd_ci __o; + uint64x2x3_t ret; + __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) __b.val[0], 0); + __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) __b.val[1], 1); + __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) __b.val[2], 2); + __o = __builtin_aarch64_ld3_lanev2di ( + (__builtin_aarch64_simd_di *) __ptr, __o, __c); + ret.val[0] = (uint64x2_t) __builtin_aarch64_get_qregciv4si (__o, 0); + ret.val[1] = (uint64x2_t) __builtin_aarch64_get_qregciv4si (__o, 1); + ret.val[2] = (uint64x2_t) __builtin_aarch64_get_qregciv4si (__o, 2); + return ret; +} + +__extension__ extern __inline int8x16x3_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld3q_lane_s8 (const int8_t * __ptr, int8x16x3_t __b, const int __c) +{ + __builtin_aarch64_simd_ci __o; + int8x16x3_t ret; + __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) __b.val[0], 0); + __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) __b.val[1], 1); + __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) __b.val[2], 2); + __o = __builtin_aarch64_ld3_lanev16qi ( + (__builtin_aarch64_simd_qi *) __ptr, __o, __c); + ret.val[0] = (int8x16_t) __builtin_aarch64_get_qregciv4si (__o, 0); + ret.val[1] = (int8x16_t) __builtin_aarch64_get_qregciv4si (__o, 1); + ret.val[2] = (int8x16_t) __builtin_aarch64_get_qregciv4si (__o, 2); + return ret; +} + +__extension__ extern __inline int16x8x3_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld3q_lane_s16 (const int16_t * __ptr, int16x8x3_t __b, const int __c) +{ + __builtin_aarch64_simd_ci __o; + int16x8x3_t ret; + __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) __b.val[0], 0); + __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) __b.val[1], 1); + __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) __b.val[2], 2); + __o = __builtin_aarch64_ld3_lanev8hi ( + (__builtin_aarch64_simd_hi *) __ptr, __o, __c); + ret.val[0] = (int16x8_t) __builtin_aarch64_get_qregciv4si (__o, 0); + ret.val[1] = (int16x8_t) __builtin_aarch64_get_qregciv4si (__o, 1); + ret.val[2] = (int16x8_t) __builtin_aarch64_get_qregciv4si (__o, 2); + return ret; +} + +__extension__ extern __inline int32x4x3_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld3q_lane_s32 (const int32_t * __ptr, int32x4x3_t __b, const int __c) +{ + __builtin_aarch64_simd_ci __o; + int32x4x3_t ret; + __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) __b.val[0], 0); + __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) __b.val[1], 1); + __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) __b.val[2], 2); + __o = __builtin_aarch64_ld3_lanev4si ( + (__builtin_aarch64_simd_si *) __ptr, __o, __c); + ret.val[0] = (int32x4_t) __builtin_aarch64_get_qregciv4si (__o, 0); + ret.val[1] = (int32x4_t) __builtin_aarch64_get_qregciv4si (__o, 1); + ret.val[2] = (int32x4_t) __builtin_aarch64_get_qregciv4si (__o, 2); + return ret; +} + +__extension__ extern __inline int64x2x3_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld3q_lane_s64 (const int64_t * __ptr, int64x2x3_t __b, const int __c) +{ + __builtin_aarch64_simd_ci __o; + int64x2x3_t ret; + __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) __b.val[0], 0); + __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) __b.val[1], 1); + __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) __b.val[2], 2); + __o = __builtin_aarch64_ld3_lanev2di ( + (__builtin_aarch64_simd_di *) __ptr, __o, __c); + ret.val[0] = (int64x2_t) __builtin_aarch64_get_qregciv4si (__o, 0); + ret.val[1] = (int64x2_t) __builtin_aarch64_get_qregciv4si (__o, 1); + ret.val[2] = (int64x2_t) __builtin_aarch64_get_qregciv4si (__o, 2); + return ret; +} + +__extension__ extern __inline float16x8x3_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld3q_lane_f16 (const float16_t * __ptr, float16x8x3_t __b, const int __c) +{ + __builtin_aarch64_simd_ci __o; + float16x8x3_t ret; + __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) __b.val[0], 0); + __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) __b.val[1], 1); + __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) __b.val[2], 2); + __o = __builtin_aarch64_ld3_lanev8hf ( + (__builtin_aarch64_simd_hf *) __ptr, __o, __c); + ret.val[0] = (float16x8_t) __builtin_aarch64_get_qregciv4si (__o, 0); + ret.val[1] = (float16x8_t) __builtin_aarch64_get_qregciv4si (__o, 1); + ret.val[2] = (float16x8_t) __builtin_aarch64_get_qregciv4si (__o, 2); + return ret; +} + +__extension__ extern __inline float32x4x3_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld3q_lane_f32 (const float32_t * __ptr, float32x4x3_t __b, const int __c) +{ + __builtin_aarch64_simd_ci __o; + float32x4x3_t ret; + __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) __b.val[0], 0); + __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) __b.val[1], 1); + __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) __b.val[2], 2); + __o = __builtin_aarch64_ld3_lanev4sf ( + (__builtin_aarch64_simd_sf *) __ptr, __o, __c); + ret.val[0] = (float32x4_t) __builtin_aarch64_get_qregciv4si (__o, 0); + ret.val[1] = (float32x4_t) __builtin_aarch64_get_qregciv4si (__o, 1); + ret.val[2] = (float32x4_t) __builtin_aarch64_get_qregciv4si (__o, 2); + return ret; +} + +__extension__ extern __inline float64x2x3_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld3q_lane_f64 (const float64_t * __ptr, float64x2x3_t __b, const int __c) +{ + __builtin_aarch64_simd_ci __o; + float64x2x3_t ret; + __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) __b.val[0], 0); + __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) __b.val[1], 1); + __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) __b.val[2], 2); + __o = __builtin_aarch64_ld3_lanev2df ( + (__builtin_aarch64_simd_df *) __ptr, __o, __c); + ret.val[0] = (float64x2_t) __builtin_aarch64_get_qregciv4si (__o, 0); + ret.val[1] = (float64x2_t) __builtin_aarch64_get_qregciv4si (__o, 1); + ret.val[2] = (float64x2_t) __builtin_aarch64_get_qregciv4si (__o, 2); + return ret; +} + +__extension__ extern __inline poly8x16x3_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld3q_lane_p8 (const poly8_t * __ptr, poly8x16x3_t __b, const int __c) +{ + __builtin_aarch64_simd_ci __o; + poly8x16x3_t ret; + __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) __b.val[0], 0); + __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) __b.val[1], 1); + __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) __b.val[2], 2); + __o = __builtin_aarch64_ld3_lanev16qi ( + (__builtin_aarch64_simd_qi *) __ptr, __o, __c); + ret.val[0] = (poly8x16_t) __builtin_aarch64_get_qregciv4si (__o, 0); + ret.val[1] = (poly8x16_t) __builtin_aarch64_get_qregciv4si (__o, 1); + ret.val[2] = (poly8x16_t) __builtin_aarch64_get_qregciv4si (__o, 2); + return ret; +} + +__extension__ extern __inline poly16x8x3_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld3q_lane_p16 (const poly16_t * __ptr, poly16x8x3_t __b, const int __c) +{ + __builtin_aarch64_simd_ci __o; + poly16x8x3_t ret; + __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) __b.val[0], 0); + __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) __b.val[1], 1); + __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) __b.val[2], 2); + __o = __builtin_aarch64_ld3_lanev8hi ( + (__builtin_aarch64_simd_hi *) __ptr, __o, __c); + ret.val[0] = (poly16x8_t) __builtin_aarch64_get_qregciv4si (__o, 0); + ret.val[1] = (poly16x8_t) __builtin_aarch64_get_qregciv4si (__o, 1); + ret.val[2] = (poly16x8_t) __builtin_aarch64_get_qregciv4si (__o, 2); + return ret; +} + +__extension__ extern __inline poly64x2x3_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld3q_lane_p64 (const poly64_t * __ptr, poly64x2x3_t __b, const int __c) +{ + __builtin_aarch64_simd_ci __o; + poly64x2x3_t ret; + __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) __b.val[0], 0); + __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) __b.val[1], 1); + __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) __b.val[2], 2); + __o = __builtin_aarch64_ld3_lanev2di ( + (__builtin_aarch64_simd_di *) __ptr, __o, __c); + ret.val[0] = (poly64x2_t) __builtin_aarch64_get_qregciv4si (__o, 0); + ret.val[1] = (poly64x2_t) __builtin_aarch64_get_qregciv4si (__o, 1); + ret.val[2] = (poly64x2_t) __builtin_aarch64_get_qregciv4si (__o, 2); + return ret; +} /* vld4_lane */ -#define __LD4_LANE_FUNC(intype, vectype, largetype, ptrtype, mode, \ - qmode, ptrmode, funcsuffix, signedtype) \ -__extension__ extern __inline intype \ -__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) \ -vld4_lane_##funcsuffix (const ptrtype * __ptr, intype __b, const int __c) \ -{ \ - __builtin_aarch64_simd_xi __o; \ - largetype __temp; \ - __temp.val[0] = \ - vcombine_##funcsuffix (__b.val[0], vcreate_##funcsuffix (0)); \ - __temp.val[1] = \ - vcombine_##funcsuffix (__b.val[1], vcreate_##funcsuffix (0)); \ - __temp.val[2] = \ - vcombine_##funcsuffix (__b.val[2], vcreate_##funcsuffix (0)); \ - __temp.val[3] = \ - vcombine_##funcsuffix (__b.val[3], vcreate_##funcsuffix (0)); \ - __o = __builtin_aarch64_set_qregxi##qmode (__o, \ - (signedtype) __temp.val[0], \ - 0); \ - __o = __builtin_aarch64_set_qregxi##qmode (__o, \ - (signedtype) __temp.val[1], \ - 1); \ - __o = __builtin_aarch64_set_qregxi##qmode (__o, \ - (signedtype) __temp.val[2], \ - 2); \ - __o = __builtin_aarch64_set_qregxi##qmode (__o, \ - (signedtype) __temp.val[3], \ - 3); \ - __o = __builtin_aarch64_ld4_lane##mode ( \ - (__builtin_aarch64_simd_##ptrmode *) __ptr, __o, __c); \ - __b.val[0] = (vectype) __builtin_aarch64_get_dregxidi (__o, 0); \ - __b.val[1] = (vectype) __builtin_aarch64_get_dregxidi (__o, 1); \ - __b.val[2] = (vectype) __builtin_aarch64_get_dregxidi (__o, 2); \ - __b.val[3] = (vectype) __builtin_aarch64_get_dregxidi (__o, 3); \ - return __b; \ +__extension__ extern __inline uint8x8x4_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld4_lane_u8 (const uint8_t * __ptr, uint8x8x4_t __b, const int __c) +{ + __builtin_aarch64_simd_xi __o; + uint8x16x4_t __temp; + __temp.val[0] = vcombine_u8 (__b.val[0], vcreate_u8 (0)); + __temp.val[1] = vcombine_u8 (__b.val[1], vcreate_u8 (0)); + __temp.val[2] = vcombine_u8 (__b.val[2], vcreate_u8 (0)); + __temp.val[3] = vcombine_u8 (__b.val[3], vcreate_u8 (0)); + __o = __builtin_aarch64_set_qregxiv16qi (__o, (int8x16_t) __temp.val[0], 0); + __o = __builtin_aarch64_set_qregxiv16qi (__o, (int8x16_t) __temp.val[1], 1); + __o = __builtin_aarch64_set_qregxiv16qi (__o, (int8x16_t) __temp.val[2], 2); + __o = __builtin_aarch64_set_qregxiv16qi (__o, (int8x16_t) __temp.val[3], 3); + __o = __builtin_aarch64_ld4_lanev8qi ( + (__builtin_aarch64_simd_qi *) __ptr, __o, __c); + __b.val[0] = (uint8x8_t) __builtin_aarch64_get_dregxidi (__o, 0); + __b.val[1] = (uint8x8_t) __builtin_aarch64_get_dregxidi (__o, 1); + __b.val[2] = (uint8x8_t) __builtin_aarch64_get_dregxidi (__o, 2); + __b.val[3] = (uint8x8_t) __builtin_aarch64_get_dregxidi (__o, 3); + return __b; +} + +__extension__ extern __inline uint16x4x4_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld4_lane_u16 (const uint16_t * __ptr, uint16x4x4_t __b, const int __c) +{ + __builtin_aarch64_simd_xi __o; + uint16x8x4_t __temp; + __temp.val[0] = vcombine_u16 (__b.val[0], vcreate_u16 (0)); + __temp.val[1] = vcombine_u16 (__b.val[1], vcreate_u16 (0)); + __temp.val[2] = vcombine_u16 (__b.val[2], vcreate_u16 (0)); + __temp.val[3] = vcombine_u16 (__b.val[3], vcreate_u16 (0)); + __o = __builtin_aarch64_set_qregxiv8hi (__o, (int16x8_t) __temp.val[0], 0); + __o = __builtin_aarch64_set_qregxiv8hi (__o, (int16x8_t) __temp.val[1], 1); + __o = __builtin_aarch64_set_qregxiv8hi (__o, (int16x8_t) __temp.val[2], 2); + __o = __builtin_aarch64_set_qregxiv8hi (__o, (int16x8_t) __temp.val[3], 3); + __o = __builtin_aarch64_ld4_lanev4hi ( + (__builtin_aarch64_simd_hi *) __ptr, __o, __c); + __b.val[0] = (uint16x4_t) __builtin_aarch64_get_dregxidi (__o, 0); + __b.val[1] = (uint16x4_t) __builtin_aarch64_get_dregxidi (__o, 1); + __b.val[2] = (uint16x4_t) __builtin_aarch64_get_dregxidi (__o, 2); + __b.val[3] = (uint16x4_t) __builtin_aarch64_get_dregxidi (__o, 3); + return __b; } -/* vld4q_lane */ +__extension__ extern __inline uint32x2x4_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld4_lane_u32 (const uint32_t * __ptr, uint32x2x4_t __b, const int __c) +{ + __builtin_aarch64_simd_xi __o; + uint32x4x4_t __temp; + __temp.val[0] = vcombine_u32 (__b.val[0], vcreate_u32 (0)); + __temp.val[1] = vcombine_u32 (__b.val[1], vcreate_u32 (0)); + __temp.val[2] = vcombine_u32 (__b.val[2], vcreate_u32 (0)); + __temp.val[3] = vcombine_u32 (__b.val[3], vcreate_u32 (0)); + __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __temp.val[0], 0); + __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __temp.val[1], 1); + __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __temp.val[2], 2); + __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __temp.val[3], 3); + __o = __builtin_aarch64_ld4_lanev2si ( + (__builtin_aarch64_simd_si *) __ptr, __o, __c); + __b.val[0] = (uint32x2_t) __builtin_aarch64_get_dregxidi (__o, 0); + __b.val[1] = (uint32x2_t) __builtin_aarch64_get_dregxidi (__o, 1); + __b.val[2] = (uint32x2_t) __builtin_aarch64_get_dregxidi (__o, 2); + __b.val[3] = (uint32x2_t) __builtin_aarch64_get_dregxidi (__o, 3); + return __b; +} + +__extension__ extern __inline uint64x1x4_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld4_lane_u64 (const uint64_t * __ptr, uint64x1x4_t __b, const int __c) +{ + __builtin_aarch64_simd_xi __o; + uint64x2x4_t __temp; + __temp.val[0] = vcombine_u64 (__b.val[0], vcreate_u64 (0)); + __temp.val[1] = vcombine_u64 (__b.val[1], vcreate_u64 (0)); + __temp.val[2] = vcombine_u64 (__b.val[2], vcreate_u64 (0)); + __temp.val[3] = vcombine_u64 (__b.val[3], vcreate_u64 (0)); + __o = __builtin_aarch64_set_qregxiv2di (__o, (int64x2_t) __temp.val[0], 0); + __o = __builtin_aarch64_set_qregxiv2di (__o, (int64x2_t) __temp.val[1], 1); + __o = __builtin_aarch64_set_qregxiv2di (__o, (int64x2_t) __temp.val[2], 2); + __o = __builtin_aarch64_set_qregxiv2di (__o, (int64x2_t) __temp.val[3], 3); + __o = __builtin_aarch64_ld4_lanedi ( + (__builtin_aarch64_simd_di *) __ptr, __o, __c); + __b.val[0] = (uint64x1_t) __builtin_aarch64_get_dregxidi (__o, 0); + __b.val[1] = (uint64x1_t) __builtin_aarch64_get_dregxidi (__o, 1); + __b.val[2] = (uint64x1_t) __builtin_aarch64_get_dregxidi (__o, 2); + __b.val[3] = (uint64x1_t) __builtin_aarch64_get_dregxidi (__o, 3); + return __b; +} + +__extension__ extern __inline int8x8x4_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld4_lane_s8 (const int8_t * __ptr, int8x8x4_t __b, const int __c) +{ + __builtin_aarch64_simd_xi __o; + int8x16x4_t __temp; + __temp.val[0] = vcombine_s8 (__b.val[0], vcreate_s8 (0)); + __temp.val[1] = vcombine_s8 (__b.val[1], vcreate_s8 (0)); + __temp.val[2] = vcombine_s8 (__b.val[2], vcreate_s8 (0)); + __temp.val[3] = vcombine_s8 (__b.val[3], vcreate_s8 (0)); + __o = __builtin_aarch64_set_qregxiv16qi (__o, (int8x16_t) __temp.val[0], 0); + __o = __builtin_aarch64_set_qregxiv16qi (__o, (int8x16_t) __temp.val[1], 1); + __o = __builtin_aarch64_set_qregxiv16qi (__o, (int8x16_t) __temp.val[2], 2); + __o = __builtin_aarch64_set_qregxiv16qi (__o, (int8x16_t) __temp.val[3], 3); + __o = __builtin_aarch64_ld4_lanev8qi ( + (__builtin_aarch64_simd_qi *) __ptr, __o, __c); + __b.val[0] = (int8x8_t) __builtin_aarch64_get_dregxidi (__o, 0); + __b.val[1] = (int8x8_t) __builtin_aarch64_get_dregxidi (__o, 1); + __b.val[2] = (int8x8_t) __builtin_aarch64_get_dregxidi (__o, 2); + __b.val[3] = (int8x8_t) __builtin_aarch64_get_dregxidi (__o, 3); + return __b; +} + +__extension__ extern __inline int16x4x4_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld4_lane_s16 (const int16_t * __ptr, int16x4x4_t __b, const int __c) +{ + __builtin_aarch64_simd_xi __o; + int16x8x4_t __temp; + __temp.val[0] = vcombine_s16 (__b.val[0], vcreate_s16 (0)); + __temp.val[1] = vcombine_s16 (__b.val[1], vcreate_s16 (0)); + __temp.val[2] = vcombine_s16 (__b.val[2], vcreate_s16 (0)); + __temp.val[3] = vcombine_s16 (__b.val[3], vcreate_s16 (0)); + __o = __builtin_aarch64_set_qregxiv8hi (__o, (int16x8_t) __temp.val[0], 0); + __o = __builtin_aarch64_set_qregxiv8hi (__o, (int16x8_t) __temp.val[1], 1); + __o = __builtin_aarch64_set_qregxiv8hi (__o, (int16x8_t) __temp.val[2], 2); + __o = __builtin_aarch64_set_qregxiv8hi (__o, (int16x8_t) __temp.val[3], 3); + __o = __builtin_aarch64_ld4_lanev4hi ( + (__builtin_aarch64_simd_hi *) __ptr, __o, __c); + __b.val[0] = (int16x4_t) __builtin_aarch64_get_dregxidi (__o, 0); + __b.val[1] = (int16x4_t) __builtin_aarch64_get_dregxidi (__o, 1); + __b.val[2] = (int16x4_t) __builtin_aarch64_get_dregxidi (__o, 2); + __b.val[3] = (int16x4_t) __builtin_aarch64_get_dregxidi (__o, 3); + return __b; +} + +__extension__ extern __inline int32x2x4_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld4_lane_s32 (const int32_t * __ptr, int32x2x4_t __b, const int __c) +{ + __builtin_aarch64_simd_xi __o; + int32x4x4_t __temp; + __temp.val[0] = vcombine_s32 (__b.val[0], vcreate_s32 (0)); + __temp.val[1] = vcombine_s32 (__b.val[1], vcreate_s32 (0)); + __temp.val[2] = vcombine_s32 (__b.val[2], vcreate_s32 (0)); + __temp.val[3] = vcombine_s32 (__b.val[3], vcreate_s32 (0)); + __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __temp.val[0], 0); + __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __temp.val[1], 1); + __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __temp.val[2], 2); + __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __temp.val[3], 3); + __o = __builtin_aarch64_ld4_lanev2si ( + (__builtin_aarch64_simd_si *) __ptr, __o, __c); + __b.val[0] = (int32x2_t) __builtin_aarch64_get_dregxidi (__o, 0); + __b.val[1] = (int32x2_t) __builtin_aarch64_get_dregxidi (__o, 1); + __b.val[2] = (int32x2_t) __builtin_aarch64_get_dregxidi (__o, 2); + __b.val[3] = (int32x2_t) __builtin_aarch64_get_dregxidi (__o, 3); + return __b; +} -__LD4_LANE_FUNC (float16x4x4_t, float16x4_t, float16x8x4_t, float16_t, v4hf, - v8hf, hf, f16, float16x8_t) -__LD4_LANE_FUNC (float32x2x4_t, float32x2_t, float32x4x4_t, float32_t, v2sf, v4sf, - sf, f32, float32x4_t) -__LD4_LANE_FUNC (float64x1x4_t, float64x1_t, float64x2x4_t, float64_t, df, v2df, - df, f64, float64x2_t) -__LD4_LANE_FUNC (poly8x8x4_t, poly8x8_t, poly8x16x4_t, poly8_t, v8qi, v16qi, qi, p8, - int8x16_t) -__LD4_LANE_FUNC (poly16x4x4_t, poly16x4_t, poly16x8x4_t, poly16_t, v4hi, v8hi, hi, - p16, int16x8_t) -__LD4_LANE_FUNC (poly64x1x4_t, poly64x1_t, poly64x2x4_t, poly64_t, di, - v2di_ssps, di, p64, poly64x2_t) -__LD4_LANE_FUNC (int8x8x4_t, int8x8_t, int8x16x4_t, int8_t, v8qi, v16qi, qi, s8, - int8x16_t) -__LD4_LANE_FUNC (int16x4x4_t, int16x4_t, int16x8x4_t, int16_t, v4hi, v8hi, hi, s16, - int16x8_t) -__LD4_LANE_FUNC (int32x2x4_t, int32x2_t, int32x4x4_t, int32_t, v2si, v4si, si, s32, - int32x4_t) -__LD4_LANE_FUNC (int64x1x4_t, int64x1_t, int64x2x4_t, int64_t, di, v2di, di, s64, - int64x2_t) -__LD4_LANE_FUNC (uint8x8x4_t, uint8x8_t, uint8x16x4_t, uint8_t, v8qi, v16qi, qi, u8, - int8x16_t) -__LD4_LANE_FUNC (uint16x4x4_t, uint16x4_t, uint16x8x4_t, uint16_t, v4hi, v8hi, hi, - u16, int16x8_t) -__LD4_LANE_FUNC (uint32x2x4_t, uint32x2_t, uint32x4x4_t, uint32_t, v2si, v4si, si, - u32, int32x4_t) -__LD4_LANE_FUNC (uint64x1x4_t, uint64x1_t, uint64x2x4_t, uint64_t, di, v2di, di, - u64, int64x2_t) +__extension__ extern __inline int64x1x4_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld4_lane_s64 (const int64_t * __ptr, int64x1x4_t __b, const int __c) +{ + __builtin_aarch64_simd_xi __o; + int64x2x4_t __temp; + __temp.val[0] = vcombine_s64 (__b.val[0], vcreate_s64 (0)); + __temp.val[1] = vcombine_s64 (__b.val[1], vcreate_s64 (0)); + __temp.val[2] = vcombine_s64 (__b.val[2], vcreate_s64 (0)); + __temp.val[3] = vcombine_s64 (__b.val[3], vcreate_s64 (0)); + __o = __builtin_aarch64_set_qregxiv2di (__o, (int64x2_t) __temp.val[0], 0); + __o = __builtin_aarch64_set_qregxiv2di (__o, (int64x2_t) __temp.val[1], 1); + __o = __builtin_aarch64_set_qregxiv2di (__o, (int64x2_t) __temp.val[2], 2); + __o = __builtin_aarch64_set_qregxiv2di (__o, (int64x2_t) __temp.val[3], 3); + __o = __builtin_aarch64_ld4_lanedi ( + (__builtin_aarch64_simd_di *) __ptr, __o, __c); + __b.val[0] = (int64x1_t) __builtin_aarch64_get_dregxidi (__o, 0); + __b.val[1] = (int64x1_t) __builtin_aarch64_get_dregxidi (__o, 1); + __b.val[2] = (int64x1_t) __builtin_aarch64_get_dregxidi (__o, 2); + __b.val[3] = (int64x1_t) __builtin_aarch64_get_dregxidi (__o, 3); + return __b; +} + +__extension__ extern __inline float16x4x4_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld4_lane_f16 (const float16_t * __ptr, float16x4x4_t __b, const int __c) +{ + __builtin_aarch64_simd_xi __o; + float16x8x4_t __temp; + __temp.val[0] = vcombine_f16 (__b.val[0], vcreate_f16 (0)); + __temp.val[1] = vcombine_f16 (__b.val[1], vcreate_f16 (0)); + __temp.val[2] = vcombine_f16 (__b.val[2], vcreate_f16 (0)); + __temp.val[3] = vcombine_f16 (__b.val[3], vcreate_f16 (0)); + __o = __builtin_aarch64_set_qregxiv8hf (__o, (float16x8_t) __temp.val[0], 0); + __o = __builtin_aarch64_set_qregxiv8hf (__o, (float16x8_t) __temp.val[1], 1); + __o = __builtin_aarch64_set_qregxiv8hf (__o, (float16x8_t) __temp.val[2], 2); + __o = __builtin_aarch64_set_qregxiv8hf (__o, (float16x8_t) __temp.val[3], 3); + __o = __builtin_aarch64_ld4_lanev4hf ( + (__builtin_aarch64_simd_hf *) __ptr, __o, __c); + __b.val[0] = (float16x4_t) __builtin_aarch64_get_dregxidi (__o, 0); + __b.val[1] = (float16x4_t) __builtin_aarch64_get_dregxidi (__o, 1); + __b.val[2] = (float16x4_t) __builtin_aarch64_get_dregxidi (__o, 2); + __b.val[3] = (float16x4_t) __builtin_aarch64_get_dregxidi (__o, 3); + return __b; +} + +__extension__ extern __inline float32x2x4_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld4_lane_f32 (const float32_t * __ptr, float32x2x4_t __b, const int __c) +{ + __builtin_aarch64_simd_xi __o; + float32x4x4_t __temp; + __temp.val[0] = vcombine_f32 (__b.val[0], vcreate_f32 (0)); + __temp.val[1] = vcombine_f32 (__b.val[1], vcreate_f32 (0)); + __temp.val[2] = vcombine_f32 (__b.val[2], vcreate_f32 (0)); + __temp.val[3] = vcombine_f32 (__b.val[3], vcreate_f32 (0)); + __o = __builtin_aarch64_set_qregxiv4sf (__o, (float32x4_t) __temp.val[0], 0); + __o = __builtin_aarch64_set_qregxiv4sf (__o, (float32x4_t) __temp.val[1], 1); + __o = __builtin_aarch64_set_qregxiv4sf (__o, (float32x4_t) __temp.val[2], 2); + __o = __builtin_aarch64_set_qregxiv4sf (__o, (float32x4_t) __temp.val[3], 3); + __o = __builtin_aarch64_ld4_lanev2si ( + (__builtin_aarch64_simd_sf *) __ptr, __o, __c); + __b.val[0] = (float32x2_t) __builtin_aarch64_get_dregxidi (__o, 0); + __b.val[1] = (float32x2_t) __builtin_aarch64_get_dregxidi (__o, 1); + __b.val[2] = (float32x2_t) __builtin_aarch64_get_dregxidi (__o, 2); + __b.val[3] = (float32x2_t) __builtin_aarch64_get_dregxidi (__o, 3); + return __b; +} + +__extension__ extern __inline float64x1x4_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld4_lane_f64 (const float64_t * __ptr, float64x1x4_t __b, const int __c) +{ + __builtin_aarch64_simd_xi __o; + float64x2x4_t __temp; + __temp.val[0] = vcombine_f64 (__b.val[0], vcreate_f64 (0)); + __temp.val[1] = vcombine_f64 (__b.val[1], vcreate_f64 (0)); + __temp.val[2] = vcombine_f64 (__b.val[2], vcreate_f64 (0)); + __temp.val[3] = vcombine_f64 (__b.val[3], vcreate_f64 (0)); + __o = __builtin_aarch64_set_qregxiv2df (__o, (float64x2_t) __temp.val[0], 0); + __o = __builtin_aarch64_set_qregxiv2df (__o, (float64x2_t) __temp.val[1], 1); + __o = __builtin_aarch64_set_qregxiv2df (__o, (float64x2_t) __temp.val[2], 2); + __o = __builtin_aarch64_set_qregxiv2df (__o, (float64x2_t) __temp.val[3], 3); + __o = __builtin_aarch64_ld4_lanedf ( + (__builtin_aarch64_simd_df *) __ptr, __o, __c); + __b.val[0] = (float64x1_t) __builtin_aarch64_get_dregxidi (__o, 0); + __b.val[1] = (float64x1_t) __builtin_aarch64_get_dregxidi (__o, 1); + __b.val[2] = (float64x1_t) __builtin_aarch64_get_dregxidi (__o, 2); + __b.val[3] = (float64x1_t) __builtin_aarch64_get_dregxidi (__o, 3); + return __b; +} + +__extension__ extern __inline poly8x8x4_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld4_lane_p8 (const poly8_t * __ptr, poly8x8x4_t __b, const int __c) +{ + __builtin_aarch64_simd_xi __o; + poly8x16x4_t __temp; + __temp.val[0] = vcombine_p8 (__b.val[0], vcreate_p8 (0)); + __temp.val[1] = vcombine_p8 (__b.val[1], vcreate_p8 (0)); + __temp.val[2] = vcombine_p8 (__b.val[2], vcreate_p8 (0)); + __temp.val[3] = vcombine_p8 (__b.val[3], vcreate_p8 (0)); + __o = __builtin_aarch64_set_qregxiv16qi (__o, (int8x16_t) __temp.val[0], 0); + __o = __builtin_aarch64_set_qregxiv16qi (__o, (int8x16_t) __temp.val[1], 1); + __o = __builtin_aarch64_set_qregxiv16qi (__o, (int8x16_t) __temp.val[2], 2); + __o = __builtin_aarch64_set_qregxiv16qi (__o, (int8x16_t) __temp.val[3], 3); + __o = __builtin_aarch64_ld4_lanev8qi ( + (__builtin_aarch64_simd_qi *) __ptr, __o, __c); + __b.val[0] = (poly8x8_t) __builtin_aarch64_get_dregxidi (__o, 0); + __b.val[1] = (poly8x8_t) __builtin_aarch64_get_dregxidi (__o, 1); + __b.val[2] = (poly8x8_t) __builtin_aarch64_get_dregxidi (__o, 2); + __b.val[3] = (poly8x8_t) __builtin_aarch64_get_dregxidi (__o, 3); + return __b; +} + +__extension__ extern __inline poly16x4x4_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld4_lane_p16 (const poly16_t * __ptr, poly16x4x4_t __b, const int __c) +{ + __builtin_aarch64_simd_xi __o; + poly16x8x4_t __temp; + __temp.val[0] = vcombine_p16 (__b.val[0], vcreate_p16 (0)); + __temp.val[1] = vcombine_p16 (__b.val[1], vcreate_p16 (0)); + __temp.val[2] = vcombine_p16 (__b.val[2], vcreate_p16 (0)); + __temp.val[3] = vcombine_p16 (__b.val[3], vcreate_p16 (0)); + __o = __builtin_aarch64_set_qregxiv8hi (__o, (int16x8_t) __temp.val[0], 0); + __o = __builtin_aarch64_set_qregxiv8hi (__o, (int16x8_t) __temp.val[1], 1); + __o = __builtin_aarch64_set_qregxiv8hi (__o, (int16x8_t) __temp.val[2], 2); + __o = __builtin_aarch64_set_qregxiv8hi (__o, (int16x8_t) __temp.val[3], 3); + __o = __builtin_aarch64_ld4_lanev4hi ( + (__builtin_aarch64_simd_hi *) __ptr, __o, __c); + __b.val[0] = (poly16x4_t) __builtin_aarch64_get_dregxidi (__o, 0); + __b.val[1] = (poly16x4_t) __builtin_aarch64_get_dregxidi (__o, 1); + __b.val[2] = (poly16x4_t) __builtin_aarch64_get_dregxidi (__o, 2); + __b.val[3] = (poly16x4_t) __builtin_aarch64_get_dregxidi (__o, 3); + return __b; +} + +__extension__ extern __inline poly64x1x4_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld4_lane_p64 (const poly64_t * __ptr, poly64x1x4_t __b, const int __c) +{ + __builtin_aarch64_simd_xi __o; + poly64x2x4_t __temp; + __temp.val[0] = vcombine_p64 (__b.val[0], vcreate_p64 (0)); + __temp.val[1] = vcombine_p64 (__b.val[1], vcreate_p64 (0)); + __temp.val[2] = vcombine_p64 (__b.val[2], vcreate_p64 (0)); + __temp.val[3] = vcombine_p64 (__b.val[3], vcreate_p64 (0)); + __o = __builtin_aarch64_set_qregxiv2di (__o, (int64x2_t) __temp.val[0], 0); + __o = __builtin_aarch64_set_qregxiv2di (__o, (int64x2_t) __temp.val[1], 1); + __o = __builtin_aarch64_set_qregxiv2di (__o, (int64x2_t) __temp.val[2], 2); + __o = __builtin_aarch64_set_qregxiv2di (__o, (int64x2_t) __temp.val[3], 3); + __o = __builtin_aarch64_ld4_lanedi ( + (__builtin_aarch64_simd_di *) __ptr, __o, __c); + __b.val[0] = (poly64x1_t) __builtin_aarch64_get_dregxidi (__o, 0); + __b.val[1] = (poly64x1_t) __builtin_aarch64_get_dregxidi (__o, 1); + __b.val[2] = (poly64x1_t) __builtin_aarch64_get_dregxidi (__o, 2); + __b.val[3] = (poly64x1_t) __builtin_aarch64_get_dregxidi (__o, 3); + return __b; +} /* vld4q_lane */ -#define __LD4Q_LANE_FUNC(intype, vtype, ptrtype, mode, ptrmode, funcsuffix) \ -__extension__ extern __inline intype \ -__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) \ -vld4q_lane_##funcsuffix (const ptrtype * __ptr, intype __b, const int __c) \ -{ \ - __builtin_aarch64_simd_xi __o; \ - intype ret; \ - __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __b.val[0], 0); \ - __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __b.val[1], 1); \ - __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __b.val[2], 2); \ - __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __b.val[3], 3); \ - __o = __builtin_aarch64_ld4_lane##mode ( \ - (__builtin_aarch64_simd_##ptrmode *) __ptr, __o, __c); \ - ret.val[0] = (vtype) __builtin_aarch64_get_qregxiv4si (__o, 0); \ - ret.val[1] = (vtype) __builtin_aarch64_get_qregxiv4si (__o, 1); \ - ret.val[2] = (vtype) __builtin_aarch64_get_qregxiv4si (__o, 2); \ - ret.val[3] = (vtype) __builtin_aarch64_get_qregxiv4si (__o, 3); \ - return ret; \ -} - -__LD4Q_LANE_FUNC (float16x8x4_t, float16x8_t, float16_t, v8hf, hf, f16) -__LD4Q_LANE_FUNC (float32x4x4_t, float32x4_t, float32_t, v4sf, sf, f32) -__LD4Q_LANE_FUNC (float64x2x4_t, float64x2_t, float64_t, v2df, df, f64) -__LD4Q_LANE_FUNC (poly8x16x4_t, poly8x16_t, poly8_t, v16qi, qi, p8) -__LD4Q_LANE_FUNC (poly16x8x4_t, poly16x8_t, poly16_t, v8hi, hi, p16) -__LD4Q_LANE_FUNC (poly64x2x4_t, poly64x2_t, poly64_t, v2di, di, p64) -__LD4Q_LANE_FUNC (int8x16x4_t, int8x16_t, int8_t, v16qi, qi, s8) -__LD4Q_LANE_FUNC (int16x8x4_t, int16x8_t, int16_t, v8hi, hi, s16) -__LD4Q_LANE_FUNC (int32x4x4_t, int32x4_t, int32_t, v4si, si, s32) -__LD4Q_LANE_FUNC (int64x2x4_t, int64x2_t, int64_t, v2di, di, s64) -__LD4Q_LANE_FUNC (uint8x16x4_t, uint8x16_t, uint8_t, v16qi, qi, u8) -__LD4Q_LANE_FUNC (uint16x8x4_t, uint16x8_t, uint16_t, v8hi, hi, u16) -__LD4Q_LANE_FUNC (uint32x4x4_t, uint32x4_t, uint32_t, v4si, si, u32) -__LD4Q_LANE_FUNC (uint64x2x4_t, uint64x2_t, uint64_t, v2di, di, u64) +__extension__ extern __inline uint8x16x4_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld4q_lane_u8 (const uint8_t * __ptr, uint8x16x4_t __b, const int __c) +{ + __builtin_aarch64_simd_xi __o; + uint8x16x4_t ret; + __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __b.val[0], 0); + __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __b.val[1], 1); + __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __b.val[2], 2); + __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __b.val[3], 3); + __o = __builtin_aarch64_ld4_lanev16qi ( + (__builtin_aarch64_simd_qi *) __ptr, __o, __c); + ret.val[0] = (uint8x16_t) __builtin_aarch64_get_qregxiv4si (__o, 0); + ret.val[1] = (uint8x16_t) __builtin_aarch64_get_qregxiv4si (__o, 1); + ret.val[2] = (uint8x16_t) __builtin_aarch64_get_qregxiv4si (__o, 2); + ret.val[3] = (uint8x16_t) __builtin_aarch64_get_qregxiv4si (__o, 3); + return ret; +} + +__extension__ extern __inline uint16x8x4_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld4q_lane_u16 (const uint16_t * __ptr, uint16x8x4_t __b, const int __c) +{ + __builtin_aarch64_simd_xi __o; + uint16x8x4_t ret; + __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __b.val[0], 0); + __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __b.val[1], 1); + __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __b.val[2], 2); + __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __b.val[3], 3); + __o = __builtin_aarch64_ld4_lanev8hi ( + (__builtin_aarch64_simd_hi *) __ptr, __o, __c); + ret.val[0] = (uint16x8_t) __builtin_aarch64_get_qregxiv4si (__o, 0); + ret.val[1] = (uint16x8_t) __builtin_aarch64_get_qregxiv4si (__o, 1); + ret.val[2] = (uint16x8_t) __builtin_aarch64_get_qregxiv4si (__o, 2); + ret.val[3] = (uint16x8_t) __builtin_aarch64_get_qregxiv4si (__o, 3); + return ret; +} + +__extension__ extern __inline uint32x4x4_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld4q_lane_u32 (const uint32_t * __ptr, uint32x4x4_t __b, const int __c) +{ + __builtin_aarch64_simd_xi __o; + uint32x4x4_t ret; + __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __b.val[0], 0); + __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __b.val[1], 1); + __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __b.val[2], 2); + __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __b.val[3], 3); + __o = __builtin_aarch64_ld4_lanev4si ( + (__builtin_aarch64_simd_si *) __ptr, __o, __c); + ret.val[0] = (uint32x4_t) __builtin_aarch64_get_qregxiv4si (__o, 0); + ret.val[1] = (uint32x4_t) __builtin_aarch64_get_qregxiv4si (__o, 1); + ret.val[2] = (uint32x4_t) __builtin_aarch64_get_qregxiv4si (__o, 2); + ret.val[3] = (uint32x4_t) __builtin_aarch64_get_qregxiv4si (__o, 3); + return ret; +} + +__extension__ extern __inline uint64x2x4_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld4q_lane_u64 (const uint64_t * __ptr, uint64x2x4_t __b, const int __c) +{ + __builtin_aarch64_simd_xi __o; + uint64x2x4_t ret; + __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __b.val[0], 0); + __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __b.val[1], 1); + __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __b.val[2], 2); + __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __b.val[3], 3); + __o = __builtin_aarch64_ld4_lanev2di ( + (__builtin_aarch64_simd_di *) __ptr, __o, __c); + ret.val[0] = (uint64x2_t) __builtin_aarch64_get_qregxiv4si (__o, 0); + ret.val[1] = (uint64x2_t) __builtin_aarch64_get_qregxiv4si (__o, 1); + ret.val[2] = (uint64x2_t) __builtin_aarch64_get_qregxiv4si (__o, 2); + ret.val[3] = (uint64x2_t) __builtin_aarch64_get_qregxiv4si (__o, 3); + return ret; +} + +__extension__ extern __inline int8x16x4_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld4q_lane_s8 (const int8_t * __ptr, int8x16x4_t __b, const int __c) +{ + __builtin_aarch64_simd_xi __o; + int8x16x4_t ret; + __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __b.val[0], 0); + __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __b.val[1], 1); + __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __b.val[2], 2); + __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __b.val[3], 3); + __o = __builtin_aarch64_ld4_lanev16qi ( + (__builtin_aarch64_simd_qi *) __ptr, __o, __c); + ret.val[0] = (int8x16_t) __builtin_aarch64_get_qregxiv4si (__o, 0); + ret.val[1] = (int8x16_t) __builtin_aarch64_get_qregxiv4si (__o, 1); + ret.val[2] = (int8x16_t) __builtin_aarch64_get_qregxiv4si (__o, 2); + ret.val[3] = (int8x16_t) __builtin_aarch64_get_qregxiv4si (__o, 3); + return ret; +} + +__extension__ extern __inline int16x8x4_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld4q_lane_s16 (const int16_t * __ptr, int16x8x4_t __b, const int __c) +{ + __builtin_aarch64_simd_xi __o; + int16x8x4_t ret; + __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __b.val[0], 0); + __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __b.val[1], 1); + __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __b.val[2], 2); + __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __b.val[3], 3); + __o = __builtin_aarch64_ld4_lanev8hi ( + (__builtin_aarch64_simd_hi *) __ptr, __o, __c); + ret.val[0] = (int16x8_t) __builtin_aarch64_get_qregxiv4si (__o, 0); + ret.val[1] = (int16x8_t) __builtin_aarch64_get_qregxiv4si (__o, 1); + ret.val[2] = (int16x8_t) __builtin_aarch64_get_qregxiv4si (__o, 2); + ret.val[3] = (int16x8_t) __builtin_aarch64_get_qregxiv4si (__o, 3); + return ret; +} + +__extension__ extern __inline int32x4x4_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld4q_lane_s32 (const int32_t * __ptr, int32x4x4_t __b, const int __c) +{ + __builtin_aarch64_simd_xi __o; + int32x4x4_t ret; + __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __b.val[0], 0); + __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __b.val[1], 1); + __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __b.val[2], 2); + __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __b.val[3], 3); + __o = __builtin_aarch64_ld4_lanev4si ( + (__builtin_aarch64_simd_si *) __ptr, __o, __c); + ret.val[0] = (int32x4_t) __builtin_aarch64_get_qregxiv4si (__o, 0); + ret.val[1] = (int32x4_t) __builtin_aarch64_get_qregxiv4si (__o, 1); + ret.val[2] = (int32x4_t) __builtin_aarch64_get_qregxiv4si (__o, 2); + ret.val[3] = (int32x4_t) __builtin_aarch64_get_qregxiv4si (__o, 3); + return ret; +} + +__extension__ extern __inline int64x2x4_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld4q_lane_s64 (const int64_t * __ptr, int64x2x4_t __b, const int __c) +{ + __builtin_aarch64_simd_xi __o; + int64x2x4_t ret; + __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __b.val[0], 0); + __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __b.val[1], 1); + __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __b.val[2], 2); + __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __b.val[3], 3); + __o = __builtin_aarch64_ld4_lanev2di ( + (__builtin_aarch64_simd_di *) __ptr, __o, __c); + ret.val[0] = (int64x2_t) __builtin_aarch64_get_qregxiv4si (__o, 0); + ret.val[1] = (int64x2_t) __builtin_aarch64_get_qregxiv4si (__o, 1); + ret.val[2] = (int64x2_t) __builtin_aarch64_get_qregxiv4si (__o, 2); + ret.val[3] = (int64x2_t) __builtin_aarch64_get_qregxiv4si (__o, 3); + return ret; +} + +__extension__ extern __inline float16x8x4_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld4q_lane_f16 (const float16_t * __ptr, float16x8x4_t __b, const int __c) +{ + __builtin_aarch64_simd_xi __o; + float16x8x4_t ret; + __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __b.val[0], 0); + __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __b.val[1], 1); + __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __b.val[2], 2); + __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __b.val[3], 3); + __o = __builtin_aarch64_ld4_lanev8hf ( + (__builtin_aarch64_simd_hf *) __ptr, __o, __c); + ret.val[0] = (float16x8_t) __builtin_aarch64_get_qregxiv4si (__o, 0); + ret.val[1] = (float16x8_t) __builtin_aarch64_get_qregxiv4si (__o, 1); + ret.val[2] = (float16x8_t) __builtin_aarch64_get_qregxiv4si (__o, 2); + ret.val[3] = (float16x8_t) __builtin_aarch64_get_qregxiv4si (__o, 3); + return ret; +} + +__extension__ extern __inline float32x4x4_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld4q_lane_f32 (const float32_t * __ptr, float32x4x4_t __b, const int __c) +{ + __builtin_aarch64_simd_xi __o; + float32x4x4_t ret; + __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __b.val[0], 0); + __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __b.val[1], 1); + __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __b.val[2], 2); + __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __b.val[3], 3); + __o = __builtin_aarch64_ld4_lanev4sf ( + (__builtin_aarch64_simd_sf *) __ptr, __o, __c); + ret.val[0] = (float32x4_t) __builtin_aarch64_get_qregxiv4si (__o, 0); + ret.val[1] = (float32x4_t) __builtin_aarch64_get_qregxiv4si (__o, 1); + ret.val[2] = (float32x4_t) __builtin_aarch64_get_qregxiv4si (__o, 2); + ret.val[3] = (float32x4_t) __builtin_aarch64_get_qregxiv4si (__o, 3); + return ret; +} + +__extension__ extern __inline float64x2x4_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld4q_lane_f64 (const float64_t * __ptr, float64x2x4_t __b, const int __c) +{ + __builtin_aarch64_simd_xi __o; + float64x2x4_t ret; + __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __b.val[0], 0); + __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __b.val[1], 1); + __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __b.val[2], 2); + __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __b.val[3], 3); + __o = __builtin_aarch64_ld4_lanev2df ( + (__builtin_aarch64_simd_di *) __ptr, __o, __c); + ret.val[0] = (float64x2_t) __builtin_aarch64_get_qregxiv4si (__o, 0); + ret.val[1] = (float64x2_t) __builtin_aarch64_get_qregxiv4si (__o, 1); + ret.val[2] = (float64x2_t) __builtin_aarch64_get_qregxiv4si (__o, 2); + ret.val[3] = (float64x2_t) __builtin_aarch64_get_qregxiv4si (__o, 3); + return ret; +} + +__extension__ extern __inline poly8x16x4_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld4q_lane_p8 (const poly8_t * __ptr, poly8x16x4_t __b, const int __c) +{ + __builtin_aarch64_simd_xi __o; + poly8x16x4_t ret; + __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __b.val[0], 0); + __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __b.val[1], 1); + __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __b.val[2], 2); + __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __b.val[3], 3); + __o = __builtin_aarch64_ld4_lanev16qi ( + (__builtin_aarch64_simd_qi *) __ptr, __o, __c); + ret.val[0] = (poly8x16_t) __builtin_aarch64_get_qregxiv4si (__o, 0); + ret.val[1] = (poly8x16_t) __builtin_aarch64_get_qregxiv4si (__o, 1); + ret.val[2] = (poly8x16_t) __builtin_aarch64_get_qregxiv4si (__o, 2); + ret.val[3] = (poly8x16_t) __builtin_aarch64_get_qregxiv4si (__o, 3); + return ret; +} + +__extension__ extern __inline poly16x8x4_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld4q_lane_p16 (const poly16_t * __ptr, poly16x8x4_t __b, const int __c) +{ + __builtin_aarch64_simd_xi __o; + poly16x8x4_t ret; + __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __b.val[0], 0); + __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __b.val[1], 1); + __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __b.val[2], 2); + __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __b.val[3], 3); + __o = __builtin_aarch64_ld4_lanev8hi ( + (__builtin_aarch64_simd_hi *) __ptr, __o, __c); + ret.val[0] = (poly16x8_t) __builtin_aarch64_get_qregxiv4si (__o, 0); + ret.val[1] = (poly16x8_t) __builtin_aarch64_get_qregxiv4si (__o, 1); + ret.val[2] = (poly16x8_t) __builtin_aarch64_get_qregxiv4si (__o, 2); + ret.val[3] = (poly16x8_t) __builtin_aarch64_get_qregxiv4si (__o, 3); + return ret; +} + +__extension__ extern __inline poly64x2x4_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld4q_lane_p64 (const poly64_t * __ptr, poly64x2x4_t __b, const int __c) +{ + __builtin_aarch64_simd_xi __o; + poly64x2x4_t ret; + __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __b.val[0], 0); + __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __b.val[1], 1); + __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __b.val[2], 2); + __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __b.val[3], 3); + __o = __builtin_aarch64_ld4_lanev2di ( + (__builtin_aarch64_simd_di *) __ptr, __o, __c); + ret.val[0] = (poly64x2_t) __builtin_aarch64_get_qregxiv4si (__o, 0); + ret.val[1] = (poly64x2_t) __builtin_aarch64_get_qregxiv4si (__o, 1); + ret.val[2] = (poly64x2_t) __builtin_aarch64_get_qregxiv4si (__o, 2); + ret.val[3] = (poly64x2_t) __builtin_aarch64_get_qregxiv4si (__o, 3); + return ret; +} /* vmax */ @@ -34584,15 +35857,116 @@ vcopyq_laneq_bf16 (bfloat16x8_t __a, const int __lane1, __a, __lane1); } -__LD2_LANE_FUNC (bfloat16x4x2_t, bfloat16x4_t, bfloat16x8x2_t, bfloat16_t, v4bf, - v8bf, bf, bf16, bfloat16x8_t) -__LD2Q_LANE_FUNC (bfloat16x8x2_t, bfloat16x8_t, bfloat16_t, v8bf, bf, bf16) -__LD3_LANE_FUNC (bfloat16x4x3_t, bfloat16x4_t, bfloat16x8x3_t, bfloat16_t, v4bf, - v8bf, bf, bf16, bfloat16x8_t) -__LD3Q_LANE_FUNC (bfloat16x8x3_t, bfloat16x8_t, bfloat16_t, v8bf, bf, bf16) -__LD4_LANE_FUNC (bfloat16x4x4_t, bfloat16x4_t, bfloat16x8x4_t, bfloat16_t, v4bf, - v8bf, bf, bf16, bfloat16x8_t) -__LD4Q_LANE_FUNC (bfloat16x8x4_t, bfloat16x8_t, bfloat16_t, v8bf, bf, bf16) +__extension__ extern __inline bfloat16x4x2_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld2_lane_bf16 (const bfloat16_t * __ptr, bfloat16x4x2_t __b, const int __c) +{ + __builtin_aarch64_simd_oi __o; + bfloat16x8x2_t __temp; + __temp.val[0] = vcombine_bf16 (__b.val[0], vcreate_bf16 (0)); + __temp.val[1] = vcombine_bf16 (__b.val[1], vcreate_bf16 (0)); + __o = __builtin_aarch64_set_qregoiv8bf (__o, (bfloat16x8_t) __temp.val[0], 0); + __o = __builtin_aarch64_set_qregoiv8bf (__o, (bfloat16x8_t) __temp.val[1], 1); + __o = __builtin_aarch64_ld2_lanev4bf ( + (__builtin_aarch64_simd_bf *) __ptr, __o, __c); + __b.val[0] = (bfloat16x4_t) __builtin_aarch64_get_dregoidi (__o, 0); + __b.val[1] = (bfloat16x4_t) __builtin_aarch64_get_dregoidi (__o, 1); + return __b; +} + +__extension__ extern __inline bfloat16x8x2_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld2q_lane_bf16 (const bfloat16_t * __ptr, bfloat16x8x2_t __b, const int __c) +{ + __builtin_aarch64_simd_oi __o; + bfloat16x8x2_t ret; + __o = __builtin_aarch64_set_qregoiv4si (__o, (int32x4_t) __b.val[0], 0); + __o = __builtin_aarch64_set_qregoiv4si (__o, (int32x4_t) __b.val[1], 1); + __o = __builtin_aarch64_ld2_lanev8bf ( + (__builtin_aarch64_simd_bf *) __ptr, __o, __c); + ret.val[0] = (bfloat16x8_t) __builtin_aarch64_get_qregoiv4si (__o, 0); + ret.val[1] = (bfloat16x8_t) __builtin_aarch64_get_qregoiv4si (__o, 1); + return ret; +} + +__extension__ extern __inline bfloat16x4x3_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld3_lane_bf16 (const bfloat16_t * __ptr, bfloat16x4x3_t __b, const int __c) +{ + __builtin_aarch64_simd_ci __o; + bfloat16x8x3_t __temp; + __temp.val[0] = vcombine_bf16 (__b.val[0], vcreate_bf16 (0)); + __temp.val[1] = vcombine_bf16 (__b.val[1], vcreate_bf16 (0)); + __temp.val[2] = vcombine_bf16 (__b.val[2], vcreate_bf16 (0)); + __o = __builtin_aarch64_set_qregciv8bf (__o, (bfloat16x8_t) __temp.val[0], 0); + __o = __builtin_aarch64_set_qregciv8bf (__o, (bfloat16x8_t) __temp.val[1], 1); + __o = __builtin_aarch64_set_qregciv8bf (__o, (bfloat16x8_t) __temp.val[2], 2); + __o = __builtin_aarch64_ld3_lanev4bf ( + (__builtin_aarch64_simd_bf *) __ptr, __o, __c); + __b.val[0] = (bfloat16x4_t) __builtin_aarch64_get_dregcidi (__o, 0); + __b.val[1] = (bfloat16x4_t) __builtin_aarch64_get_dregcidi (__o, 1); + __b.val[2] = (bfloat16x4_t) __builtin_aarch64_get_dregcidi (__o, 2); + return __b; +} + +__extension__ extern __inline bfloat16x8x3_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld3q_lane_bf16 (const bfloat16_t * __ptr, bfloat16x8x3_t __b, const int __c) +{ + __builtin_aarch64_simd_ci __o; + bfloat16x8x3_t ret; + __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) __b.val[0], 0); + __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) __b.val[1], 1); + __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) __b.val[2], 2); + __o = __builtin_aarch64_ld3_lanev8bf ( + (__builtin_aarch64_simd_bf *) __ptr, __o, __c); + ret.val[0] = (bfloat16x8_t) __builtin_aarch64_get_qregciv4si (__o, 0); + ret.val[1] = (bfloat16x8_t) __builtin_aarch64_get_qregciv4si (__o, 1); + ret.val[2] = (bfloat16x8_t) __builtin_aarch64_get_qregciv4si (__o, 2); + return ret; +} + +__extension__ extern __inline bfloat16x4x4_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld4_lane_bf16 (const bfloat16_t * __ptr, bfloat16x4x4_t __b, const int __c) +{ + __builtin_aarch64_simd_xi __o; + bfloat16x8x4_t __temp; + __temp.val[0] = vcombine_bf16 (__b.val[0], vcreate_bf16 (0)); + __temp.val[1] = vcombine_bf16 (__b.val[1], vcreate_bf16 (0)); + __temp.val[2] = vcombine_bf16 (__b.val[2], vcreate_bf16 (0)); + __temp.val[3] = vcombine_bf16 (__b.val[3], vcreate_bf16 (0)); + __o = __builtin_aarch64_set_qregxiv8bf (__o, (bfloat16x8_t) __temp.val[0], 0); + __o = __builtin_aarch64_set_qregxiv8bf (__o, (bfloat16x8_t) __temp.val[1], 1); + __o = __builtin_aarch64_set_qregxiv8bf (__o, (bfloat16x8_t) __temp.val[2], 2); + __o = __builtin_aarch64_set_qregxiv8bf (__o, (bfloat16x8_t) __temp.val[3], 3); + __o = __builtin_aarch64_ld4_lanev4bf ( + (__builtin_aarch64_simd_bf *) __ptr, __o, __c); + __b.val[0] = (bfloat16x4_t) __builtin_aarch64_get_dregxidi (__o, 0); + __b.val[1] = (bfloat16x4_t) __builtin_aarch64_get_dregxidi (__o, 1); + __b.val[2] = (bfloat16x4_t) __builtin_aarch64_get_dregxidi (__o, 2); + __b.val[3] = (bfloat16x4_t) __builtin_aarch64_get_dregxidi (__o, 3); + return __b; +} + +__extension__ extern __inline bfloat16x8x4_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld4q_lane_bf16 (const bfloat16_t * __ptr, bfloat16x8x4_t __b, const int __c) +{ + __builtin_aarch64_simd_xi __o; + bfloat16x8x4_t ret; + __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __b.val[0], 0); + __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __b.val[1], 1); + __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __b.val[2], 2); + __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __b.val[3], 3); + __o = __builtin_aarch64_ld4_lanev8bf ( + (__builtin_aarch64_simd_bf *) __ptr, __o, __c); + ret.val[0] = (bfloat16x8_t) __builtin_aarch64_get_qregxiv4si (__o, 0); + ret.val[1] = (bfloat16x8_t) __builtin_aarch64_get_qregxiv4si (__o, 1); + ret.val[2] = (bfloat16x8_t) __builtin_aarch64_get_qregxiv4si (__o, 2); + ret.val[3] = (bfloat16x8_t) __builtin_aarch64_get_qregxiv4si (__o, 3); + return ret; +} __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) @@ -34888,11 +36262,4 @@ vaddq_p128 (poly128_t __a, poly128_t __b) #undef __aarch64_vdupq_laneq_u32 #undef __aarch64_vdupq_laneq_u64 -#undef __LD2_LANE_FUNC -#undef __LD2Q_LANE_FUNC -#undef __LD3_LANE_FUNC -#undef __LD3Q_LANE_FUNC -#undef __LD4_LANE_FUNC -#undef __LD4Q_LANE_FUNC - #endif diff --git a/gcc/config/arc/arc.c b/gcc/config/arc/arc.c index 69f6ae4..92797db 100644 --- a/gcc/config/arc/arc.c +++ b/gcc/config/arc/arc.c @@ -1440,9 +1440,6 @@ arc_override_options (void) if (flag_pic) target_flags |= MASK_NO_SDATA_SET; - if (flag_no_common == 255) - flag_no_common = !TARGET_NO_SDATA_SET; - /* Check for small data option */ if (!global_options_set.x_g_switch_value && !TARGET_NO_SDATA_SET) g_switch_value = TARGET_LL64 ? 8 : 4; diff --git a/gcc/config/arm/arm_neon.h b/gcc/config/arm/arm_neon.h index 5a91d15..3364b37 100644 --- a/gcc/config/arm/arm_neon.h +++ b/gcc/config/arm/arm_neon.h @@ -6664,63 +6664,63 @@ __extension__ extern __inline int8x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) vdup_n_s8 (int8_t __a) { - return (int8x8_t)__builtin_neon_vdup_nv8qi ((__builtin_neon_qi) __a); + return (int8x8_t) {__a, __a, __a, __a, __a, __a, __a, __a}; } __extension__ extern __inline int16x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) vdup_n_s16 (int16_t __a) { - return (int16x4_t)__builtin_neon_vdup_nv4hi ((__builtin_neon_hi) __a); + return (int16x4_t) {__a, __a, __a, __a}; } __extension__ extern __inline int32x2_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) vdup_n_s32 (int32_t __a) { - return (int32x2_t)__builtin_neon_vdup_nv2si ((__builtin_neon_si) __a); + return (int32x2_t) {__a, __a}; } __extension__ extern __inline float32x2_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) vdup_n_f32 (float32_t __a) { - return (float32x2_t)__builtin_neon_vdup_nv2sf ((__builtin_neon_sf) __a); + return (float32x2_t) {__a, __a}; } __extension__ extern __inline uint8x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) vdup_n_u8 (uint8_t __a) { - return (uint8x8_t)__builtin_neon_vdup_nv8qi ((__builtin_neon_qi) __a); + return (uint8x8_t) {__a, __a, __a, __a, __a, __a, __a, __a}; } __extension__ extern __inline uint16x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) vdup_n_u16 (uint16_t __a) { - return (uint16x4_t)__builtin_neon_vdup_nv4hi ((__builtin_neon_hi) __a); + return (uint16x4_t) {__a, __a, __a, __a}; } __extension__ extern __inline uint32x2_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) vdup_n_u32 (uint32_t __a) { - return (uint32x2_t)__builtin_neon_vdup_nv2si ((__builtin_neon_si) __a); + return (uint32x2_t) {__a, __a}; } __extension__ extern __inline poly8x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) vdup_n_p8 (poly8_t __a) { - return (poly8x8_t)__builtin_neon_vdup_nv8qi ((__builtin_neon_qi) __a); + return (poly8x8_t) {__a, __a, __a, __a, __a, __a, __a, __a}; } __extension__ extern __inline poly16x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) vdup_n_p16 (poly16_t __a) { - return (poly16x4_t)__builtin_neon_vdup_nv4hi ((__builtin_neon_hi) __a); + return (poly16x4_t) {__a, __a, __a, __a}; } #pragma GCC push_options @@ -6729,7 +6729,7 @@ __extension__ extern __inline poly64x1_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) vdup_n_p64 (poly64_t __a) { - return (poly64x1_t)__builtin_neon_vdup_ndi ((__builtin_neon_di) __a); + return (poly64x1_t) {__a}; } #pragma GCC pop_options @@ -6737,14 +6737,14 @@ __extension__ extern __inline int64x1_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) vdup_n_s64 (int64_t __a) { - return (int64x1_t)__builtin_neon_vdup_ndi ((__builtin_neon_di) __a); + return (int64x1_t) {__a}; } __extension__ extern __inline uint64x1_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) vdup_n_u64 (uint64_t __a) { - return (uint64x1_t)__builtin_neon_vdup_ndi ((__builtin_neon_di) __a); + return (uint64x1_t) {__a}; } #pragma GCC push_options @@ -6753,7 +6753,7 @@ __extension__ extern __inline poly64x2_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) vdupq_n_p64 (poly64_t __a) { - return (poly64x2_t)__builtin_neon_vdup_nv2di ((__builtin_neon_di) __a); + return (poly64x2_t) {__a, __a}; } #pragma GCC pop_options @@ -6761,231 +6761,234 @@ __extension__ extern __inline int8x16_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) vdupq_n_s8 (int8_t __a) { - return (int8x16_t)__builtin_neon_vdup_nv16qi ((__builtin_neon_qi) __a); + return (int8x16_t) {__a, __a, __a, __a, __a, __a, __a, __a, + __a, __a, __a, __a, __a, __a, __a, __a}; } __extension__ extern __inline int16x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) vdupq_n_s16 (int16_t __a) { - return (int16x8_t)__builtin_neon_vdup_nv8hi ((__builtin_neon_hi) __a); + return (int16x8_t) {__a, __a, __a, __a, __a, __a, __a, __a}; } __extension__ extern __inline int32x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) vdupq_n_s32 (int32_t __a) { - return (int32x4_t)__builtin_neon_vdup_nv4si ((__builtin_neon_si) __a); + return (int32x4_t) {__a, __a, __a, __a}; } __extension__ extern __inline float32x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) vdupq_n_f32 (float32_t __a) { - return (float32x4_t)__builtin_neon_vdup_nv4sf ((__builtin_neon_sf) __a); + return (float32x4_t) {__a, __a, __a, __a}; } __extension__ extern __inline uint8x16_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) vdupq_n_u8 (uint8_t __a) { - return (uint8x16_t)__builtin_neon_vdup_nv16qi ((__builtin_neon_qi) __a); + return (uint8x16_t) {__a, __a, __a, __a, __a, __a, __a, __a, + __a, __a, __a, __a, __a, __a, __a, __a}; } __extension__ extern __inline uint16x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) vdupq_n_u16 (uint16_t __a) { - return (uint16x8_t)__builtin_neon_vdup_nv8hi ((__builtin_neon_hi) __a); + return (uint16x8_t) {__a, __a, __a, __a, __a, __a, __a, __a}; } __extension__ extern __inline uint32x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) vdupq_n_u32 (uint32_t __a) { - return (uint32x4_t)__builtin_neon_vdup_nv4si ((__builtin_neon_si) __a); + return (uint32x4_t) {__a, __a, __a, __a}; } __extension__ extern __inline poly8x16_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) vdupq_n_p8 (poly8_t __a) { - return (poly8x16_t)__builtin_neon_vdup_nv16qi ((__builtin_neon_qi) __a); + return (poly8x16_t) {__a, __a, __a, __a, __a, __a, __a, __a, + __a, __a, __a, __a, __a, __a, __a, __a}; } __extension__ extern __inline poly16x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) vdupq_n_p16 (poly16_t __a) { - return (poly16x8_t)__builtin_neon_vdup_nv8hi ((__builtin_neon_hi) __a); + return (poly16x8_t) {__a, __a, __a, __a, __a, __a, __a, __a}; } __extension__ extern __inline int64x2_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) vdupq_n_s64 (int64_t __a) { - return (int64x2_t)__builtin_neon_vdup_nv2di ((__builtin_neon_di) __a); + return (int64x2_t) {__a, __a}; } __extension__ extern __inline uint64x2_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) vdupq_n_u64 (uint64_t __a) { - return (uint64x2_t)__builtin_neon_vdup_nv2di ((__builtin_neon_di) __a); + return (uint64x2_t) {__a, __a}; } __extension__ extern __inline int8x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) vmov_n_s8 (int8_t __a) { - return (int8x8_t)__builtin_neon_vdup_nv8qi ((__builtin_neon_qi) __a); + return vdup_n_s8 (__a); } __extension__ extern __inline int16x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) vmov_n_s16 (int16_t __a) { - return (int16x4_t)__builtin_neon_vdup_nv4hi ((__builtin_neon_hi) __a); + return vdup_n_s16 (__a); } __extension__ extern __inline int32x2_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) vmov_n_s32 (int32_t __a) { - return (int32x2_t)__builtin_neon_vdup_nv2si ((__builtin_neon_si) __a); + return vdup_n_s32 (__a); } __extension__ extern __inline float32x2_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) vmov_n_f32 (float32_t __a) { - return (float32x2_t)__builtin_neon_vdup_nv2sf ((__builtin_neon_sf) __a); + return vdup_n_f32 (__a); } __extension__ extern __inline uint8x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) vmov_n_u8 (uint8_t __a) { - return (uint8x8_t)__builtin_neon_vdup_nv8qi ((__builtin_neon_qi) __a); + return vdup_n_u8 (__a); } __extension__ extern __inline uint16x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) vmov_n_u16 (uint16_t __a) { - return (uint16x4_t)__builtin_neon_vdup_nv4hi ((__builtin_neon_hi) __a); + return vdup_n_u16 (__a); } __extension__ extern __inline uint32x2_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) vmov_n_u32 (uint32_t __a) { - return (uint32x2_t)__builtin_neon_vdup_nv2si ((__builtin_neon_si) __a); + return vdup_n_u32 (__a); } __extension__ extern __inline poly8x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) vmov_n_p8 (poly8_t __a) { - return (poly8x8_t)__builtin_neon_vdup_nv8qi ((__builtin_neon_qi) __a); + return vdup_n_p8 (__a); } __extension__ extern __inline poly16x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) vmov_n_p16 (poly16_t __a) { - return (poly16x4_t)__builtin_neon_vdup_nv4hi ((__builtin_neon_hi) __a); + return vdup_n_p16 (__a); } __extension__ extern __inline int64x1_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) vmov_n_s64 (int64_t __a) { - return (int64x1_t)__builtin_neon_vdup_ndi ((__builtin_neon_di) __a); + return vdup_n_s64 (__a); } __extension__ extern __inline uint64x1_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) vmov_n_u64 (uint64_t __a) { - return (uint64x1_t)__builtin_neon_vdup_ndi ((__builtin_neon_di) __a); + return vdup_n_u64 (__a); } __extension__ extern __inline int8x16_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) vmovq_n_s8 (int8_t __a) { - return (int8x16_t)__builtin_neon_vdup_nv16qi ((__builtin_neon_qi) __a); + return vdupq_n_s8 (__a); } __extension__ extern __inline int16x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) vmovq_n_s16 (int16_t __a) { - return (int16x8_t)__builtin_neon_vdup_nv8hi ((__builtin_neon_hi) __a); + return vdupq_n_s16 (__a); } __extension__ extern __inline int32x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) vmovq_n_s32 (int32_t __a) { - return (int32x4_t)__builtin_neon_vdup_nv4si ((__builtin_neon_si) __a); + return vdupq_n_s32 (__a); } __extension__ extern __inline float32x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) vmovq_n_f32 (float32_t __a) { - return (float32x4_t)__builtin_neon_vdup_nv4sf ((__builtin_neon_sf) __a); + return vdupq_n_f32 (__a); } __extension__ extern __inline uint8x16_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) vmovq_n_u8 (uint8_t __a) { - return (uint8x16_t)__builtin_neon_vdup_nv16qi ((__builtin_neon_qi) __a); + return vdupq_n_u8 (__a); } __extension__ extern __inline uint16x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) vmovq_n_u16 (uint16_t __a) { - return (uint16x8_t)__builtin_neon_vdup_nv8hi ((__builtin_neon_hi) __a); + return vdupq_n_u16 (__a); } __extension__ extern __inline uint32x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) vmovq_n_u32 (uint32_t __a) { - return (uint32x4_t)__builtin_neon_vdup_nv4si ((__builtin_neon_si) __a); + return vdupq_n_u32 (__a); } __extension__ extern __inline poly8x16_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) vmovq_n_p8 (poly8_t __a) { - return (poly8x16_t)__builtin_neon_vdup_nv16qi ((__builtin_neon_qi) __a); + return vdupq_n_p8 (__a); } __extension__ extern __inline poly16x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) vmovq_n_p16 (poly16_t __a) { - return (poly16x8_t)__builtin_neon_vdup_nv8hi ((__builtin_neon_hi) __a); + return vdupq_n_p16 (__a); } __extension__ extern __inline int64x2_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) vmovq_n_s64 (int64_t __a) { - return (int64x2_t)__builtin_neon_vdup_nv2di ((__builtin_neon_di) __a); + return vdupq_n_s64 (__a); } __extension__ extern __inline uint64x2_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) vmovq_n_u64 (uint64_t __a) { - return (uint64x2_t)__builtin_neon_vdup_nv2di ((__builtin_neon_di) __a); + return vdupq_n_u64 (__a); } __extension__ extern __inline int8x8_t @@ -18005,14 +18008,14 @@ __extension__ extern __inline float16x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) vdup_n_f16 (float16_t __a) { - return __builtin_neon_vdup_nv4hf (__a); + return (float16x4_t) {__a, __a, __a, __a}; } __extension__ extern __inline float16x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) vdupq_n_f16 (float16_t __a) { - return __builtin_neon_vdup_nv8hf (__a); + return (float16x8_t) {__a, __a, __a, __a, __a, __a, __a, __a}; } __extension__ extern __inline float16x4_t @@ -18047,14 +18050,14 @@ __extension__ extern __inline float16x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) vmov_n_f16 (float16_t __a) { - return __builtin_neon_vdup_nv4hf (__a); + return vdup_n_f16 (__a); } __extension__ extern __inline float16x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) vmovq_n_f16 (float16_t __a) { - return __builtin_neon_vdup_nv8hf (__a); + return vdupq_n_f16 (__a); } __extension__ extern __inline float16x4_t @@ -18978,14 +18981,14 @@ __extension__ extern __inline bfloat16x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) vdup_n_bf16 (bfloat16_t __a) { - return __builtin_neon_vdup_nv4bf (__a); + return (bfloat16x4_t) {__a, __a, __a, __a}; } __extension__ extern __inline bfloat16x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) vdupq_n_bf16 (bfloat16_t __a) { - return __builtin_neon_vdup_nv8bf (__a); + return (bfloat16x8_t) {__a, __a, __a, __a, __a, __a, __a, __a}; } __extension__ extern __inline bfloat16x4_t diff --git a/gcc/config/arm/arm_neon_builtins.def b/gcc/config/arm/arm_neon_builtins.def index fb6d66e..fafb5c6 100644 --- a/gcc/config/arm/arm_neon_builtins.def +++ b/gcc/config/arm/arm_neon_builtins.def @@ -211,9 +211,6 @@ VAR10 (GETLANE, vget_lane, VAR6 (GETLANE, vget_laneu, v8qi, v4hi, v2si, v16qi, v8hi, v4si) VAR10 (SETLANE, vset_lane, v8qi, v4hi, v2si, v2sf, di, v16qi, v8hi, v4si, v4sf, v2di) -VAR10 (UNOP, vdup_n, - v8qi, v4hi, v2si, v2sf, di, v16qi, v8hi, v4si, v4sf, v2di) -VAR4 (UNOP, vdup_n, v8hf, v4hf, v8bf, v4bf) VAR10 (GETLANE, vdup_lane, v8qi, v4hi, v2si, v2sf, di, v16qi, v8hi, v4si, v4sf, v2di) VAR4 (GETLANE, vdup_lane, v8hf, v4hf, v8bf, v4bf) diff --git a/gcc/config/darwin.c b/gcc/config/darwin.c index b160c23..5d1d13c 100644 --- a/gcc/config/darwin.c +++ b/gcc/config/darwin.c @@ -3129,6 +3129,14 @@ darwin_file_end (void) re-arranging data. */ if (!DARWIN_SECTION_ANCHORS || !flag_section_anchors) fprintf (asm_out_file, "\t.subsections_via_symbols\n"); + + /* We rely on this being NULL at the start of compilation; reset it here + so that JIT can reuse a context. */ + if (dwarf_sect_names_table != NULL) + { + dwarf_sect_names_table->truncate (0); + dwarf_sect_names_table = NULL; + } } /* TODO: Add a language hook for identifying if a decl is a vtable. */ diff --git a/gcc/config/h8300/h8300.c b/gcc/config/h8300/h8300.c index d2f6548..0c4e508 100644 --- a/gcc/config/h8300/h8300.c +++ b/gcc/config/h8300/h8300.c @@ -228,18 +228,18 @@ static enum shift_alg shift_alg_si[2][3][32] = { /* 8 9 10 11 12 13 14 15 */ /* 16 17 18 19 20 21 22 23 */ /* 24 25 26 27 28 29 30 31 */ - { INL, INL, INL, INL, INL, LOP, LOP, LOP, + { INL, INL, INL, INL, INL, INL, INL, LOP, SPC, LOP, LOP, LOP, LOP, LOP, LOP, SPC, - SPC, SPC, SPC, SPC, LOP, LOP, LOP, LOP, - SPC, LOP, LOP, LOP, SPC, SPC, SPC, SPC }, /* SHIFT_ASHIFT */ - { INL, INL, INL, INL, INL, LOP, LOP, LOP, + SPC, SPC, SPC, SPC, SPC, SPC, SPC, SPC, + SPC, SPC, SPC, SPC, SPC, SPC, SPC, SPC }, /* SHIFT_ASHIFT */ + { INL, INL, INL, INL, INL, INL, INL, LOP, SPC, LOP, LOP, LOP, LOP, LOP, LOP, SPC, - SPC, SPC, SPC, SPC, LOP, LOP, LOP, LOP, - SPC, LOP, LOP, LOP, SPC, SPC, SPC, SPC }, /* SHIFT_LSHIFTRT */ - { INL, INL, INL, INL, INL, LOP, LOP, LOP, + SPC, SPC, SPC, SPC, SPC, SPC, SPC, SPC, + SPC, SPC, SPC, SPC, SPC, SPC, SPC, SPC }, /* SHIFT_LSHIFTRT */ + { INL, INL, INL, INL, INL, INL, INL, LOP, SPC, LOP, LOP, LOP, LOP, LOP, LOP, LOP, - SPC, SPC, SPC, SPC, LOP, LOP, LOP, LOP, - SPC, LOP, LOP, LOP, LOP, LOP, LOP, SPC }, /* SHIFT_ASHIFTRT */ + SPC, SPC, SPC, SPC, SPC, SPC, SPC, SPC, + SPC, SPC, SPC, SPC, LOP, LOP, LOP, SPC }, /* SHIFT_ASHIFTRT */ }, { /* TARGET_H8300S */ @@ -248,17 +248,17 @@ static enum shift_alg shift_alg_si[2][3][32] = { /* 16 17 18 19 20 21 22 23 */ /* 24 25 26 27 28 29 30 31 */ { INL, INL, INL, INL, INL, INL, INL, INL, - INL, INL, INL, LOP, LOP, LOP, LOP, SPC, - SPC, SPC, SPC, SPC, SPC, SPC, LOP, LOP, - SPC, SPC, LOP, LOP, SPC, SPC, SPC, SPC }, /* SHIFT_ASHIFT */ + INL, INL, INL, INL, INL, INL, INL, SPC, + SPC, SPC, SPC, SPC, SPC, SPC, SPC, SPC, + SPC, SPC, SPC, SPC, SPC, SPC, SPC, SPC }, /* SHIFT_ASHIFT */ { INL, INL, INL, INL, INL, INL, INL, INL, - INL, INL, INL, LOP, LOP, LOP, LOP, SPC, - SPC, SPC, SPC, SPC, SPC, SPC, LOP, LOP, - SPC, SPC, LOP, LOP, SPC, SPC, SPC, SPC }, /* SHIFT_LSHIFTRT */ + INL, INL, INL, INL, INL, INL, INL, SPC, + SPC, SPC, SPC, SPC, SPC, SPC, SPC, SPC, + SPC, SPC, SPC, SPC, SPC, SPC, SPC, SPC }, /* SHIFT_LSHIFTRT */ { INL, INL, INL, INL, INL, INL, INL, INL, - INL, INL, INL, LOP, LOP, LOP, LOP, LOP, - SPC, SPC, SPC, SPC, SPC, SPC, LOP, LOP, - SPC, SPC, LOP, LOP, LOP, LOP, LOP, SPC }, /* SHIFT_ASHIFTRT */ + INL, INL, INL, INL, INL, INL, INL, LOP, + SPC, SPC, SPC, SPC, SPC, SPC, SPC, SPC, + SPC, SPC, SPC, SPC, SPC, SPC, SPC, SPC }, /* SHIFT_ASHIFTRT */ } }; @@ -343,8 +343,68 @@ h8300_option_override (void) shift_alg_hi[H8_300H][SHIFT_ASHIFTRT][13] = SHIFT_LOOP; shift_alg_hi[H8_300H][SHIFT_ASHIFTRT][14] = SHIFT_LOOP; + shift_alg_si[H8_300H][SHIFT_ASHIFT][5] = SHIFT_LOOP; + shift_alg_si[H8_300H][SHIFT_ASHIFT][6] = SHIFT_LOOP; + shift_alg_si[H8_300H][SHIFT_ASHIFT][20] = SHIFT_LOOP; + shift_alg_si[H8_300H][SHIFT_ASHIFT][21] = SHIFT_LOOP; + shift_alg_si[H8_300H][SHIFT_ASHIFT][22] = SHIFT_LOOP; + shift_alg_si[H8_300H][SHIFT_ASHIFT][23] = SHIFT_LOOP; + shift_alg_si[H8_300H][SHIFT_ASHIFT][25] = SHIFT_LOOP; + shift_alg_si[H8_300H][SHIFT_ASHIFT][26] = SHIFT_LOOP; + shift_alg_si[H8_300H][SHIFT_ASHIFT][27] = SHIFT_LOOP; + + shift_alg_si[H8_300H][SHIFT_LSHIFTRT][5] = SHIFT_LOOP; + shift_alg_si[H8_300H][SHIFT_LSHIFTRT][6] = SHIFT_LOOP; + shift_alg_si[H8_300H][SHIFT_LSHIFTRT][20] = SHIFT_LOOP; + shift_alg_si[H8_300H][SHIFT_LSHIFTRT][21] = SHIFT_LOOP; + shift_alg_si[H8_300H][SHIFT_LSHIFTRT][22] = SHIFT_LOOP; + shift_alg_si[H8_300H][SHIFT_LSHIFTRT][23] = SHIFT_LOOP; + shift_alg_si[H8_300H][SHIFT_LSHIFTRT][25] = SHIFT_LOOP; + shift_alg_si[H8_300H][SHIFT_LSHIFTRT][26] = SHIFT_LOOP; + shift_alg_si[H8_300H][SHIFT_LSHIFTRT][27] = SHIFT_LOOP; + + shift_alg_si[H8_300H][SHIFT_ASHIFTRT][5] = SHIFT_LOOP; + shift_alg_si[H8_300H][SHIFT_ASHIFTRT][6] = SHIFT_LOOP; + shift_alg_si[H8_300H][SHIFT_ASHIFTRT][20] = SHIFT_LOOP; + shift_alg_si[H8_300H][SHIFT_ASHIFTRT][21] = SHIFT_LOOP; + shift_alg_si[H8_300H][SHIFT_ASHIFTRT][22] = SHIFT_LOOP; + shift_alg_si[H8_300H][SHIFT_ASHIFTRT][23] = SHIFT_LOOP; + shift_alg_si[H8_300H][SHIFT_ASHIFTRT][25] = SHIFT_LOOP; + shift_alg_si[H8_300H][SHIFT_ASHIFTRT][26] = SHIFT_LOOP; + shift_alg_si[H8_300H][SHIFT_ASHIFTRT][27] = SHIFT_LOOP; + /* H8S */ shift_alg_hi[H8_S][SHIFT_ASHIFTRT][14] = SHIFT_LOOP; + + shift_alg_si[H8_S][SHIFT_ASHIFT][11] = SHIFT_LOOP; + shift_alg_si[H8_S][SHIFT_ASHIFT][12] = SHIFT_LOOP; + shift_alg_si[H8_S][SHIFT_ASHIFT][13] = SHIFT_LOOP; + shift_alg_si[H8_S][SHIFT_ASHIFT][14] = SHIFT_LOOP; + shift_alg_si[H8_S][SHIFT_ASHIFT][22] = SHIFT_LOOP; + shift_alg_si[H8_S][SHIFT_ASHIFT][23] = SHIFT_LOOP; + shift_alg_si[H8_S][SHIFT_ASHIFT][26] = SHIFT_LOOP; + shift_alg_si[H8_S][SHIFT_ASHIFT][27] = SHIFT_LOOP; + + shift_alg_si[H8_S][SHIFT_LSHIFTRT][11] = SHIFT_LOOP; + shift_alg_si[H8_S][SHIFT_LSHIFTRT][12] = SHIFT_LOOP; + shift_alg_si[H8_S][SHIFT_LSHIFTRT][13] = SHIFT_LOOP; + shift_alg_si[H8_S][SHIFT_LSHIFTRT][14] = SHIFT_LOOP; + shift_alg_si[H8_S][SHIFT_LSHIFTRT][22] = SHIFT_LOOP; + shift_alg_si[H8_S][SHIFT_LSHIFTRT][23] = SHIFT_LOOP; + shift_alg_si[H8_S][SHIFT_LSHIFTRT][26] = SHIFT_LOOP; + shift_alg_si[H8_S][SHIFT_LSHIFTRT][27] = SHIFT_LOOP; + + shift_alg_si[H8_S][SHIFT_ASHIFTRT][11] = SHIFT_LOOP; + shift_alg_si[H8_S][SHIFT_ASHIFTRT][12] = SHIFT_LOOP; + shift_alg_si[H8_S][SHIFT_ASHIFTRT][13] = SHIFT_LOOP; + shift_alg_si[H8_S][SHIFT_ASHIFTRT][14] = SHIFT_LOOP; + shift_alg_si[H8_S][SHIFT_ASHIFTRT][22] = SHIFT_LOOP; + shift_alg_si[H8_S][SHIFT_ASHIFTRT][23] = SHIFT_LOOP; + shift_alg_si[H8_S][SHIFT_ASHIFTRT][26] = SHIFT_LOOP; + shift_alg_si[H8_S][SHIFT_ASHIFTRT][27] = SHIFT_LOOP; + shift_alg_si[H8_S][SHIFT_ASHIFTRT][28] = SHIFT_LOOP; + shift_alg_si[H8_S][SHIFT_ASHIFTRT][29] = SHIFT_LOOP; + shift_alg_si[H8_S][SHIFT_ASHIFTRT][30] = SHIFT_LOOP; } /* Work out a value for MOVE_RATIO. */ @@ -3784,8 +3844,7 @@ get_shift_alg (enum shift_type shift_type, enum shift_mode shift_mode, gcc_unreachable (); } } - else if ((TARGET_H8300H && count >= 16 && count <= 19) - || (TARGET_H8300S && count >= 16 && count <= 21)) + else if (count >= 16 && count <= 23) { info->remainder = count - 16; @@ -3804,8 +3863,7 @@ get_shift_alg (enum shift_type shift_type, enum shift_mode shift_mode, goto end; } } - else if ((TARGET_H8300H && count == 24) - || (TARGET_H8300S && count >= 24 && count <= 25)) + else if (count >= 24 && count <= 27) { info->remainder = count - 24; @@ -3844,7 +3902,10 @@ get_shift_alg (enum shift_type shift_type, enum shift_mode shift_mode, info->special = "sub.w\t%f0,%f0\n\trotl.l\t#2,%S0\n\trotl.l\t#2,%S0\n\textu.l\t%S0"; goto end; case SHIFT_ASHIFTRT: - gcc_unreachable (); + info->remainder = count - 24; + info->special = "mov.w\t%e0,%f0\n\tmov.b\t%t0,%s0\n\texts.w\t%f0\n\texts.l\t%S0"; + info->cc_special = OLD_CC_SET_ZNV; + goto end; } } else if (count == 29) @@ -3870,7 +3931,10 @@ get_shift_alg (enum shift_type shift_type, enum shift_mode shift_mode, } goto end; case SHIFT_ASHIFTRT: - gcc_unreachable (); + info->remainder = count - 24; + info->special = "mov.w\t%e0,%f0\n\tmov.b\t%t0,%s0\n\texts.w\t%f0\n\texts.l\t%S0"; + info->cc_special = OLD_CC_SET_ZNV; + goto end; } } else if (count == 30) @@ -3890,7 +3954,10 @@ get_shift_alg (enum shift_type shift_type, enum shift_mode shift_mode, info->special = "sub.w\t%f0,%f0\n\trotl.l\t#2,%S0\n\textu.l\t%S0"; goto end; case SHIFT_ASHIFTRT: - gcc_unreachable (); + info->remainder = count - 24; + info->special = "mov.w\t%e0,%f0\n\tmov.b\t%t0,%s0\n\texts.w\t%f0\n\texts.l\t%S0"; + info->cc_special = OLD_CC_SET_ZNV; + goto end; } } else if (count == 31) diff --git a/gcc/config/i386/darwin.h b/gcc/config/i386/darwin.h index bac3219..73b06e2 100644 --- a/gcc/config/i386/darwin.h +++ b/gcc/config/i386/darwin.h @@ -125,10 +125,18 @@ along with GCC; see the file COPYING3. If not see %{mfentry*:%eDarwin does not support -mfentry or associated options}" \ DARWIN_CC1_SPEC +/* This is a workaround for a tool bug: see PR100340. */ + +#ifdef HAVE_AS_MLLVM_X86_PAD_FOR_ALIGN +#define EXTRA_ASM_OPTS " -mllvm -x86-pad-for-align=false" +#else +#define EXTRA_ASM_OPTS "" +#endif + #undef ASM_SPEC #define ASM_SPEC "-arch %(darwin_arch) \ " ASM_OPTIONS " -force_cpusubtype_ALL \ - %{static}" ASM_MMACOSX_VERSION_MIN_SPEC + %{static}" ASM_MMACOSX_VERSION_MIN_SPEC EXTRA_ASM_OPTS #undef ENDFILE_SPEC #define ENDFILE_SPEC \ diff --git a/gcc/config/i386/i386-expand.c b/gcc/config/i386/i386-expand.c index bd21efa..9bf13db 100644 --- a/gcc/config/i386/i386-expand.c +++ b/gcc/config/i386/i386-expand.c @@ -4778,6 +4778,18 @@ ix86_expand_vec_perm_vpermt2 (rtx target, rtx mask, rtx op0, rtx op1, switch (mode) { + case E_V16QImode: + if (TARGET_AVX512VL && TARGET_AVX512VBMI) + gen = gen_avx512vl_vpermt2varv16qi3; + break; + case E_V32QImode: + if (TARGET_AVX512VL && TARGET_AVX512VBMI) + gen = gen_avx512vl_vpermt2varv32qi3; + break; + case E_V64QImode: + if (TARGET_AVX512VBMI) + gen = gen_avx512bw_vpermt2varv64qi3; + break; case E_V8HImode: if (TARGET_AVX512VL && TARGET_AVX512BW) gen = gen_avx512vl_vpermt2varv8hi3; @@ -4786,10 +4798,6 @@ ix86_expand_vec_perm_vpermt2 (rtx target, rtx mask, rtx op0, rtx op1, if (TARGET_AVX512VL && TARGET_AVX512BW) gen = gen_avx512vl_vpermt2varv16hi3; break; - case E_V64QImode: - if (TARGET_AVX512VBMI) - gen = gen_avx512bw_vpermt2varv64qi3; - break; case E_V32HImode: if (TARGET_AVX512BW) gen = gen_avx512bw_vpermt2varv32hi3; @@ -5487,6 +5495,45 @@ ix86_expand_sse_unpack (rtx dest, rtx src, bool unsigned_p, bool high_p) } } +/* Return true if mem is pool constant which contains a const_vector + perm index, assign the index to PERM. */ +bool +ix86_extract_perm_from_pool_constant (int* perm, rtx mem) +{ + machine_mode mode = GET_MODE (mem); + int nelt = GET_MODE_NUNITS (mode); + + if (!INTEGRAL_MODE_P (mode)) + return false; + + /* Needs to be constant pool. */ + if (!(MEM_P (mem)) + || !SYMBOL_REF_P (XEXP (mem, 0)) + || !CONSTANT_POOL_ADDRESS_P (XEXP (mem, 0))) + return false; + + rtx constant = get_pool_constant (XEXP (mem, 0)); + + if (GET_CODE (constant) != CONST_VECTOR) + return false; + + /* There could be some rtx like + (mem/u/c:V16QI (symbol_ref/u:DI ("*.LC1"))) + but with "*.LC1" refer to V2DI constant vector. */ + if (GET_MODE (constant) != mode) + { + constant = simplify_subreg (mode, constant, GET_MODE (constant), 0); + + if (constant == nullptr || GET_CODE (constant) != CONST_VECTOR) + return false; + } + + for (int i = 0; i != nelt; i++) + perm[i] = UINTVAL (XVECEXP (constant, 0, i)); + + return true; +} + /* Split operands 0 and 1 into half-mode parts. Similar to split_double_mode, but works for floating pointer parameters and nonoffsetable memories. For pushes, it returns just stack offsets; the values will be saved @@ -18086,6 +18133,7 @@ ix86_expand_vec_one_operand_perm_avx512 (struct expand_vec_perm_d *d) { machine_mode mode = GET_MODE (d->op0); machine_mode maskmode = mode; + unsigned inner_size = GET_MODE_SIZE (GET_MODE_INNER (mode)); rtx (*gen) (rtx, rtx, rtx) = NULL; rtx target, op0, mask; rtx vec[64]; @@ -18096,6 +18144,18 @@ ix86_expand_vec_one_operand_perm_avx512 (struct expand_vec_perm_d *d) if (!TARGET_AVX512F) return false; + /* Accept VNxHImode and VNxQImode now. */ + if (!TARGET_AVX512VL && GET_MODE_SIZE (mode) < 64) + return false; + + /* vpermw. */ + if (!TARGET_AVX512BW && inner_size == 2) + return false; + + /* vpermb. */ + if (!TARGET_AVX512VBMI && inner_size == 1) + return false; + switch (mode) { case E_V16SImode: @@ -18112,10 +18172,32 @@ ix86_expand_vec_one_operand_perm_avx512 (struct expand_vec_perm_d *d) gen = gen_avx512f_permvarv8df; maskmode = V8DImode; break; + case E_V32HImode: + gen = gen_avx512bw_permvarv32hi; + break; + case E_V16HImode: + gen = gen_avx512vl_permvarv16hi; + break; + case E_V8HImode: + gen = gen_avx512vl_permvarv8hi; + break; + case E_V64QImode: + gen = gen_avx512bw_permvarv64qi; + break; + case E_V32QImode: + gen = gen_avx512vl_permvarv32qi; + break; + case E_V16QImode: + gen = gen_avx512vl_permvarv16qi; + break; + default: return false; } + if (d->testing_p) + return true; + target = d->target; op0 = d->op0; for (int i = 0; i < d->nelt; ++i) @@ -18298,7 +18380,7 @@ expand_vec_perm_1 (struct expand_vec_perm_d *d) if (expand_vec_perm_palignr (d, true)) return true; - /* Try the AVX512F vperm{s,d} instructions. */ + /* Try the AVX512F vperm{w,b,s,d} instructions */ if (ix86_expand_vec_one_operand_perm_avx512 (d)) return true; @@ -20337,6 +20419,11 @@ expand_vec_perm_even_odd (struct expand_vec_perm_d *d) if (d->perm[i] != 2 * i + odd) return false; + if (d->vmode == E_V32HImode + && d->testing_p + && !TARGET_AVX512BW) + return false; + return expand_vec_perm_even_odd_1 (d, odd); } @@ -20466,7 +20553,6 @@ expand_vec_perm_broadcast_1 (struct expand_vec_perm_d *d) emit_move_insn (d->target, gen_lowpart (d->vmode, dest)); return true; - case E_V64QImode: case E_V32QImode: case E_V16HImode: case E_V8SImode: @@ -20476,6 +20562,14 @@ expand_vec_perm_broadcast_1 (struct expand_vec_perm_d *d) gcc_assert (!TARGET_AVX2 || d->perm[0]); return false; + case E_V64QImode: + gcc_assert (!TARGET_AVX512BW || d->perm[0]); + return false; + + case E_V32HImode: + gcc_assert (!TARGET_AVX512BW); + return false; + default: gcc_unreachable (); } @@ -20877,16 +20971,16 @@ ix86_vectorize_vec_perm_const (machine_mode vmode, rtx target, rtx op0, return true; break; case E_V32HImode: - if (!TARGET_AVX512BW) + if (!TARGET_AVX512F) return false; - if (d.testing_p) + if (d.testing_p && TARGET_AVX512BW) /* All implementable with a single vperm[it]2 insn. */ return true; break; case E_V64QImode: - if (!TARGET_AVX512BW) + if (!TARGET_AVX512F) return false; - if (d.testing_p) + if (d.testing_p && TARGET_AVX512BW) /* Implementable with 2 vperm[it]2, 2 vpshufb and 1 or insn. */ return true; break; diff --git a/gcc/config/i386/i386-protos.h b/gcc/config/i386/i386-protos.h index 07ac02a..2fd1307 100644 --- a/gcc/config/i386/i386-protos.h +++ b/gcc/config/i386/i386-protos.h @@ -260,6 +260,7 @@ extern void ix86_expand_sse2_mulvxdi3 (rtx, rtx, rtx); extern void ix86_expand_sse2_abs (rtx, rtx); extern bool ix86_expand_vector_init_duplicate (bool, machine_mode, rtx, rtx); +extern bool ix86_extract_perm_from_pool_constant (int*, rtx); /* In i386-c.c */ extern void ix86_target_macros (void); diff --git a/gcc/config/i386/i386.h b/gcc/config/i386/i386.h index 21fe51b..b3e57a8 100644 --- a/gcc/config/i386/i386.h +++ b/gcc/config/i386/i386.h @@ -418,6 +418,8 @@ extern unsigned char ix86_tune_features[X86_TUNE_LAST]; ix86_tune_features[X86_TUNE_EMIT_VZEROUPPER] #define TARGET_EXPAND_ABS \ ix86_tune_features[X86_TUNE_EXPAND_ABS] +#define TARGET_V2DF_REDUCTION_PREFER_HADDPD \ + ix86_tune_features[X86_TUNE_V2DF_REDUCTION_PREFER_HADDPD] /* Feature tests against the various architecture variations. */ enum ix86_arch_indices { diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md index bc1c30b..41d8562 100644 --- a/gcc/config/i386/i386.md +++ b/gcc/config/i386/i386.md @@ -125,6 +125,9 @@ UNSPEC_RSQRT UNSPEC_PSADBW + ;; For AVX512F support + UNSPEC_SCALEF + ;; Generic math support UNSPEC_COPYSIGN UNSPEC_XORSIGN @@ -17894,6 +17897,17 @@ DONE; }) +(define_insn "avx512f_scalef<mode>2" + [(set (match_operand:MODEF 0 "register_operand" "=v") + (unspec:MODEF + [(match_operand:MODEF 1 "register_operand" "v") + (match_operand:MODEF 2 "nonimmediate_operand" "vm")] + UNSPEC_SCALEF))] + "TARGET_AVX512F" + "vscalef<ssemodesuffix>\t{%2, %1, %0|%0, %1, %2}" + [(set_attr "prefix" "evex") + (set_attr "mode" "<MODE>")]) + (define_expand "ldexpxf3" [(match_operand:XF 0 "register_operand") (match_operand:XF 1 "register_operand") @@ -17914,17 +17928,30 @@ [(use (match_operand:MODEF 0 "register_operand")) (use (match_operand:MODEF 1 "general_operand")) (use (match_operand:SI 2 "register_operand"))] - "TARGET_USE_FANCY_MATH_387 - && (!(SSE_FLOAT_MODE_P (<MODE>mode) && TARGET_SSE_MATH) - || TARGET_MIX_SSE_I387) + "((TARGET_USE_FANCY_MATH_387 + && (!(SSE_FLOAT_MODE_P (<MODE>mode) && TARGET_SSE_MATH) + || TARGET_MIX_SSE_I387)) + || (TARGET_AVX512F && TARGET_SSE_MATH)) && flag_unsafe_math_optimizations" { - rtx op0 = gen_reg_rtx (XFmode); - rtx op1 = gen_reg_rtx (XFmode); + /* Prefer avx512f version. */ + if (TARGET_AVX512F && TARGET_SSE_MATH) + { + rtx op2 = gen_reg_rtx (<MODE>mode); + operands[1] = force_reg (<MODE>mode, operands[1]); - emit_insn (gen_extend<mode>xf2 (op1, operands[1])); - emit_insn (gen_ldexpxf3 (op0, op1, operands[2])); - emit_insn (gen_truncxf<mode>2 (operands[0], op0)); + emit_insn (gen_floatsi<mode>2 (op2, operands[2])); + emit_insn (gen_avx512f_scalef<mode>2 (operands[0], operands[1], op2)); + } + else + { + rtx op0 = gen_reg_rtx (XFmode); + rtx op1 = gen_reg_rtx (XFmode); + + emit_insn (gen_extend<mode>xf2 (op1, operands[1])); + emit_insn (gen_ldexpxf3 (op0, op1, operands[2])); + emit_insn (gen_truncxf<mode>2 (operands[0], op0)); + } DONE; }) diff --git a/gcc/config/i386/mingw-w64.h b/gcc/config/i386/mingw-w64.h index 0cec6b0..6cc7ac5 100644 --- a/gcc/config/i386/mingw-w64.h +++ b/gcc/config/i386/mingw-w64.h @@ -89,6 +89,14 @@ along with GCC; see the file COPYING3. If not see # define LINK_SPEC_LARGE_ADDR_AWARE "" #endif +#undef LINK_SPEC_DISABLE_DYNAMICBASE +#if HAVE_LD_PE_DISABLE_DYNAMICBASE +# define LINK_SPEC_DISABLE_DYNAMICBASE \ + "%{!shared:%{!mdll:%{no-pie:--disable-dynamicbase}}}" +#else +# define LINK_SPEC_DISABLE_DYNAMICBASE "" +#endif + #undef LINK_SPEC #define LINK_SPEC SUB_LINK_SPEC " %{mwindows:--subsystem windows} \ %{mconsole:--subsystem console} \ @@ -97,6 +105,7 @@ along with GCC; see the file COPYING3. If not see %{static:-Bstatic} %{!static:-Bdynamic} \ %{shared|mdll: " SUB_LINK_ENTRY " --enable-auto-image-base} \ " LINK_SPEC_LARGE_ADDR_AWARE "\ + " LINK_SPEC_DISABLE_DYNAMICBASE "\ %(shared_libgcc_undefs)" /* Enable sincos optimization, overriding cygming.h. sincos, sincosf diff --git a/gcc/config/i386/mingw32.h b/gcc/config/i386/mingw32.h index 36e7bae..779c933 100644 --- a/gcc/config/i386/mingw32.h +++ b/gcc/config/i386/mingw32.h @@ -148,6 +148,13 @@ along with GCC; see the file COPYING3. If not see "%{!shared:%{!mdll:%{!m64:--large-address-aware}}}" #endif +#if HAVE_LD_PE_DISABLE_DYNAMICBASE +# define LINK_SPEC_DISABLE_DYNAMICBASE \ + "%{!shared:%{!mdll:%{no-pie:--disable-dynamicbase}}}" +#else +# define LINK_SPEC_DISABLE_DYNAMICBASE "" +#endif + #define LINK_SPEC "%{mwindows:--subsystem windows} \ %{mconsole:--subsystem console} \ %{shared: %{mdll: %eshared and mdll are not compatible}} \ @@ -155,6 +162,7 @@ along with GCC; see the file COPYING3. If not see %{static:-Bstatic} %{!static:-Bdynamic} \ %{shared|mdll: " SUB_LINK_ENTRY " --enable-auto-image-base} \ " LINK_SPEC_LARGE_ADDR_AWARE "\ + " LINK_SPEC_DISABLE_DYNAMICBASE "\ %(shared_libgcc_undefs)" /* Include in the mingw32 libraries with libgcc */ diff --git a/gcc/config/i386/predicates.md b/gcc/config/i386/predicates.md index 129205a..9321f33 100644 --- a/gcc/config/i386/predicates.md +++ b/gcc/config/i386/predicates.md @@ -1713,6 +1713,96 @@ return true; }) +;; Return true if OP is a constant pool in perm{w,d,b} which constains index +;; match pmov{dw,wb,qd}. +(define_predicate "permvar_truncate_operand" + (match_code "mem") +{ + int nelt = GET_MODE_NUNITS (mode); + int perm[128]; + int id; + + if (!INTEGRAL_MODE_P (mode) || !VECTOR_MODE_P (mode)) + return false; + + if (nelt < 2) + return false; + + if (!ix86_extract_perm_from_pool_constant (&perm[0], op)) + return false; + + id = exact_log2 (nelt); + + /* Check that the permutation is suitable for pmovz{bw,wd,dq}. + For example V16HImode to V8HImode + { 0 2 4 6 8 10 12 14 * * * * * * * * }. */ + for (int i = 0; i != nelt / 2; i++) + if ((perm[i] & ((1 << id) - 1)) != i * 2) + return false; + + return true; +}) + +;; Return true if OP is a constant pool in shufb which constains index +;; match pmovdw. +(define_predicate "pshufb_truncv4siv4hi_operand" + (match_code "mem") +{ + int perm[128]; + + if (mode != E_V16QImode) + return false; + + if (!ix86_extract_perm_from_pool_constant (&perm[0], op)) + return false; + + /* Check that the permutation is suitable for pmovdw. + For example V4SImode to V4HImode + { 0 1 4 5 8 9 12 13 * * * * * * * * }. + index = i % 2 + (i / 2) * 4. */ + for (int i = 0; i != 8; i++) + { + /* if (SRC2[(i * 8)+7] = 1) then DEST[(i*8)+7..(i*8)+0] := 0; */ + if (perm[i] & 128) + return false; + + if ((perm[i] & 15) != ((i & 1) + (i & 0xFE) * 2)) + return false; + } + + return true; +}) + +;; Return true if OP is a constant pool in shufb which constains index +;; match pmovdw. +(define_predicate "pshufb_truncv8hiv8qi_operand" + (match_code "mem") +{ + int perm[128]; + + if (mode != E_V16QImode) + return false; + + if (!ix86_extract_perm_from_pool_constant (&perm[0], op)) + return false; + + /* Check that the permutation is suitable for pmovwb. + For example V16QImode to V8QImode + { 0 2 4 6 8 10 12 14 * * * * * * * * }. + index = i % 2 + (i / 2) * 4. */ + for (int i = 0; i != 8; i++) + { + /* if (SRC2[(i * 8)+7] = 1) then DEST[(i*8)+7..(i*8)+0] := 0; */ + if (perm[i] & 128) + return false; + + if ((perm[i] & 15) != i * 2) + return false; + } + + return true; +}) + ;; Return true if OP is a parallel for an pmovz{bw,wd,dq} vec_select, ;; where one of the two operands of the vec_concat is const0_operand. (define_predicate "pmovzx_parallel" diff --git a/gcc/config/i386/sse.md b/gcc/config/i386/sse.md index 2b0d10e..1388968 100644 --- a/gcc/config/i386/sse.md +++ b/gcc/config/i386/sse.md @@ -92,7 +92,6 @@ UNSPEC_RCP14 UNSPEC_RSQRT14 UNSPEC_FIXUPIMM - UNSPEC_SCALEF UNSPEC_VTERNLOG UNSPEC_GETEXP UNSPEC_GETMANT @@ -681,7 +680,12 @@ (define_mode_iterator VI124_128 [V16QI V8HI V4SI]) (define_mode_iterator VI24_128 [V8HI V4SI]) (define_mode_iterator VI248_128 [V8HI V4SI V2DI]) +(define_mode_iterator VI248_256 [V16HI V8SI V4DI]) +(define_mode_iterator VI248_512 [V32HI V16SI V8DI]) (define_mode_iterator VI48_128 [V4SI V2DI]) +(define_mode_iterator VI148_512 [V64QI V16SI V8DI]) +(define_mode_iterator VI148_256 [V32QI V8SI V4DI]) +(define_mode_iterator VI148_128 [V16QI V4SI V2DI]) ;; Various 256bit and 512 vector integer mode combinations (define_mode_iterator VI124_256 [V32QI V16HI V8SI]) @@ -2767,7 +2771,7 @@ (vec_select:DF (match_dup 1) (parallel [(match_operand:SI 3 "const_0_to_1_operand")]))))] - "TARGET_SSE3 + "TARGET_SSE3 && TARGET_V2DF_REDUCTION_PREFER_HADDPD && INTVAL (operands[2]) != INTVAL (operands[3])" "@ haddpd\t{%0, %0|%0, %0} @@ -2786,7 +2790,7 @@ (vec_select:DF (match_dup 1) (parallel [(const_int 1)]))))] - "TARGET_SSE3" + "TARGET_SSE3 && TARGET_V2DF_REDUCTION_PREFER_HADDPD" "@ hsubpd\t{%0, %0|%0, %0} vhsubpd\t{%1, %1, %0|%0, %1, %1}" @@ -10973,6 +10977,64 @@ (set_attr "prefix" "evex") (set_attr "mode" "<sseinsnmode>")]) +(define_insn_and_split "*avx512bw_permvar_truncv16siv16hi_1" + [(set (match_operand:V16HI 0 "nonimmediate_operand") + (vec_select:V16HI + (unspec:V32HI + [(match_operand:V32HI 1 "register_operand") + (match_operand:V32HI 2 "permvar_truncate_operand")] + UNSPEC_VPERMVAR) + (parallel [(const_int 0) (const_int 1) + (const_int 2) (const_int 3) + (const_int 4) (const_int 5) + (const_int 6) (const_int 7) + (const_int 8) (const_int 9) + (const_int 10) (const_int 11) + (const_int 12) (const_int 13) + (const_int 14) (const_int 15)])))] + "TARGET_AVX512BW && ix86_pre_reload_split ()" + "#" + "&& 1" + [(set (match_dup 0) + (truncate:V16HI (match_dup 1)))] + "operands[1] = lowpart_subreg (V16SImode, operands[1], V32HImode);") + +(define_insn_and_split "*avx512f_permvar_truncv8siv8hi_1" + [(set (match_operand:V8HI 0 "nonimmediate_operand") + (vec_select:V8HI + (unspec:V16HI + [(match_operand:V16HI 1 "register_operand") + (match_operand:V16HI 2 "permvar_truncate_operand")] + UNSPEC_VPERMVAR) + (parallel [(const_int 0) (const_int 1) + (const_int 2) (const_int 3) + (const_int 4) (const_int 5) + (const_int 6) (const_int 7)])))] + "TARGET_AVX512VL && TARGET_AVX512BW && ix86_pre_reload_split ()" + "#" + "&& 1" + [(set (match_dup 0) + (truncate:V8HI (match_dup 1)))] + "operands[1] = lowpart_subreg (V8SImode, operands[1], V16HImode);") + +(define_insn_and_split "*avx512f_vpermvar_truncv8div8si_1" + [(set (match_operand:V8SI 0 "nonimmediate_operand") + (vec_select:V8SI + (unspec:V16SI + [(match_operand:V16SI 1 "register_operand") + (match_operand:V16SI 2 "permvar_truncate_operand")] + UNSPEC_VPERMVAR) + (parallel [(const_int 0) (const_int 1) + (const_int 2) (const_int 3) + (const_int 4) (const_int 5) + (const_int 6) (const_int 7)])))] + "TARGET_AVX512F && ix86_pre_reload_split ()" + "#" + "&& 1" + [(set (match_dup 0) + (truncate:V8SI (match_dup 1)))] + "operands[1] = lowpart_subreg (V8DImode, operands[1], V16SImode);") + (define_insn "avx512f_<code><pmov_src_lower><mode>2_mask" [(set (match_operand:PMOV_DST_MODE_1 0 "nonimmediate_operand" "=v,m") (vec_merge:PMOV_DST_MODE_1 @@ -11013,6 +11075,36 @@ (set_attr "prefix" "evex") (set_attr "mode" "XI")]) +(define_insn_and_split "*avx512f_permvar_truncv32hiv32qi_1" + [(set (match_operand:V32QI 0 "nonimmediate_operand") + (vec_select:V32QI + (unspec:V64QI + [(match_operand:V64QI 1 "register_operand") + (match_operand:V64QI 2 "permvar_truncate_operand")] + UNSPEC_VPERMVAR) + (parallel [(const_int 0) (const_int 1) + (const_int 2) (const_int 3) + (const_int 4) (const_int 5) + (const_int 6) (const_int 7) + (const_int 8) (const_int 9) + (const_int 10) (const_int 11) + (const_int 12) (const_int 13) + (const_int 14) (const_int 15) + (const_int 16) (const_int 17) + (const_int 18) (const_int 19) + (const_int 20) (const_int 21) + (const_int 22) (const_int 23) + (const_int 24) (const_int 25) + (const_int 26) (const_int 27) + (const_int 28) (const_int 29) + (const_int 30) (const_int 31)])))] + "TARGET_AVX512VBMI && ix86_pre_reload_split ()" + "#" + "&& 1" + [(set (match_dup 0) + (truncate:V32QI (match_dup 1)))] + "operands[1] = lowpart_subreg (V32HImode, operands[1], V64QImode);") + (define_insn "avx512bw_<code>v32hiv32qi2_mask" [(set (match_operand:V32QI 0 "nonimmediate_operand" "=v,m") (vec_merge:V32QI @@ -11058,6 +11150,45 @@ (set_attr "prefix" "evex") (set_attr "mode" "<sseinsnmode>")]) +(define_insn_and_split "*avx512f_permvar_truncv16hiv16qi_1" + [(set (match_operand:V16QI 0 "nonimmediate_operand") + (vec_select:V16QI + (unspec:V32QI + [(match_operand:V32QI 1 "register_operand") + (match_operand:V32QI 2 "permvar_truncate_operand")] + UNSPEC_VPERMVAR) + (parallel [(const_int 0) (const_int 1) + (const_int 2) (const_int 3) + (const_int 4) (const_int 5) + (const_int 6) (const_int 7) + (const_int 8) (const_int 9) + (const_int 10) (const_int 11) + (const_int 12) (const_int 13) + (const_int 14) (const_int 15)])))] + "TARGET_AVX512VL && TARGET_AVX512VBMI + && ix86_pre_reload_split ()" + "#" + "&& 1" + [(set (match_dup 0) + (truncate:V16QI (match_dup 1)))] + "operands[1] = lowpart_subreg (V16HImode, operands[1], V32QImode);") + +(define_insn_and_split "*avx512f_permvar_truncv4div4si_1" + [(set (match_operand:V4SI 0 "nonimmediate_operand") + (vec_select:V4SI + (unspec:V8SI + [(match_operand:V8SI 1 "register_operand") + (match_operand:V8SI 2 "permvar_truncate_operand")] + UNSPEC_VPERMVAR) + (parallel [(const_int 0) (const_int 1) + (const_int 2) (const_int 3)])))] + "TARGET_AVX512VL && ix86_pre_reload_split ()" + "#" + "&& 1" + [(set (match_dup 0) + (truncate:V4SI (match_dup 1)))] + "operands[1] = lowpart_subreg (V4DImode, operands[1], V8SImode);") + (define_insn "<avx512>_<code><ssedoublemodelower><mode>2_mask" [(set (match_operand:PMOV_DST_MODE_2 0 "nonimmediate_operand" "=v,m") (vec_merge:PMOV_DST_MODE_2 @@ -11116,6 +11247,27 @@ (set_attr "prefix" "evex") (set_attr "mode" "TI")]) +(define_insn_and_split "*avx512f_pshufb_truncv8hiv8qi_1" + [(set (match_operand:DI 0 "register_operand") + (vec_select:DI + (subreg:V2DI + (unspec:V16QI + [(match_operand:V16QI 1 "register_operand") + (match_operand:V16QI 2 "pshufb_truncv8hiv8qi_operand")] + UNSPEC_PSHUFB) 0) + (parallel [(const_int 0)])))] + "TARGET_AVX512VL && ix86_pre_reload_split ()" + "#" + "&& 1" + [(const_int 0)] +{ + rtx op1 = gen_reg_rtx (V8QImode); + operands[1] = lowpart_subreg (V8HImode, operands[1], V16QImode); + emit_insn (gen_truncv8hiv8qi2 (op1, operands[1])); + emit_move_insn (operands[0], lowpart_subreg (DImode, op1, V8QImode)); + DONE; +}) + (define_insn "*avx512vl_<code>v2div2qi2_store_1" [(set (match_operand:V2QI 0 "memory_operand" "=m") (any_truncate:V2QI @@ -11471,6 +11623,27 @@ (set_attr "prefix" "evex") (set_attr "mode" "TI")]) +(define_insn_and_split "*avx512f_pshufb_truncv4siv4hi_1" + [(set (match_operand:DI 0 "register_operand") + (vec_select:DI + (subreg:V2DI + (unspec:V16QI + [(match_operand:V16QI 1 "register_operand") + (match_operand:V16QI 2 "pshufb_truncv4siv4hi_operand")] + UNSPEC_PSHUFB) 0) + (parallel [(const_int 0)])))] + "TARGET_AVX512VL && ix86_pre_reload_split ()" + "#" + "&& 1" + [(const_int 0)] +{ + rtx op1 = gen_reg_rtx (V4HImode); + operands[1] = lowpart_subreg (V4SImode, operands[1], V16QImode); + emit_insn (gen_truncv4siv4hi2 (op1, operands[1])); + emit_move_insn (operands[0], lowpart_subreg (DImode, op1, V4HImode)); + DONE; +}) + (define_insn "*avx512vl_<code><mode>v4hi2_store_1" [(set (match_operand:V4HI 0 "memory_operand" "=m") (any_truncate:V4HI @@ -11694,6 +11867,27 @@ (set_attr "prefix" "evex") (set_attr "mode" "TI")]) +(define_insn_and_split "*avx512f_pshufd_truncv2div2si_1" + [(set (match_operand:DI 0 "register_operand") + (vec_select:DI + (subreg:V2DI + (vec_select:V4SI + (match_operand:V4SI 1 "register_operand") + (parallel [(const_int 0) (const_int 2) + (const_int 2) (const_int 3)])) 0) + (parallel [(const_int 0)])))] + "TARGET_AVX512VL && ix86_pre_reload_split ()" + "#" + "&& 1" + [(const_int 0)] +{ + rtx op1 = gen_reg_rtx (V2SImode); + operands[1] = lowpart_subreg (V2DImode, operands[1], V4SImode); + emit_insn (gen_truncv2div2si2 (op1, operands[1])); + emit_move_insn (operands[0], lowpart_subreg (DImode, op1, V2SImode)); + DONE; +}) + (define_insn "*avx512vl_<code>v2div2si2_store_1" [(set (match_operand:V2SI 0 "memory_operand" "=m") (any_truncate:V2SI @@ -15336,6 +15530,42 @@ (set_attr "prefix" "evex") (set_attr "mode" "<sseinsnmode>")]) +(define_insn "*avx512f_shuf_<shuffletype>64x2_1<mask_name>_1" + [(set (match_operand:V8FI 0 "register_operand" "=v") + (vec_select:V8FI + (match_operand:V8FI 1 "register_operand" "v") + (parallel [(match_operand 2 "const_0_to_7_operand") + (match_operand 3 "const_0_to_7_operand") + (match_operand 4 "const_0_to_7_operand") + (match_operand 5 "const_0_to_7_operand") + (match_operand 6 "const_0_to_7_operand") + (match_operand 7 "const_0_to_7_operand") + (match_operand 8 "const_0_to_7_operand") + (match_operand 9 "const_0_to_7_operand")])))] + "TARGET_AVX512F + && (INTVAL (operands[2]) & 1) == 0 + && INTVAL (operands[2]) == INTVAL (operands[3]) - 1 + && (INTVAL (operands[4]) & 1) == 0 + && INTVAL (operands[4]) == INTVAL (operands[5]) - 1 + && (INTVAL (operands[6]) & 1) == 0 + && INTVAL (operands[6]) == INTVAL (operands[7]) - 1 + && (INTVAL (operands[8]) & 1) == 0 + && INTVAL (operands[8]) == INTVAL (operands[9]) - 1" +{ + int mask; + mask = INTVAL (operands[2]) / 2; + mask |= INTVAL (operands[4]) / 2 << 2; + mask |= INTVAL (operands[6]) / 2 << 4; + mask |= INTVAL (operands[8]) / 2 << 6; + operands[2] = GEN_INT (mask); + + return "vshuf<shuffletype>64x2\t{%2, %1, %1, %0<mask_operand10>|%0<mask_operand10>, %1, %1, %2}"; +} + [(set_attr "type" "sselog") + (set_attr "length_immediate" "1") + (set_attr "prefix" "evex") + (set_attr "mode" "<sseinsnmode>")]) + (define_expand "avx512vl_shuf_<shuffletype>32x4_mask" [(match_operand:VI4F_256 0 "register_operand") (match_operand:VI4F_256 1 "register_operand") @@ -15482,6 +15712,58 @@ (set_attr "prefix" "evex") (set_attr "mode" "<sseinsnmode>")]) +(define_insn "*avx512f_shuf_<shuffletype>32x4_1<mask_name>_1" + [(set (match_operand:V16FI 0 "register_operand" "=v") + (vec_select:V16FI + (match_operand:V16FI 1 "register_operand" "v") + (parallel [(match_operand 2 "const_0_to_15_operand") + (match_operand 3 "const_0_to_15_operand") + (match_operand 4 "const_0_to_15_operand") + (match_operand 5 "const_0_to_15_operand") + (match_operand 6 "const_0_to_15_operand") + (match_operand 7 "const_0_to_15_operand") + (match_operand 8 "const_0_to_15_operand") + (match_operand 9 "const_0_to_15_operand") + (match_operand 10 "const_0_to_15_operand") + (match_operand 11 "const_0_to_15_operand") + (match_operand 12 "const_0_to_15_operand") + (match_operand 13 "const_0_to_15_operand") + (match_operand 14 "const_0_to_15_operand") + (match_operand 15 "const_0_to_15_operand") + (match_operand 16 "const_0_to_15_operand") + (match_operand 17 "const_0_to_15_operand")])))] + "TARGET_AVX512F + && (INTVAL (operands[2]) & 3) == 0 + && INTVAL (operands[2]) == INTVAL (operands[3]) - 1 + && INTVAL (operands[2]) == INTVAL (operands[4]) - 2 + && INTVAL (operands[2]) == INTVAL (operands[5]) - 3 + && (INTVAL (operands[6]) & 3) == 0 + && INTVAL (operands[6]) == INTVAL (operands[7]) - 1 + && INTVAL (operands[6]) == INTVAL (operands[8]) - 2 + && INTVAL (operands[6]) == INTVAL (operands[9]) - 3 + && (INTVAL (operands[10]) & 3) == 0 + && INTVAL (operands[10]) == INTVAL (operands[11]) - 1 + && INTVAL (operands[10]) == INTVAL (operands[12]) - 2 + && INTVAL (operands[10]) == INTVAL (operands[13]) - 3 + && (INTVAL (operands[14]) & 3) == 0 + && INTVAL (operands[14]) == INTVAL (operands[15]) - 1 + && INTVAL (operands[14]) == INTVAL (operands[16]) - 2 + && INTVAL (operands[14]) == INTVAL (operands[17]) - 3" +{ + int mask; + mask = INTVAL (operands[2]) / 4; + mask |= INTVAL (operands[6]) / 4 << 2; + mask |= INTVAL (operands[10]) / 4 << 4; + mask |= INTVAL (operands[14]) / 4 << 6; + operands[2] = GEN_INT (mask); + + return "vshuf<shuffletype>32x4\t{%2, %1, %1, %0<mask_operand18>|%0<mask_operand18>, %1, %1, %2}"; +} + [(set_attr "type" "sselog") + (set_attr "length_immediate" "1") + (set_attr "prefix" "evex") + (set_attr "mode" "<sseinsnmode>")]) + (define_expand "avx512f_pshufdv3_mask" [(match_operand:V16SI 0 "register_operand") (match_operand:V16SI 1 "nonimmediate_operand") @@ -18515,6 +18797,26 @@ operands[1] = lowpart_subreg (V16QImode, operands[1], V32QImode); }) +(define_insn_and_split "*avx2_zero_extendv16qiv16hi2_2" + [(set (match_operand:V32QI 0 "register_operand" "=v") + (vec_select:V32QI + (vec_concat:V64QI + (subreg:V32QI + (vec_concat:VI248_256 + (match_operand:<ssehalfvecmode> 1 "nonimmediate_operand" "vm") + (match_operand:<ssehalfvecmode> 2 "const0_operand" "C")) 0) + (match_operand:V32QI 3 "const0_operand" "C")) + (match_parallel 4 "pmovzx_parallel" + [(match_operand 5 "const_int_operand" "n")])))] + "TARGET_AVX2" + "#" + "&& reload_completed" + [(set (match_dup 0) (zero_extend:V16HI (match_dup 1)))] +{ + operands[0] = lowpart_subreg (V16HImode, operands[0], V32QImode); + operands[1] = lowpart_subreg (V16QImode, operands[1], <ssehalfvecmode>mode); +}) + (define_expand "<insn>v16qiv16hi2" [(set (match_operand:V16HI 0 "register_operand") (any_extend:V16HI @@ -18549,6 +18851,26 @@ operands[1] = lowpart_subreg (V32QImode, operands[1], V64QImode); }) +(define_insn_and_split "*avx512bw_zero_extendv32qiv32hi2_2" + [(set (match_operand:V64QI 0 "register_operand" "=v") + (vec_select:V64QI + (vec_concat:V128QI + (subreg:V64QI + (vec_concat:VI248_512 + (match_operand:<ssehalfvecmode> 1 "nonimmediate_operand" "vm") + (match_operand:<ssehalfvecmode> 2 "const0_operand" "C")) 0) + (match_operand:V64QI 3 "const0_operand" "C")) + (match_parallel 4 "pmovzx_parallel" + [(match_operand 5 "const_int_operand" "n")])))] + "TARGET_AVX512BW" + "#" + "&& reload_completed" + [(set (match_dup 0) (zero_extend:V32HI (match_dup 1)))] +{ + operands[0] = lowpart_subreg (V32HImode, operands[0], V64QImode); + operands[1] = lowpart_subreg (V32QImode, operands[1], <ssehalfvecmode>mode); +}) + (define_expand "<insn>v32qiv32hi2" [(set (match_operand:V32HI 0 "register_operand") (any_extend:V32HI @@ -18635,6 +18957,41 @@ } [(set_attr "isa" "noavx,noavx,avx")]) +(define_insn_and_split "*sse4_1_zero_extendv8qiv8hi2_4" + [(set (match_operand:V16QI 0 "register_operand" "=Yr,*x,Yw") + (vec_select:V16QI + (vec_concat:V32QI + (subreg:V16QI + (vec_concat:VI248_128 + (match_operand:<ssehalfvecmode> 1 "vector_operand" "YrBm,*xBm,Ywm") + (match_operand:<ssehalfvecmode> 2 "const0_operand" "C,C,C")) 0) + (match_operand:V16QI 3 "const0_operand" "C,C,C")) + (match_parallel 4 "pmovzx_parallel" + [(match_operand 5 "const_int_operand" "n,n,n")])))] + "TARGET_SSE4_1" + "#" + "&& reload_completed" + [(set (match_dup 0) + (zero_extend:V8HI + (vec_select:V8QI + (match_dup 1) + (parallel [(const_int 0) (const_int 1) + (const_int 2) (const_int 3) + (const_int 4) (const_int 5) + (const_int 6) (const_int 7)]))))] +{ + operands[0] = lowpart_subreg (V8HImode, operands[0], V16QImode); + if (MEM_P (operands[1])) + { + operands[1] = lowpart_subreg (V8QImode, operands[1], <ssehalfvecmode>mode); + operands[1] = gen_rtx_ZERO_EXTEND (V8HImode, operands[1]); + emit_insn (gen_rtx_SET (operands[0], operands[1])); + DONE; + } + operands[1] = lowpart_subreg (V16QImode, operands[1], <ssehalfvecmode>mode); +} + [(set_attr "isa" "noavx,noavx,avx")]) + (define_expand "<insn>v8qiv8hi2" [(set (match_operand:V8HI 0 "register_operand") (any_extend:V8HI @@ -18825,6 +19182,26 @@ operands[1] = lowpart_subreg (V16HImode, operands[1], V32HImode); }) +(define_insn_and_split "*avx512f_zero_extendv16hiv16si2_2" + [(set (match_operand:V32HI 0 "register_operand" "=v") + (vec_select:V32HI + (vec_concat:V64HI + (subreg:V32HI + (vec_concat:VI148_512 + (match_operand:<ssehalfvecmode> 1 "nonimmediate_operand" "vm") + (match_operand:<ssehalfvecmode> 2 "const0_operand" "C")) 0) + (match_operand:V32HI 3 "const0_operand" "C")) + (match_parallel 4 "pmovzx_parallel" + [(match_operand 5 "const_int_operand" "n")])))] + "TARGET_AVX512F" + "#" + "&& reload_completed" + [(set (match_dup 0) (zero_extend:V16SI (match_dup 1)))] +{ + operands[0] = lowpart_subreg (V16SImode, operands[0], V32HImode); + operands[1] = lowpart_subreg (V16HImode, operands[1], <ssehalfvecmode>mode); +}) + (define_insn "avx2_<code>v8hiv8si2<mask_name>" [(set (match_operand:V8SI 0 "register_operand" "=v") (any_extend:V8SI @@ -18859,6 +19236,27 @@ operands[1] = lowpart_subreg (V8HImode, operands[1], V16HImode); }) +(define_insn_and_split "*avx2_zero_extendv8hiv8si2_2" + [(set (match_operand:V16HI 0 "register_operand" "=v") + (vec_select:V16HI + (vec_concat:V32HI + (subreg:V16HI + (vec_concat:VI148_256 + (match_operand:<ssehalfvecmode> 1 "nonimmediate_operand" "vm") + (match_operand:<ssehalfvecmode> 2 "const0_operand" "C")) 0) + (match_operand:V16HI 3 "const0_operand" "C")) + (match_parallel 4 "pmovzx_parallel" + [(match_operand 5 "const_int_operand" "n")])))] + "TARGET_AVX2" + "#" + "&& reload_completed" + [(set (match_dup 0) (zero_extend:V8SI (match_dup 1)))] +{ + operands[0] = lowpart_subreg (V8SImode, operands[0], V16HImode); + operands[1] = lowpart_subreg (V8HImode, operands[1], <ssehalfvecmode>mode); +}) + + (define_insn "sse4_1_<code>v4hiv4si2<mask_name>" [(set (match_operand:V4SI 0 "register_operand" "=Yr,*x,v") (any_extend:V4SI @@ -18948,6 +19346,39 @@ } [(set_attr "isa" "noavx,noavx,avx")]) +(define_insn_and_split "*sse4_1_zero_extendv4hiv4si2_4" + [(set (match_operand:V8HI 0 "register_operand" "=Yr,*x,v") + (vec_select:V8HI + (vec_concat:V16HI + (subreg:V8HI + (vec_concat:VI148_128 + (match_operand:<ssehalfvecmode> 1 "vector_operand" "YrBm,*xBm,vm") + (match_operand:<ssehalfvecmode> 2 "const0_operand" "C,C,C")) 0) + (match_operand:V8HI 3 "const0_operand" "C,C,C")) + (match_parallel 4 "pmovzx_parallel" + [(match_operand 5 "const_int_operand" "n,n,n")])))] + "TARGET_SSE4_1" + "#" + "&& reload_completed" + [(set (match_dup 0) + (zero_extend:V4SI + (vec_select:V4HI + (match_dup 1) + (parallel [(const_int 0) (const_int 1) + (const_int 2) (const_int 3)]))))] +{ + operands[0] = lowpart_subreg (V4SImode, operands[0], V8HImode); + if (MEM_P (operands[1])) + { + operands[1] = lowpart_subreg (V4HImode, operands[1], <ssehalfvecmode>mode); + operands[1] = gen_rtx_ZERO_EXTEND (V4SImode, operands[1]); + emit_insn (gen_rtx_SET (operands[0], operands[1])); + DONE; + } + operands[1] = lowpart_subreg (V8HImode, operands[1], <ssehalfvecmode>mode); +} + [(set_attr "isa" "noavx,noavx,avx")]) + (define_insn "avx512f_<code>v8qiv8di2<mask_name>" [(set (match_operand:V8DI 0 "register_operand" "=v") (any_extend:V8DI @@ -19258,6 +19689,24 @@ operands[1] = lowpart_subreg (V8SImode, operands[1], V16SImode); }) +(define_insn_and_split "*avx512f_zero_extendv8siv8di2_2" + [(set (match_operand:V16SI 0 "register_operand" "=v") + (vec_select:V16SI + (vec_concat:V32SI + (vec_concat:V16SI + (match_operand:V8SI 1 "nonimmediate_operand" "vm") + (match_operand:V8SI 2 "const0_operand" "C")) + (match_operand:V16SI 3 "const0_operand" "C")) + (match_parallel 4 "pmovzx_parallel" + [(match_operand 5 "const_int_operand" "n")])))] + "TARGET_AVX512F" + "#" + "&& reload_completed" + [(set (match_dup 0) (zero_extend:V8DI (match_dup 1)))] +{ + operands[0] = lowpart_subreg (V8DImode, operands[0], V16SImode); +}) + (define_expand "<insn>v8siv8di2" [(set (match_operand:V8DI 0 "register_operand" "=v") (any_extend:V8DI @@ -19292,6 +19741,24 @@ operands[1] = lowpart_subreg (V4SImode, operands[1], V8SImode); }) +(define_insn_and_split "*avx2_zero_extendv4siv4di2_2" + [(set (match_operand:V8SI 0 "register_operand" "=v") + (vec_select:V8SI + (vec_concat:V16SI + (vec_concat:V8SI + (match_operand:V4SI 1 "nonimmediate_operand" "vm") + (match_operand:V4SI 2 "const0_operand" "C")) + (match_operand:V8SI 3 "const0_operand" "C")) + (match_parallel 4 "pmovzx_parallel" + [(match_operand 5 "const_int_operand" "n")])))] + "TARGET_AVX2" + "#" + "&& reload_completed" + [(set (match_dup 0) (zero_extend:V4DI (match_dup 1)))] +{ + operands[0] = lowpart_subreg (V4DImode, operands[0], V8SImode); +}) + (define_expand "<insn>v4siv4di2" [(set (match_operand:V4DI 0 "register_operand") (any_extend:V4DI @@ -19368,6 +19835,35 @@ } [(set_attr "isa" "noavx,noavx,avx")]) +(define_insn_and_split "*sse4_1_zero_extendv2siv2di2_4" + [(set (match_operand:V4SI 0 "register_operand" "=Yr,*x,v") + (vec_select:V4SI + (vec_concat:V8SI + (vec_concat:V4SI + (match_operand:V2SI 1 "vector_operand" "YrBm, *xBm, vm") + (match_operand:V2SI 2 "const0_operand" "C,C,C")) + (match_operand:V4SI 3 "const0_operand" "C,C,C")) + (match_parallel 4 "pmovzx_parallel" + [(match_operand 5 "const_int_operand" "n,n,n")])))] + "TARGET_SSE4_1" + "#" + "&& reload_completed" + [(set (match_dup 0) + (zero_extend:V2DI + (vec_select:V2SI (match_dup 1) + (parallel [(const_int 0) (const_int 1)]))))] +{ + operands[0] = lowpart_subreg (V2DImode, operands[0], V4SImode); + if (MEM_P (operands[1])) + { + operands[1] = gen_rtx_ZERO_EXTEND (V2DImode, operands[1]); + emit_insn (gen_rtx_SET (operands[0], operands[1])); + DONE; + } + operands[1] = lowpart_subreg (V4SImode, operands[1], V2SImode); +} + [(set_attr "isa" "noavx,noavx,avx")]) + (define_expand "<insn>v2siv2di2" [(set (match_operand:V2DI 0 "register_operand") (any_extend:V2DI diff --git a/gcc/config/i386/x86-tune.def b/gcc/config/i386/x86-tune.def index eb057a6..8f55da8 100644 --- a/gcc/config/i386/x86-tune.def +++ b/gcc/config/i386/x86-tune.def @@ -452,6 +452,11 @@ DEF_TUNE (X86_TUNE_AVOID_128FMA_CHAINS, "avoid_fma_chains", m_ZNVER) smaller FMA chain. */ DEF_TUNE (X86_TUNE_AVOID_256FMA_CHAINS, "avoid_fma256_chains", m_ZNVER2 | m_ZNVER3) +/* X86_TUNE_V2DF_REDUCTION_PREFER_PHADDPD: Prefer haddpd + for v2df vector reduction. */ +DEF_TUNE (X86_TUNE_V2DF_REDUCTION_PREFER_HADDPD, + "v2df_reduction_prefer_haddpd", m_NONE) + /*****************************************************************************/ /* AVX instruction selection tuning (some of SSE flags affects AVX, too) */ /*****************************************************************************/ diff --git a/gcc/config/or1k/or1k-opts.h b/gcc/config/or1k/or1k-opts.h new file mode 100644 index 0000000..f791b89 --- /dev/null +++ b/gcc/config/or1k/or1k-opts.h @@ -0,0 +1,30 @@ +/* Definitions for option handling for OpenRISC. + Copyright (C) 2021 Free Software Foundation, Inc. + Contributed by Stafford Horne. + + 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 GCC_OR1K_OPTS_H +#define GCC_OR1K_OPTS_H + +/* The OpenRISC code generation models available. */ +enum or1k_cmodel_type { + CMODEL_SMALL, + CMODEL_LARGE +}; + +#endif /* GCC_OR1K_OPTS_H */ diff --git a/gcc/config/or1k/or1k.c b/gcc/config/or1k/or1k.c index e772a7a..27d3fa1 100644 --- a/gcc/config/or1k/or1k.c +++ b/gcc/config/or1k/or1k.c @@ -750,7 +750,14 @@ or1k_legitimize_address_1 (rtx x, rtx scratch) { base = gen_sym_unspec (base, UNSPEC_GOT); crtl->uses_pic_offset_table = 1; - t2 = gen_rtx_LO_SUM (Pmode, pic_offset_table_rtx, base); + if (TARGET_CMODEL_LARGE) + { + emit_insn (gen_rtx_SET (t1, gen_rtx_HIGH (Pmode, base))); + emit_insn (gen_add3_insn (t1, t1, pic_offset_table_rtx)); + t2 = gen_rtx_LO_SUM (Pmode, t1, base); + } + else + t2 = gen_rtx_LO_SUM (Pmode, pic_offset_table_rtx, base); t2 = gen_const_mem (Pmode, t2); emit_insn (gen_rtx_SET (t1, t2)); base = t1; @@ -1089,7 +1096,7 @@ print_reloc (FILE *stream, rtx x, HOST_WIDE_INT add, reloc_kind kind) no special markup. */ static const char * const relocs[RKIND_MAX][RTYPE_MAX] = { { "lo", "got", "gotofflo", "tpofflo", "gottpofflo", "tlsgdlo" }, - { "ha", NULL, "gotoffha", "tpoffha", "gottpoffha", "tlsgdhi" }, + { "ha", "gotha", "gotoffha", "tpoffha", "gottpoffha", "tlsgdhi" }, }; reloc_type type = RTYPE_DIRECT; diff --git a/gcc/config/or1k/or1k.h b/gcc/config/or1k/or1k.h index fe01ab8..669907e 100644 --- a/gcc/config/or1k/or1k.h +++ b/gcc/config/or1k/or1k.h @@ -21,6 +21,8 @@ #ifndef GCC_OR1K_H #define GCC_OR1K_H +#include "config/or1k/or1k-opts.h" + /* Names to predefine in the preprocessor for this target machine. */ #define TARGET_CPU_CPP_BUILTINS() \ do \ @@ -37,6 +39,11 @@ } \ while (0) +#define TARGET_CMODEL_SMALL \ + (or1k_code_model == CMODEL_SMALL) +#define TARGET_CMODEL_LARGE \ + (or1k_code_model == CMODEL_LARGE) + /* Storage layout. */ #define DEFAULT_SIGNED_CHAR 1 diff --git a/gcc/config/or1k/or1k.opt b/gcc/config/or1k/or1k.opt index 6bd0f3e..cc23e3b 100644 --- a/gcc/config/or1k/or1k.opt +++ b/gcc/config/or1k/or1k.opt @@ -21,6 +21,9 @@ ; See the GCC internals manual (options.texi) for a description of ; this file's format. +HeaderInclude +config/or1k/or1k-opts.h + mhard-div Target RejectNegative InverseMask(SOFT_DIV) Enable generation of hardware divide (l.div, l.divu) instructions. This is the @@ -63,6 +66,22 @@ When -mhard-float is selected, enables generation of unordered floating point compare and set flag (lf.sfun*) instructions. By default functions from libgcc are used to perform unordered floating point compare and set flag operations. +mcmodel= +Target RejectNegative Joined Enum(or1k_cmodel_type) Var(or1k_code_model) Init(CMODEL_SMALL) +Specify the code model used for accessing memory addresses. Specifying large +enables generating binaries with large global offset tables. By default the +value is small. + +Enum +Name(or1k_cmodel_type) Type(enum or1k_cmodel_type) +Known code model types (for use with the -mcmodel= option): + +EnumValue +Enum(or1k_cmodel_type) String(small) Value(CMODEL_SMALL) + +EnumValue +Enum(or1k_cmodel_type) String(large) Value(CMODEL_LARGE) + mcmov Target RejectNegative Mask(CMOV) Enable generation of conditional move (l.cmov) instructions. By default the diff --git a/gcc/config/riscv/multilib-generator b/gcc/config/riscv/multilib-generator index a204543..358bda9 100755 --- a/gcc/config/riscv/multilib-generator +++ b/gcc/config/riscv/multilib-generator @@ -40,6 +40,7 @@ import collections import itertools from functools import reduce import subprocess +import argparse # # TODO: Add test for this script. @@ -127,44 +128,69 @@ def expand_combination(ext): return ext -for cfg in sys.argv[1:]: - try: - (arch, abi, extra, ext) = cfg.split('-') - except: - print ("Invalid configure string %s, <arch>-<abi>-<extra>-<extensions>\n" - "<extra> and <extensions> can be empty, " - "e.g. rv32imafd-ilp32--" % cfg) - sys.exit(1) - - arch = arch_canonicalize (arch) - arches[arch] = 1 - abis[abi] = 1 - extra = list(filter(None, extra.split(','))) - ext_combs = expand_combination(ext) - alts = sum([[x] + [x + y for y in ext_combs] for x in [arch] + extra], []) - alts = list(map(arch_canonicalize, alts)) +multilib_cfgs = filter(lambda x:not x.startswith("--"), sys.argv[1:]) +options = filter(lambda x:x.startswith("--"), sys.argv[1:]) + +parser = argparse.ArgumentParser() +parser.add_argument("--cmodel", type=str) +parser.add_argument("cfgs", type=str, nargs='*') +args = parser.parse_args() + +if args.cmodel: + cmodels = [None] + args.cmodel.split(",") +else: + cmodels = [None] + +cmodel_options = '/'.join(['mcmodel=%s' % x for x in cmodels[1:]]) +cmodel_dirnames = ' \\\n'.join(cmodels[1:]) + +for cmodel in cmodels: + for cfg in args.cfgs: + try: + (arch, abi, extra, ext) = cfg.split('-') + except: + print ("Invalid configure string %s, <arch>-<abi>-<extra>-<extensions>\n" + "<extra> and <extensions> can be empty, " + "e.g. rv32imafd-ilp32--" % cfg) + sys.exit(1) + + # Compact code model only support rv64. + if cmodel == "compact" and arch.startswith("rv32"): + continue - # Drop duplicated entry. - alts = unique(alts) + arch = arch_canonicalize (arch) + arches[arch] = 1 + abis[abi] = 1 + extra = list(filter(None, extra.split(','))) + ext_combs = expand_combination(ext) + alts = sum([[x] + [x + y for y in ext_combs] for x in [arch] + extra], []) + alts = list(map(arch_canonicalize, alts)) - for alt in alts: - if alt == arch: - continue - arches[alt] = 1 - reuse.append('march.%s/mabi.%s=march.%s/mabi.%s' % (arch, abi, alt, abi)) - required.append('march=%s/mabi=%s' % (arch, abi)) + # Drop duplicated entry. + alts = unique(alts) + + for alt in alts[1:]: + if alt == arch: + continue + arches[alt] = 1 + reuse.append('march.%s/mabi.%s=march.%s/mabi.%s' % (arch, abi, alt, abi)) + + if cmodel: + required.append('march=%s/mabi=%s/mcmodel=%s' % (arch, abi, cmodel)) + else: + required.append('march=%s/mabi=%s' % (arch, abi)) -arch_options = '/'.join(['march=%s' % x for x in arches.keys()]) -arch_dirnames = ' \\\n'.join(arches.keys()) + arch_options = '/'.join(['march=%s' % x for x in arches.keys()]) + arch_dirnames = ' \\\n'.join(arches.keys()) -abi_options = '/'.join(['mabi=%s' % x for x in abis.keys()]) -abi_dirnames = ' \\\n'.join(abis.keys()) + abi_options = '/'.join(['mabi=%s' % x for x in abis.keys()]) + abi_dirnames = ' \\\n'.join(abis.keys()) prog = sys.argv[0].split('/')[-1] print('# This file was generated by %s with the command:' % prog) print('# %s' % ' '.join(sys.argv)) -print('MULTILIB_OPTIONS = %s %s' % (arch_options, abi_options)) -print('MULTILIB_DIRNAMES = %s %s' % (arch_dirnames, abi_dirnames)) +print('MULTILIB_OPTIONS = %s %s %s' % (arch_options, abi_options, cmodel_options)) +print('MULTILIB_DIRNAMES = %s %s %s' % (arch_dirnames, abi_dirnames, cmodel_dirnames)) print('MULTILIB_REQUIRED = %s' % ' \\\n'.join(required)) print('MULTILIB_REUSE = %s' % ' \\\n'.join(reuse)) diff --git a/gcc/config/rs6000/altivec.md b/gcc/config/rs6000/altivec.md index d70c17e..fd86c300 100644 --- a/gcc/config/rs6000/altivec.md +++ b/gcc/config/rs6000/altivec.md @@ -3875,9 +3875,9 @@ (define_insn "xxeval" [(set (match_operand:V2DI 0 "register_operand" "=wa") - (unspec:V2DI [(match_operand:V2DI 1 "altivec_register_operand" "wa") - (match_operand:V2DI 2 "altivec_register_operand" "wa") - (match_operand:V2DI 3 "altivec_register_operand" "wa") + (unspec:V2DI [(match_operand:V2DI 1 "register_operand" "wa") + (match_operand:V2DI 2 "register_operand" "wa") + (match_operand:V2DI 3 "register_operand" "wa") (match_operand:QI 4 "u8bit_cint_operand" "n")] UNSPEC_XXEVAL))] "TARGET_POWER10" diff --git a/gcc/config/rs6000/rs6000-builtin-new.def b/gcc/config/rs6000/rs6000-builtin-new.def index a84a3de..61f5b94 100644 --- a/gcc/config/rs6000/rs6000-builtin-new.def +++ b/gcc/config/rs6000/rs6000-builtin-new.def @@ -184,6 +184,82 @@ +; Builtins that have been around since time immemorial or are just +; considered available everywhere. +[always] + void __builtin_cpu_init (); + CPU_INIT nothing {cpu} + + bool __builtin_cpu_is (string); + CPU_IS nothing {cpu} + + bool __builtin_cpu_supports (string); + CPU_SUPPORTS nothing {cpu} + + unsigned long long __builtin_ppc_get_timebase (); + GET_TB rs6000_get_timebase {} + + double __builtin_mffs (); + MFFS rs6000_mffs {} + +; This thing really assumes long double == __ibm128, and I'm told it has +; been used as such within libgcc. Given that __builtin_pack_ibm128 +; exists for the same purpose, this should really not be used at all. +; TODO: Consider adding special handling for this to warn whenever +; long double is not __ibm128. + const long double __builtin_pack_longdouble (double, double); + PACK_TF packtf {} + + unsigned long __builtin_ppc_mftb (); + MFTB rs6000_mftb_di {32bit} + + void __builtin_mtfsb0 (const int<5>); + MTFSB0 rs6000_mtfsb0 {} + + void __builtin_mtfsb1 (const int<5>); + MTFSB1 rs6000_mtfsb1 {} + + void __builtin_mtfsf (const int<8>, double); + MTFSF rs6000_mtfsf {} + + const __ibm128 __builtin_pack_ibm128 (double, double); + PACK_IF packif {} + + void __builtin_set_fpscr_rn (const int[0,3]); + SET_FPSCR_RN rs6000_set_fpscr_rn {} + + const double __builtin_unpack_ibm128 (__ibm128, const int<1>); + UNPACK_IF unpackif {} + +; See above comments for __builtin_pack_longdouble. + const double __builtin_unpack_longdouble (long double, const int<1>); + UNPACK_TF unpacktf {} + + +; Builtins that have been around just about forever, but not quite. +[power5] + fpmath double __builtin_recipdiv (double, double); + RECIP recipdf3 {} + + fpmath float __builtin_recipdivf (float, float); + RECIPF recipsf3 {} + + fpmath double __builtin_rsqrt (double); + RSQRT rsqrtdf2 {} + + fpmath float __builtin_rsqrtf (float); + RSQRTF rsqrtsf2 {} + + +; Power6 builtins (ISA 2.05). +[power6] + const signed long __builtin_p6_cmpb (signed long, signed long); + CMPB cmpbdi3 {} + + const signed int __builtin_p6_cmpb_32 (signed int, signed int); + CMPB_32 cmpbsi3 {} + + ; AltiVec builtins. [altivec] const vsc __builtin_altivec_abs_v16qi (vsc); @@ -197,3 +273,1691 @@ const vss __builtin_altivec_abs_v8hi (vss); ABS_V8HI absv8hi2 {} + + const vsc __builtin_altivec_abss_v16qi (vsc); + ABSS_V16QI altivec_abss_v16qi {} + + const vsi __builtin_altivec_abss_v4si (vsi); + ABSS_V4SI altivec_abss_v4si {} + + const vss __builtin_altivec_abss_v8hi (vss); + ABSS_V8HI altivec_abss_v8hi {} + + const vf __builtin_altivec_copysignfp (vf, vf); + COPYSIGN_V4SF vector_copysignv4sf3 {} + + void __builtin_altivec_dss (const int<2>); + DSS altivec_dss {} + + void __builtin_altivec_dssall (); + DSSALL altivec_dssall {} + + void __builtin_altivec_dst (void *, const int, const int<2>); + DST altivec_dst {} + + void __builtin_altivec_dstst (void *, const int, const int<2>); + DSTST altivec_dstst {} + + void __builtin_altivec_dststt (void *, const int, const int<2>); + DSTSTT altivec_dststt {} + + void __builtin_altivec_dstt (void *, const int, const int<2>); + DSTT altivec_dstt {} + + fpmath vsi __builtin_altivec_fix_sfsi (vf); + FIX_V4SF_V4SI fix_truncv4sfv4si2 {} + + fpmath vui __builtin_altivec_fixuns_sfsi (vf); + FIXUNS_V4SF_V4SI fixuns_truncv4sfv4si2 {} + + fpmath vf __builtin_altivec_float_sisf (vsi); + FLOAT_V4SI_V4SF floatv4siv4sf2 {} + + pure vsc __builtin_altivec_lvebx (signed long, const void *); + LVEBX altivec_lvebx {ldvec} + + pure vss __builtin_altivec_lvehx (signed long, const void *); + LVEHX altivec_lvehx {ldvec} + + pure vsi __builtin_altivec_lvewx (signed long, const void *); + LVEWX altivec_lvewx {ldvec} + + pure vuc __builtin_altivec_lvsl (signed long, const void *); + LVSL altivec_lvsl {ldvec} + + pure vuc __builtin_altivec_lvsr (signed long, const void *); + LVSR altivec_lvsr {ldvec} + + pure vsi __builtin_altivec_lvx (signed long, const void *); + LVX altivec_lvx_v4si {ldvec} + + pure vsq __builtin_altivec_lvx_v1ti (signed long, const void *); + LVX_V1TI altivec_lvx_v1ti {ldvec} + + pure vsc __builtin_altivec_lvx_v16qi (signed long, const void *); + LVX_V16QI altivec_lvx_v16qi {ldvec} + + pure vf __builtin_altivec_lvx_v4sf (signed long, const void *); + LVX_V4SF altivec_lvx_v4sf {ldvec} + + pure vsi __builtin_altivec_lvx_v4si (signed long, const void *); + LVX_V4SI altivec_lvx_v4si {ldvec} + + pure vss __builtin_altivec_lvx_v8hi (signed long, const void *); + LVX_V8HI altivec_lvx_v8hi {ldvec} + + pure vsi __builtin_altivec_lvxl (signed long, const void *); + LVXL altivec_lvxl_v4si {ldvec} + + pure vsc __builtin_altivec_lvxl_v16qi (signed long, const void *); + LVXL_V16QI altivec_lvxl_v16qi {ldvec} + + pure vf __builtin_altivec_lvxl_v4sf (signed long, const void *); + LVXL_V4SF altivec_lvxl_v4sf {ldvec} + + pure vsi __builtin_altivec_lvxl_v4si (signed long, const void *); + LVXL_V4SI altivec_lvxl_v4si {ldvec} + + pure vss __builtin_altivec_lvxl_v8hi (signed long, const void *); + LVXL_V8HI altivec_lvxl_v8hi {ldvec} + + const vsc __builtin_altivec_mask_for_load (const void *); + MASK_FOR_LOAD altivec_lvsr_direct {ldstmask} + + vss __builtin_altivec_mfvscr (); + MFVSCR altivec_mfvscr {} + + void __builtin_altivec_mtvscr (vsi); + MTVSCR altivec_mtvscr {} + + const vsll __builtin_altivec_vmulesw (vsi, vsi); + VMULESW vec_widen_smult_even_v4si {} + + const vull __builtin_altivec_vmuleuw (vui, vui); + VMULEUW vec_widen_umult_even_v4si {} + + const vsll __builtin_altivec_vmulosw (vsi, vsi); + VMULOSW vec_widen_smult_odd_v4si {} + + const vull __builtin_altivec_vmulouw (vui, vui); + VMULOUW vec_widen_umult_odd_v4si {} + + const vsc __builtin_altivec_nabs_v16qi (vsc); + NABS_V16QI nabsv16qi2 {} + + const vf __builtin_altivec_nabs_v4sf (vf); + NABS_V4SF vsx_nabsv4sf2 {} + + const vsi __builtin_altivec_nabs_v4si (vsi); + NABS_V4SI nabsv4si2 {} + + const vss __builtin_altivec_nabs_v8hi (vss); + NABS_V8HI nabsv8hi2 {} + + void __builtin_altivec_stvebx (vsc, signed long, void *); + STVEBX altivec_stvebx {stvec} + + void __builtin_altivec_stvehx (vss, signed long, void *); + STVEHX altivec_stvehx {stvec} + + void __builtin_altivec_stvewx (vsi, signed long, void *); + STVEWX altivec_stvewx {stvec} + + void __builtin_altivec_stvx (vsi, signed long, void *); + STVX altivec_stvx_v4si {stvec} + + void __builtin_altivec_stvx_v16qi (vsc, signed long, void *); + STVX_V16QI altivec_stvx_v16qi {stvec} + + void __builtin_altivec_stvx_v4sf (vf, signed long, void *); + STVX_V4SF altivec_stvx_v4sf {stvec} + + void __builtin_altivec_stvx_v4si (vsi, signed long, void *); + STVX_V4SI altivec_stvx_v4si {stvec} + + void __builtin_altivec_stvx_v8hi (vss, signed long, void *); + STVX_V8HI altivec_stvx_v8hi {stvec} + + void __builtin_altivec_stvxl (vsi, signed long, void *); + STVXL altivec_stvxl_v4si {stvec} + + void __builtin_altivec_stvxl_v16qi (vsc, signed long, void *); + STVXL_V16QI altivec_stvxl_v16qi {stvec} + + void __builtin_altivec_stvxl_v4sf (vf, signed long, void *); + STVXL_V4SF altivec_stvxl_v4sf {stvec} + + void __builtin_altivec_stvxl_v4si (vsi, signed long, void *); + STVXL_V4SI altivec_stvxl_v4si {stvec} + + void __builtin_altivec_stvxl_v8hi (vss, signed long, void *); + STVXL_V8HI altivec_stvxl_v8hi {stvec} + + fpmath vf __builtin_altivec_uns_float_sisf (vui); + UNSFLOAT_V4SI_V4SF floatunsv4siv4sf2 {} + + const vui __builtin_altivec_vaddcuw (vui, vui); + VADDCUW altivec_vaddcuw {} + + const vf __builtin_altivec_vaddfp (vf, vf); + VADDFP addv4sf3 {} + + const vsc __builtin_altivec_vaddsbs (vsc, vsc); + VADDSBS altivec_vaddsbs {} + + const vss __builtin_altivec_vaddshs (vss, vss); + VADDSHS altivec_vaddshs {} + + const vsi __builtin_altivec_vaddsws (vsi, vsi); + VADDSWS altivec_vaddsws {} + + const vuc __builtin_altivec_vaddubm (vuc, vuc); + VADDUBM addv16qi3 {} + + const vuc __builtin_altivec_vaddubs (vuc, vuc); + VADDUBS altivec_vaddubs {} + + const vus __builtin_altivec_vadduhm (vus, vus); + VADDUHM addv8hi3 {} + + const vus __builtin_altivec_vadduhs (vus, vus); + VADDUHS altivec_vadduhs {} + + const vsi __builtin_altivec_vadduwm (vsi, vsi); + VADDUWM addv4si3 {} + + const vui __builtin_altivec_vadduws (vui, vui); + VADDUWS altivec_vadduws {} + + const vsc __builtin_altivec_vand_v16qi (vsc, vsc); + VAND_V16QI andv16qi3 {} + + const vuc __builtin_altivec_vand_v16qi_uns (vuc, vuc); + VAND_V16QI_UNS andv16qi3 {} + + const vf __builtin_altivec_vand_v4sf (vf, vf); + VAND_V4SF andv4sf3 {} + + const vsi __builtin_altivec_vand_v4si (vsi, vsi); + VAND_V4SI andv4si3 {} + + const vui __builtin_altivec_vand_v4si_uns (vui, vui); + VAND_V4SI_UNS andv4si3 {} + + const vss __builtin_altivec_vand_v8hi (vss, vss); + VAND_V8HI andv8hi3 {} + + const vus __builtin_altivec_vand_v8hi_uns (vus, vus); + VAND_V8HI_UNS andv8hi3 {} + + const vsc __builtin_altivec_vandc_v16qi (vsc, vsc); + VANDC_V16QI andcv16qi3 {} + + const vuc __builtin_altivec_vandc_v16qi_uns (vuc, vuc); + VANDC_V16QI_UNS andcv16qi3 {} + + const vf __builtin_altivec_vandc_v4sf (vf, vf); + VANDC_V4SF andcv4sf3 {} + + const vsi __builtin_altivec_vandc_v4si (vsi, vsi); + VANDC_V4SI andcv4si3 {} + + const vui __builtin_altivec_vandc_v4si_uns (vui, vui); + VANDC_V4SI_UNS andcv4si3 {} + + const vss __builtin_altivec_vandc_v8hi (vss, vss); + VANDC_V8HI andcv8hi3 {} + + const vus __builtin_altivec_vandc_v8hi_uns (vus, vus); + VANDC_V8HI_UNS andcv8hi3 {} + + const vsc __builtin_altivec_vavgsb (vsc, vsc); + VAVGSB avgv16qi3_ceil {} + + const vss __builtin_altivec_vavgsh (vss, vss); + VAVGSH avgv8hi3_ceil {} + + const vsi __builtin_altivec_vavgsw (vsi, vsi); + VAVGSW avgv4si3_ceil {} + + const vuc __builtin_altivec_vavgub (vuc, vuc); + VAVGUB uavgv16qi3_ceil {} + + const vus __builtin_altivec_vavguh (vus, vus); + VAVGUH uavgv8hi3_ceil {} + + const vui __builtin_altivec_vavguw (vui, vui); + VAVGUW uavgv4si3_ceil {} + + const vf __builtin_altivec_vcfsx (vsi, const int<5>); + VCFSX altivec_vcfsx {} + + const vf __builtin_altivec_vcfux (vui, const int<5>); + VCFUX altivec_vcfux {} + + const vsi __builtin_altivec_vcmpbfp (vf, vf); + VCMPBFP altivec_vcmpbfp {} + + const int __builtin_altivec_vcmpbfp_p (int, vf, vf); + VCMPBFP_P altivec_vcmpbfp_p {pred} + + const vf __builtin_altivec_vcmpeqfp (vf, vf); + VCMPEQFP vector_eqv4sf {} + + const int __builtin_altivec_vcmpeqfp_p (int, vf, vf); + VCMPEQFP_P vector_eq_v4sf_p {pred} + + const vsc __builtin_altivec_vcmpequb (vuc, vuc); + VCMPEQUB vector_eqv16qi {} + + const int __builtin_altivec_vcmpequb_p (int, vsc, vsc); + VCMPEQUB_P vector_eq_v16qi_p {pred} + + const vss __builtin_altivec_vcmpequh (vus, vus); + VCMPEQUH vector_eqv8hi {} + + const int __builtin_altivec_vcmpequh_p (int, vss, vss); + VCMPEQUH_P vector_eq_v8hi_p {pred} + + const vsi __builtin_altivec_vcmpequw (vui, vui); + VCMPEQUW vector_eqv4si {} + + const int __builtin_altivec_vcmpequw_p (int, vsi, vsi); + VCMPEQUW_P vector_eq_v4si_p {pred} + + const vf __builtin_altivec_vcmpgefp (vf, vf); + VCMPGEFP vector_gev4sf {} + + const int __builtin_altivec_vcmpgefp_p (int, vf, vf); + VCMPGEFP_P vector_ge_v4sf_p {pred} + + const vf __builtin_altivec_vcmpgtfp (vf, vf); + VCMPGTFP vector_gtv4sf {} + + const int __builtin_altivec_vcmpgtfp_p (int, vf, vf); + VCMPGTFP_P vector_gt_v4sf_p {pred} + + const vsc __builtin_altivec_vcmpgtsb (vsc, vsc); + VCMPGTSB vector_gtv16qi {} + + const int __builtin_altivec_vcmpgtsb_p (int, vsc, vsc); + VCMPGTSB_P vector_gt_v16qi_p {pred} + + const vss __builtin_altivec_vcmpgtsh (vss, vss); + VCMPGTSH vector_gtv8hi {} + + const int __builtin_altivec_vcmpgtsh_p (int, vss, vss); + VCMPGTSH_P vector_gt_v8hi_p {pred} + + const vsi __builtin_altivec_vcmpgtsw (vsi, vsi); + VCMPGTSW vector_gtv4si {} + + const int __builtin_altivec_vcmpgtsw_p (int, vsi, vsi); + VCMPGTSW_P vector_gt_v4si_p {pred} + + const vsc __builtin_altivec_vcmpgtub (vuc, vuc); + VCMPGTUB vector_gtuv16qi {} + + const int __builtin_altivec_vcmpgtub_p (int, vsc, vsc); + VCMPGTUB_P vector_gtu_v16qi_p {pred} + + const vss __builtin_altivec_vcmpgtuh (vus, vus); + VCMPGTUH vector_gtuv8hi {} + + const int __builtin_altivec_vcmpgtuh_p (int, vss, vss); + VCMPGTUH_P vector_gtu_v8hi_p {pred} + + const vsi __builtin_altivec_vcmpgtuw (vui, vui); + VCMPGTUW vector_gtuv4si {} + + const int __builtin_altivec_vcmpgtuw_p (int, vsi, vsi); + VCMPGTUW_P vector_gtu_v4si_p {pred} + + const vsi __builtin_altivec_vctsxs (vf, const int<5>); + VCTSXS altivec_vctsxs {} + + const vui __builtin_altivec_vctuxs (vf, const int<5>); + VCTUXS altivec_vctuxs {} + + fpmath vf __builtin_altivec_vexptefp (vf); + VEXPTEFP altivec_vexptefp {} + + fpmath vf __builtin_altivec_vlogefp (vf); + VLOGEFP altivec_vlogefp {} + + fpmath vf __builtin_altivec_vmaddfp (vf, vf, vf); + VMADDFP fmav4sf4 {} + + const vf __builtin_altivec_vmaxfp (vf, vf); + VMAXFP smaxv4sf3 {} + + const vsc __builtin_altivec_vmaxsb (vsc, vsc); + VMAXSB smaxv16qi3 {} + + const vuc __builtin_altivec_vmaxub (vuc, vuc); + VMAXUB umaxv16qi3 {} + + const vss __builtin_altivec_vmaxsh (vss, vss); + VMAXSH smaxv8hi3 {} + + const vsi __builtin_altivec_vmaxsw (vsi, vsi); + VMAXSW smaxv4si3 {} + + const vus __builtin_altivec_vmaxuh (vus, vus); + VMAXUH umaxv8hi3 {} + + const vui __builtin_altivec_vmaxuw (vui, vui); + VMAXUW umaxv4si3 {} + + vss __builtin_altivec_vmhaddshs (vss, vss, vss); + VMHADDSHS altivec_vmhaddshs {} + + vss __builtin_altivec_vmhraddshs (vss, vss, vss); + VMHRADDSHS altivec_vmhraddshs {} + + const vf __builtin_altivec_vminfp (vf, vf); + VMINFP sminv4sf3 {} + + const vsc __builtin_altivec_vminsb (vsc, vsc); + VMINSB sminv16qi3 {} + + const vss __builtin_altivec_vminsh (vss, vss); + VMINSH sminv8hi3 {} + + const vsi __builtin_altivec_vminsw (vsi, vsi); + VMINSW sminv4si3 {} + + const vuc __builtin_altivec_vminub (vuc, vuc); + VMINUB uminv16qi3 {} + + const vus __builtin_altivec_vminuh (vus, vus); + VMINUH uminv8hi3 {} + + const vui __builtin_altivec_vminuw (vui, vui); + VMINUW uminv4si3 {} + + const vss __builtin_altivec_vmladduhm (vss, vss, vss); + VMLADDUHM fmav8hi4 {} + + const vsc __builtin_altivec_vmrghb (vsc, vsc); + VMRGHB altivec_vmrghb {} + + const vss __builtin_altivec_vmrghh (vss, vss); + VMRGHH altivec_vmrghh {} + + const vsi __builtin_altivec_vmrghw (vsi, vsi); + VMRGHW altivec_vmrghw {} + + const vsc __builtin_altivec_vmrglb (vsc, vsc); + VMRGLB altivec_vmrglb {} + + const vss __builtin_altivec_vmrglh (vss, vss); + VMRGLH altivec_vmrglh {} + + const vsi __builtin_altivec_vmrglw (vsi, vsi); + VMRGLW altivec_vmrglw {} + + const vsi __builtin_altivec_vmsummbm (vsc, vuc, vsi); + VMSUMMBM altivec_vmsummbm {} + + const vsi __builtin_altivec_vmsumshm (vss, vss, vsi); + VMSUMSHM altivec_vmsumshm {} + + vsi __builtin_altivec_vmsumshs (vss, vss, vsi); + VMSUMSHS altivec_vmsumshs {} + + const vui __builtin_altivec_vmsumubm (vuc, vuc, vui); + VMSUMUBM altivec_vmsumubm {} + + const vui __builtin_altivec_vmsumuhm (vus, vus, vui); + VMSUMUHM altivec_vmsumuhm {} + + vui __builtin_altivec_vmsumuhs (vus, vus, vui); + VMSUMUHS altivec_vmsumuhs {} + + const vss __builtin_altivec_vmulesb (vsc, vsc); + VMULESB vec_widen_smult_even_v16qi {} + + const vsi __builtin_altivec_vmulesh (vss, vss); + VMULESH vec_widen_smult_even_v8hi {} + + const vus __builtin_altivec_vmuleub (vuc, vuc); + VMULEUB vec_widen_umult_even_v16qi {} + + const vui __builtin_altivec_vmuleuh (vus, vus); + VMULEUH vec_widen_umult_even_v8hi {} + + const vss __builtin_altivec_vmulosb (vsc, vsc); + VMULOSB vec_widen_smult_odd_v16qi {} + + const vus __builtin_altivec_vmuloub (vuc, vuc); + VMULOUB vec_widen_umult_odd_v16qi {} + + const vsi __builtin_altivec_vmulosh (vss, vss); + VMULOSH vec_widen_smult_odd_v8hi {} + + const vui __builtin_altivec_vmulouh (vus, vus); + VMULOUH vec_widen_umult_odd_v8hi {} + + fpmath vf __builtin_altivec_vnmsubfp (vf, vf, vf); + VNMSUBFP nfmsv4sf4 {} + + const vsc __builtin_altivec_vnor_v16qi (vsc, vsc); + VNOR_V16QI norv16qi3 {} + + const vuc __builtin_altivec_vnor_v16qi_uns (vuc, vuc); + VNOR_V16QI_UNS norv16qi3 {} + + const vf __builtin_altivec_vnor_v4sf (vf, vf); + VNOR_V4SF norv4sf3 {} + + const vsi __builtin_altivec_vnor_v4si (vsi, vsi); + VNOR_V4SI norv4si3 {} + + const vui __builtin_altivec_vnor_v4si_uns (vui, vui); + VNOR_V4SI_UNS norv4si3 {} + + const vss __builtin_altivec_vnor_v8hi (vss, vss); + VNOR_V8HI norv8hi3 {} + + const vus __builtin_altivec_vnor_v8hi_uns (vus, vus); + VNOR_V8HI_UNS norv8hi3 {} + + const vsc __builtin_altivec_vor_v16qi (vsc, vsc); + VOR_V16QI iorv16qi3 {} + + const vuc __builtin_altivec_vor_v16qi_uns (vuc, vuc); + VOR_V16QI_UNS iorv16qi3 {} + + const vf __builtin_altivec_vor_v4sf (vf, vf); + VOR_V4SF iorv4sf3 {} + + const vsi __builtin_altivec_vor_v4si (vsi, vsi); + VOR_V4SI iorv4si3 {} + + const vui __builtin_altivec_vor_v4si_uns (vui, vui); + VOR_V4SI_UNS iorv4si3 {} + + const vss __builtin_altivec_vor_v8hi (vss, vss); + VOR_V8HI iorv8hi3 {} + + const vus __builtin_altivec_vor_v8hi_uns (vus, vus); + VOR_V8HI_UNS iorv8hi3 {} + + const vsc __builtin_altivec_vperm_16qi (vsc, vsc, vuc); + VPERM_16QI altivec_vperm_v16qi {} + + const vuc __builtin_altivec_vperm_16qi_uns (vuc, vuc, vuc); + VPERM_16QI_UNS altivec_vperm_v16qi_uns {} + + const vsq __builtin_altivec_vperm_1ti (vsq, vsq, vuc); + VPERM_1TI altivec_vperm_v1ti {} + + const vuq __builtin_altivec_vperm_1ti_uns (vuq, vuq, vuc); + VPERM_1TI_UNS altivec_vperm_v1ti_uns {} + + const vf __builtin_altivec_vperm_4sf (vf, vf, vuc); + VPERM_4SF altivec_vperm_v4sf {} + + const vsi __builtin_altivec_vperm_4si (vsi, vsi, vuc); + VPERM_4SI altivec_vperm_v4si {} + + const vui __builtin_altivec_vperm_4si_uns (vui, vui, vuc); + VPERM_4SI_UNS altivec_vperm_v4si_uns {} + + const vss __builtin_altivec_vperm_8hi (vss, vss, vuc); + VPERM_8HI altivec_vperm_v8hi {} + + const vus __builtin_altivec_vperm_8hi_uns (vus, vus, vuc); + VPERM_8HI_UNS altivec_vperm_v8hi_uns {} + + const vp __builtin_altivec_vpkpx (vui, vui); + VPKPX altivec_vpkpx {} + + const vsc __builtin_altivec_vpkshss (vss, vss); + VPKSHSS altivec_vpkshss {} + + const vuc __builtin_altivec_vpkshus (vss, vss); + VPKSHUS altivec_vpkshus {} + + const vss __builtin_altivec_vpkswss (vsi, vsi); + VPKSWSS altivec_vpkswss {} + + const vus __builtin_altivec_vpkswus (vsi, vsi); + VPKSWUS altivec_vpkswus {} + + const vsc __builtin_altivec_vpkuhum (vss, vss); + VPKUHUM altivec_vpkuhum {} + + const vuc __builtin_altivec_vpkuhus (vus, vus); + VPKUHUS altivec_vpkuhus {} + + const vss __builtin_altivec_vpkuwum (vsi, vsi); + VPKUWUM altivec_vpkuwum {} + + const vus __builtin_altivec_vpkuwus (vui, vui); + VPKUWUS altivec_vpkuwus {} + + const vf __builtin_altivec_vrecipdivfp (vf, vf); + VRECIPFP recipv4sf3 {} + + fpmath vf __builtin_altivec_vrefp (vf); + VREFP rev4sf2 {} + + const vsc __builtin_altivec_vreve_v16qi (vsc); + VREVE_V16QI altivec_vrevev16qi2 {} + + const vf __builtin_altivec_vreve_v4sf (vf); + VREVE_V4SF altivec_vrevev4sf2 {} + + const vsi __builtin_altivec_vreve_v4si (vsi); + VREVE_V4SI altivec_vrevev4si2 {} + + const vss __builtin_altivec_vreve_v8hi (vss); + VREVE_V8HI altivec_vrevev8hi2 {} + + fpmath vf __builtin_altivec_vrfim (vf); + VRFIM vector_floorv4sf2 {} + + fpmath vf __builtin_altivec_vrfin (vf); + VRFIN altivec_vrfin {} + + fpmath vf __builtin_altivec_vrfip (vf); + VRFIP vector_ceilv4sf2 {} + + fpmath vf __builtin_altivec_vrfiz (vf); + VRFIZ vector_btruncv4sf2 {} + + const vsc __builtin_altivec_vrlb (vsc, vsc); + VRLB vrotlv16qi3 {} + + const vss __builtin_altivec_vrlh (vss, vss); + VRLH vrotlv8hi3 {} + + const vsi __builtin_altivec_vrlw (vsi, vsi); + VRLW vrotlv4si3 {} + + fpmath vf __builtin_altivec_vrsqrtefp (vf); + VRSQRTEFP rsqrtev4sf2 {} + + fpmath vf __builtin_altivec_vrsqrtfp (vf); + VRSQRTFP rsqrtv4sf2 {} + + const vsc __builtin_altivec_vsel_16qi (vsc, vsc, vuc); + VSEL_16QI vector_select_v16qi {} + + const vuc __builtin_altivec_vsel_16qi_uns (vuc, vuc, vuc); + VSEL_16QI_UNS vector_select_v16qi_uns {} + + const vsq __builtin_altivec_vsel_1ti (vsq, vsq, vuq); + VSEL_1TI vector_select_v1ti {} + + const vuq __builtin_altivec_vsel_1ti_uns (vuq, vuq, vuq); + VSEL_1TI_UNS vector_select_v1ti_uns {} + + const vf __builtin_altivec_vsel_4sf (vf, vf, vf); + VSEL_4SF vector_select_v4sf {} + + const vsi __builtin_altivec_vsel_4si (vsi, vsi, vui); + VSEL_4SI vector_select_v4si {} + + const vui __builtin_altivec_vsel_4si_uns (vui, vui, vui); + VSEL_4SI_UNS vector_select_v4si_uns {} + + const vss __builtin_altivec_vsel_8hi (vss, vss, vus); + VSEL_8HI vector_select_v8hi {} + + const vus __builtin_altivec_vsel_8hi_uns (vus, vus, vus); + VSEL_8HI_UNS vector_select_v8hi_uns {} + + const vsi __builtin_altivec_vsl (vsi, vsi); + VSL altivec_vsl {} + + const vsc __builtin_altivec_vslb (vsc, vuc); + VSLB vashlv16qi3 {} + + const vsc __builtin_altivec_vsldoi_16qi (vsc, vsc, const int<4>); + VSLDOI_16QI altivec_vsldoi_v16qi {} + + const vf __builtin_altivec_vsldoi_4sf (vf, vf, const int<4>); + VSLDOI_4SF altivec_vsldoi_v4sf {} + + const vsi __builtin_altivec_vsldoi_4si (vsi, vsi, const int<4>); + VSLDOI_4SI altivec_vsldoi_v4si {} + + const vss __builtin_altivec_vsldoi_8hi (vss, vss, const int<4>); + VSLDOI_8HI altivec_vsldoi_v8hi {} + + const vss __builtin_altivec_vslh (vss, vus); + VSLH vashlv8hi3 {} + + const vsi __builtin_altivec_vslo (vsi, vsi); + VSLO altivec_vslo {} + + const vsi __builtin_altivec_vslw (vsi, vui); + VSLW vashlv4si3 {} + + const vsc __builtin_altivec_vspltb (vsc, const int<4>); + VSPLTB altivec_vspltb {} + + const vss __builtin_altivec_vsplth (vss, const int<3>); + VSPLTH altivec_vsplth {} + + const vsc __builtin_altivec_vspltisb (const int<-16,15>); + VSPLTISB altivec_vspltisb {} + + const vss __builtin_altivec_vspltish (const int<-16,15>); + VSPLTISH altivec_vspltish {} + + const vsi __builtin_altivec_vspltisw (const int<-16,15>); + VSPLTISW altivec_vspltisw {} + + const vsi __builtin_altivec_vspltw (vsi, const int<2>); + VSPLTW altivec_vspltw {} + + const vsi __builtin_altivec_vsr (vsi, vsi); + VSR altivec_vsr {} + + const vsc __builtin_altivec_vsrab (vsc, vuc); + VSRAB vashrv16qi3 {} + + const vss __builtin_altivec_vsrah (vss, vus); + VSRAH vashrv8hi3 {} + + const vsi __builtin_altivec_vsraw (vsi, vui); + VSRAW vashrv4si3 {} + + const vsc __builtin_altivec_vsrb (vsc, vuc); + VSRB vlshrv16qi3 {} + + const vss __builtin_altivec_vsrh (vss, vus); + VSRH vlshrv8hi3 {} + + const vsi __builtin_altivec_vsro (vsi, vsi); + VSRO altivec_vsro {} + + const vsi __builtin_altivec_vsrw (vsi, vui); + VSRW vlshrv4si3 {} + + const vsi __builtin_altivec_vsubcuw (vsi, vsi); + VSUBCUW altivec_vsubcuw {} + + const vf __builtin_altivec_vsubfp (vf, vf); + VSUBFP subv4sf3 {} + + const vsc __builtin_altivec_vsubsbs (vsc, vsc); + VSUBSBS altivec_vsubsbs {} + + const vss __builtin_altivec_vsubshs (vss, vss); + VSUBSHS altivec_vsubshs {} + + const vsi __builtin_altivec_vsubsws (vsi, vsi); + VSUBSWS altivec_vsubsws {} + + const vuc __builtin_altivec_vsububm (vuc, vuc); + VSUBUBM subv16qi3 {} + + const vuc __builtin_altivec_vsububs (vuc, vuc); + VSUBUBS altivec_vsububs {} + + const vus __builtin_altivec_vsubuhm (vus, vus); + VSUBUHM subv8hi3 {} + + const vus __builtin_altivec_vsubuhs (vus, vus); + VSUBUHS altivec_vsubuhs {} + + const vui __builtin_altivec_vsubuwm (vui, vui); + VSUBUWM subv4si3 {} + + const vui __builtin_altivec_vsubuws (vui, vui); + VSUBUWS altivec_vsubuws {} + + const vsi __builtin_altivec_vsum2sws (vsi, vsi); + VSUM2SWS altivec_vsum2sws {} + + const vsi __builtin_altivec_vsum4sbs (vsc, vsi); + VSUM4SBS altivec_vsum4sbs {} + + const vsi __builtin_altivec_vsum4shs (vss, vsi); + VSUM4SHS altivec_vsum4shs {} + + const vui __builtin_altivec_vsum4ubs (vuc, vui); + VSUM4UBS altivec_vsum4ubs {} + + const vsi __builtin_altivec_vsumsws (vsi, vsi); + VSUMSWS altivec_vsumsws {} + + const vsi __builtin_altivec_vsumsws_be (vsi, vsi); + VSUMSWS_BE altivec_vsumsws_direct {} + + const vui __builtin_altivec_vupkhpx (vp); + VUPKHPX altivec_vupkhpx {} + + const vss __builtin_altivec_vupkhsb (vsc); + VUPKHSB altivec_vupkhsb {} + + const vsi __builtin_altivec_vupkhsh (vss); + VUPKHSH altivec_vupkhsh {} + + const vui __builtin_altivec_vupklpx (vp); + VUPKLPX altivec_vupklpx {} + + const vss __builtin_altivec_vupklsb (vsc); + VUPKLSB altivec_vupklsb {} + + const vsi __builtin_altivec_vupklsh (vss); + VUPKLSH altivec_vupklsh {} + + const vsc __builtin_altivec_vxor_v16qi (vsc, vsc); + VXOR_V16QI xorv16qi3 {} + + const vuc __builtin_altivec_vxor_v16qi_uns (vuc, vuc); + VXOR_V16QI_UNS xorv16qi3 {} + + const vf __builtin_altivec_vxor_v4sf (vf, vf); + VXOR_V4SF xorv4sf3 {} + + const vsi __builtin_altivec_vxor_v4si (vsi, vsi); + VXOR_V4SI xorv4si3 {} + + const vui __builtin_altivec_vxor_v4si_uns (vui, vui); + VXOR_V4SI_UNS xorv4si3 {} + + const vss __builtin_altivec_vxor_v8hi (vss, vss); + VXOR_V8HI xorv8hi3 {} + + const vus __builtin_altivec_vxor_v8hi_uns (vus, vus); + VXOR_V8HI_UNS xorv8hi3 {} + + const signed char __builtin_vec_ext_v16qi (vsc, signed int); + VEC_EXT_V16QI nothing {extract} + + const float __builtin_vec_ext_v4sf (vf, signed int); + VEC_EXT_V4SF nothing {extract} + + const signed int __builtin_vec_ext_v4si (vsi, signed int); + VEC_EXT_V4SI nothing {extract} + + const signed short __builtin_vec_ext_v8hi (vss, signed int); + VEC_EXT_V8HI nothing {extract} + + const vsc __builtin_vec_init_v16qi (signed char, signed char, signed char, signed char, signed char, signed char, signed char, signed char, signed char, signed char, signed char, signed char, signed char, signed char, signed char, signed char); + VEC_INIT_V16QI nothing {init} + + const vf __builtin_vec_init_v4sf (float, float, float, float); + VEC_INIT_V4SF nothing {init} + + const vsi __builtin_vec_init_v4si (signed int, signed int, signed int, signed int); + VEC_INIT_V4SI nothing {init} + + const vss __builtin_vec_init_v8hi (signed short, signed short, signed short, signed short, signed short, signed short, signed short, signed short); + VEC_INIT_V8HI nothing {init} + + const vsc __builtin_vec_set_v16qi (vsc, signed char, const int<4>); + VEC_SET_V16QI nothing {set} + + const vf __builtin_vec_set_v4sf (vf, float, const int<2>); + VEC_SET_V4SF nothing {set} + + const vsi __builtin_vec_set_v4si (vsi, signed int, const int<2>); + VEC_SET_V4SI nothing {set} + + const vss __builtin_vec_set_v8hi (vss, signed short, const int<3>); + VEC_SET_V8HI nothing {set} + + +; VSX builtins. +[vsx] + pure vd __builtin_altivec_lvx_v2df (signed long, const void *); + LVX_V2DF altivec_lvx_v2df {ldvec} + + pure vsll __builtin_altivec_lvx_v2di (signed long, const void *); + LVX_V2DI altivec_lvx_v2di {ldvec} + + pure vd __builtin_altivec_lvxl_v2df (signed long, const void *); + LVXL_V2DF altivec_lvxl_v2df {ldvec} + + pure vsll __builtin_altivec_lvxl_v2di (signed long, const void *); + LVXL_V2DI altivec_lvxl_v2di {ldvec} + + const vd __builtin_altivec_nabs_v2df (vd); + NABS_V2DF vsx_nabsv2df2 {} + + const vsll __builtin_altivec_nabs_v2di (vsll); + NABS_V2DI nabsv2di2 {} + + void __builtin_altivec_stvx_v2df (vd, signed long, void *); + STVX_V2DF altivec_stvx_v2df {stvec} + + void __builtin_altivec_stvx_v2di (vsll, signed long, void *); + STVX_V2DI altivec_stvx_v2di {stvec} + + void __builtin_altivec_stvxl_v2df (vd, signed long, void *); + STVXL_V2DF altivec_stvxl_v2df {stvec} + + void __builtin_altivec_stvxl_v2di (vsll, signed long, void *); + STVXL_V2DI altivec_stvxl_v2di {stvec} + + const vd __builtin_altivec_vand_v2df (vd, vd); + VAND_V2DF andv2df3 {} + + const vsll __builtin_altivec_vand_v2di (vsll, vsll); + VAND_V2DI andv2di3 {} + + const vull __builtin_altivec_vand_v2di_uns (vull, vull); + VAND_V2DI_UNS andv2di3 {} + + const vd __builtin_altivec_vandc_v2df (vd, vd); + VANDC_V2DF andcv2df3 {} + + const vsll __builtin_altivec_vandc_v2di (vsll, vsll); + VANDC_V2DI andcv2di3 {} + + const vull __builtin_altivec_vandc_v2di_uns (vull, vull); + VANDC_V2DI_UNS andcv2di3 {} + + const vsll __builtin_altivec_vcmpequd (vull, vull); + VCMPEQUD vector_eqv2di {} + + const int __builtin_altivec_vcmpequd_p (int, vsll, vsll); + VCMPEQUD_P vector_eq_v2di_p {pred} + + const vsll __builtin_altivec_vcmpgtsd (vsll, vsll); + VCMPGTSD vector_gtv2di {} + + const int __builtin_altivec_vcmpgtsd_p (int, vsll, vsll); + VCMPGTSD_P vector_gt_v2di_p {pred} + + const vsll __builtin_altivec_vcmpgtud (vull, vull); + VCMPGTUD vector_gtuv2di {} + + const int __builtin_altivec_vcmpgtud_p (int, vsll, vsll); + VCMPGTUD_P vector_gtu_v2di_p {pred} + + const vd __builtin_altivec_vnor_v2df (vd, vd); + VNOR_V2DF norv2df3 {} + + const vsll __builtin_altivec_vnor_v2di (vsll, vsll); + VNOR_V2DI norv2di3 {} + + const vull __builtin_altivec_vnor_v2di_uns (vull, vull); + VNOR_V2DI_UNS norv2di3 {} + + const vd __builtin_altivec_vor_v2df (vd, vd); + VOR_V2DF iorv2df3 {} + + const vsll __builtin_altivec_vor_v2di (vsll, vsll); + VOR_V2DI iorv2di3 {} + + const vull __builtin_altivec_vor_v2di_uns (vull, vull); + VOR_V2DI_UNS iorv2di3 {} + + const vd __builtin_altivec_vperm_2df (vd, vd, vuc); + VPERM_2DF altivec_vperm_v2df {} + + const vsll __builtin_altivec_vperm_2di (vsll, vsll, vuc); + VPERM_2DI altivec_vperm_v2di {} + + const vull __builtin_altivec_vperm_2di_uns (vull, vull, vuc); + VPERM_2DI_UNS altivec_vperm_v2di_uns {} + + const vd __builtin_altivec_vreve_v2df (vd); + VREVE_V2DF altivec_vrevev2df2 {} + + const vsll __builtin_altivec_vreve_v2di (vsll); + VREVE_V2DI altivec_vrevev2di2 {} + + const vd __builtin_altivec_vsel_2df (vd, vd, vd); + VSEL_2DF vector_select_v2df {} + + const vsll __builtin_altivec_vsel_2di (vsll, vsll, vsll); + VSEL_2DI_B vector_select_v2di {} + + const vull __builtin_altivec_vsel_2di_uns (vull, vull, vull); + VSEL_2DI_UNS vector_select_v2di_uns {} + + const vd __builtin_altivec_vsldoi_2df (vd, vd, const int<4>); + VSLDOI_2DF altivec_vsldoi_v2df {} + + const vsll __builtin_altivec_vsldoi_2di (vsll, vsll, const int<4>); + VSLDOI_2DI altivec_vsldoi_v2di {} + + const vd __builtin_altivec_vxor_v2df (vd, vd); + VXOR_V2DF xorv2df3 {} + + const vsll __builtin_altivec_vxor_v2di (vsll, vsll); + VXOR_V2DI xorv2di3 {} + + const vull __builtin_altivec_vxor_v2di_uns (vull, vull); + VXOR_V2DI_UNS xorv2di3 {} + + const signed __int128 __builtin_vec_ext_v1ti (vsq, signed int); + VEC_EXT_V1TI nothing {extract} + + const double __builtin_vec_ext_v2df (vd, signed int); + VEC_EXT_V2DF nothing {extract} + + const signed long long __builtin_vec_ext_v2di (vsll, signed int); + VEC_EXT_V2DI nothing {extract} + + const vsq __builtin_vec_init_v1ti (signed __int128); + VEC_INIT_V1TI nothing {init} + + const vd __builtin_vec_init_v2df (double, double); + VEC_INIT_V2DF nothing {init} + + const vsll __builtin_vec_init_v2di (signed long long, signed long long); + VEC_INIT_V2DI nothing {init} + + const vsq __builtin_vec_set_v1ti (vsq, signed __int128, const int<0,0>); + VEC_SET_V1TI nothing {set} + + const vd __builtin_vec_set_v2df (vd, double, const int<1>); + VEC_SET_V2DF nothing {set} + + const vsll __builtin_vec_set_v2di (vsll, signed long long, const int<1>); + VEC_SET_V2DI nothing {set} + + const vsc __builtin_vsx_cmpge_16qi (vsc, vsc); + CMPGE_16QI vector_nltv16qi {} + + const vsll __builtin_vsx_cmpge_2di (vsll, vsll); + CMPGE_2DI vector_nltv2di {} + + const vsi __builtin_vsx_cmpge_4si (vsi, vsi); + CMPGE_4SI vector_nltv4si {} + + const vss __builtin_vsx_cmpge_8hi (vss, vss); + CMPGE_8HI vector_nltv8hi {} + + const vsc __builtin_vsx_cmpge_u16qi (vuc, vuc); + CMPGE_U16QI vector_nltuv16qi {} + + const vsll __builtin_vsx_cmpge_u2di (vull, vull); + CMPGE_U2DI vector_nltuv2di {} + + const vsi __builtin_vsx_cmpge_u4si (vui, vui); + CMPGE_U4SI vector_nltuv4si {} + + const vss __builtin_vsx_cmpge_u8hi (vus, vus); + CMPGE_U8HI vector_nltuv8hi {} + + const vsc __builtin_vsx_cmple_16qi (vsc, vsc); + CMPLE_16QI vector_ngtv16qi {} + + const vsll __builtin_vsx_cmple_2di (vsll, vsll); + CMPLE_2DI vector_ngtv2di {} + + const vsi __builtin_vsx_cmple_4si (vsi, vsi); + CMPLE_4SI vector_ngtv4si {} + + const vss __builtin_vsx_cmple_8hi (vss, vss); + CMPLE_8HI vector_ngtv8hi {} + + const vsc __builtin_vsx_cmple_u16qi (vsc, vsc); + CMPLE_U16QI vector_ngtuv16qi {} + + const vsll __builtin_vsx_cmple_u2di (vsll, vsll); + CMPLE_U2DI vector_ngtuv2di {} + + const vsi __builtin_vsx_cmple_u4si (vsi, vsi); + CMPLE_U4SI vector_ngtuv4si {} + + const vss __builtin_vsx_cmple_u8hi (vss, vss); + CMPLE_U8HI vector_ngtuv8hi {} + + const vd __builtin_vsx_concat_2df (double, double); + CONCAT_2DF vsx_concat_v2df {} + + const vsll __builtin_vsx_concat_2di (signed long long, signed long long); + CONCAT_2DI vsx_concat_v2di {} + + const vd __builtin_vsx_cpsgndp (vd, vd); + CPSGNDP vector_copysignv2df3 {} + + const vf __builtin_vsx_cpsgnsp (vf, vf); + CPSGNSP vector_copysignv4sf3 {} + + const vsll __builtin_vsx_div_2di (vsll, vsll); + DIV_V2DI vsx_div_v2di {} + + const vd __builtin_vsx_doublee_v4sf (vf); + DOUBLEE_V4SF doubleev4sf2 {} + + const vd __builtin_vsx_doublee_v4si (vsi); + DOUBLEE_V4SI doubleev4si2 {} + + const vd __builtin_vsx_doubleh_v4sf (vf); + DOUBLEH_V4SF doublehv4sf2 {} + + const vd __builtin_vsx_doubleh_v4si (vsi); + DOUBLEH_V4SI doublehv4si2 {} + + const vd __builtin_vsx_doublel_v4sf (vf); + DOUBLEL_V4SF doublelv4sf2 {} + + const vd __builtin_vsx_doublel_v4si (vsi); + DOUBLEL_V4SI doublelv4si2 {} + + const vd __builtin_vsx_doubleo_v4sf (vf); + DOUBLEO_V4SF doubleov4sf2 {} + + const vd __builtin_vsx_doubleo_v4si (vsi); + DOUBLEO_V4SI doubleov4si2 {} + + const vf __builtin_vsx_floate_v2df (vd); + FLOATE_V2DF floatev2df {} + + const vf __builtin_vsx_floate_v2di (vsll); + FLOATE_V2DI floatev2di {} + + const vf __builtin_vsx_floato_v2df (vd); + FLOATO_V2DF floatov2df {} + + const vf __builtin_vsx_floato_v2di (vsll); + FLOATO_V2DI floatov2di {} + + pure vsq __builtin_vsx_ld_elemrev_v1ti (signed long, const void *); + LD_ELEMREV_V1TI vsx_ld_elemrev_v1ti {ldvec,endian} + + pure vd __builtin_vsx_ld_elemrev_v2df (signed long, const void *); + LD_ELEMREV_V2DF vsx_ld_elemrev_v2df {ldvec,endian} + + pure vsll __builtin_vsx_ld_elemrev_v2di (signed long, const void *); + LD_ELEMREV_V2DI vsx_ld_elemrev_v2di {ldvec,endian} + + pure vf __builtin_vsx_ld_elemrev_v4sf (signed long, const void *); + LD_ELEMREV_V4SF vsx_ld_elemrev_v4sf {ldvec,endian} + + pure vsi __builtin_vsx_ld_elemrev_v4si (signed long, const void *); + LD_ELEMREV_V4SI vsx_ld_elemrev_v4si {ldvec,endian} + + pure vss __builtin_vsx_ld_elemrev_v8hi (signed long, const void *); + LD_ELEMREV_V8HI vsx_ld_elemrev_v8hi {ldvec,endian} + + pure vsc __builtin_vsx_ld_elemrev_v16qi (signed long, const void *); + LD_ELEMREV_V16QI vsx_ld_elemrev_v16qi {ldvec,endian} + +; TODO: There is apparent intent in rs6000-builtin.def to have +; RS6000_BTC_SPECIAL processing for LXSDX, LXVDSX, and STXSDX, but there are +; no def_builtin calls for any of them. At some point, we may want to add a +; set of built-ins for whichever vector types make sense for these. + + pure vsq __builtin_vsx_lxvd2x_v1ti (signed long, const void *); + LXVD2X_V1TI vsx_load_v1ti {ldvec} + + pure vd __builtin_vsx_lxvd2x_v2df (signed long, const void *); + LXVD2X_V2DF vsx_load_v2df {ldvec} + + pure vsll __builtin_vsx_lxvd2x_v2di (signed long, const void *); + LXVD2X_V2DI vsx_load_v2di {ldvec} + + pure vsc __builtin_vsx_lxvw4x_v16qi (signed long, const void *); + LXVW4X_V16QI vsx_load_v16qi {ldvec} + + pure vf __builtin_vsx_lxvw4x_v4sf (signed long, const void *); + LXVW4X_V4SF vsx_load_v4sf {ldvec} + + pure vsi __builtin_vsx_lxvw4x_v4si (signed long, const void *); + LXVW4X_V4SI vsx_load_v4si {ldvec} + + pure vss __builtin_vsx_lxvw4x_v8hi (signed long, const void *); + LXVW4X_V8HI vsx_load_v8hi {ldvec} + + const vd __builtin_vsx_mergeh_2df (vd, vd); + VEC_MERGEH_V2DF vsx_mergeh_v2df {} + + const vsll __builtin_vsx_mergeh_2di (vsll, vsll); + VEC_MERGEH_V2DI vsx_mergeh_v2di {} + + const vd __builtin_vsx_mergel_2df (vd, vd); + VEC_MERGEL_V2DF vsx_mergel_v2df {} + + const vsll __builtin_vsx_mergel_2di (vsll, vsll); + VEC_MERGEL_V2DI vsx_mergel_v2di {} + + const vsll __builtin_vsx_mul_2di (vsll, vsll); + MUL_V2DI vsx_mul_v2di {} + + const vsq __builtin_vsx_set_1ti (vsq, signed __int128, const int<0,0>); + SET_1TI vsx_set_v1ti {set} + + const vd __builtin_vsx_set_2df (vd, double, const int<0,1>); + SET_2DF vsx_set_v2df {set} + + const vsll __builtin_vsx_set_2di (vsll, signed long long, const int<0,1>); + SET_2DI vsx_set_v2di {set} + + const vd __builtin_vsx_splat_2df (double); + SPLAT_2DF vsx_splat_v2df {} + + const vsll __builtin_vsx_splat_2di (signed long long); + SPLAT_2DI vsx_splat_v2di {} + + void __builtin_vsx_st_elemrev_v1ti (vsq, signed long, void *); + ST_ELEMREV_V1TI vsx_st_elemrev_v1ti {stvec,endian} + + void __builtin_vsx_st_elemrev_v2df (vd, signed long, void *); + ST_ELEMREV_V2DF vsx_st_elemrev_v2df {stvec,endian} + + void __builtin_vsx_st_elemrev_v2di (vsll, signed long, void *); + ST_ELEMREV_V2DI vsx_st_elemrev_v2di {stvec,endian} + + void __builtin_vsx_st_elemrev_v4sf (vf, signed long, void *); + ST_ELEMREV_V4SF vsx_st_elemrev_v4sf {stvec,endian} + + void __builtin_vsx_st_elemrev_v4si (vsi, signed long, void *); + ST_ELEMREV_V4SI vsx_st_elemrev_v4si {stvec,endian} + + void __builtin_vsx_st_elemrev_v8hi (vss, signed long, void *); + ST_ELEMREV_V8HI vsx_st_elemrev_v8hi {stvec,endian} + + void __builtin_vsx_st_elemrev_v16qi (vsc, signed long, void *); + ST_ELEMREV_V16QI vsx_st_elemrev_v16qi {stvec,endian} + + void __builtin_vsx_stxvd2x_v1ti (vsq, signed long, void *); + STXVD2X_V1TI vsx_store_v1ti {stvec} + + void __builtin_vsx_stxvd2x_v2df (vd, signed long, void *); + STXVD2X_V2DF vsx_store_v2df {stvec} + + void __builtin_vsx_stxvd2x_v2di (vsll, signed long, void *); + STXVD2X_V2DI vsx_store_v2di {stvec} + + void __builtin_vsx_stxvw4x_v4sf (vf, signed long, void *); + STXVW4X_V4SF vsx_store_v4sf {stvec} + + void __builtin_vsx_stxvw4x_v4si (vsi, signed long, void *); + STXVW4X_V4SI vsx_store_v4si {stvec} + + void __builtin_vsx_stxvw4x_v8hi (vss, signed long, void *); + STXVW4X_V8HI vsx_store_v8hi {stvec} + + void __builtin_vsx_stxvw4x_v16qi (vsc, signed long, void *); + STXVW4X_V16QI vsx_store_v16qi {stvec} + + const vull __builtin_vsx_udiv_2di (vull, vull); + UDIV_V2DI vsx_udiv_v2di {} + + const vd __builtin_vsx_uns_doublee_v4si (vsi); + UNS_DOUBLEE_V4SI unsdoubleev4si2 {} + + const vd __builtin_vsx_uns_doubleh_v4si (vsi); + UNS_DOUBLEH_V4SI unsdoublehv4si2 {} + + const vd __builtin_vsx_uns_doublel_v4si (vsi); + UNS_DOUBLEL_V4SI unsdoublelv4si2 {} + + const vd __builtin_vsx_uns_doubleo_v4si (vsi); + UNS_DOUBLEO_V4SI unsdoubleov4si2 {} + + const vf __builtin_vsx_uns_floate_v2di (vsll); + UNS_FLOATE_V2DI unsfloatev2di {} + + const vf __builtin_vsx_uns_floato_v2di (vsll); + UNS_FLOATO_V2DI unsfloatov2di {} + +; These are duplicates of __builtin_altivec_* counterparts, and are being +; kept for backwards compatibility. The reason for their existence is +; unclear. TODO: Consider deprecation/removal at some point. + const vsc __builtin_vsx_vperm_16qi (vsc, vsc, vuc); + VPERM_16QI_X altivec_vperm_v16qi {} + + const vuc __builtin_vsx_vperm_16qi_uns (vuc, vuc, vuc); + VPERM_16QI_UNS_X altivec_vperm_v16qi_uns {} + + const vsq __builtin_vsx_vperm_1ti (vsq, vsq, vsc); + VPERM_1TI_X altivec_vperm_v1ti {} + + const vsq __builtin_vsx_vperm_1ti_uns (vsq, vsq, vsc); + VPERM_1TI_UNS_X altivec_vperm_v1ti_uns {} + + const vd __builtin_vsx_vperm_2df (vd, vd, vuc); + VPERM_2DF_X altivec_vperm_v2df {} + + const vsll __builtin_vsx_vperm_2di (vsll, vsll, vuc); + VPERM_2DI_X altivec_vperm_v2di {} + + const vull __builtin_vsx_vperm_2di_uns (vull, vull, vuc); + VPERM_2DI_UNS_X altivec_vperm_v2di_uns {} + + const vf __builtin_vsx_vperm_4sf (vf, vf, vuc); + VPERM_4SF_X altivec_vperm_v4sf {} + + const vsi __builtin_vsx_vperm_4si (vsi, vsi, vuc); + VPERM_4SI_X altivec_vperm_v4si {} + + const vui __builtin_vsx_vperm_4si_uns (vui, vui, vuc); + VPERM_4SI_UNS_X altivec_vperm_v4si_uns {} + + const vss __builtin_vsx_vperm_8hi (vss, vss, vuc); + VPERM_8HI_X altivec_vperm_v8hi {} + + const vus __builtin_vsx_vperm_8hi_uns (vus, vus, vuc); + VPERM_8HI_UNS_X altivec_vperm_v8hi_uns {} + + const vsll __builtin_vsx_vsigned_v2df (vd); + VEC_VSIGNED_V2DF vsx_xvcvdpsxds {} + + const vsi __builtin_vsx_vsigned_v4sf (vf); + VEC_VSIGNED_V4SF vsx_xvcvspsxws {} + + const vsi __builtin_vsx_vsignede_v2df (vd); + VEC_VSIGNEDE_V2DF vsignede_v2df {} + + const vsi __builtin_vsx_vsignedo_v2df (vd); + VEC_VSIGNEDO_V2DF vsignedo_v2df {} + + const vsll __builtin_vsx_vunsigned_v2df (vd); + VEC_VUNSIGNED_V2DF vsx_xvcvdpsxds {} + + const vsi __builtin_vsx_vunsigned_v4sf (vf); + VEC_VUNSIGNED_V4SF vsx_xvcvspsxws {} + + const vsi __builtin_vsx_vunsignede_v2df (vd); + VEC_VUNSIGNEDE_V2DF vunsignede_v2df {} + + const vsi __builtin_vsx_vunsignedo_v2df (vd); + VEC_VUNSIGNEDO_V2DF vunsignedo_v2df {} + + const vf __builtin_vsx_xscvdpsp (double); + XSCVDPSP vsx_xscvdpsp {} + + const double __builtin_vsx_xscvspdp (vf); + XSCVSPDP vsx_xscvspdp {} + + const double __builtin_vsx_xsmaxdp (double, double); + XSMAXDP smaxdf3 {} + + const double __builtin_vsx_xsmindp (double, double); + XSMINDP smindf3 {} + + const double __builtin_vsx_xsrdpi (double); + XSRDPI vsx_xsrdpi {} + + const double __builtin_vsx_xsrdpic (double); + XSRDPIC vsx_xsrdpic {} + + const double __builtin_vsx_xsrdpim (double); + XSRDPIM floordf2 {} + + const double __builtin_vsx_xsrdpip (double); + XSRDPIP ceildf2 {} + + const double __builtin_vsx_xsrdpiz (double); + XSRDPIZ btruncdf2 {} + + const signed int __builtin_vsx_xstdivdp_fe (double, double); + XSTDIVDP_FE vsx_tdivdf3_fe {} + + const signed int __builtin_vsx_xstdivdp_fg (double, double); + XSTDIVDP_FG vsx_tdivdf3_fg {} + + const signed int __builtin_vsx_xstsqrtdp_fe (double); + XSTSQRTDP_FE vsx_tsqrtdf2_fe {} + + const signed int __builtin_vsx_xstsqrtdp_fg (double); + XSTSQRTDP_FG vsx_tsqrtdf2_fg {} + + const vd __builtin_vsx_xvabsdp (vd); + XVABSDP absv2df2 {} + + const vf __builtin_vsx_xvabssp (vf); + XVABSSP absv4sf2 {} + + fpmath vd __builtin_vsx_xvadddp (vd, vd); + XVADDDP addv2df3 {} + + fpmath vf __builtin_vsx_xvaddsp (vf, vf); + XVADDSP addv4sf3 {} + + const vd __builtin_vsx_xvcmpeqdp (vd, vd); + XVCMPEQDP vector_eqv2df {} + + const signed int __builtin_vsx_xvcmpeqdp_p (signed int, vd, vd); + XVCMPEQDP_P vector_eq_v2df_p {pred} + + const vf __builtin_vsx_xvcmpeqsp (vf, vf); + XVCMPEQSP vector_eqv4sf {} + + const signed int __builtin_vsx_xvcmpeqsp_p (signed int, vf, vf); + XVCMPEQSP_P vector_eq_v4sf_p {pred} + + const vd __builtin_vsx_xvcmpgedp (vd, vd); + XVCMPGEDP vector_gev2df {} + + const signed int __builtin_vsx_xvcmpgedp_p (signed int, vd, vd); + XVCMPGEDP_P vector_ge_v2df_p {pred} + + const vf __builtin_vsx_xvcmpgesp (vf, vf); + XVCMPGESP vector_gev4sf {} + + const signed int __builtin_vsx_xvcmpgesp_p (signed int, vf, vf); + XVCMPGESP_P vector_ge_v4sf_p {pred} + + const vd __builtin_vsx_xvcmpgtdp (vd, vd); + XVCMPGTDP vector_gtv2df {} + + const signed int __builtin_vsx_xvcmpgtdp_p (signed int, vd, vd); + XVCMPGTDP_P vector_gt_v2df_p {pred} + + const vf __builtin_vsx_xvcmpgtsp (vf, vf); + XVCMPGTSP vector_gtv4sf {} + + const signed int __builtin_vsx_xvcmpgtsp_p (signed int, vf, vf); + XVCMPGTSP_P vector_gt_v4sf_p {pred} + + const vf __builtin_vsx_xvcvdpsp (vd); + XVCVDPSP vsx_xvcvdpsp {} + + const vsll __builtin_vsx_xvcvdpsxds (vd); + XVCVDPSXDS vsx_fix_truncv2dfv2di2 {} + + const vsll __builtin_vsx_xvcvdpsxds_scale (vd, const int); + XVCVDPSXDS_SCALE vsx_xvcvdpsxds_scale {} + + const vsi __builtin_vsx_xvcvdpsxws (vd); + XVCVDPSXWS vsx_xvcvdpsxws {} + + const vsll __builtin_vsx_xvcvdpuxds (vd); + XVCVDPUXDS vsx_fixuns_truncv2dfv2di2 {} + + const vsll __builtin_vsx_xvcvdpuxds_scale (vd, const int); + XVCVDPUXDS_SCALE vsx_xvcvdpuxds_scale {} + + const vull __builtin_vsx_xvcvdpuxds_uns (vd); + XVCVDPUXDS_UNS vsx_fixuns_truncv2dfv2di2 {} + + const vsi __builtin_vsx_xvcvdpuxws (vd); + XVCVDPUXWS vsx_xvcvdpuxws {} + + const vd __builtin_vsx_xvcvspdp (vf); + XVCVSPDP vsx_xvcvspdp {} + + const vsll __builtin_vsx_xvcvspsxds (vf); + XVCVSPSXDS vsx_xvcvspsxds {} + + const vsi __builtin_vsx_xvcvspsxws (vf); + XVCVSPSXWS vsx_fix_truncv4sfv4si2 {} + + const vsll __builtin_vsx_xvcvspuxds (vf); + XVCVSPUXDS vsx_xvcvspuxds {} + + const vsi __builtin_vsx_xvcvspuxws (vf); + XVCVSPUXWS vsx_fixuns_truncv4sfv4si2 {} + + const vd __builtin_vsx_xvcvsxddp (vsll); + XVCVSXDDP vsx_floatv2div2df2 {} + + const vd __builtin_vsx_xvcvsxddp_scale (vsll, const int<5>); + XVCVSXDDP_SCALE vsx_xvcvsxddp_scale {} + + const vf __builtin_vsx_xvcvsxdsp (vsll); + XVCVSXDSP vsx_xvcvsxdsp {} + + const vd __builtin_vsx_xvcvsxwdp (vsi); + XVCVSXWDP vsx_xvcvsxwdp {} + + const vf __builtin_vsx_xvcvsxwsp (vsi); + XVCVSXWSP vsx_floatv4siv4sf2 {} + + const vd __builtin_vsx_xvcvuxddp (vsll); + XVCVUXDDP vsx_floatunsv2div2df2 {} + + const vd __builtin_vsx_xvcvuxddp_scale (vsll, const int<5>); + XVCVUXDDP_SCALE vsx_xvcvuxddp_scale {} + + const vd __builtin_vsx_xvcvuxddp_uns (vull); + XVCVUXDDP_UNS vsx_floatunsv2div2df2 {} + + const vf __builtin_vsx_xvcvuxdsp (vull); + XVCVUXDSP vsx_xvcvuxdsp {} + + const vd __builtin_vsx_xvcvuxwdp (vsi); + XVCVUXWDP vsx_xvcvuxwdp {} + + const vf __builtin_vsx_xvcvuxwsp (vsi); + XVCVUXWSP vsx_floatunsv4siv4sf2 {} + + fpmath vd __builtin_vsx_xvdivdp (vd, vd); + XVDIVDP divv2df3 {} + + fpmath vf __builtin_vsx_xvdivsp (vf, vf); + XVDIVSP divv4sf3 {} + + const vd __builtin_vsx_xvmadddp (vd, vd, vd); + XVMADDDP fmav2df4 {} + + const vf __builtin_vsx_xvmaddsp (vf, vf, vf); + XVMADDSP fmav4sf4 {} + + const vd __builtin_vsx_xvmaxdp (vd, vd); + XVMAXDP smaxv2df3 {} + + const vf __builtin_vsx_xvmaxsp (vf, vf); + XVMAXSP smaxv4sf3 {} + + const vd __builtin_vsx_xvmindp (vd, vd); + XVMINDP sminv2df3 {} + + const vf __builtin_vsx_xvminsp (vf, vf); + XVMINSP sminv4sf3 {} + + const vd __builtin_vsx_xvmsubdp (vd, vd, vd); + XVMSUBDP fmsv2df4 {} + + const vf __builtin_vsx_xvmsubsp (vf, vf, vf); + XVMSUBSP fmsv4sf4 {} + + fpmath vd __builtin_vsx_xvmuldp (vd, vd); + XVMULDP mulv2df3 {} + + fpmath vf __builtin_vsx_xvmulsp (vf, vf); + XVMULSP mulv4sf3 {} + + const vd __builtin_vsx_xvnabsdp (vd); + XVNABSDP vsx_nabsv2df2 {} + + const vf __builtin_vsx_xvnabssp (vf); + XVNABSSP vsx_nabsv4sf2 {} + + const vd __builtin_vsx_xvnegdp (vd); + XVNEGDP negv2df2 {} + + const vf __builtin_vsx_xvnegsp (vf); + XVNEGSP negv4sf2 {} + + const vd __builtin_vsx_xvnmadddp (vd, vd, vd); + XVNMADDDP nfmav2df4 {} + + const vf __builtin_vsx_xvnmaddsp (vf, vf, vf); + XVNMADDSP nfmav4sf4 {} + + const vd __builtin_vsx_xvnmsubdp (vd, vd, vd); + XVNMSUBDP nfmsv2df4 {} + + const vf __builtin_vsx_xvnmsubsp (vf, vf, vf); + XVNMSUBSP nfmsv4sf4 {} + + const vd __builtin_vsx_xvrdpi (vd); + XVRDPI vsx_xvrdpi {} + + const vd __builtin_vsx_xvrdpic (vd); + XVRDPIC vsx_xvrdpic {} + + const vd __builtin_vsx_xvrdpim (vd); + XVRDPIM vsx_floorv2df2 {} + + const vd __builtin_vsx_xvrdpip (vd); + XVRDPIP vsx_ceilv2df2 {} + + const vd __builtin_vsx_xvrdpiz (vd); + XVRDPIZ vsx_btruncv2df2 {} + + fpmath vd __builtin_vsx_xvrecipdivdp (vd, vd); + RECIP_V2DF recipv2df3 {} + + fpmath vf __builtin_vsx_xvrecipdivsp (vf, vf); + RECIP_V4SF recipv4sf3 {} + + const vd __builtin_vsx_xvredp (vd); + XVREDP vsx_frev2df2 {} + + const vf __builtin_vsx_xvresp (vf); + XVRESP vsx_frev4sf2 {} + + const vf __builtin_vsx_xvrspi (vf); + XVRSPI vsx_xvrspi {} + + const vf __builtin_vsx_xvrspic (vf); + XVRSPIC vsx_xvrspic {} + + const vf __builtin_vsx_xvrspim (vf); + XVRSPIM vsx_floorv4sf2 {} + + const vf __builtin_vsx_xvrspip (vf); + XVRSPIP vsx_ceilv4sf2 {} + + const vf __builtin_vsx_xvrspiz (vf); + XVRSPIZ vsx_btruncv4sf2 {} + + const vd __builtin_vsx_xvrsqrtdp (vd); + RSQRT_2DF rsqrtv2df2 {} + + const vf __builtin_vsx_xvrsqrtsp (vf); + RSQRT_4SF rsqrtv4sf2 {} + + const vd __builtin_vsx_xvrsqrtedp (vd); + XVRSQRTEDP rsqrtev2df2 {} + + const vf __builtin_vsx_xvrsqrtesp (vf); + XVRSQRTESP rsqrtev4sf2 {} + + const vd __builtin_vsx_xvsqrtdp (vd); + XVSQRTDP sqrtv2df2 {} + + const vf __builtin_vsx_xvsqrtsp (vf); + XVSQRTSP sqrtv4sf2 {} + + fpmath vd __builtin_vsx_xvsubdp (vd, vd); + XVSUBDP subv2df3 {} + + fpmath vf __builtin_vsx_xvsubsp (vf, vf); + XVSUBSP subv4sf3 {} + + const signed int __builtin_vsx_xvtdivdp_fe (vd, vd); + XVTDIVDP_FE vsx_tdivv2df3_fe {} + + const signed int __builtin_vsx_xvtdivdp_fg (vd, vd); + XVTDIVDP_FG vsx_tdivv2df3_fg {} + + const signed int __builtin_vsx_xvtdivsp_fe (vf, vf); + XVTDIVSP_FE vsx_tdivv4sf3_fe {} + + const signed int __builtin_vsx_xvtdivsp_fg (vf, vf); + XVTDIVSP_FG vsx_tdivv4sf3_fg {} + + const signed int __builtin_vsx_xvtsqrtdp_fe (vd); + XVTSQRTDP_FE vsx_tsqrtv2df2_fe {} + + const signed int __builtin_vsx_xvtsqrtdp_fg (vd); + XVTSQRTDP_FG vsx_tsqrtv2df2_fg {} + + const signed int __builtin_vsx_xvtsqrtsp_fe (vf); + XVTSQRTSP_FE vsx_tsqrtv4sf2_fe {} + + const signed int __builtin_vsx_xvtsqrtsp_fg (vf); + XVTSQRTSP_FG vsx_tsqrtv4sf2_fg {} + + const vf __builtin_vsx_xxmrghw (vf, vf); + XXMRGHW_4SF vsx_xxmrghw_v4sf {} + + const vsi __builtin_vsx_xxmrghw_4si (vsi, vsi); + XXMRGHW_4SI vsx_xxmrghw_v4si {} + + const vf __builtin_vsx_xxmrglw (vf, vf); + XXMRGLW_4SF vsx_xxmrglw_v4sf {} + + const vsi __builtin_vsx_xxmrglw_4si (vsi, vsi); + XXMRGLW_4SI vsx_xxmrglw_v4si {} + + const vsc __builtin_vsx_xxpermdi_16qi (vsc, vsc, const int<2>); + XXPERMDI_16QI vsx_xxpermdi_v16qi {} + + const vsq __builtin_vsx_xxpermdi_1ti (vsq, vsq, const int<2>); + XXPERMDI_1TI vsx_xxpermdi_v1ti {} + + const vd __builtin_vsx_xxpermdi_2df (vd, vd, const int<2>); + XXPERMDI_2DF vsx_xxpermdi_v2df {} + + const vsll __builtin_vsx_xxpermdi_2di (vsll, vsll, const int<2>); + XXPERMDI_2DI vsx_xxpermdi_v2di {} + + const vf __builtin_vsx_xxpermdi_4sf (vf, vf, const int<2>); + XXPERMDI_4SF vsx_xxpermdi_v4sf {} + + const vsi __builtin_vsx_xxpermdi_4si (vsi, vsi, const int<2>); + XXPERMDI_4SI vsx_xxpermdi_v4si {} + + const vss __builtin_vsx_xxpermdi_8hi (vss, vss, const int<2>); + XXPERMDI_8HI vsx_xxpermdi_v8hi {} + + const vsc __builtin_vsx_xxsel_16qi (vsc, vsc, vsc); + XXSEL_16QI vector_select_v16qi {} + + const vuc __builtin_vsx_xxsel_16qi_uns (vuc, vuc, vuc); + XXSEL_16QI_UNS vector_select_v16qi_uns {} + + const vsq __builtin_vsx_xxsel_1ti (vsq, vsq, vsq); + XXSEL_1TI vector_select_v1ti {} + + const vsq __builtin_vsx_xxsel_1ti_uns (vsq, vsq, vsq); + XXSEL_1TI_UNS vector_select_v1ti_uns {} + + const vd __builtin_vsx_xxsel_2df (vd, vd, vd); + XXSEL_2DF vector_select_v2df {} + + const vsll __builtin_vsx_xxsel_2di (vsll, vsll, vsll); + XXSEL_2DI vector_select_v2di {} + + const vull __builtin_vsx_xxsel_2di_uns (vull, vull, vull); + XXSEL_2DI_UNS vector_select_v2di_uns {} + + const vf __builtin_vsx_xxsel_4sf (vf, vf, vf); + XXSEL_4SF vector_select_v4sf {} + + const vsi __builtin_vsx_xxsel_4si (vsi, vsi, vsi); + XXSEL_4SI vector_select_v4si {} + + const vui __builtin_vsx_xxsel_4si_uns (vui, vui, vui); + XXSEL_4SI_UNS vector_select_v4si_uns {} + + const vss __builtin_vsx_xxsel_8hi (vss, vss, vss); + XXSEL_8HI vector_select_v8hi {} + + const vus __builtin_vsx_xxsel_8hi_uns (vus, vus, vus); + XXSEL_8HI_UNS vector_select_v8hi_uns {} + + const vsc __builtin_vsx_xxsldwi_16qi (vsc, vsc, const int<2>); + XXSLDWI_16QI vsx_xxsldwi_v16qi {} + + const vd __builtin_vsx_xxsldwi_2df (vd, vd, const int<2>); + XXSLDWI_2DF vsx_xxsldwi_v2df {} + + const vsll __builtin_vsx_xxsldwi_2di (vsll, vsll, const int<2>); + XXSLDWI_2DI vsx_xxsldwi_v2di {} + + const vf __builtin_vsx_xxsldwi_4sf (vf, vf, const int<2>); + XXSLDWI_4SF vsx_xxsldwi_v4sf {} + + const vsi __builtin_vsx_xxsldwi_4si (vsi, vsi, const int<2>); + XXSLDWI_4SI vsx_xxsldwi_v4si {} + + const vss __builtin_vsx_xxsldwi_8hi (vss, vss, const int<2>); + XXSLDWI_8HI vsx_xxsldwi_v8hi {} + + const vd __builtin_vsx_xxspltd_2df (vd, const int<1>); + XXSPLTD_V2DF vsx_xxspltd_v2df {} + + const vsll __builtin_vsx_xxspltd_2di (vsll, const int<1>); + XXSPLTD_V2DI vsx_xxspltd_v2di {} diff --git a/gcc/config/rs6000/rs6000-call.c b/gcc/config/rs6000/rs6000-call.c index 904e104..8b16d65 100644 --- a/gcc/config/rs6000/rs6000-call.c +++ b/gcc/config/rs6000/rs6000-call.c @@ -13493,6 +13493,9 @@ rs6000_init_builtins (void) intTI_type_node, 1); pixel_V8HI_type_node = rs6000_vector_type ("__vector __pixel", pixel_type_node, 8); + pcvoid_type_node + = build_pointer_type (build_qualified_type (void_type_node, + TYPE_QUAL_CONST)); /* Create Altivec, VSX and MMA builtins on machines with at least the general purpose extensions (970 and newer) to allow the use of @@ -13652,10 +13655,6 @@ altivec_init_builtins (void) tree pvoid_type_node = build_pointer_type (void_type_node); - tree pcvoid_type_node - = build_pointer_type (build_qualified_type (void_type_node, - TYPE_QUAL_CONST)); - tree int_ftype_opaque = build_function_type_list (integer_type_node, opaque_V4SI_type_node, NULL_TREE); diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c index 60f406a..e073b26 100644 --- a/gcc/config/rs6000/rs6000.c +++ b/gcc/config/rs6000/rs6000.c @@ -127,6 +127,9 @@ scalar_int_mode rs6000_pmode; bool rs6000_passes_ieee128 = false; #endif +/* Track use of r13 in 64bit AIX TLS. */ +static bool xcoff_tls_exec_model_detected = false; + /* Generate the manged name (i.e. U10__float128) used in GCC 8.1, and not the name used in current releases (i.e. u9__ieee128). */ static bool ieee128_mangling_gcc_8_1; @@ -9397,7 +9400,10 @@ rs6000_legitimize_tls_address_aix (rtx addr, enum tls_model model) emit_insn (gen_tls_get_tpointer (tlsreg)); } else - tlsreg = gen_rtx_REG (DImode, 13); + { + tlsreg = gen_rtx_REG (DImode, 13); + xcoff_tls_exec_model_detected = true; + } /* Load the TOC value into temporary register. */ tmpreg = gen_reg_rtx (Pmode); @@ -21122,6 +21128,12 @@ rs6000_xcoff_file_end (void) fputs (TARGET_32BIT ? "\t.long _section_.text\n" : "\t.llong _section_.text\n", asm_out_file); + + if (xcoff_tls_exec_model_detected) + { + /* Add a .ref to __tls_get_addr to force libpthread dependency. */ + fputs ("\t.extern __tls_get_addr\n\t.ref __tls_get_addr\n", asm_out_file); + } } struct declare_alias_data diff --git a/gcc/config/rs6000/rs6000.h b/gcc/config/rs6000/rs6000.h index 4ca6372..c5d20d2 100644 --- a/gcc/config/rs6000/rs6000.h +++ b/gcc/config/rs6000/rs6000.h @@ -2460,6 +2460,7 @@ enum rs6000_builtin_type_index RS6000_BTI_const_str, /* pointer to const char * */ RS6000_BTI_vector_pair, /* unsigned 256-bit types (vector pair). */ RS6000_BTI_vector_quad, /* unsigned 512-bit types (vector quad). */ + RS6000_BTI_const_ptr_void, /* const pointer to void */ RS6000_BTI_MAX }; @@ -2515,6 +2516,7 @@ enum rs6000_builtin_type_index #define const_str_type_node (rs6000_builtin_types[RS6000_BTI_const_str]) #define vector_pair_type_node (rs6000_builtin_types[RS6000_BTI_vector_pair]) #define vector_quad_type_node (rs6000_builtin_types[RS6000_BTI_vector_quad]) +#define pcvoid_type_node (rs6000_builtin_types[RS6000_BTI_const_ptr_void]) extern GTY(()) tree rs6000_builtin_types[RS6000_BTI_MAX]; extern GTY(()) tree rs6000_builtin_decls[RS6000_BUILTIN_COUNT]; diff --git a/gcc/config/sparc/rtemself.h b/gcc/config/sparc/rtemself.h index fa972af..d64ce90 100644 --- a/gcc/config/sparc/rtemself.h +++ b/gcc/config/sparc/rtemself.h @@ -40,3 +40,5 @@ /* Use the default */ #undef LINK_GCC_C_SEQUENCE_SPEC + +#define SPARC_GCOV_TYPE_SIZE 32 diff --git a/gcc/config/sparc/sparc.c b/gcc/config/sparc/sparc.c index 04fc80f..06f41d7 100644 --- a/gcc/config/sparc/sparc.c +++ b/gcc/config/sparc/sparc.c @@ -944,6 +944,17 @@ char sparc_hard_reg_printed[8]; #undef TARGET_ZERO_CALL_USED_REGS #define TARGET_ZERO_CALL_USED_REGS sparc_zero_call_used_regs +#ifdef SPARC_GCOV_TYPE_SIZE +static HOST_WIDE_INT +sparc_gcov_type_size (void) +{ + return SPARC_GCOV_TYPE_SIZE; +} + +#undef TARGET_GCOV_TYPE_SIZE +#define TARGET_GCOV_TYPE_SIZE sparc_gcov_type_size +#endif + struct gcc_target targetm = TARGET_INITIALIZER; /* Return the memory reference contained in X if any, zero otherwise. */ diff --git a/gcc/configure b/gcc/configure index 8b5acd7..a2d1003 100755 --- a/gcc/configure +++ b/gcc/configure @@ -27082,6 +27082,41 @@ $as_echo "$as_me: WARNING: LTO for $target requires binutils >= 2.20.1, but vers fi ;; esac + case $target_os in + darwin2[0-9]* | darwin19*) + { $as_echo "$as_me:${as_lineno-$LINENO}: checking assembler for llvm assembler x86-pad-for-align option" >&5 +$as_echo_n "checking assembler for llvm assembler x86-pad-for-align option... " >&6; } +if ${gcc_cv_as_mllvm_x86_pad_for_align+:} false; then : + $as_echo_n "(cached) " >&6 +else + gcc_cv_as_mllvm_x86_pad_for_align=no + if test x$gcc_cv_as != x; then + $as_echo '.text' > conftest.s + if { ac_try='$gcc_cv_as $gcc_cv_as_flags -mllvm -x86-pad-for-align=false -o conftest.o conftest.s >&5' + { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5 + (eval $ac_try) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; } + then + gcc_cv_as_mllvm_x86_pad_for_align=yes + else + echo "configure: failed program was" >&5 + cat conftest.s >&5 + fi + rm -f conftest.o conftest.s + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gcc_cv_as_mllvm_x86_pad_for_align" >&5 +$as_echo "$gcc_cv_as_mllvm_x86_pad_for_align" >&6; } +if test $gcc_cv_as_mllvm_x86_pad_for_align = yes; then + +$as_echo "#define HAVE_AS_MLLVM_X86_PAD_FOR_ALIGN 1" >>confdefs.h + +fi + + ;; + esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking assembler for -xbrace_comment" >&5 $as_echo_n "checking assembler for -xbrace_comment... " >&6; } @@ -30613,6 +30648,26 @@ $as_echo "#define HAVE_LD_BROKEN_PE_DWARF5 1" >>confdefs.h fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $gcc_cv_ld_broken_pe_dwarf5" >&5 $as_echo "$gcc_cv_ld_broken_pe_dwarf5" >&6; } + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking PE linker --disable-dynamicbase support" >&5 +$as_echo_n "checking PE linker --disable-dynamicbase support... " >&6; } + gcc_cv_ld_disable_dynamicbase=no + if test $in_tree_ld = yes; then + if test "$gcc_cv_gld_major_version" -eq 2 -a "$gcc_cv_gld_minor_version" -ge 36 -o "$gcc_cv_gld_major_version" -gt 2; then \ + gcc_cv_ld_disable_dynamicbase=yes + fi + else + if $gcc_cv_ld --help 2>&1 | grep -q 'disable\-]dynamicbase' > /dev/null; then + gcc_cv_ld_disable_dynamicbase=yes + fi + fi + if test x"$gcc_cv_ld_disable_dynamicbase" = xyes; then + +$as_echo "#define HAVE_LD_PE_DISABLE_DYNAMICBASE 1" >>confdefs.h + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $gcc_cv_ld_disable_dynamicbase" >&5 +$as_echo "$gcc_cv_ld_disable_dynamicbase" >&6; } ;; esac diff --git a/gcc/configure.ac b/gcc/configure.ac index c8e0d63..ad8fa5a 100644 --- a/gcc/configure.ac +++ b/gcc/configure.ac @@ -4799,6 +4799,15 @@ foo: nop fi ;; esac + case $target_os in + darwin2[[0-9]]* | darwin19*) + gcc_GAS_CHECK_FEATURE([llvm assembler x86-pad-for-align option], + gcc_cv_as_mllvm_x86_pad_for_align,, + [-mllvm -x86-pad-for-align=false], [.text],, + [AC_DEFINE(HAVE_AS_MLLVM_X86_PAD_FOR_ALIGN, 1, + [Define if your Mac OS X assembler supports -mllvm -x86-pad-for-align=false.])]) + ;; + esac gcc_GAS_CHECK_FEATURE([-xbrace_comment], gcc_cv_as_ix86_xbrace_comment,, [-xbrace_comment=no], [.text],, @@ -6383,6 +6392,23 @@ case $target_os in [Define if the PE linker has broken DWARF 5 support.]) fi AC_MSG_RESULT($gcc_cv_ld_broken_pe_dwarf5) + + AC_MSG_CHECKING(PE linker --disable-dynamicbase support) + gcc_cv_ld_disable_dynamicbase=no + if test $in_tree_ld = yes; then + if test "$gcc_cv_gld_major_version" -eq 2 -a "$gcc_cv_gld_minor_version" -ge 36 -o "$gcc_cv_gld_major_version" -gt 2; then \ + gcc_cv_ld_disable_dynamicbase=yes + fi + else + if $gcc_cv_ld --help 2>&1 | grep -q 'disable\-]dynamicbase' > /dev/null; then + gcc_cv_ld_disable_dynamicbase=yes + fi + fi + if test x"$gcc_cv_ld_disable_dynamicbase" = xyes; then + AC_DEFINE(HAVE_LD_PE_DISABLE_DYNAMICBASE, 1, + [Define if the PE linker supports --disable-dynamicbase option.]) + fi + AC_MSG_RESULT($gcc_cv_ld_disable_dynamicbase) ;; esac diff --git a/gcc/coverage.c b/gcc/coverage.c index ac9a9fd..10d7f83 100644 --- a/gcc/coverage.c +++ b/gcc/coverage.c @@ -146,7 +146,7 @@ tree get_gcov_type (void) { scalar_int_mode mode - = smallest_int_mode_for_size (LONG_LONG_TYPE_SIZE > 32 ? 64 : 32); + = smallest_int_mode_for_size (targetm.gcov_type_size ()); return lang_hooks.types.type_for_mode (mode, false); } diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index a8f70b0..a2d47b3 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,204 @@ +2021-08-17 Jakub Jelinek <jakub@redhat.com> + + PR c++/101539 + * cp-tree.h (enum cp_trait_kind): Add CPTK_IS_LAYOUT_COMPATIBLE. + (enum cp_built_in_function): Add CP_BUILT_IN_IS_CORRESPONDING_MEMBER. + (fold_builtin_is_corresponding_member, next_common_initial_seqence, + layout_compatible_type_p): Declare. + * parser.c (cp_parser_primary_expression): Handle + RID_IS_LAYOUT_COMPATIBLE. + (cp_parser_trait_expr): Likewise. + * cp-objcp-common.c (names_builtin_p): Likewise. + * constraint.cc (diagnose_trait_expr): Handle + CPTK_IS_LAYOUT_COMPATIBLE. + * decl.c (cxx_init_decl_processing): Register + __builtin_is_corresponding_member builtin. + * constexpr.c (cxx_eval_builtin_function_call): Handle + CP_BUILT_IN_IS_CORRESPONDING_MEMBER builtin. + * semantics.c (is_corresponding_member_union, + is_corresponding_member_aggr, fold_builtin_is_corresponding_member): + New functions. + (trait_expr_value): Handle CPTK_IS_LAYOUT_COMPATIBLE. + (finish_trait_expr): Likewise. + * typeck.c (next_common_initial_seqence, layout_compatible_type_p): + New functions. + * cp-gimplify.c (cp_gimplify_expr): Fold + CP_BUILT_IN_IS_CORRESPONDING_MEMBER. + (cp_fold): Likewise. + * tree.c (builtin_valid_in_constant_expr_p): Handle + CP_BUILT_IN_IS_CORRESPONDING_MEMBER. + * cxx-pretty-print.c (pp_cxx_trait_expression): Handle + CPTK_IS_LAYOUT_COMPATIBLE. + * class.c (remove_zero_width_bit_fields): Remove. + (layout_class_type): Don't call it. + +2021-08-17 Jakub Jelinek <jakub@redhat.com> + + * parser.c (OMP_SCOPE_CLAUSE_MASK): Define. + (cp_parser_omp_scope): New function. + (cp_parser_omp_construct, cp_parser_pragma): Handle PRAGMA_OMP_SCOPE. + * pt.c (tsubst_expr): Handle OMP_SCOPE. + +2021-08-12 Jakub Jelinek <jakub@redhat.com> + + * parser.c (cp_parser_omp_clause_name): Parse filter clause name. + (cp_parser_omp_clause_filter): New function. + (cp_parser_omp_all_clauses): Handle PRAGMA_OMP_CLAUSE_FILTER. + (OMP_MASKED_CLAUSE_MASK): Define. + (cp_parser_omp_masked): New function. + (cp_parser_omp_parallel): Handle parallel masked. + (cp_parser_omp_construct, cp_parser_pragma): Handle PRAGMA_OMP_MASKED. + * semantics.c (finish_omp_clauses): Handle OMP_CLAUSE_FILTER. + * pt.c (tsubst_omp_clauses): Likewise. + (tsubst_expr): Handle OMP_MASKED. + +2021-08-12 Sergei Trofimovich <siarheit@google.com> + + PR c++/101219 + * pt.c (tsubst_copy_and_build): Use build_ptrmemfunc_access_expr + to construct ptrmemfunc expression instantiation. + +2021-08-12 Tobias Burnus <tobias@codesourcery.com> + + * parser.c (cp_parser_omp_clause_proc_bind): Accept + 'primary' as alias for 'master'. + +2021-08-12 Jakub Jelinek <jakub@redhat.com> + + * cp-tree.h (omp_declare_target_attr): New type. + (struct saved_scope): Change type of omp_declare_target_attribute + from int to vec<omp_declare_target_attr, va_gc> * and move it. + * parser.c (cp_parser_omp_declare_target): Instead of + incrementing scope_chain->omp_declare_target_attribute, push + a struct containing parser->lexer->in_omp_attribute_pragma to + the vector. + (cp_parser_omp_end_declare_target): Instead of decrementing + scope_chain->omp_declare_target_attribute, pop a structure + from it. Diagnose mismatching declare target vs. + end declare target syntax. + * semantics.c (finish_translation_unit): Use vec_safe_length + and vec_safe_truncate on scope_chain->omp_declare_target_attributes. + * decl2.c (cplus_decl_attributes): Use vec_safe_length + on scope_chain->omp_declare_target_attributes. + +2021-08-12 Jakub Jelinek <jakub@redhat.com> + + * parser.c (cp_parser_lambda_body): Add temp overrides + for parser->{omp_declare_simd,oacc_routine,omp_attrs_forbidden_p}. + (cp_parser_statement): Restore parser->omp_attrs_forbidden_p for + cp_parser_declaration_statement. + (cp_parser_default_argument): Add temp override for + parser->omp_attrs_forbidden_p. + (cp_parser_late_parsing_omp_declare_simd): Diagnose declare simd + or declare variant in attribute syntax on a declaration immediately + following an OpenMP construct in pragma syntax. + +2021-08-12 Jakub Jelinek <jakub@redhat.com> + + PR c++/94162 + * method.c (cat_tag_for): Return cc_last for !CLASS_TYPE_P + or for classes not in std namespace. + +2021-08-12 Jakub Jelinek <jakub@redhat.com> + + * name-lookup.c (finish_using_directive): Diagnose omp::directive + or omp::sequence attributes on using-directive. + +2021-08-12 Jakub Jelinek <jakub@redhat.com> + + * parser.c (cp_parser_block_declaration): Call + cp_parser_using_directive for C++11 attributes followed by + using namespace tokens. + (cp_parser_using_directive): Parse C++11 attributes at the start + of the directive rather than at the end, only parse GNU attributes + at the end. + +2021-08-12 Patrick Palka <ppalka@redhat.com> + + PR c++/101663 + * constexpr.c (cxx_eval_store_expression): Handle the lval=true + case in the early exit code path for empty stores with mismatched + types. + +2021-08-11 Patrick Palka <ppalka@redhat.com> + + PR c++/101725 + DR 2082 + * cp-tree.h (unevaluated_p): Return true for REQUIRES_EXPR. + * decl.c (local_variable_p_walkfn): Don't walk into unevaluated + operands. + * parser.c (cp_parser_primary_expression) <case CPP_NAME>: Never + reject uses of local variables in unevaluated contexts. + * tree.c (cp_walk_subtrees) <case REQUIRES_EXPR>: Increment + cp_unevaluated_operand. Use cp_walk_tree directly instead of + WALK_SUBTREE to avoid the goto. Use REQUIRES_EXPR_REQS instead + of TREE_OPERAND directly. + +2021-08-11 Jakub Jelinek <jakub@redhat.com> + + PR c++/101786 + * decl2.c (var_defined_without_dynamic_init): Return true for + DECL_DECLARED_CONSTINIT_P with complete type and trivial destructor. + +2021-08-11 Patrick Palka <ppalka@redhat.com> + + PR c++/79501 + * parser.c (maybe_adjust_declarator_for_dguide): New, split + out from ... + (cp_parser_init_declarator): ... here. + (cp_parser_member_declaration): Use it. + +2021-08-11 Patrick Palka <ppalka@redhat.com> + + PR c++/89062 + * parser.c (cp_parser_parameter_declaration_list): Don't call + grokdeclarator if cp_parser_error_occurred. + (cp_parser_parameter_declaration): Simulate an error if we see + the beginning of a CTAD form, i.e. if we see an opening brace + after the decl-specifier-seq and the type is a CTAD placeholder. + +2021-08-10 Jakub Jelinek <jakub@redhat.com> + + * parser.c (cp_parser_member_declaration): Move odsd declaration + before cp_parser_using_declaration call to avoid errors with + GCC 4.8 to 6. + +2021-08-10 Jakub Jelinek <jakub@redhat.com> + + * parser.h (struct cp_omp_declare_simd_data): Remove + in_omp_attribute_pragma and clauses members, add loc and attribs. + (struct cp_oacc_routine_data): Remove loc member, add clauses + member. + * parser.c (cp_finalize_omp_declare_simd): New function. + (cp_parser_handle_statement_omp_attributes): Mention in + function comment the function is used also for + attribute-declaration. + (cp_parser_handle_directive_omp_attributes): New function. + (cp_parser_statement): Don't call + cp_parser_handle_statement_omp_attributes if statement doesn't + have attribute-specifier-seq at the beginning at all or if + if those attributes don't appertain to the statement. + (cp_parser_simple_declaration): Call + cp_parser_handle_directive_omp_attributes and + cp_finalize_omp_declare_simd. + (cp_parser_explicit_instantiation): Likewise. + (cp_parser_init_declarator): Initialize prefix_attributes + only after parsing declarators. + (cp_parser_direct_declarator): Call + cp_parser_handle_directive_omp_attributes and + cp_finalize_omp_declare_simd. + (cp_parser_member_declaration): Likewise. + (cp_parser_single_declaration): Likewise. + (cp_parser_omp_declare_simd): Don't initialize + data.in_omp_attribute_pragma, instead initialize + data.attribs[0] and data.attribs[1]. + (cp_finish_omp_declare_variant): Remove + in_omp_attribute_pragma argument, instead use + parser->lexer->in_omp_attribute_pragma. + (cp_parser_late_parsing_omp_declare_simd): Adjust + cp_finish_omp_declare_variant caller. Handle attribute-syntax + declare simd/variant. + 2021-08-06 Tamar Christina <tamar.christina@arm.com> * cp-objcp-common.h (cxx_simulate_enum_decl): Pass vec<> by pointer. diff --git a/gcc/cp/class.c b/gcc/cp/class.c index 6f31700..7138e30 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -136,7 +136,6 @@ static bool check_field_decl (tree, tree, int *, int *); static void check_field_decls (tree, tree *, int *, int *); static void build_base_fields (record_layout_info, splay_tree, tree *); static void check_methods (tree); -static void remove_zero_width_bit_fields (tree); static bool accessible_nvdtor_p (tree); /* Used by find_flexarrays and related functions. */ @@ -5754,31 +5753,6 @@ type_build_dtor_call (tree t) return false; } -/* Remove all zero-width bit-fields from T. */ - -static void -remove_zero_width_bit_fields (tree t) -{ - tree *fieldsp; - - fieldsp = &TYPE_FIELDS (t); - while (*fieldsp) - { - if (TREE_CODE (*fieldsp) == FIELD_DECL - && DECL_C_BIT_FIELD (*fieldsp) - /* We should not be confused by the fact that grokbitfield - temporarily sets the width of the bit field into - DECL_BIT_FIELD_REPRESENTATIVE (*fieldsp). - check_bitfield_decl eventually sets DECL_SIZE (*fieldsp) - to that width. */ - && (DECL_SIZE (*fieldsp) == NULL_TREE - || integer_zerop (DECL_SIZE (*fieldsp)))) - *fieldsp = DECL_CHAIN (*fieldsp); - else - fieldsp = &DECL_CHAIN (*fieldsp); - } -} - /* Returns TRUE iff we need a cookie when dynamically allocating an array whose elements have the indicated class TYPE. */ @@ -6770,10 +6744,6 @@ layout_class_type (tree t, tree *virtuals_p) normalize_rli (rli); } - /* Delete all zero-width bit-fields from the list of fields. Now - that the type is laid out they are no longer important. */ - remove_zero_width_bit_fields (t); - if (CLASSTYPE_NON_LAYOUT_POD_P (t) || CLASSTYPE_EMPTY_P (t)) { /* T needs a different layout as a base (eliding virtual bases diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c index 1af365d..b9c0062 100644 --- a/gcc/cp/constexpr.c +++ b/gcc/cp/constexpr.c @@ -1438,6 +1438,18 @@ cxx_eval_builtin_function_call (const constexpr_ctx *ctx, tree t, tree fun, = fold_builtin_is_pointer_inverconvertible_with_class (loc, nargs, args); } + else if (fndecl_built_in_p (fun, + CP_BUILT_IN_IS_CORRESPONDING_MEMBER, + BUILT_IN_FRONTEND)) + { + location_t loc = EXPR_LOCATION (t); + if (nargs >= 2) + { + VERIFY_CONSTANT (args[0]); + VERIFY_CONSTANT (args[1]); + } + new_call = fold_builtin_is_corresponding_member (loc, nargs, args); + } else new_call = fold_builtin_call_array (EXPR_LOCATION (t), TREE_TYPE (t), CALL_EXPR_FN (t), nargs, args); @@ -5588,8 +5600,8 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t, argument, which has the derived type rather than the base type. In this situation, just evaluate the initializer and return, since there's no actual data to store. */ - gcc_assert (is_empty_class (TREE_TYPE (init)) && !lval); - return init; + gcc_assert (is_empty_class (TREE_TYPE (init))); + return lval ? target : init; } CONSTRUCTOR_ELTS (*valp) = CONSTRUCTOR_ELTS (init); TREE_CONSTANT (*valp) = TREE_CONSTANT (init); diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc index e608c5a..1aaf1e2 100644 --- a/gcc/cp/constraint.cc +++ b/gcc/cp/constraint.cc @@ -3628,6 +3628,9 @@ diagnose_trait_expr (tree expr, tree args) case CPTK_IS_FINAL: inform (loc, " %qT is not a final class", t1); break; + case CPTK_IS_LAYOUT_COMPATIBLE: + inform (loc, " %qT is not layout compatible with %qT", t1, t2); + break; case CPTK_IS_LITERAL_TYPE: inform (loc, " %qT is not a literal type", t1); break; diff --git a/gcc/cp/cp-gimplify.c b/gcc/cp/cp-gimplify.c index 6e274ac..bf928a8 100644 --- a/gcc/cp/cp-gimplify.c +++ b/gcc/cp/cp-gimplify.c @@ -658,12 +658,20 @@ cp_gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p) *expr_p = fold_builtin_source_location (EXPR_LOCATION (*expr_p)); break; + case CP_BUILT_IN_IS_CORRESPONDING_MEMBER: + *expr_p + = fold_builtin_is_corresponding_member + (EXPR_LOCATION (*expr_p), call_expr_nargs (*expr_p), + &CALL_EXPR_ARG (*expr_p, 0)); + break; case CP_BUILT_IN_IS_POINTER_INTERCONVERTIBLE_WITH_CLASS: *expr_p = fold_builtin_is_pointer_inverconvertible_with_class (EXPR_LOCATION (*expr_p), call_expr_nargs (*expr_p), &CALL_EXPR_ARG (*expr_p, 0)); break; + default: + break; } } break; @@ -2579,6 +2587,11 @@ cp_fold (tree x) case CP_BUILT_IN_SOURCE_LOCATION: x = fold_builtin_source_location (EXPR_LOCATION (x)); break; + case CP_BUILT_IN_IS_CORRESPONDING_MEMBER: + x = fold_builtin_is_corresponding_member + (EXPR_LOCATION (x), call_expr_nargs (x), + &CALL_EXPR_ARG (x, 0)); + break; case CP_BUILT_IN_IS_POINTER_INTERCONVERTIBLE_WITH_CLASS: x = fold_builtin_is_pointer_inverconvertible_with_class (EXPR_LOCATION (x), call_expr_nargs (x), diff --git a/gcc/cp/cp-objcp-common.c b/gcc/cp/cp-objcp-common.c index beef012..98fd962 100644 --- a/gcc/cp/cp-objcp-common.c +++ b/gcc/cp/cp-objcp-common.c @@ -413,6 +413,7 @@ names_builtin_p (const char *name) case RID_IS_EMPTY: case RID_IS_ENUM: case RID_IS_FINAL: + case RID_IS_LAYOUT_COMPATIBLE: case RID_IS_LITERAL_TYPE: case RID_IS_POINTER_INTERCONVERTIBLE_BASE_OF: case RID_IS_POD: diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 9a47a87..7ba02be 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -1365,6 +1365,7 @@ enum cp_trait_kind CPTK_IS_EMPTY, CPTK_IS_ENUM, CPTK_IS_FINAL, + CPTK_IS_LAYOUT_COMPATIBLE, CPTK_IS_LITERAL_TYPE, CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF, CPTK_IS_POD, @@ -1789,6 +1790,10 @@ union GTY((desc ("cp_tree_node_structure (&%h)"), }; +struct GTY(()) omp_declare_target_attr { + bool attr_syntax; +}; + /* Global state. */ struct GTY(()) saved_scope { @@ -1826,9 +1831,6 @@ struct GTY(()) saved_scope { int unevaluated_operand; int inhibit_evaluation_warnings; int noexcept_operand; - /* If non-zero, implicit "omp declare target" attribute is added into the - attribute lists. */ - int omp_declare_target_attribute; int ref_temp_count; struct stmt_tree_s x_stmt_tree; @@ -1837,6 +1839,7 @@ struct GTY(()) saved_scope { cp_binding_level *bindings; hash_map<tree, tree> *GTY((skip)) x_local_specializations; + vec<omp_declare_target_attr, va_gc> *omp_declare_target_attribute; struct saved_scope *prev; }; @@ -4500,6 +4503,12 @@ more_aggr_init_expr_args_p (const aggr_init_expr_arg_iterator *iter) #define CONSTRUCTOR_IS_PAREN_INIT(NODE) \ (CONSTRUCTOR_CHECK(NODE)->base.private_flag) +/* True if reshape_init built this CONSTRUCTOR to undo the brace elision + of another CONSTRUCTOR. This flag is used during C++20 aggregate + CTAD. */ +#define CONSTRUCTOR_BRACES_ELIDED_P(NODE) \ + (CONSTRUCTOR_CHECK (NODE)->base.protected_flag) + /* True if NODE represents a conversion for direct-initialization in a template. Set by perform_implicit_conversion_flags. */ #define IMPLICIT_CONV_EXPR_DIRECT_INIT(NODE) \ @@ -6356,6 +6365,7 @@ struct GTY((chain_next ("%h.next"))) tinst_level { enum cp_built_in_function { CP_BUILT_IN_IS_CONSTANT_EVALUATED, CP_BUILT_IN_INTEGER_PACK, + CP_BUILT_IN_IS_CORRESPONDING_MEMBER, CP_BUILT_IN_IS_POINTER_INTERCONVERTIBLE_WITH_CLASS, CP_BUILT_IN_SOURCE_LOCATION, CP_BUILT_IN_LAST @@ -7572,6 +7582,7 @@ extern tree baselink_for_fns (tree); extern void finish_static_assert (tree, tree, location_t, bool, bool); extern tree finish_decltype_type (tree, bool, tsubst_flags_t); +extern tree fold_builtin_is_corresponding_member (location_t, int, tree *); extern tree fold_builtin_is_pointer_inverconvertible_with_class (location_t, int, tree *); extern tree finish_trait_expr (location_t, enum cp_trait_kind, tree, tree); extern tree build_lambda_expr (void); @@ -7798,6 +7809,8 @@ extern bool comp_except_specs (const_tree, const_tree, int); extern bool comptypes (tree, tree, int); extern bool same_type_ignoring_top_level_qualifiers_p (tree, tree); extern bool similar_type_p (tree, tree); +extern bool next_common_initial_seqence (tree &, tree &); +extern bool layout_compatible_type_p (tree, tree); extern bool compparms (const_tree, const_tree); extern int comp_cv_qualification (const_tree, const_tree); extern int comp_cv_qualification (int, int); @@ -8494,7 +8507,8 @@ unevaluated_p (tree_code code) return (code == DECLTYPE_TYPE || code == ALIGNOF_EXPR || code == SIZEOF_EXPR - || code == NOEXCEPT_EXPR); + || code == NOEXCEPT_EXPR + || code == REQUIRES_EXPR); } /* RAII class to push/pop the access scope for T. */ diff --git a/gcc/cp/cxx-pretty-print.c b/gcc/cp/cxx-pretty-print.c index b899162..25cabfe 100644 --- a/gcc/cp/cxx-pretty-print.c +++ b/gcc/cp/cxx-pretty-print.c @@ -2645,6 +2645,9 @@ pp_cxx_trait_expression (cxx_pretty_printer *pp, tree t) case CPTK_IS_FINAL: pp_cxx_ws_string (pp, "__is_final"); break; + case CPTK_IS_LAYOUT_COMPATIBLE: + pp_cxx_ws_string (pp, "__is_layout_compatible"); + break; case CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF: pp_cxx_ws_string (pp, "__is_pointer_interconvertible_base_of"); break; @@ -2700,6 +2703,7 @@ pp_cxx_trait_expression (cxx_pretty_printer *pp, tree t) if (kind == CPTK_IS_BASE_OF || kind == CPTK_IS_SAME_AS + || kind == CPTK_IS_LAYOUT_COMPATIBLE || kind == CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF) { pp_cxx_separate_with (pp, ','); diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index f626f1e..3414cbd 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -4470,6 +4470,13 @@ cxx_init_decl_processing (void) tree bool_vaftype = build_varargs_function_type_list (boolean_type_node, NULL_TREE); decl + = add_builtin_function ("__builtin_is_corresponding_member", + bool_vaftype, + CP_BUILT_IN_IS_CORRESPONDING_MEMBER, + BUILT_IN_FRONTEND, NULL, NULL_TREE); + set_call_expr_flags (decl, ECF_CONST | ECF_NOTHROW | ECF_LEAF); + + decl = add_builtin_function ("__builtin_is_pointer_interconvertible_with_class", bool_vaftype, CP_BUILT_IN_IS_POINTER_INTERCONVERTIBLE_WITH_CLASS, @@ -6650,7 +6657,8 @@ reshape_init_r (tree type, reshape_iter *d, tree first_initializer_p, /* A non-aggregate type is always initialized with a single initializer. */ if (!CP_AGGREGATE_TYPE_P (type) - /* As is an array with dependent bound. */ + /* As is an array with dependent bound, which we can see + during C++20 aggregate CTAD. */ || (cxx_dialect >= cxx20 && TREE_CODE (type) == ARRAY_TYPE && uses_template_parms (TYPE_DOMAIN (type)))) @@ -6767,6 +6775,7 @@ reshape_init_r (tree type, reshape_iter *d, tree first_initializer_p, initializer already, and there is not a CONSTRUCTOR, it means that there is a missing set of braces (that is, we are processing the case for which reshape_init exists). */ + bool braces_elided_p = false; if (!first_initializer_p) { if (TREE_CODE (stripped_init) == CONSTRUCTOR) @@ -6802,17 +6811,25 @@ reshape_init_r (tree type, reshape_iter *d, tree first_initializer_p, warning (OPT_Wmissing_braces, "missing braces around initializer for %qT", type); + braces_elided_p = true; } /* Dispatch to specialized routines. */ + tree new_init; if (CLASS_TYPE_P (type)) - return reshape_init_class (type, d, first_initializer_p, complain); + new_init = reshape_init_class (type, d, first_initializer_p, complain); else if (TREE_CODE (type) == ARRAY_TYPE) - return reshape_init_array (type, d, first_initializer_p, complain); + new_init = reshape_init_array (type, d, first_initializer_p, complain); else if (VECTOR_TYPE_P (type)) - return reshape_init_vector (type, d, complain); + new_init = reshape_init_vector (type, d, complain); else gcc_unreachable(); + + if (braces_elided_p + && TREE_CODE (new_init) == CONSTRUCTOR) + CONSTRUCTOR_BRACES_ELIDED_P (new_init) = true; + + return new_init; } /* Undo the brace-elision allowed by [dcl.init.aggr] in a @@ -14270,6 +14287,14 @@ static tree local_variable_p_walkfn (tree *tp, int *walk_subtrees, void * /*data*/) { + if (unevaluated_p (TREE_CODE (*tp))) + { + /* DR 2082 permits local variables in unevaluated contexts + within a default argument. */ + *walk_subtrees = 0; + return NULL_TREE; + } + if (local_variable_p (*tp) && (!DECL_ARTIFICIAL (*tp) || DECL_NAME (*tp) == this_identifier)) return *tp; diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c index 9564b0d..0c9d2f4 100644 --- a/gcc/cp/decl2.c +++ b/gcc/cp/decl2.c @@ -1551,7 +1551,7 @@ cplus_decl_attributes (tree *decl, tree attributes, int flags) return; /* Add implicit "omp declare target" attribute if requested. */ - if (scope_chain->omp_declare_target_attribute + if (vec_safe_length (scope_chain->omp_declare_target_attribute) && ((VAR_P (*decl) && (TREE_STATIC (*decl) || DECL_EXTERNAL (*decl))) || TREE_CODE (*decl) == FUNCTION_DECL)) @@ -3447,6 +3447,12 @@ set_guard (tree guard) static bool var_defined_without_dynamic_init (tree var) { + /* constinit vars are guaranteed to not have dynamic initializer, + but still registering the destructor counts as dynamic initialization. */ + if (DECL_DECLARED_CONSTINIT_P (var) + && COMPLETE_TYPE_P (TREE_TYPE (var)) + && !TYPE_HAS_NONTRIVIAL_DESTRUCTOR (TREE_TYPE (var))) + return true; /* If it's defined in another TU, we can't tell. */ if (DECL_EXTERNAL (var)) return false; diff --git a/gcc/cp/method.c b/gcc/cp/method.c index f268aab..353046d 100644 --- a/gcc/cp/method.c +++ b/gcc/cp/method.c @@ -1029,6 +1029,8 @@ is_cat (tree type, comp_cat_tag tag) static comp_cat_tag cat_tag_for (tree type) { + if (!CLASS_TYPE_P (type) || !decl_in_std_namespace_p (TYPE_MAIN_DECL (type))) + return cc_last; for (int i = 0; i < cc_last; ++i) { comp_cat_tag tag = (comp_cat_tag)i; diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c index 1be5f3d..8e9c61e 100644 --- a/gcc/cp/name-lookup.c +++ b/gcc/cp/name-lookup.c @@ -8560,6 +8560,7 @@ finish_using_directive (tree target, tree attribs) add_using_namespace (current_binding_level->using_directives, ORIGINAL_NAMESPACE (target)); + bool diagnosed = false; if (attribs != error_mark_node) for (tree a = attribs; a; a = TREE_CHAIN (a)) { @@ -8572,6 +8573,16 @@ finish_using_directive (tree target, tree attribs) inform (DECL_SOURCE_LOCATION (target), "you can use an inline namespace instead"); } + else if ((flag_openmp || flag_openmp_simd) + && get_attribute_namespace (a) == omp_identifier + && (is_attribute_p ("directive", name) + || is_attribute_p ("sequence", name))) + { + if (!diagnosed) + error ("%<omp::%E%> not allowed to be specified in this " + "context", name); + diagnosed = true; + } else warning (OPT_Wattributes, "%qD attribute directive ignored", name); } diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 02ce954..04116fb 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -1440,6 +1440,24 @@ cp_finalize_omp_declare_simd (cp_parser *parser, tree fndecl) } } +/* Similarly, but for use in declaration parsing functions + which call cp_parser_handle_directive_omp_attributes. */ + +static inline void +cp_finalize_omp_declare_simd (cp_parser *parser, cp_omp_declare_simd_data *data) +{ + if (parser->omp_declare_simd != data) + return; + + if (!parser->omp_declare_simd->error_seen + && !parser->omp_declare_simd->fndecl_seen) + error_at (parser->omp_declare_simd->loc, + "%<declare %s%> directive not immediately followed by " + "function declaration or definition", + parser->omp_declare_simd->variant_p ? "variant" : "simd"); + parser->omp_declare_simd = NULL; +} + /* Diagnose if #pragma acc routine isn't followed immediately by function declaration or definition. */ @@ -5798,6 +5816,7 @@ cp_parser_primary_expression (cp_parser *parser, case RID_IS_EMPTY: case RID_IS_ENUM: case RID_IS_FINAL: + case RID_IS_LAYOUT_COMPATIBLE: case RID_IS_LITERAL_TYPE: case RID_IS_POINTER_INTERCONVERTIBLE_BASE_OF: case RID_IS_POD: @@ -5971,7 +5990,10 @@ cp_parser_primary_expression (cp_parser *parser, /* Check to see if DECL is a local variable in a context where that is forbidden. */ if ((parser->local_variables_forbidden_p & LOCAL_VARS_FORBIDDEN) - && local_variable_p (decl)) + && local_variable_p (decl) + /* DR 2082 permits local variables in unevaluated contexts + within a default argument. */ + && !cp_unevaluated_operand) { const char *msg = (TREE_CODE (decl) == PARM_DECL @@ -10686,6 +10708,10 @@ cp_parser_trait_expr (cp_parser* parser, enum rid keyword) case RID_IS_FINAL: kind = CPTK_IS_FINAL; break; + case RID_IS_LAYOUT_COMPATIBLE: + kind = CPTK_IS_LAYOUT_COMPATIBLE; + binary = true; + break; case RID_IS_LITERAL_TYPE: kind = CPTK_IS_LITERAL_TYPE; break; @@ -11607,6 +11633,9 @@ cp_parser_lambda_body (cp_parser* parser, tree lambda_expr) middle of an expression. */ ++function_depth; + auto odsd = make_temp_override (parser->omp_declare_simd, NULL); + auto ord = make_temp_override (parser->oacc_routine, NULL); + auto oafp = make_temp_override (parser->omp_attrs_forbidden_p, false); vec<tree> omp_privatization_save; save_omp_privatization_clauses (omp_privatization_save); /* Clear this in case we're in the middle of a default argument. */ @@ -11661,7 +11690,7 @@ struct cp_omp_attribute_data }; /* Handle omp::directive and omp::sequence attributes in ATTRS - (if any) at the start of a statement. */ + (if any) at the start of a statement or in attribute-declaration. */ static tree cp_parser_handle_statement_omp_attributes (cp_parser *parser, tree attrs) @@ -11858,6 +11887,98 @@ cp_parser_handle_statement_omp_attributes (cp_parser *parser, tree attrs) return attrs; } +/* Handle omp::directive and omp::sequence attributes in *PATTRS + (if any) at the start or after declaration-id of a declaration. */ + +static void +cp_parser_handle_directive_omp_attributes (cp_parser *parser, tree *pattrs, + cp_omp_declare_simd_data *data, + bool start) +{ + if (!flag_openmp && !flag_openmp_simd) + return; + + int cnt = 0; + bool bad = false; + bool variant_p = false; + location_t loc = UNKNOWN_LOCATION; + for (tree pa = *pattrs; pa; pa = TREE_CHAIN (pa)) + if (get_attribute_namespace (pa) == omp_identifier + && is_attribute_p ("directive", get_attribute_name (pa))) + { + for (tree a = TREE_VALUE (pa); a; a = TREE_CHAIN (a)) + { + tree d = TREE_VALUE (a); + gcc_assert (TREE_CODE (d) == DEFERRED_PARSE); + cp_token *first = DEFPARSE_TOKENS (d)->first; + cp_token *last = DEFPARSE_TOKENS (d)->last; + const char *directive[3] = {}; + for (int i = 0; i < 3; i++) + { + tree id = NULL_TREE; + if (first + i == last) + break; + if (first[i].type == CPP_NAME) + id = first[i].u.value; + else if (first[i].type == CPP_KEYWORD) + id = ridpointers[(int) first[i].keyword]; + else + break; + directive[i] = IDENTIFIER_POINTER (id); + } + const c_omp_directive *dir = NULL; + if (directive[0]) + dir = c_omp_categorize_directive (directive[0], directive[1], + directive[2]); + if (dir == NULL) + continue; + if (dir->id == PRAGMA_OMP_DECLARE + && (strcmp (directive[1], "simd") == 0 + || strcmp (directive[1], "variant") == 0)) + { + if (cnt++ == 0) + { + variant_p = strcmp (directive[1], "variant") == 0; + loc = first->location; + } + if (start && parser->omp_declare_simd && !bad) + { + error_at (first->location, + "mixing OpenMP directives with attribute and " + "pragma syntax on the same declaration"); + bad = true; + } + } + } + } + + if (bad) + { + for (tree *pa = pattrs; *pa; ) + if (get_attribute_namespace (*pa) == omp_identifier + && is_attribute_p ("directive", get_attribute_name (*pa))) + *pa = TREE_CHAIN (*pa); + else + pa = &TREE_CHAIN (*pa); + return; + } + if (cnt == 0) + return; + + if (parser->omp_declare_simd == NULL) + { + data->error_seen = false; + data->fndecl_seen = false; + data->variant_p = variant_p; + data->loc = loc; + data->tokens = vNULL; + data->attribs[0] = NULL; + data->attribs[1] = NULL; + parser->omp_declare_simd = data; + } + parser->omp_declare_simd->attribs[!start] = pattrs; +} + /* Parse a statement. statement: @@ -11935,12 +12056,57 @@ cp_parser_statement (cp_parser* parser, tree in_statement_expr, } has_std_attrs = cp_lexer_peek_token (parser->lexer) != token; + /* Peek at the next token. */ + token = cp_lexer_peek_token (parser->lexer); + bool omp_attrs_forbidden_p; + omp_attrs_forbidden_p = parser->omp_attrs_forbidden_p; + if (std_attrs && (flag_openmp || flag_openmp_simd)) - std_attrs = cp_parser_handle_statement_omp_attributes (parser, std_attrs); + { + bool handle_omp_attribs = false; + if (token->type == CPP_KEYWORD) + switch (token->keyword) + { + case RID_IF: + case RID_SWITCH: + case RID_WHILE: + case RID_DO: + case RID_FOR: + case RID_BREAK: + case RID_CONTINUE: + case RID_RETURN: + case RID_CO_RETURN: + case RID_GOTO: + case RID_AT_TRY: + case RID_AT_CATCH: + case RID_AT_FINALLY: + case RID_AT_SYNCHRONIZED: + case RID_AT_THROW: + case RID_TRY: + case RID_TRANSACTION_ATOMIC: + case RID_TRANSACTION_RELAXED: + case RID_SYNCHRONIZED: + case RID_ATOMIC_NOEXCEPT: + case RID_ATOMIC_CANCEL: + case RID_TRANSACTION_CANCEL: + handle_omp_attribs = true; + break; + default: + break; + } + else if (token->type == CPP_SEMICOLON + || token->type == CPP_OPEN_BRACE + || token->type == CPP_PRAGMA) + handle_omp_attribs = true; + if (handle_omp_attribs) + { + std_attrs = cp_parser_handle_statement_omp_attributes (parser, + std_attrs); + token = cp_lexer_peek_token (parser->lexer); + } + } parser->omp_attrs_forbidden_p = false; - /* Peek at the next token. */ - token = cp_lexer_peek_token (parser->lexer); /* Remember the location of the first token in the statement. */ cp_token *statement_token = token; statement_location = token->location; @@ -12058,6 +12224,7 @@ cp_parser_statement (cp_parser* parser, tree in_statement_expr, a statement all its own. */ else if (token->type == CPP_PRAGMA) { + do_pragma:; cp_lexer *lexer = parser->lexer; bool do_restart = false; /* Only certain OpenMP pragmas are attached to statements, and thus @@ -12112,15 +12279,56 @@ cp_parser_statement (cp_parser* parser, tree in_statement_expr, so let's un-parse them. */ saved_tokens.rollback(); + parser->omp_attrs_forbidden_p = omp_attrs_forbidden_p; cp_parser_parse_tentatively (parser); /* Try to parse the declaration-statement. */ cp_parser_declaration_statement (parser); + parser->omp_attrs_forbidden_p = false; /* If that worked, we're done. */ if (cp_parser_parse_definitely (parser)) return; /* It didn't work, restore the post-attribute position. */ if (has_std_attrs) - cp_lexer_set_token_position (parser->lexer, statement_token); + { + cp_lexer_set_token_position (parser->lexer, statement_token); + if (flag_openmp || flag_openmp_simd) + { + size_t i = 1; + bool handle_omp_attribs = true; + while (cp_lexer_peek_nth_token (parser->lexer, i)->keyword + == RID_EXTENSION) + i++; + switch (cp_lexer_peek_nth_token (parser->lexer, i)->keyword) + { + case RID_ASM: + case RID_NAMESPACE: + case RID_USING: + case RID_LABEL: + case RID_STATIC_ASSERT: + /* Don't handle OpenMP attribs on keywords that + always start a declaration statement but don't + accept attribute before it and therefore + the tentative cp_parser_declaration_statement + fails to parse because of that. */ + handle_omp_attribs = false; + break; + default: + break; + } + + if (handle_omp_attribs) + { + parser->omp_attrs_forbidden_p = omp_attrs_forbidden_p; + std_attrs + = cp_parser_handle_statement_omp_attributes + (parser, std_attrs); + parser->omp_attrs_forbidden_p = false; + token = cp_lexer_peek_token (parser->lexer); + if (token->type == CPP_PRAGMA) + goto do_pragma; + } + } + } } /* All preceding labels have been parsed at this point. */ if (loc_after_labels != NULL) @@ -14655,6 +14863,7 @@ cp_parser_block_declaration (cp_parser *parser, /* Peek at the next token to figure out which kind of declaration is present. */ cp_token *token1 = cp_lexer_peek_token (parser->lexer); + size_t attr_idx; /* If the next keyword is `asm', we have an asm-definition. */ if (token1->keyword == RID_ASM) @@ -14708,6 +14917,18 @@ cp_parser_block_declaration (cp_parser *parser, /* If the next token is `static_assert' we have a static assertion. */ else if (token1->keyword == RID_STATIC_ASSERT) cp_parser_static_assert (parser, /*member_p=*/false); + /* If the next tokens after attributes is `using namespace', then we have + a using-directive. */ + else if ((attr_idx = cp_parser_skip_std_attribute_spec_seq (parser, 1)) != 1 + && cp_lexer_nth_token_is_keyword (parser->lexer, attr_idx, + RID_USING) + && cp_lexer_nth_token_is_keyword (parser->lexer, attr_idx + 1, + RID_NAMESPACE)) + { + if (statement_p) + cp_parser_commit_to_tentative_parse (parser); + cp_parser_using_directive (parser); + } /* Anything else must be a simple-declaration. */ else cp_parser_simple_declaration (parser, !statement_p, @@ -14770,6 +14991,12 @@ cp_parser_simple_declaration (cp_parser* parser, /* We no longer need to defer access checks. */ stop_deferring_access_checks (); + cp_omp_declare_simd_data odsd; + if (decl_specifiers.attributes && (flag_openmp || flag_openmp_simd)) + cp_parser_handle_directive_omp_attributes (parser, + &decl_specifiers.attributes, + &odsd, true); + /* In a block scope, a valid declaration must always have a decl-specifier-seq. By not trying to parse declarators, we can resolve the declaration/expression ambiguity more quickly. */ @@ -14962,6 +15189,7 @@ cp_parser_simple_declaration (cp_parser* parser, else { pop_deferring_access_checks (); + cp_finalize_omp_declare_simd (parser, &odsd); return; } } @@ -15042,6 +15270,7 @@ cp_parser_simple_declaration (cp_parser* parser, done: pop_deferring_access_checks (); + cp_finalize_omp_declare_simd (parser, &odsd); } /* Helper of cp_parser_simple_declaration, parse a decomposition declaration. @@ -18659,6 +18888,13 @@ cp_parser_explicit_instantiation (cp_parser* parser) CP_PARSER_FLAGS_OPTIONAL, &decl_specifiers, &declares_class_or_enum); + + cp_omp_declare_simd_data odsd; + if (decl_specifiers.attributes && (flag_openmp || flag_openmp_simd)) + cp_parser_handle_directive_omp_attributes (parser, + &decl_specifiers.attributes, + &odsd, true); + /* If there was exactly one decl-specifier, and it declared a class, and there's no declarator, then we have an explicit type instantiation. */ @@ -18727,6 +18963,8 @@ cp_parser_explicit_instantiation (cp_parser* parser) cp_parser_consume_semicolon_at_end_of_statement (parser); timevar_pop (TV_TEMPLATE_INST); + + cp_finalize_omp_declare_simd (parser, &odsd); } /* Parse an explicit-specialization. @@ -21394,14 +21632,21 @@ cp_parser_alias_declaration (cp_parser* parser) /* Parse a using-directive. using-directive: - using namespace :: [opt] nested-name-specifier [opt] - namespace-name ; */ + attribute-specifier-seq [opt] using namespace :: [opt] + nested-name-specifier [opt] namespace-name ; */ static void cp_parser_using_directive (cp_parser* parser) { tree namespace_decl; - tree attribs; + tree attribs = cp_parser_std_attribute_spec_seq (parser); + if (cp_lexer_next_token_is (parser->lexer, CPP_SEMICOLON)) + { + /* Error during attribute parsing that resulted in skipping + to next semicolon. */ + cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON); + return; + } /* Look for the `using' keyword. */ cp_parser_require_keyword (parser, RID_USING, RT_USING); @@ -21418,8 +21663,9 @@ cp_parser_using_directive (cp_parser* parser) /* Get the namespace being used. */ namespace_decl = cp_parser_namespace_name (parser); cp_warn_deprecated_use_scopes (namespace_decl); - /* And any specified attributes. */ - attribs = cp_parser_attributes_opt (parser); + /* And any specified GNU attributes. */ + if (cp_next_tokens_can_be_gnu_attribute_p (parser)) + attribs = chainon (attribs, cp_parser_gnu_attributes_opt (parser)); /* Update the symbol table. */ finish_using_directive (namespace_decl, attribs); @@ -21866,6 +22112,37 @@ warn_about_ambiguous_parse (const cp_decl_specifier_seq *decl_specifiers, } } +/* If DECLARATOR with DECL_SPECS is a function declarator that has + the form of a deduction guide, tag it as such. CTOR_DTOR_OR_CONV_P + has the same meaning as in cp_parser_declarator. */ + +static void +cp_parser_maybe_adjust_declarator_for_dguide (cp_parser *parser, + cp_decl_specifier_seq *decl_specs, + cp_declarator *declarator, + int *ctor_dtor_or_conv_p) +{ + if (cxx_dialect >= cxx17 + && *ctor_dtor_or_conv_p <= 0 + && !decl_specs->type + && !decl_specs->any_type_specifiers_p + && function_declarator_p (declarator)) + { + cp_declarator *id = get_id_declarator (declarator); + tree name = id->u.id.unqualified_name; + parser->scope = id->u.id.qualifying_scope; + tree tmpl = cp_parser_lookup_name_simple (parser, name, id->id_loc); + if (tmpl + && (DECL_CLASS_TEMPLATE_P (tmpl) + || DECL_TEMPLATE_TEMPLATE_PARM_P (tmpl))) + { + id->u.id.unqualified_name = dguide_name (tmpl); + id->u.id.sfk = sfk_deduction_guide; + *ctor_dtor_or_conv_p = 1; + } + } +} + /* Declarators [gram.dcl.decl] */ /* Parse an init-declarator. @@ -21964,10 +22241,6 @@ cp_parser_init_declarator (cp_parser* parser, if (decl_spec_seq_has_spec_p (decl_specifiers, ds_consteval)) flags |= CP_PARSER_FLAGS_CONSTEVAL; - /* Gather the attributes that were provided with the - decl-specifiers. */ - prefix_attributes = decl_specifiers->attributes; - /* Assume that this is not the declarator for a function definition. */ if (function_definition_p) @@ -22031,6 +22304,10 @@ cp_parser_init_declarator (cp_parser* parser, else asm_specification = NULL_TREE; + /* Gather the attributes that were provided with the + decl-specifiers. */ + prefix_attributes = decl_specifiers->attributes; + /* Look for attributes. */ attributes_start_token = cp_lexer_peek_token (parser->lexer); attributes = cp_parser_attributes_opt (parser); @@ -22042,25 +22319,13 @@ cp_parser_init_declarator (cp_parser* parser, if (function_declarator_p (declarator)) { - /* Handle C++17 deduction guides. */ - if (!decl_specifiers->type - && !decl_specifiers->any_type_specifiers_p - && ctor_dtor_or_conv_p <= 0 - && cxx_dialect >= cxx17) - { - cp_declarator *id = get_id_declarator (declarator); - tree name = id->u.id.unqualified_name; - parser->scope = id->u.id.qualifying_scope; - tree tmpl = cp_parser_lookup_name_simple (parser, name, id->id_loc); - if (tmpl - && (DECL_CLASS_TEMPLATE_P (tmpl) - || DECL_TEMPLATE_TEMPLATE_PARM_P (tmpl))) - { - id->u.id.unqualified_name = dguide_name (tmpl); - id->u.id.sfk = sfk_deduction_guide; - ctor_dtor_or_conv_p = 1; - } - } + /* Handle C++17 deduction guides. Note that class-scope + non-template deduction guides are instead handled in + cp_parser_member_declaration. */ + cp_parser_maybe_adjust_declarator_for_dguide (parser, + decl_specifiers, + declarator, + &ctor_dtor_or_conv_p); if (!member_p && !cp_parser_error_occurred (parser)) warn_about_ambiguous_parse (decl_specifiers, declarator); @@ -22679,13 +22944,27 @@ cp_parser_direct_declarator (cp_parser* parser, attrs = cp_parser_std_attribute_spec_seq (parser); + cp_omp_declare_simd_data odsd; + if ((flag_openmp || flag_openmp_simd) + && declarator + && declarator->std_attributes + && declarator->kind == cdk_id) + { + tree *pa = &declarator->std_attributes; + cp_parser_handle_directive_omp_attributes (parser, pa, + &odsd, false); + } + /* In here, we handle cases where attribute is used after the function declaration. For example: void func (int x) __attribute__((vector(..))); */ tree gnu_attrs = NULL_TREE; tree requires_clause = NULL_TREE; - late_return = (cp_parser_late_return_type_opt - (parser, declarator, requires_clause)); + late_return + = cp_parser_late_return_type_opt (parser, declarator, + requires_clause); + + cp_finalize_omp_declare_simd (parser, &odsd); /* Parse the virt-specifier-seq. */ virt_specifiers = cp_parser_virt_specifier_seq_opt (parser); @@ -24058,7 +24337,7 @@ cp_parser_parameter_declaration_list (cp_parser* parser, cp_parser_flags flags) and warn in grokparms if appropriate. */ deprecated_state = DEPRECATED_SUPPRESS; - if (parameter) + if (parameter && !cp_parser_error_occurred (parser)) { decl = grokdeclarator (parameter->declarator, ¶meter->decl_specifiers, @@ -24273,7 +24552,7 @@ cp_parser_parameter_declaration (cp_parser *parser, parser->default_arg_ok_p = false; /* After seeing a decl-specifier-seq, if the next token is not a - "(", there is no possibility that the code is a valid + "(" or "{", there is no possibility that the code is a valid expression. Therefore, if parsing tentatively, we commit at this point. */ if (!parser->in_template_argument_list_p @@ -24286,9 +24565,18 @@ cp_parser_parameter_declaration (cp_parser *parser, of some object of type "char" to "int". */ && !parser->in_type_id_in_expr_p && cp_parser_uncommitted_to_tentative_parse_p (parser) - && cp_lexer_next_token_is_not (parser->lexer, CPP_OPEN_BRACE) && cp_lexer_next_token_is_not (parser->lexer, CPP_OPEN_PAREN)) - cp_parser_commit_to_tentative_parse (parser); + { + if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE)) + { + if (decl_specifiers.type + && template_placeholder_p (decl_specifiers.type)) + /* This is a CTAD expression, not a parameter declaration. */ + cp_parser_simulate_error (parser); + } + else + cp_parser_commit_to_tentative_parse (parser); + } /* Parse the declarator. */ declarator_token_start = token; declarator = cp_parser_declarator (parser, @@ -24490,6 +24778,8 @@ cp_parser_default_argument (cp_parser *parser, bool template_parm_p) parser->greater_than_is_operator_p = !template_parm_p; auto odsd = make_temp_override (parser->omp_declare_simd, NULL); auto ord = make_temp_override (parser->oacc_routine, NULL); + auto oafp = make_temp_override (parser->omp_attrs_forbidden_p, false); + /* Local variable names (and the `this' keyword) may not appear in a default argument. */ saved_local_variables_forbidden_p = parser->local_variables_forbidden_p; @@ -26425,8 +26715,9 @@ cp_parser_member_declaration (cp_parser* parser) parser->colon_corrects_to_scope_p = false; + cp_omp_declare_simd_data odsd; if (cp_parser_using_declaration (parser, /*access_declaration=*/true)) - goto out; + goto out; /* Parse the decl-specifier-seq. */ decl_spec_token_start = cp_lexer_peek_token (parser->lexer); @@ -26435,6 +26726,12 @@ cp_parser_member_declaration (cp_parser* parser) | CP_PARSER_FLAGS_TYPENAME_OPTIONAL), &decl_specifiers, &declares_class_or_enum); + + if (decl_specifiers.attributes && (flag_openmp || flag_openmp_simd)) + cp_parser_handle_directive_omp_attributes (parser, + &decl_specifiers.attributes, + &odsd, true); + /* Check for an invalid type-name. */ if (!decl_specifiers.any_type_specifiers_p && cp_parser_parse_and_diagnose_invalid_type_name (parser)) @@ -26554,6 +26851,10 @@ cp_parser_member_declaration (cp_parser* parser) being declared. */ prefix_attributes = decl_specifiers.attributes; decl_specifiers.attributes = NULL_TREE; + if (parser->omp_declare_simd + && (parser->omp_declare_simd->attribs[0] + == &decl_specifiers.attributes)) + parser->omp_declare_simd->attribs[0] = &prefix_attributes; /* See if these declarations will be friends. */ friend_p = cp_parser_friend_p (&decl_specifiers); @@ -26710,6 +27011,12 @@ cp_parser_member_declaration (cp_parser* parser) goto out; } + /* Handle class-scope non-template C++17 deduction guides. */ + cp_parser_maybe_adjust_declarator_for_dguide (parser, + &decl_specifiers, + declarator, + &ctor_dtor_or_conv_p); + if (declares_class_or_enum & 2) cp_parser_check_for_definition_in_return_type (declarator, decl_specifiers.type, @@ -26942,6 +27249,7 @@ cp_parser_member_declaration (cp_parser* parser) cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON); out: parser->colon_corrects_to_scope_p = saved_colon_corrects_to_scope_p; + cp_finalize_omp_declare_simd (parser, &odsd); } /* Parse a pure-specifier. @@ -31067,6 +31375,13 @@ cp_parser_single_declaration (cp_parser* parser, | CP_PARSER_FLAGS_TYPENAME_OPTIONAL), &decl_specifiers, &declares_class_or_enum); + + cp_omp_declare_simd_data odsd; + if (decl_specifiers.attributes && (flag_openmp || flag_openmp_simd)) + cp_parser_handle_directive_omp_attributes (parser, + &decl_specifiers.attributes, + &odsd, true); + if (friend_p) *friend_p = cp_parser_friend_p (&decl_specifiers); @@ -31195,6 +31510,8 @@ cp_parser_single_declaration (cp_parser* parser, parser->qualifying_scope = NULL_TREE; parser->object_scope = NULL_TREE; + cp_finalize_omp_declare_simd (parser, &odsd); + return decl; } @@ -35692,7 +36009,9 @@ cp_parser_omp_clause_name (cp_parser *parser) result = PRAGMA_OMP_CLAUSE_DIST_SCHEDULE; break; case 'f': - if (!strcmp ("final", p)) + if (!strcmp ("filter", p)) + result = PRAGMA_OMP_CLAUSE_FILTER; + else if (!strcmp ("final", p)) result = PRAGMA_OMP_CLAUSE_FINAL; else if (!strcmp ("finalize", p)) result = PRAGMA_OACC_CLAUSE_FINALIZE; @@ -37028,6 +37347,34 @@ cp_parser_omp_clause_hint (cp_parser *parser, tree list, location_t location) return c; } +/* OpenMP 5.1: + filter ( integer-expression ) */ + +static tree +cp_parser_omp_clause_filter (cp_parser *parser, tree list, location_t location) +{ + tree t, c; + + matching_parens parens; + if (!parens.require_open (parser)) + return list; + + t = cp_parser_assignment_expression (parser); + + if (t == error_mark_node + || !parens.require_close (parser)) + cp_parser_skip_to_closing_parenthesis (parser, /*recovering=*/true, + /*or_comma=*/false, + /*consume_paren=*/true); + check_no_duplicate_clause (list, OMP_CLAUSE_FILTER, "filter", location); + + c = build_omp_clause (location, OMP_CLAUSE_FILTER); + OMP_CLAUSE_FILTER_EXPR (c) = t; + OMP_CLAUSE_CHAIN (c) = list; + + return c; +} + /* OpenMP 4.5: defaultmap ( tofrom : scalar ) @@ -38708,7 +39055,8 @@ cp_parser_omp_clause_dist_schedule (cp_parser *parser, tree list, proc_bind ( proc-bind-kind ) proc-bind-kind: - master | close | spread */ + primary | master | close | spread + where OpenMP 5.1 added 'primary' and deprecated the alias 'master'. */ static tree cp_parser_omp_clause_proc_bind (cp_parser *parser, tree list, @@ -38725,7 +39073,9 @@ cp_parser_omp_clause_proc_bind (cp_parser *parser, tree list, tree id = cp_lexer_peek_token (parser->lexer)->u.value; const char *p = IDENTIFIER_POINTER (id); - if (strcmp ("master", p) == 0) + if (strcmp ("primary", p) == 0) + kind = OMP_CLAUSE_PROC_BIND_PRIMARY; + else if (strcmp ("master", p) == 0) kind = OMP_CLAUSE_PROC_BIND_MASTER; else if (strcmp ("close", p) == 0) kind = OMP_CLAUSE_PROC_BIND_CLOSE; @@ -39134,6 +39484,11 @@ cp_parser_omp_all_clauses (cp_parser *parser, omp_clause_mask mask, token->location, false); c_name = "default"; break; + case PRAGMA_OMP_CLAUSE_FILTER: + clauses = cp_parser_omp_clause_filter (parser, clauses, + token->location); + c_name = "filter"; + break; case PRAGMA_OMP_CLAUSE_FINAL: clauses = cp_parser_omp_clause_final (parser, clauses, token->location); c_name = "final"; @@ -41670,6 +42025,73 @@ cp_parser_omp_master (cp_parser *parser, cp_token *pragma_tok, cp_parser_omp_structured_block (parser, if_p)); } +/* OpenMP 5.1: + # pragma omp masked masked-clauses new-line + structured-block */ + +#define OMP_MASKED_CLAUSE_MASK \ + (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FILTER) + +static tree +cp_parser_omp_masked (cp_parser *parser, cp_token *pragma_tok, + char *p_name, omp_clause_mask mask, tree *cclauses, + bool *if_p) +{ + tree clauses, sb, ret; + unsigned int save; + location_t loc = cp_lexer_peek_token (parser->lexer)->location; + + strcat (p_name, " masked"); + mask |= OMP_MASKED_CLAUSE_MASK; + + if (cp_lexer_next_token_is (parser->lexer, CPP_NAME)) + { + tree id = cp_lexer_peek_token (parser->lexer)->u.value; + const char *p = IDENTIFIER_POINTER (id); + + if (strcmp (p, "taskloop") == 0) + { + tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT]; + if (cclauses == NULL) + cclauses = cclauses_buf; + + cp_lexer_consume_token (parser->lexer); + if (!flag_openmp) /* flag_openmp_simd */ + return cp_parser_omp_taskloop (parser, pragma_tok, p_name, mask, + cclauses, if_p); + sb = begin_omp_structured_block (); + save = cp_parser_begin_omp_structured_block (parser); + ret = cp_parser_omp_taskloop (parser, pragma_tok, p_name, mask, + cclauses, if_p); + cp_parser_end_omp_structured_block (parser, save); + tree body = finish_omp_structured_block (sb); + if (ret == NULL) + return ret; + ret = c_finish_omp_masked (loc, body, + cclauses[C_OMP_CLAUSE_SPLIT_MASKED]); + OMP_MASKED_COMBINED (ret) = 1; + return ret; + } + } + if (!flag_openmp) /* flag_openmp_simd */ + { + cp_parser_skip_to_pragma_eol (parser, pragma_tok); + return NULL_TREE; + } + + clauses = cp_parser_omp_all_clauses (parser, mask, p_name, pragma_tok, + cclauses == NULL); + if (cclauses) + { + cp_omp_split_clauses (loc, OMP_MASTER, mask, clauses, cclauses); + clauses = cclauses[C_OMP_CLAUSE_SPLIT_MASKED]; + } + + return c_finish_omp_masked (loc, + cp_parser_omp_structured_block (parser, if_p), + clauses); +} + /* OpenMP 2.5: # pragma omp ordered new-line structured-block @@ -41715,7 +42137,7 @@ cp_parser_omp_ordered (cp_parser *parser, cp_token *pragma_tok, "%<depend%> clause may only be used in compound " "statements"); cp_parser_skip_to_pragma_eol (parser, pragma_tok); - return false; + return true; } tree clauses = cp_parser_omp_all_clauses (parser, @@ -41923,7 +42345,37 @@ cp_parser_omp_parallel (cp_parser *parser, cp_token *pragma_tok, { tree id = cp_lexer_peek_token (parser->lexer)->u.value; const char *p = IDENTIFIER_POINTER (id); - if (cclauses == NULL && strcmp (p, "master") == 0) + if (cclauses == NULL && strcmp (p, "masked") == 0) + { + tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT]; + cclauses = cclauses_buf; + + cp_lexer_consume_token (parser->lexer); + if (!flag_openmp) /* flag_openmp_simd */ + return cp_parser_omp_masked (parser, pragma_tok, p_name, mask, + cclauses, if_p); + block = begin_omp_parallel (); + save = cp_parser_begin_omp_structured_block (parser); + tree ret = cp_parser_omp_masked (parser, pragma_tok, p_name, mask, + cclauses, if_p); + cp_parser_end_omp_structured_block (parser, save); + stmt = finish_omp_parallel (cclauses[C_OMP_CLAUSE_SPLIT_PARALLEL], + block); + if (ret == NULL_TREE) + return ret; + /* masked does have just filter clause, but during gimplification + isn't represented by a gimplification omp context, so for + #pragma omp parallel masked don't set OMP_PARALLEL_COMBINED, + so that + #pragma omp parallel masked + #pragma omp taskloop simd lastprivate (x) + isn't confused with + #pragma omp parallel masked taskloop simd lastprivate (x) */ + if (OMP_MASKED_COMBINED (ret)) + OMP_PARALLEL_COMBINED (stmt) = 1; + return stmt; + } + else if (cclauses == NULL && strcmp (p, "master") == 0) { tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT]; cclauses = cclauses_buf; @@ -42045,6 +42497,30 @@ cp_parser_omp_single (cp_parser *parser, cp_token *pragma_tok, bool *if_p) return add_stmt (stmt); } +/* OpenMP 5.1: + # pragma omp scope scope-clause[optseq] new-line + structured-block */ + +#define OMP_SCOPE_CLAUSE_MASK \ + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_REDUCTION) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT)) + +static tree +cp_parser_omp_scope (cp_parser *parser, cp_token *pragma_tok, bool *if_p) +{ + tree stmt = make_node (OMP_SCOPE); + TREE_TYPE (stmt) = void_type_node; + SET_EXPR_LOCATION (stmt, pragma_tok->location); + + OMP_SCOPE_CLAUSES (stmt) + = cp_parser_omp_all_clauses (parser, OMP_SCOPE_CLAUSE_MASK, + "#pragma omp scope", pragma_tok); + OMP_SCOPE_BODY (stmt) = cp_parser_omp_structured_block (parser, if_p); + + return add_stmt (stmt); +} + /* OpenMP 3.0: # pragma omp task task-clause[optseq] new-line structured-block */ @@ -42185,7 +42661,7 @@ cp_parser_omp_cancel (cp_parser *parser, cp_token *pragma_tok) | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SECTIONS) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_TASKGROUP)) -static void +static bool cp_parser_omp_cancellation_point (cp_parser *parser, cp_token *pragma_tok, enum pragma_context context) { @@ -42207,7 +42683,7 @@ cp_parser_omp_cancellation_point (cp_parser *parser, cp_token *pragma_tok, { cp_parser_error (parser, "expected %<point%>"); cp_parser_skip_to_pragma_eol (parser, pragma_tok); - return; + return false; } if (context != pragma_compound) @@ -42219,7 +42695,7 @@ cp_parser_omp_cancellation_point (cp_parser *parser, cp_token *pragma_tok, else cp_parser_error (parser, "expected declaration specifiers"); cp_parser_skip_to_pragma_eol (parser, pragma_tok); - return; + return true; } clauses = cp_parser_omp_all_clauses (parser, @@ -42227,6 +42703,7 @@ cp_parser_omp_cancellation_point (cp_parser *parser, cp_token *pragma_tok, "#pragma omp cancellation point", pragma_tok); finish_omp_cancellation_point (clauses); + return true; } /* OpenMP 4.0: @@ -42522,7 +42999,7 @@ cp_parser_omp_target_data (cp_parser *parser, cp_token *pragma_tok, bool *if_p) | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEPEND) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT)) -static tree +static bool cp_parser_omp_target_enter_data (cp_parser *parser, cp_token *pragma_tok, enum pragma_context context) { @@ -42542,7 +43019,7 @@ cp_parser_omp_target_enter_data (cp_parser *parser, cp_token *pragma_tok, { cp_parser_error (parser, "expected %<data%>"); cp_parser_skip_to_pragma_eol (parser, pragma_tok); - return NULL_TREE; + return false; } if (context == pragma_stmt) @@ -42551,7 +43028,7 @@ cp_parser_omp_target_enter_data (cp_parser *parser, cp_token *pragma_tok, "%<#pragma %s%> may only be used in compound statements", "omp target enter data"); cp_parser_skip_to_pragma_eol (parser, pragma_tok); - return NULL_TREE; + return true; } tree clauses @@ -42591,14 +43068,15 @@ cp_parser_omp_target_enter_data (cp_parser *parser, cp_token *pragma_tok, error_at (pragma_tok->location, "%<#pragma omp target enter data%> must contain at least " "one %<map%> clause"); - return NULL_TREE; + return true; } tree stmt = make_node (OMP_TARGET_ENTER_DATA); TREE_TYPE (stmt) = void_type_node; OMP_TARGET_ENTER_DATA_CLAUSES (stmt) = clauses; SET_EXPR_LOCATION (stmt, pragma_tok->location); - return add_stmt (stmt); + add_stmt (stmt); + return true; } /* OpenMP 4.5: @@ -42612,7 +43090,7 @@ cp_parser_omp_target_enter_data (cp_parser *parser, cp_token *pragma_tok, | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEPEND) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT)) -static tree +static bool cp_parser_omp_target_exit_data (cp_parser *parser, cp_token *pragma_tok, enum pragma_context context) { @@ -42632,7 +43110,7 @@ cp_parser_omp_target_exit_data (cp_parser *parser, cp_token *pragma_tok, { cp_parser_error (parser, "expected %<data%>"); cp_parser_skip_to_pragma_eol (parser, pragma_tok); - return NULL_TREE; + return false; } if (context == pragma_stmt) @@ -42641,7 +43119,7 @@ cp_parser_omp_target_exit_data (cp_parser *parser, cp_token *pragma_tok, "%<#pragma %s%> may only be used in compound statements", "omp target exit data"); cp_parser_skip_to_pragma_eol (parser, pragma_tok); - return NULL_TREE; + return true; } tree clauses @@ -42683,14 +43161,15 @@ cp_parser_omp_target_exit_data (cp_parser *parser, cp_token *pragma_tok, error_at (pragma_tok->location, "%<#pragma omp target exit data%> must contain at least " "one %<map%> clause"); - return NULL_TREE; + return true; } tree stmt = make_node (OMP_TARGET_EXIT_DATA); TREE_TYPE (stmt) = void_type_node; OMP_TARGET_EXIT_DATA_CLAUSES (stmt) = clauses; SET_EXPR_LOCATION (stmt, pragma_tok->location); - return add_stmt (stmt); + add_stmt (stmt); + return true; } /* OpenMP 4.0: @@ -42714,7 +43193,7 @@ cp_parser_omp_target_update (cp_parser *parser, cp_token *pragma_tok, "%<#pragma %s%> may only be used in compound statements", "omp target update"); cp_parser_skip_to_pragma_eol (parser, pragma_tok); - return false; + return true; } tree clauses @@ -42726,7 +43205,7 @@ cp_parser_omp_target_update (cp_parser *parser, cp_token *pragma_tok, error_at (pragma_tok->location, "%<#pragma omp target update%> must contain at least one " "%<from%> or %<to%> clauses"); - return false; + return true; } tree stmt = make_node (OMP_TARGET_UPDATE); @@ -42734,7 +43213,7 @@ cp_parser_omp_target_update (cp_parser *parser, cp_token *pragma_tok, OMP_TARGET_UPDATE_CLAUSES (stmt) = clauses; SET_EXPR_LOCATION (stmt, pragma_tok->location); add_stmt (stmt); - return false; + return true; } /* OpenMP 4.0: @@ -42888,14 +43367,12 @@ cp_parser_omp_target (cp_parser *parser, cp_token *pragma_tok, else if (strcmp (p, "enter") == 0) { cp_lexer_consume_token (parser->lexer); - cp_parser_omp_target_enter_data (parser, pragma_tok, context); - return false; + return cp_parser_omp_target_enter_data (parser, pragma_tok, context); } else if (strcmp (p, "exit") == 0) { cp_lexer_consume_token (parser->lexer); - cp_parser_omp_target_exit_data (parser, pragma_tok, context); - return false; + return cp_parser_omp_target_exit_data (parser, pragma_tok, context); } else if (strcmp (p, "update") == 0) { @@ -43546,9 +44023,10 @@ cp_parser_omp_declare_simd (cp_parser *parser, cp_token *pragma_tok, data.error_seen = false; data.fndecl_seen = false; data.variant_p = variant_p; - data.in_omp_attribute_pragma = parser->lexer->in_omp_attribute_pragma; data.tokens = vNULL; - data.clauses = NULL_TREE; + data.attribs[0] = NULL; + data.attribs[1] = NULL; + data.loc = UNKNOWN_LOCATION; /* It is safe to take the address of a local variable; it will only be used while this scope is live. */ parser->omp_declare_simd = &data; @@ -43985,7 +44463,7 @@ cp_parser_omp_context_selector_specification (cp_parser *parser, static tree cp_finish_omp_declare_variant (cp_parser *parser, cp_token *pragma_tok, - tree attrs, bool in_omp_attribute_pragma) + tree attrs) { matching_parens parens; if (!parens.require_open (parser)) @@ -44044,7 +44522,7 @@ cp_finish_omp_declare_variant (cp_parser *parser, cp_token *pragma_tok, location_t varid_loc = make_location (caret_loc, start_loc, finish_loc); /* For now only in C++ attributes, do it always for OpenMP 5.1. */ - if (in_omp_attribute_pragma + if (parser->lexer->in_omp_attribute_pragma && cp_lexer_next_token_is (parser->lexer, CPP_COMMA) && cp_lexer_nth_token_is (parser->lexer, 2, CPP_NAME)) cp_lexer_consume_token (parser->lexer); @@ -44121,11 +44599,10 @@ cp_parser_late_parsing_omp_declare_simd (cp_parser *parser, tree attrs) cp_lexer_consume_token (parser->lexer); if (strcmp (kind, "simd") == 0) { - /* For now only in C++ attributes, do it always for OpenMP 5.1. */ - if (data->in_omp_attribute_pragma - && cp_lexer_next_token_is (parser->lexer, CPP_COMMA) + /* For now only in C++ attributes, do it always for OpenMP 5.1. + if (cp_lexer_next_token_is (parser->lexer, CPP_COMMA) && cp_lexer_nth_token_is (parser->lexer, 2, CPP_NAME)) - cp_lexer_consume_token (parser->lexer); + cp_lexer_consume_token (parser->lexer); */ cl = cp_parser_omp_all_clauses (parser, OMP_DECLARE_SIMD_CLAUSE_MASK, "#pragma omp declare simd", @@ -44142,12 +44619,150 @@ cp_parser_late_parsing_omp_declare_simd (cp_parser *parser, tree attrs) { gcc_assert (strcmp (kind, "variant") == 0); attrs - = cp_finish_omp_declare_variant (parser, pragma_tok, attrs, - data->in_omp_attribute_pragma); + = cp_finish_omp_declare_variant (parser, pragma_tok, attrs); } cp_parser_pop_lexer (parser); } + cp_lexer *lexer = NULL; + for (int i = 0; i < 2; i++) + { + if (data->attribs[i] == NULL) + continue; + for (tree *pa = data->attribs[i]; *pa; ) + if (get_attribute_namespace (*pa) == omp_identifier + && is_attribute_p ("directive", get_attribute_name (*pa))) + { + for (tree a = TREE_VALUE (*pa); a; a = TREE_CHAIN (a)) + { + tree d = TREE_VALUE (a); + gcc_assert (TREE_CODE (d) == DEFERRED_PARSE); + cp_token *first = DEFPARSE_TOKENS (d)->first; + cp_token *last = DEFPARSE_TOKENS (d)->last; + const char *directive[3] = {}; + for (int j = 0; j < 3; j++) + { + tree id = NULL_TREE; + if (first + j == last) + break; + if (first[j].type == CPP_NAME) + id = first[j].u.value; + else if (first[j].type == CPP_KEYWORD) + id = ridpointers[(int) first[j].keyword]; + else + break; + directive[j] = IDENTIFIER_POINTER (id); + } + const c_omp_directive *dir = NULL; + if (directive[0]) + dir = c_omp_categorize_directive (directive[0], directive[1], + directive[2]); + if (dir == NULL) + { + error_at (first->location, + "unknown OpenMP directive name in " + "%<omp::directive%> attribute argument"); + continue; + } + if (dir->id != PRAGMA_OMP_DECLARE + || (strcmp (directive[1], "simd") != 0 + && strcmp (directive[1], "variant") != 0)) + { + error_at (first->location, + "OpenMP directive other than %<declare simd%> " + "or %<declare variant%> appertains to a " + "declaration"); + continue; + } + + if (parser->omp_attrs_forbidden_p) + { + error_at (first->location, + "mixing OpenMP directives with attribute and " + "pragma syntax on the same statement"); + parser->omp_attrs_forbidden_p = false; + } + + if (!flag_openmp && strcmp (directive[1], "simd") != 0) + continue; + if (lexer == NULL) + { + lexer = cp_lexer_alloc (); + lexer->debugging_p = parser->lexer->debugging_p; + } + vec_safe_reserve (lexer->buffer, (last - first) + 2); + cp_token tok = {}; + tok.type = CPP_PRAGMA; + tok.keyword = RID_MAX; + tok.u.value = build_int_cst (NULL, PRAGMA_OMP_DECLARE); + tok.location = first->location; + lexer->buffer->quick_push (tok); + while (++first < last) + lexer->buffer->quick_push (*first); + tok = {}; + tok.type = CPP_PRAGMA_EOL; + tok.keyword = RID_MAX; + tok.location = last->location; + lexer->buffer->quick_push (tok); + tok = {}; + tok.type = CPP_EOF; + tok.keyword = RID_MAX; + tok.location = last->location; + lexer->buffer->quick_push (tok); + lexer->next = parser->lexer; + lexer->next_token = lexer->buffer->address (); + lexer->last_token = lexer->next_token + + lexer->buffer->length () + - 1; + lexer->in_omp_attribute_pragma = true; + parser->lexer = lexer; + /* Move the current source position to that of the first token + in the new lexer. */ + cp_lexer_set_source_position_from_token (lexer->next_token); + + cp_token *pragma_tok = cp_lexer_consume_token (parser->lexer); + tree id = cp_lexer_peek_token (parser->lexer)->u.value; + const char *kind = IDENTIFIER_POINTER (id); + cp_lexer_consume_token (parser->lexer); + + tree c, cl; + if (strcmp (kind, "simd") == 0) + { + if (cp_lexer_next_token_is (parser->lexer, CPP_COMMA) + && cp_lexer_nth_token_is (parser->lexer, 2, CPP_NAME)) + cp_lexer_consume_token (parser->lexer); + + omp_clause_mask mask = OMP_DECLARE_SIMD_CLAUSE_MASK; + cl = cp_parser_omp_all_clauses (parser, mask, + "#pragma omp declare simd", + pragma_tok); + if (cl) + cl = tree_cons (NULL_TREE, cl, NULL_TREE); + c = build_tree_list (get_identifier ("omp declare simd"), + cl); + TREE_CHAIN (c) = attrs; + if (processing_template_decl) + ATTR_IS_DEPENDENT (c) = 1; + attrs = c; + } + else + { + gcc_assert (strcmp (kind, "variant") == 0); + attrs + = cp_finish_omp_declare_variant (parser, pragma_tok, + attrs); + } + gcc_assert (parser->lexer != lexer); + vec_safe_truncate (lexer->buffer, 0); + } + *pa = TREE_CHAIN (*pa); + } + else + pa = &TREE_CHAIN (*pa); + } + if (lexer) + cp_lexer_destroy (lexer); + data->fndecl_seen = true; return attrs; } @@ -44191,8 +44806,10 @@ cp_parser_omp_declare_target (cp_parser *parser, cp_token *pragma_tok) } else { + struct omp_declare_target_attr a + = { parser->lexer->in_omp_attribute_pragma }; + vec_safe_push (scope_chain->omp_declare_target_attribute, a); cp_parser_require_pragma_eol (parser, pragma_tok); - scope_chain->omp_declare_target_attribute++; return; } for (tree c = clauses; c; c = OMP_CLAUSE_CHAIN (c)) @@ -44273,6 +44890,7 @@ static void cp_parser_omp_end_declare_target (cp_parser *parser, cp_token *pragma_tok) { const char *p = ""; + bool in_omp_attribute_pragma = parser->lexer->in_omp_attribute_pragma; if (cp_lexer_next_token_is (parser->lexer, CPP_NAME)) { tree id = cp_lexer_peek_token (parser->lexer)->u.value; @@ -44303,12 +44921,26 @@ cp_parser_omp_end_declare_target (cp_parser *parser, cp_token *pragma_tok) return; } cp_parser_require_pragma_eol (parser, pragma_tok); - if (!scope_chain->omp_declare_target_attribute) + if (!vec_safe_length (scope_chain->omp_declare_target_attribute)) error_at (pragma_tok->location, "%<#pragma omp end declare target%> without corresponding " "%<#pragma omp declare target%>"); else - scope_chain->omp_declare_target_attribute--; + { + omp_declare_target_attr + a = scope_chain->omp_declare_target_attribute->pop (); + if (a.attr_syntax != in_omp_attribute_pragma) + { + if (a.attr_syntax) + error_at (pragma_tok->location, + "%<declare target%> in attribute syntax terminated " + "with %<end declare target%> in pragma syntax"); + else + error_at (pragma_tok->location, + "%<declare target%> in pragma syntax terminated " + "with %<end declare target%> in attribute syntax"); + } + } } /* Helper function of cp_parser_omp_declare_reduction. Parse the combiner @@ -44932,6 +45564,16 @@ cp_parser_omp_requires (cp_parser *parser, cp_token *pragma_tok) } +/* OpenMP 5.1: + #pragma omp nothing new-line */ + +static void +cp_parser_omp_nothing (cp_parser *parser, cp_token *pragma_tok) +{ + cp_parser_skip_to_pragma_eol (parser, pragma_tok); +} + + /* OpenMP 4.5: #pragma omp taskloop taskloop-clause[optseq] new-line for-loop @@ -45354,6 +45996,11 @@ cp_parser_omp_construct (cp_parser *parser, cp_token *pragma_tok, bool *if_p) stmt = cp_parser_omp_loop (parser, pragma_tok, p_name, mask, NULL, if_p); break; + case PRAGMA_OMP_MASKED: + strcpy (p_name, "#pragma omp"); + stmt = cp_parser_omp_masked (parser, pragma_tok, p_name, mask, NULL, + if_p); + break; case PRAGMA_OMP_MASTER: strcpy (p_name, "#pragma omp"); stmt = cp_parser_omp_master (parser, pragma_tok, p_name, mask, NULL, @@ -45364,6 +46011,9 @@ cp_parser_omp_construct (cp_parser *parser, cp_token *pragma_tok, bool *if_p) stmt = cp_parser_omp_parallel (parser, pragma_tok, p_name, mask, NULL, if_p); break; + case PRAGMA_OMP_SCOPE: + stmt = cp_parser_omp_scope (parser, pragma_tok, if_p); + break; case PRAGMA_OMP_SECTIONS: strcpy (p_name, "#pragma omp"); stmt = cp_parser_omp_sections (parser, pragma_tok, p_name, mask, NULL); @@ -45793,7 +46443,7 @@ cp_parser_pragma (cp_parser *parser, enum pragma_context context, bool *if_p) cp_token *pragma_tok; unsigned int id; tree stmt; - bool ret; + bool ret = false; pragma_tok = cp_lexer_consume_token (parser->lexer); gcc_assert (pragma_tok->type == CPP_PRAGMA); @@ -45818,6 +46468,7 @@ cp_parser_pragma (cp_parser *parser, enum pragma_context context, bool *if_p) case pragma_stmt: error_at (pragma_tok->location, "%<#pragma %s%> may only be " "used in compound statements", "omp barrier"); + ret = true; break; default: goto bad_stmt; @@ -45833,6 +46484,7 @@ cp_parser_pragma (cp_parser *parser, enum pragma_context context, bool *if_p) case pragma_stmt: error_at (pragma_tok->location, "%<#pragma %s%> may only be " "used in compound statements", "omp depobj"); + ret = true; break; default: goto bad_stmt; @@ -45848,6 +46500,7 @@ cp_parser_pragma (cp_parser *parser, enum pragma_context context, bool *if_p) case pragma_stmt: error_at (pragma_tok->location, "%<#pragma %s%> may only be " "used in compound statements", "omp flush"); + ret = true; break; default: goto bad_stmt; @@ -45864,6 +46517,7 @@ cp_parser_pragma (cp_parser *parser, enum pragma_context context, bool *if_p) error_at (pragma_tok->location, "%<#pragma %s%> may only be used in compound statements", "omp taskwait"); + ret = true; break; default: goto bad_stmt; @@ -45880,6 +46534,7 @@ cp_parser_pragma (cp_parser *parser, enum pragma_context context, bool *if_p) error_at (pragma_tok->location, "%<#pragma %s%> may only be used in compound statements", "omp taskyield"); + ret = true; break; default: goto bad_stmt; @@ -45896,6 +46551,7 @@ cp_parser_pragma (cp_parser *parser, enum pragma_context context, bool *if_p) error_at (pragma_tok->location, "%<#pragma %s%> may only be used in compound statements", "omp cancel"); + ret = true; break; default: goto bad_stmt; @@ -45903,8 +46559,7 @@ cp_parser_pragma (cp_parser *parser, enum pragma_context context, bool *if_p) break; case PRAGMA_OMP_CANCELLATION_POINT: - cp_parser_omp_cancellation_point (parser, pragma_tok, context); - return false; + return cp_parser_omp_cancellation_point (parser, pragma_tok, context); case PRAGMA_OMP_THREADPRIVATE: cp_parser_omp_threadprivate (parser, pragma_tok); @@ -45923,6 +46578,7 @@ cp_parser_pragma (cp_parser *parser, enum pragma_context context, bool *if_p) error_at (pragma_tok->location, "%<#pragma %s%> may only be used in compound statements", "acc enter data"); + ret = true; break; } else if (context != pragma_compound) @@ -45936,6 +46592,7 @@ cp_parser_pragma (cp_parser *parser, enum pragma_context context, bool *if_p) error_at (pragma_tok->location, "%<#pragma %s%> may only be used in compound statements", "acc exit data"); + ret = true; break; } else if (context != pragma_compound) @@ -45948,6 +46605,7 @@ cp_parser_pragma (cp_parser *parser, enum pragma_context context, bool *if_p) { error_at (pragma_tok->location, "%<#pragma acc routine%> must be at file scope"); + ret = true; break; } cp_parser_oacc_routine (parser, pragma_tok, context); @@ -45959,6 +46617,7 @@ cp_parser_pragma (cp_parser *parser, enum pragma_context context, bool *if_p) error_at (pragma_tok->location, "%<#pragma %s%> may only be used in compound statements", "acc update"); + ret = true; break; } else if (context != pragma_compound) @@ -45972,6 +46631,7 @@ cp_parser_pragma (cp_parser *parser, enum pragma_context context, bool *if_p) error_at (pragma_tok->location, "%<#pragma %s%> may only be used in compound statements", "acc wait"); + ret = true; break; } else if (context != pragma_compound) @@ -45994,8 +46654,10 @@ cp_parser_pragma (cp_parser *parser, enum pragma_context context, bool *if_p) case PRAGMA_OMP_DISTRIBUTE: case PRAGMA_OMP_FOR: case PRAGMA_OMP_LOOP: + case PRAGMA_OMP_MASKED: case PRAGMA_OMP_MASTER: case PRAGMA_OMP_PARALLEL: + case PRAGMA_OMP_SCOPE: case PRAGMA_OMP_SECTIONS: case PRAGMA_OMP_SIMD: case PRAGMA_OMP_SINGLE: @@ -46016,10 +46678,15 @@ cp_parser_pragma (cp_parser *parser, enum pragma_context context, bool *if_p) error_at (pragma_tok->location, "%<#pragma omp requires%> may only be used at file or " "namespace scope"); + ret = true; break; } return cp_parser_omp_requires (parser, pragma_tok); + case PRAGMA_OMP_NOTHING: + cp_parser_omp_nothing (parser, pragma_tok); + return false; + case PRAGMA_OMP_ORDERED: if (context != pragma_stmt && context != pragma_compound) goto bad_stmt; @@ -46128,7 +46795,7 @@ cp_parser_pragma (cp_parser *parser, enum pragma_context context, bool *if_p) } cp_parser_skip_to_pragma_eol (parser, pragma_tok); - return false; + return ret; } /* The interface the pragma parsers have to the lexer. */ diff --git a/gcc/cp/parser.h b/gcc/cp/parser.h index e62742d..3669587 100644 --- a/gcc/cp/parser.h +++ b/gcc/cp/parser.h @@ -216,15 +216,14 @@ struct cp_omp_declare_simd_data { bool error_seen; /* Set if error has been reported. */ bool fndecl_seen; /* Set if one fn decl/definition has been seen already. */ bool variant_p; /* Set for #pragma omp declare variant. */ - bool in_omp_attribute_pragma; /* True if declare simd/variant comes from - C++11 attribute rather than pragma. */ + location_t loc; vec<cp_token_cache_ptr> tokens; - tree clauses; + tree *attribs[2]; }; /* Helper data structure for parsing #pragma acc routine. */ struct cp_oacc_routine_data : cp_omp_declare_simd_data { - location_t loc; + tree clauses; }; /* The cp_parser structure represents the C++ parser. */ diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index b396ddd..020a4bf 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -8486,7 +8486,8 @@ convert_template_argument (tree parm, can happen in the context of -fnew-ttp-matching. */; else if (tree a = type_uses_auto (t)) { - t = do_auto_deduction (t, arg, a, complain, adc_unify, args); + t = do_auto_deduction (t, arg, a, complain, adc_unify, args, + LOOKUP_IMPLICIT); if (t == error_mark_node) return error_mark_node; } @@ -17394,6 +17395,7 @@ tsubst_omp_clauses (tree clauses, enum c_omp_region_type ort, case OMP_CLAUSE_PRIORITY: case OMP_CLAUSE_ORDERED: case OMP_CLAUSE_HINT: + case OMP_CLAUSE_FILTER: case OMP_CLAUSE_NUM_GANGS: case OMP_CLAUSE_NUM_WORKERS: case OMP_CLAUSE_VECTOR_LENGTH: @@ -18786,9 +18788,11 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl, break; case OMP_SECTIONS: + case OMP_MASKED: omp_parallel_combined_clauses = NULL; /* FALLTHRU */ case OMP_SINGLE: + case OMP_SCOPE: case OMP_TEAMS: case OMP_CRITICAL: case OMP_TASKGROUP: @@ -20530,7 +20534,13 @@ tsubst_copy_and_build (tree t, if (member == error_mark_node) RETURN (error_mark_node); - if (TREE_CODE (member) == FIELD_DECL) + if (object_type && TYPE_PTRMEMFUNC_P (object_type) + && TREE_CODE (member) == FIELD_DECL) + { + r = build_ptrmemfunc_access_expr (object, DECL_NAME (member)); + RETURN (r); + } + else if (TREE_CODE (member) == FIELD_DECL) { r = finish_non_static_data_member (member, object, NULL_TREE); if (TREE_CODE (r) == COMPONENT_REF) @@ -28827,12 +28837,7 @@ collect_ctor_idx_types (tree ctor, tree list, tree elt = NULL_TREE) { tree ftype = elt ? elt : TREE_TYPE (idx); if (BRACE_ENCLOSED_INITIALIZER_P (val) - && CONSTRUCTOR_NELTS (val) - /* As in reshape_init_r, a non-aggregate or array-of-dependent-bound - type gets a single initializer. */ - && CP_AGGREGATE_TYPE_P (ftype) - && !(TREE_CODE (ftype) == ARRAY_TYPE - && uses_template_parms (TYPE_DOMAIN (ftype)))) + && CONSTRUCTOR_BRACES_ELIDED_P (val)) { tree subelt = NULL_TREE; if (TREE_CODE (ftype) == ARRAY_TYPE) diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index 34e5d76..e191aa3 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -3271,12 +3271,12 @@ finish_translation_unit (void) /* Do file scope __FUNCTION__ et al. */ finish_fname_decls (); - if (scope_chain->omp_declare_target_attribute) + if (vec_safe_length (scope_chain->omp_declare_target_attribute)) { if (!errorcount) error ("%<#pragma omp declare target%> without corresponding " "%<#pragma omp end declare target%>"); - scope_chain->omp_declare_target_attribute = 0; + vec_safe_truncate (scope_chain->omp_declare_target_attribute, 0); } } @@ -8204,6 +8204,29 @@ finish_omp_clauses (tree clauses, enum c_omp_region_type ort) } break; + case OMP_CLAUSE_FILTER: + t = OMP_CLAUSE_FILTER_EXPR (c); + if (t == error_mark_node) + remove = true; + else if (!type_dependent_expression_p (t) + && !INTEGRAL_TYPE_P (TREE_TYPE (t))) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%<filter%> expression must be integral"); + remove = true; + } + else + { + t = mark_rvalue_use (t); + if (!processing_template_decl) + { + t = maybe_constant_value (t); + t = fold_build_cleanup_point_expr (TREE_TYPE (t), t); + } + OMP_CLAUSE_FILTER_EXPR (c) = t; + } + break; + case OMP_CLAUSE_IS_DEVICE_PTR: case OMP_CLAUSE_USE_DEVICE_PTR: field_ok = (ort & C_ORT_OMP_DECLARE_SIMD) == C_ORT_OMP; @@ -10670,6 +10693,258 @@ fold_builtin_is_pointer_inverconvertible_with_class (location_t loc, int nargs, build_zero_cst (TREE_TYPE (arg))); } +/* Helper function for is_corresponding_member_aggr. Return true if + MEMBERTYPE pointer-to-data-member ARG can be found in anonymous + union or structure BASETYPE. */ + +static bool +is_corresponding_member_union (tree basetype, tree membertype, tree arg) +{ + for (tree field = TYPE_FIELDS (basetype); field; field = DECL_CHAIN (field)) + if (TREE_CODE (field) != FIELD_DECL || DECL_BIT_FIELD_TYPE (field)) + continue; + else if (same_type_ignoring_top_level_qualifiers_p (TREE_TYPE (field), + membertype)) + { + if (TREE_CODE (arg) != INTEGER_CST + || tree_int_cst_equal (arg, byte_position (field))) + return true; + } + else if (ANON_AGGR_TYPE_P (TREE_TYPE (field))) + { + tree narg = arg; + if (TREE_CODE (basetype) != UNION_TYPE + && TREE_CODE (narg) == INTEGER_CST) + narg = size_binop (MINUS_EXPR, arg, byte_position (field)); + if (is_corresponding_member_union (TREE_TYPE (field), + membertype, narg)) + return true; + } + return false; +} + +/* Helper function for fold_builtin_is_corresponding_member call. + Return boolean_false_node if MEMBERTYPE1 BASETYPE1::*ARG1 and + MEMBERTYPE2 BASETYPE2::*ARG2 aren't corresponding members, + boolean_true_node if they are corresponding members, or for + non-constant ARG2 the highest member offset for corresponding + members. */ + +static tree +is_corresponding_member_aggr (location_t loc, tree basetype1, tree membertype1, + tree arg1, tree basetype2, tree membertype2, + tree arg2) +{ + tree field1 = TYPE_FIELDS (basetype1); + tree field2 = TYPE_FIELDS (basetype2); + tree ret = boolean_false_node; + while (1) + { + bool r = next_common_initial_seqence (field1, field2); + if (field1 == NULL_TREE || field2 == NULL_TREE) + break; + if (r + && same_type_ignoring_top_level_qualifiers_p (TREE_TYPE (field1), + membertype1) + && same_type_ignoring_top_level_qualifiers_p (TREE_TYPE (field2), + membertype2)) + { + tree pos = byte_position (field1); + if (TREE_CODE (arg1) == INTEGER_CST + && tree_int_cst_equal (arg1, pos)) + { + if (TREE_CODE (arg2) == INTEGER_CST) + return boolean_true_node; + return pos; + } + else if (TREE_CODE (arg1) != INTEGER_CST) + ret = pos; + } + else if (ANON_AGGR_TYPE_P (TREE_TYPE (field1)) + && ANON_AGGR_TYPE_P (TREE_TYPE (field2))) + { + if ((!lookup_attribute ("no_unique_address", + DECL_ATTRIBUTES (field1))) + != !lookup_attribute ("no_unique_address", + DECL_ATTRIBUTES (field2))) + break; + if (!tree_int_cst_equal (bit_position (field1), + bit_position (field2))) + break; + bool overlap = true; + tree pos = byte_position (field1); + if (TREE_CODE (arg1) == INTEGER_CST) + { + tree off1 = fold_convert (sizetype, arg1); + tree sz1 = TYPE_SIZE_UNIT (TREE_TYPE (field1)); + if (tree_int_cst_lt (off1, pos) + || tree_int_cst_le (size_binop (PLUS_EXPR, pos, sz1), off1)) + overlap = false; + } + if (TREE_CODE (arg2) == INTEGER_CST) + { + tree off2 = fold_convert (sizetype, arg2); + tree sz2 = TYPE_SIZE_UNIT (TREE_TYPE (field2)); + if (tree_int_cst_lt (off2, pos) + || tree_int_cst_le (size_binop (PLUS_EXPR, pos, sz2), off2)) + overlap = false; + } + if (overlap + && NON_UNION_CLASS_TYPE_P (TREE_TYPE (field1)) + && NON_UNION_CLASS_TYPE_P (TREE_TYPE (field2))) + { + tree narg1 = arg1; + if (TREE_CODE (arg1) == INTEGER_CST) + narg1 = size_binop (MINUS_EXPR, + fold_convert (sizetype, arg1), pos); + tree narg2 = arg2; + if (TREE_CODE (arg2) == INTEGER_CST) + narg2 = size_binop (MINUS_EXPR, + fold_convert (sizetype, arg2), pos); + tree t1 = TREE_TYPE (field1); + tree t2 = TREE_TYPE (field2); + tree nret = is_corresponding_member_aggr (loc, t1, membertype1, + narg1, t2, membertype2, + narg2); + if (nret != boolean_false_node) + { + if (nret == boolean_true_node) + return nret; + if (TREE_CODE (arg1) == INTEGER_CST) + return size_binop (PLUS_EXPR, nret, pos); + ret = size_binop (PLUS_EXPR, nret, pos); + } + } + else if (overlap + && TREE_CODE (TREE_TYPE (field1)) == UNION_TYPE + && TREE_CODE (TREE_TYPE (field2)) == UNION_TYPE) + { + tree narg1 = arg1; + if (TREE_CODE (arg1) == INTEGER_CST) + narg1 = size_binop (MINUS_EXPR, + fold_convert (sizetype, arg1), pos); + tree narg2 = arg2; + if (TREE_CODE (arg2) == INTEGER_CST) + narg2 = size_binop (MINUS_EXPR, + fold_convert (sizetype, arg2), pos); + if (is_corresponding_member_union (TREE_TYPE (field1), + membertype1, narg1) + && is_corresponding_member_union (TREE_TYPE (field2), + membertype2, narg2)) + { + sorry_at (loc, "%<__builtin_is_corresponding_member%> " + "not well defined for anonymous unions"); + return boolean_false_node; + } + } + } + if (!r) + break; + field1 = DECL_CHAIN (field1); + field2 = DECL_CHAIN (field2); + } + return ret; +} + +/* Fold __builtin_is_corresponding_member call. */ + +tree +fold_builtin_is_corresponding_member (location_t loc, int nargs, + tree *args) +{ + /* Unless users call the builtin directly, the following 3 checks should be + ensured from std::is_corresponding_member function template. */ + if (nargs != 2) + { + error_at (loc, "%<__builtin_is_corresponding_member%> " + "needs two arguments"); + return boolean_false_node; + } + tree arg1 = args[0]; + tree arg2 = args[1]; + if (error_operand_p (arg1) || error_operand_p (arg2)) + return boolean_false_node; + if (!TYPE_PTRMEM_P (TREE_TYPE (arg1)) + || !TYPE_PTRMEM_P (TREE_TYPE (arg2))) + { + error_at (loc, "%<__builtin_is_corresponding_member%> " + "argument is not pointer to member"); + return boolean_false_node; + } + + if (!TYPE_PTRDATAMEM_P (TREE_TYPE (arg1)) + || !TYPE_PTRDATAMEM_P (TREE_TYPE (arg2))) + return boolean_false_node; + + tree membertype1 = TREE_TYPE (TREE_TYPE (arg1)); + tree basetype1 = TYPE_OFFSET_BASETYPE (TREE_TYPE (arg1)); + if (!complete_type_or_else (basetype1, NULL_TREE)) + return boolean_false_node; + + tree membertype2 = TREE_TYPE (TREE_TYPE (arg2)); + tree basetype2 = TYPE_OFFSET_BASETYPE (TREE_TYPE (arg2)); + if (!complete_type_or_else (basetype2, NULL_TREE)) + return boolean_false_node; + + if (!NON_UNION_CLASS_TYPE_P (basetype1) + || !NON_UNION_CLASS_TYPE_P (basetype2) + || !std_layout_type_p (basetype1) + || !std_layout_type_p (basetype2)) + return boolean_false_node; + + /* If the member types aren't layout compatible, then they + can't be corresponding members. */ + if (!layout_compatible_type_p (membertype1, membertype2)) + return boolean_false_node; + + if (TREE_CODE (arg1) == PTRMEM_CST) + arg1 = cplus_expand_constant (arg1); + if (TREE_CODE (arg2) == PTRMEM_CST) + arg2 = cplus_expand_constant (arg2); + + if (null_member_pointer_value_p (arg1) + || null_member_pointer_value_p (arg2)) + return boolean_false_node; + + if (TREE_CODE (arg1) == INTEGER_CST + && TREE_CODE (arg2) == INTEGER_CST + && !tree_int_cst_equal (arg1, arg2)) + return boolean_false_node; + + if (TREE_CODE (arg2) == INTEGER_CST + && TREE_CODE (arg1) != INTEGER_CST) + { + std::swap (arg1, arg2); + std::swap (membertype1, membertype2); + std::swap (basetype1, basetype2); + } + + tree ret = is_corresponding_member_aggr (loc, basetype1, membertype1, arg1, + basetype2, membertype2, arg2); + if (TREE_TYPE (ret) == boolean_type_node) + return ret; + /* If both arg1 and arg2 are INTEGER_CSTs, is_corresponding_member_aggr + already returns boolean_{true,false}_node whether those particular + members are corresponding members or not. Otherwise, if only + one of them is INTEGER_CST (canonicalized to first being INTEGER_CST + above), it returns boolean_false_node if it is certainly not a + corresponding member and otherwise we need to do a runtime check that + those two OFFSET_TYPE offsets are equal. + If neither of the operands is INTEGER_CST, is_corresponding_member_aggr + returns the largest offset at which the members would be corresponding + members, so perform arg1 <= ret && arg1 == arg2 runtime check. */ + gcc_assert (TREE_CODE (arg2) != INTEGER_CST); + if (TREE_CODE (arg1) == INTEGER_CST) + return fold_build2 (EQ_EXPR, boolean_type_node, arg1, + fold_convert (TREE_TYPE (arg1), arg2)); + ret = fold_build2 (LE_EXPR, boolean_type_node, + fold_convert (pointer_sized_int_node, arg1), + fold_convert (pointer_sized_int_node, ret)); + return fold_build2 (TRUTH_AND_EXPR, boolean_type_node, ret, + fold_build2 (EQ_EXPR, boolean_type_node, arg1, + fold_convert (TREE_TYPE (arg1), arg2))); +} + /* Actually evaluates the trait. */ static bool @@ -10760,6 +11035,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2) case CPTK_IS_FINAL: return CLASS_TYPE_P (type1) && CLASSTYPE_FINAL (type1); + case CPTK_IS_LAYOUT_COMPATIBLE: + return layout_compatible_type_p (type1, type2); + case CPTK_IS_LITERAL_TYPE: return literal_type_p (type1); @@ -10907,6 +11185,19 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2) case CPTK_IS_SAME_AS: break; + case CPTK_IS_LAYOUT_COMPATIBLE: + if (!array_of_unknown_bound_p (type1) + && TREE_CODE (type1) != VOID_TYPE + && !complete_type_or_else (type1, NULL_TREE)) + /* We already issued an error. */ + return error_mark_node; + if (!array_of_unknown_bound_p (type2) + && TREE_CODE (type2) != VOID_TYPE + && !complete_type_or_else (type2, NULL_TREE)) + /* We already issued an error. */ + return error_mark_node; + break; + default: gcc_unreachable (); } diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c index 8345396..3c62dd7 100644 --- a/gcc/cp/tree.c +++ b/gcc/cp/tree.c @@ -455,6 +455,7 @@ builtin_valid_in_constant_expr_p (const_tree decl) { case CP_BUILT_IN_IS_CONSTANT_EVALUATED: case CP_BUILT_IN_SOURCE_LOCATION: + case CP_BUILT_IN_IS_CORRESPONDING_MEMBER: case CP_BUILT_IN_IS_POINTER_INTERCONVERTIBLE_WITH_CLASS: return true; default: @@ -5386,7 +5387,9 @@ cp_walk_subtrees (tree *tp, int *walk_subtrees_p, walk_tree_fn func, // walk the parameter list. Doing so causes false // positives in the pack expansion checker since the // requires parameters are introduced as pack expansions. - WALK_SUBTREE (TREE_OPERAND (*tp, 1)); + ++cp_unevaluated_operand; + result = cp_walk_tree (&REQUIRES_EXPR_REQS (*tp), func, data, pset); + --cp_unevaluated_operand; *walk_subtrees_p = 0; break; diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c index 738e69a..a46c6d2 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -1621,6 +1621,176 @@ similar_type_p (tree type1, tree type2) return false; } +/* Helper function for layout_compatible_type_p and + is_corresponding_member_aggr. Advance to next members (NULL if + no further ones) and return true if those members are still part of + the common initial sequence. */ + +bool +next_common_initial_seqence (tree &memb1, tree &memb2) +{ + while (memb1) + { + if (TREE_CODE (memb1) != FIELD_DECL + || (DECL_FIELD_IS_BASE (memb1) && is_empty_field (memb1))) + { + memb1 = DECL_CHAIN (memb1); + continue; + } + if (DECL_FIELD_IS_BASE (memb1)) + { + memb1 = TYPE_FIELDS (TREE_TYPE (memb1)); + continue; + } + break; + } + while (memb2) + { + if (TREE_CODE (memb2) != FIELD_DECL + || (DECL_FIELD_IS_BASE (memb2) && is_empty_field (memb2))) + { + memb2 = DECL_CHAIN (memb2); + continue; + } + if (DECL_FIELD_IS_BASE (memb2)) + { + memb2 = TYPE_FIELDS (TREE_TYPE (memb2)); + continue; + } + break; + } + if (memb1 == NULL_TREE && memb2 == NULL_TREE) + return true; + if (memb1 == NULL_TREE || memb2 == NULL_TREE) + return false; + if (DECL_BIT_FIELD_TYPE (memb1)) + { + if (!DECL_BIT_FIELD_TYPE (memb2)) + return false; + if (!layout_compatible_type_p (DECL_BIT_FIELD_TYPE (memb1), + DECL_BIT_FIELD_TYPE (memb2))) + return false; + if (TYPE_PRECISION (TREE_TYPE (memb1)) + != TYPE_PRECISION (TREE_TYPE (memb2))) + return false; + } + else if (DECL_BIT_FIELD_TYPE (memb2)) + return false; + else if (!layout_compatible_type_p (TREE_TYPE (memb1), TREE_TYPE (memb2))) + return false; + if ((!lookup_attribute ("no_unique_address", DECL_ATTRIBUTES (memb1))) + != !lookup_attribute ("no_unique_address", DECL_ATTRIBUTES (memb2))) + return false; + if (!tree_int_cst_equal (bit_position (memb1), bit_position (memb2))) + return false; + return true; +} + +/* Return true if TYPE1 and TYPE2 are layout-compatible types. */ + +bool +layout_compatible_type_p (tree type1, tree type2) +{ + if (type1 == error_mark_node || type2 == error_mark_node) + return false; + if (type1 == type2) + return true; + if (TREE_CODE (type1) != TREE_CODE (type2)) + return false; + + type1 = cp_build_qualified_type (type1, TYPE_UNQUALIFIED); + type2 = cp_build_qualified_type (type2, TYPE_UNQUALIFIED); + + if (TREE_CODE (type1) == ENUMERAL_TYPE) + return (TYPE_ALIGN (type1) == TYPE_ALIGN (type2) + && tree_int_cst_equal (TYPE_SIZE (type1), TYPE_SIZE (type2)) + && same_type_p (finish_underlying_type (type1), + finish_underlying_type (type2))); + + if (CLASS_TYPE_P (type1) + && std_layout_type_p (type1) + && std_layout_type_p (type2) + && TYPE_ALIGN (type1) == TYPE_ALIGN (type2) + && tree_int_cst_equal (TYPE_SIZE (type1), TYPE_SIZE (type2))) + { + tree field1 = TYPE_FIELDS (type1); + tree field2 = TYPE_FIELDS (type2); + if (TREE_CODE (type1) == RECORD_TYPE) + { + while (1) + { + if (!next_common_initial_seqence (field1, field2)) + return false; + if (field1 == NULL_TREE) + return true; + field1 = DECL_CHAIN (field1); + field2 = DECL_CHAIN (field2); + } + } + /* Otherwise both types must be union types. + The standard says: + "Two standard-layout unions are layout-compatible if they have + the same number of non-static data members and corresponding + non-static data members (in any order) have layout-compatible + types." + but the code anticipates that bitfield vs. non-bitfield, + different bitfield widths or presence/absence of + [[no_unique_address]] should be checked as well. */ + auto_vec<tree, 16> vec; + unsigned int count = 0; + for (; field1; field1 = DECL_CHAIN (field1)) + if (TREE_CODE (field1) == FIELD_DECL) + count++; + for (; field2; field2 = DECL_CHAIN (field2)) + if (TREE_CODE (field2) == FIELD_DECL) + vec.safe_push (field2); + /* Discussions on core lean towards treating multiple union fields + of the same type as the same field, so this might need changing + in the future. */ + if (count != vec.length ()) + return false; + for (field1 = TYPE_FIELDS (type1); field1; field1 = DECL_CHAIN (field1)) + { + if (TREE_CODE (field1) != FIELD_DECL) + continue; + unsigned int j; + tree t1 = DECL_BIT_FIELD_TYPE (field1); + if (t1 == NULL_TREE) + t1 = TREE_TYPE (field1); + FOR_EACH_VEC_ELT (vec, j, field2) + { + tree t2 = DECL_BIT_FIELD_TYPE (field2); + if (t2 == NULL_TREE) + t2 = TREE_TYPE (field2); + if (DECL_BIT_FIELD_TYPE (field1)) + { + if (!DECL_BIT_FIELD_TYPE (field2)) + continue; + if (TYPE_PRECISION (TREE_TYPE (field1)) + != TYPE_PRECISION (TREE_TYPE (field2))) + continue; + } + else if (DECL_BIT_FIELD_TYPE (field2)) + continue; + if (!layout_compatible_type_p (t1, t2)) + continue; + if ((!lookup_attribute ("no_unique_address", + DECL_ATTRIBUTES (field1))) + != !lookup_attribute ("no_unique_address", + DECL_ATTRIBUTES (field2))) + continue; + break; + } + if (j == vec.length ()) + return false; + vec.unordered_remove (j); + } + return true; + } + + return same_type_p (type1, type2); +} + /* Returns 1 if TYPE1 is at least as qualified as TYPE2. */ bool diff --git a/gcc/doc/gty.texi b/gcc/doc/gty.texi index cf070c1..2ad7793 100644 --- a/gcc/doc/gty.texi +++ b/gcc/doc/gty.texi @@ -654,7 +654,10 @@ The GCC garbage collector GGC is only invoked explicitly. In contrast with many other garbage collectors, it is not implicitly invoked by allocation routines when a lot of memory has been consumed. So the only way to have GGC reclaim storage is to call the @code{ggc_collect} -function explicitly. This call is an expensive operation, as it may +function explicitly. +With @var{mode} @code{GGC_COLLECT_FORCE} or otherwise (default +@code{GGC_COLLECT_HEURISTIC}) when the internal heuristic decides to +collect, this call is potentially an expensive operation, as it may have to scan the entire heap. Beware that local variables (on the GCC call stack) are not followed by such an invocation (as many other garbage collectors do): you should reference all your data from static diff --git a/gcc/doc/install.texi b/gcc/doc/install.texi index 5d4c00a..9b4d7a4 100644 --- a/gcc/doc/install.texi +++ b/gcc/doc/install.texi @@ -1308,6 +1308,23 @@ rv64imac with lp64 and rv64imafc with lp64 will reuse this multi-lib set. rv64ima-lp64--f,c,fc @end smallexample +@option{--with-multilib-generator} have an optional configuration argument +@option{--cmodel=val} for code model, this option will expand with other +config options, @var{val} is a comma separated list of possible code model, +currently we support medlow and medany. + +Example 5: Add multi-lib suppport for rv64ima with lp64; rv64ima with lp64 and +medlow code model +@smallexample +rv64ima-lp64--;--cmodel=medlow +@end smallexample + +Example 6: Add multi-lib suppport for rv64ima with lp64; rv64ima with lp64 and +medlow code model; rv64ima with lp64 and medany code model +@smallexample +rv64ima-lp64--;--cmodel=medlow,medany +@end smallexample + @item --with-endian=@var{endians} Specify what endians to use. Currently only implemented for sh*-*-*. diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index 2551832..e8c8644 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -1104,7 +1104,8 @@ Objective-C and Objective-C++ Dialects}. @gccoptlist{-mboard=@var{name} -mnewlib -mhard-mul -mhard-div @gol -msoft-mul -msoft-div @gol -msoft-float -mhard-float -mdouble-float -munordered-float @gol --mcmov -mror -mrori -msext -msfimm -mshftimm} +-mcmov -mror -mrori -msext -msfimm -mshftimm @gol +-mcmodel=@var{code-model}} @emph{PDP-11 Options} @gccoptlist{-mfpu -msoft-float -mac0 -mno-ac0 -m40 -m45 -m10 @gol @@ -13384,9 +13385,6 @@ Setting to 0 disables the analysis completely. @item modref-max-escape-points Specifies the maximum number of escape points tracked by modref per SSA-name. -@item threader-mode -Specifies the mode the backwards threader should run in. - @item profile-func-internal-id A parameter to control whether to use function internal id in profile database lookup. If the value is 0, the compiler uses an id that @@ -26646,6 +26644,15 @@ Enable generation of shift with immediate (@code{l.srai}, @code{l.srli}, @code{l.slli}) instructions. By default extra instructions will be generated to store the immediate to a register first. +@item -mcmodel=small +@opindex mcmodel=small +Generate OpenRISC code for the small model: The GOT is limited to 64k. This is +the default model. + +@item -mcmodel=large +@opindex mcmodel=large +Generate OpenRISC code for the large model: The GOT may grow up to 4G in size. + @end table diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi index 3e12ddf..bbdbf5f 100644 --- a/gcc/doc/tm.texi +++ b/gcc/doc/tm.texi @@ -13558,3 +13558,16 @@ Store the result in @var{target} if convenient. The default clears the top byte of the original pointer. @end deftypefn @c hook-end + +@deftypefn {Target Hook} HOST_WIDE_INT TARGET_GCOV_TYPE_SIZE (void) +@c hook-start:TARGET_GCOV_TYPE_SIZE +Returns the gcov type size in bits. This type is used for example for +counters incremented by profiling and code-coverage events. The default +value is 64, if the type size of long long is greater than 32, otherwise the +default value is 32. A 64-bit type is recommended to avoid overflows of the +counters. If the @option{-fprofile-update=atomic} is used, then the +counters are incremented using atomic operations. Targets not supporting +64-bit atomic operations may override the default value and request a 32-bit +type. +@end deftypefn +@c hook-end diff --git a/gcc/doc/tm.texi.in b/gcc/doc/tm.texi.in index 611fc50..fdf16b9 100644 --- a/gcc/doc/tm.texi.in +++ b/gcc/doc/tm.texi.in @@ -8180,3 +8180,5 @@ maintainer is familiar with. @hook TARGET_MEMTAG_EXTRACT_TAG @hook TARGET_MEMTAG_UNTAGGED_POINTER + +@hook TARGET_GCOV_TYPE_SIZE diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c index b91a9b5..ba0a6d6 100644 --- a/gcc/dwarf2out.c +++ b/gcc/dwarf2out.c @@ -19915,22 +19915,23 @@ add_data_member_location_attribute (dw_die_ref die, { loc_descr = field_byte_offset (decl, ctx, &offset); - /* If loc_descr is available then we know the field offset is dynamic. - However, GDB does not handle dynamic field offsets very well at the - moment. */ - if (loc_descr != NULL && gnat_encodings != DWARF_GNAT_ENCODINGS_MINIMAL) + if (!loc_descr) + ; + + /* If loc_descr is available, then we know the offset is dynamic. */ + else if (gnat_encodings == DWARF_GNAT_ENCODINGS_ALL) { loc_descr = NULL; offset = 0; } - /* Data member location evalutation starts with the base address on the + /* Data member location evaluation starts with the base address on the stack. Compute the field offset and add it to this base address. */ - else if (loc_descr != NULL) + else add_loc_descr (&loc_descr, new_loc_descr (DW_OP_plus, 0, 0)); } - if (! loc_descr) + if (!loc_descr) { /* While DW_AT_data_bit_offset has been added already in DWARF4, e.g. GDB only added support to it in November 2016. For DWARF5 @@ -21252,6 +21253,7 @@ add_scalar_info (dw_die_ref die, enum dwarf_attribute attr, tree value, { if (get_AT (decl_die, DW_AT_location) || get_AT (decl_die, DW_AT_data_member_location) + || get_AT (decl_die, DW_AT_data_bit_offset) || get_AT (decl_die, DW_AT_const_value)) { add_AT_die_ref (die, attr, decl_die); @@ -21389,12 +21391,9 @@ add_bound_info (dw_die_ref subrange_die, enum dwarf_attribute bound_attr, /* FALLTHRU */ default: - /* Because of the complex interaction there can be with other GNAT - encodings, GDB isn't ready yet to handle proper DWARF description - for self-referencial subrange bounds: let GNAT encodings do the - magic in such a case. */ + /* Let GNAT encodings do the magic for self-referential bounds. */ if (is_ada () - && gnat_encodings != DWARF_GNAT_ENCODINGS_MINIMAL + && gnat_encodings == DWARF_GNAT_ENCODINGS_ALL && contains_placeholder_p (bound)) return; @@ -21566,7 +21565,7 @@ add_byte_size_attribute (dw_die_ref die, tree tree_node) /* Support for dynamically-sized objects was introduced in DWARF3. */ else if (TYPE_P (tree_node) && (dwarf_version >= 3 || !dwarf_strict) - && gnat_encodings == DWARF_GNAT_ENCODINGS_MINIMAL) + && gnat_encodings != DWARF_GNAT_ENCODINGS_ALL) { struct loc_descr_context ctx = { const_cast<tree> (tree_node), /* context_type */ @@ -25629,11 +25628,11 @@ gen_member_die (tree type, dw_die_ref context_die) splice_child_die (context_die, child); } - /* Do not generate standard DWARF for variant parts if we are generating - the corresponding GNAT encodings: DIEs generated for both would - conflict in our mappings. */ + /* Do not generate DWARF for variant parts if we are generating the + corresponding GNAT encodings: DIEs generated for the two schemes + would conflict in our mappings. */ else if (is_variant_part (member) - && gnat_encodings == DWARF_GNAT_ENCODINGS_MINIMAL) + && gnat_encodings != DWARF_GNAT_ENCODINGS_ALL) { vlr_ctx.variant_part_offset = byte_position (member); gen_variant_part (member, &vlr_ctx, context_die); diff --git a/gcc/flag-types.h b/gcc/flag-types.h index e39673f..4fb1cb4 100644 --- a/gcc/flag-types.h +++ b/gcc/flag-types.h @@ -444,21 +444,15 @@ enum parloops_schedule_type /* EVRP mode. */ enum evrp_mode { - EVRP_MODE_EVRP_FIRST = 0, + EVRP_MODE_RVRP_ONLY = 0, EVRP_MODE_EVRP_ONLY = 1, - EVRP_MODE_RVRP_ONLY = 2, + EVRP_MODE_EVRP_FIRST = 2, EVRP_MODE_RVRP_FIRST = 3, EVRP_MODE_TRACE = 4, - EVRP_MODE_DEBUG = 8 | EVRP_MODE_TRACE, - EVRP_MODE_RVRP_TRACE = EVRP_MODE_RVRP_ONLY | EVRP_MODE_TRACE, - EVRP_MODE_RVRP_DEBUG = EVRP_MODE_RVRP_ONLY | EVRP_MODE_DEBUG -}; - -/* Backwards threader mode. */ -enum threader_mode -{ - THREADER_MODE_LEGACY = 0, - THREADER_MODE_RANGER = 1 + EVRP_MODE_CACHE = (8 | EVRP_MODE_TRACE), + EVRP_MODE_GORI = 16, + EVRP_MODE_TRACE_GORI = (EVRP_MODE_TRACE | EVRP_MODE_GORI), + EVRP_MODE_DEBUG = (EVRP_MODE_GORI | EVRP_MODE_CACHE) }; /* Modes of OpenACC 'kernels' constructs handling. */ diff --git a/gcc/fold-const.c b/gcc/fold-const.c index 7dcecc9..ff23f12 100644 --- a/gcc/fold-const.c +++ b/gcc/fold-const.c @@ -12497,6 +12497,8 @@ fold_binary_loc (location_t loc, enum tree_code code, tree type, we can't optimize this. E.g. (unsigned long long) (1 << Y) for Y 31 might be 0xffffffff80000000. */ if ((code == LT_EXPR || code == GE_EXPR) + && (INTEGRAL_TYPE_P (TREE_TYPE (arg0)) + || VECTOR_INTEGER_TYPE_P (TREE_TYPE (arg0))) && TYPE_UNSIGNED (TREE_TYPE (arg0)) && CONVERT_EXPR_P (arg1) && TREE_CODE (TREE_OPERAND (arg1, 0)) == LSHIFT_EXPR diff --git a/gcc/fortran/ChangeLog b/gcc/fortran/ChangeLog index 2e7a9ad..86a2bda 100644 --- a/gcc/fortran/ChangeLog +++ b/gcc/fortran/ChangeLog @@ -1,3 +1,99 @@ +2021-08-17 Tobias Burnus <tobias@codesourcery.com> + + * dump-parse-tree.c (show_omp_node, show_code_node): Handle + EXEC_OMP_SCOPE. + * gfortran.h (enum gfc_statement): Add ST_OMP_(END_)SCOPE. + (enum gfc_exec_op): Add EXEC_OMP_SCOPE. + * match.h (gfc_match_omp_scope): New. + * openmp.c (OMP_SCOPE_CLAUSES): Define + (gfc_match_omp_scope): New. + (gfc_match_omp_cancellation_point, gfc_match_omp_end_nowait): + Improve error diagnostic. + (omp_code_to_statement): Handle ST_OMP_SCOPE. + (gfc_resolve_omp_directive): Handle EXEC_OMP_SCOPE. + * parse.c (decode_omp_directive, next_statement, + gfc_ascii_statement, parse_omp_structured_block, + parse_executable): Handle OpenMP's scope construct. + * resolve.c (gfc_resolve_blocks): Likewise + * st.c (gfc_free_statement): Likewise + * trans-openmp.c (gfc_trans_omp_scope): New. + (gfc_trans_omp_directive): Call it. + * trans.c (trans_code): handle EXEC_OMP_SCOPE. + +2021-08-16 Tobias Burnus <tobias@codesourcery.com> + + * dump-parse-tree.c (show_omp_clauses): Handle 'filter' clause. + (show_omp_node, show_code_node): Handle (combined) omp masked construct. + * frontend-passes.c (gfc_code_walker): Likewise. + * gfortran.h (enum gfc_statement): Add ST_OMP_*_MASKED*. + (enum gfc_exec_op): Add EXEC_OMP_*_MASKED*. + * match.h (gfc_match_omp_masked, gfc_match_omp_masked_taskloop, + gfc_match_omp_masked_taskloop_simd, gfc_match_omp_parallel_masked, + gfc_match_omp_parallel_masked_taskloop, + gfc_match_omp_parallel_masked_taskloop_simd): New prototypes. + * openmp.c (enum omp_mask1): Add OMP_CLAUSE_FILTER. + (gfc_match_omp_clauses): Match it. + (OMP_MASKED_CLAUSES, gfc_match_omp_parallel_masked, + gfc_match_omp_parallel_masked_taskloop, + gfc_match_omp_parallel_masked_taskloop_simd, + gfc_match_omp_masked, gfc_match_omp_masked_taskloop, + gfc_match_omp_masked_taskloop_simd): New. + (resolve_omp_clauses): Resolve filter clause. + (gfc_resolve_omp_parallel_blocks, resolve_omp_do, + omp_code_to_statement, gfc_resolve_omp_directive): Handle + omp masked constructs. + * parse.c (decode_omp_directive, case_exec_markers, + gfc_ascii_statement, parse_omp_do, parse_omp_structured_block, + parse_executable): Likewise. + * resolve.c (gfc_resolve_blocks, gfc_resolve_code): Likewise. + * st.c (gfc_free_statement): Likewise. + * trans-openmp.c (gfc_trans_omp_clauses): Handle filter clause. + (GFC_OMP_SPLIT_MASKED, GFC_OMP_MASK_MASKED): New enum values. + (gfc_trans_omp_masked): New. + (gfc_split_omp_clauses): Handle combined masked directives. + (gfc_trans_omp_master_taskloop): Rename to ... + (gfc_trans_omp_master_masked_taskloop): ... this; handle also + combined masked directives. + (gfc_trans_omp_parallel_master): Rename to ... + (gfc_trans_omp_parallel_master_masked): ... this; handle + combined masked directives. + (gfc_trans_omp_directive): Handle EXEC_OMP_*_MASKED*. + * trans.c (trans_code): Likewise. + +2021-08-15 Harald Anlauf <anlauf@gmx.de> + + PR fortran/99351 + * match.c (sync_statement): Replace %v code by %e in gfc_match to + allow for function references as STAT and ERRMSG arguments. + * resolve.c (resolve_sync): Adjust checks of STAT= and ERRMSG= to + being definable arguments. Function references with a data + pointer result are accepted. + * trans-stmt.c (gfc_trans_sync): Adjust assertion. + +2021-08-12 Tobias Burnus <tobias@codesourcery.com> + + * gfortran.h (gfc_omp_proc_bind_kind): Add OMP_PROC_BIND_PRIMARY. + * dump-parse-tree.c (show_omp_clauses): Add TODO comment to + change 'master' to 'primary' in proc_bind for OpenMP 5.1. + * intrinsic.texi (OMP_LIB): Mention OpenMP 5.1; add + omp_proc_bind_primary. + * openmp.c (gfc_match_omp_clauses): Accept + 'primary' as alias for 'master'. + * trans-openmp.c (gfc_trans_omp_clauses): Handle + OMP_PROC_BIND_PRIMARY. + +2021-08-11 Sandra Loosemore <sandra@codesourcery.com> + + * iso-c-binding.def (c_float128, c_float128_complex): Check + float128_type_node instead of gfc_float128_type_node. + * trans-types.c (gfc_init_kinds, gfc_build_real_type): + Update comments re supported 128-bit floating-point types. + +2021-08-11 Richard Biener <rguenther@suse.de> + + * trans-common.c (create_common): Set TREE_THIS_VOLATILE on the + COMPONENT_REF if the field is volatile. + 2021-08-07 Harald Anlauf <anlauf@gmx.de> PR fortran/68568 diff --git a/gcc/fortran/dump-parse-tree.c b/gcc/fortran/dump-parse-tree.c index 8e4a101..92d9f9e 100644 --- a/gcc/fortran/dump-parse-tree.c +++ b/gcc/fortran/dump-parse-tree.c @@ -1712,6 +1712,7 @@ show_omp_clauses (gfc_omp_clauses *omp_clauses) const char *type; switch (omp_clauses->proc_bind) { + case OMP_PROC_BIND_PRIMARY: type = "PRIMARY"; break; case OMP_PROC_BIND_MASTER: type = "MASTER"; break; case OMP_PROC_BIND_SPREAD: type = "SPREAD"; break; case OMP_PROC_BIND_CLOSE: type = "CLOSE"; break; @@ -1807,6 +1808,12 @@ show_omp_clauses (gfc_omp_clauses *omp_clauses) show_expr (omp_clauses->grainsize); fputc (')', dumpfile); } + if (omp_clauses->filter) + { + fputs (" FILTER(", dumpfile); + show_expr (omp_clauses->filter); + fputc (')', dumpfile); + } if (omp_clauses->hint) { fputs (" HINT(", dumpfile); @@ -1945,6 +1952,9 @@ show_omp_node (int level, gfc_code *c) case EXEC_OMP_DO_SIMD: name = "DO SIMD"; break; case EXEC_OMP_LOOP: name = "LOOP"; break; case EXEC_OMP_FLUSH: name = "FLUSH"; break; + case EXEC_OMP_MASKED: name = "MASKED"; break; + case EXEC_OMP_MASKED_TASKLOOP: name = "MASKED TASKLOOP"; break; + case EXEC_OMP_MASKED_TASKLOOP_SIMD: name = "MASKED TASKLOOP SIMD"; break; case EXEC_OMP_MASTER: name = "MASTER"; break; case EXEC_OMP_MASTER_TASKLOOP: name = "MASTER TASKLOOP"; break; case EXEC_OMP_MASTER_TASKLOOP_SIMD: name = "MASTER TASKLOOP SIMD"; break; @@ -1955,6 +1965,11 @@ show_omp_node (int level, gfc_code *c) case EXEC_OMP_PARALLEL_DO_SIMD: name = "PARALLEL DO SIMD"; break; case EXEC_OMP_PARALLEL_LOOP: name = "PARALLEL LOOP"; break; case EXEC_OMP_PARALLEL_MASTER: name = "PARALLEL MASTER"; break; + case EXEC_OMP_PARALLEL_MASKED: name = "PARALLEL MASK"; break; + case EXEC_OMP_PARALLEL_MASKED_TASKLOOP: + name = "PARALLEL MASK TASKLOOP"; break; + case EXEC_OMP_PARALLEL_MASKED_TASKLOOP_SIMD: + name = "PARALLEL MASK TASKLOOP SIMD"; break; case EXEC_OMP_PARALLEL_MASTER_TASKLOOP: name = "PARALLEL MASTER TASKLOOP"; break; case EXEC_OMP_PARALLEL_MASTER_TASKLOOP_SIMD: @@ -1962,6 +1977,7 @@ show_omp_node (int level, gfc_code *c) case EXEC_OMP_PARALLEL_SECTIONS: name = "PARALLEL SECTIONS"; break; case EXEC_OMP_PARALLEL_WORKSHARE: name = "PARALLEL WORKSHARE"; break; case EXEC_OMP_SCAN: name = "SCAN"; break; + case EXEC_OMP_SCOPE: name = "SCOPE"; break; case EXEC_OMP_SECTIONS: name = "SECTIONS"; break; case EXEC_OMP_SIMD: name = "SIMD"; break; case EXEC_OMP_SINGLE: name = "SINGLE"; break; @@ -2031,16 +2047,21 @@ show_omp_node (int level, gfc_code *c) case EXEC_OMP_DO_SIMD: case EXEC_OMP_LOOP: case EXEC_OMP_ORDERED: + case EXEC_OMP_MASKED: case EXEC_OMP_PARALLEL: case EXEC_OMP_PARALLEL_DO: case EXEC_OMP_PARALLEL_DO_SIMD: case EXEC_OMP_PARALLEL_LOOP: + case EXEC_OMP_PARALLEL_MASKED: + case EXEC_OMP_PARALLEL_MASKED_TASKLOOP: + case EXEC_OMP_PARALLEL_MASKED_TASKLOOP_SIMD: case EXEC_OMP_PARALLEL_MASTER: case EXEC_OMP_PARALLEL_MASTER_TASKLOOP: case EXEC_OMP_PARALLEL_MASTER_TASKLOOP_SIMD: case EXEC_OMP_PARALLEL_SECTIONS: case EXEC_OMP_PARALLEL_WORKSHARE: case EXEC_OMP_SCAN: + case EXEC_OMP_SCOPE: case EXEC_OMP_SECTIONS: case EXEC_OMP_SIMD: case EXEC_OMP_SINGLE: @@ -3249,6 +3270,9 @@ show_code_node (int level, gfc_code *c) case EXEC_OMP_DO_SIMD: case EXEC_OMP_FLUSH: case EXEC_OMP_LOOP: + case EXEC_OMP_MASKED: + case EXEC_OMP_MASKED_TASKLOOP: + case EXEC_OMP_MASKED_TASKLOOP_SIMD: case EXEC_OMP_MASTER: case EXEC_OMP_MASTER_TASKLOOP: case EXEC_OMP_MASTER_TASKLOOP_SIMD: @@ -3257,12 +3281,16 @@ show_code_node (int level, gfc_code *c) case EXEC_OMP_PARALLEL_DO: case EXEC_OMP_PARALLEL_DO_SIMD: case EXEC_OMP_PARALLEL_LOOP: + case EXEC_OMP_PARALLEL_MASKED: + case EXEC_OMP_PARALLEL_MASKED_TASKLOOP: + case EXEC_OMP_PARALLEL_MASKED_TASKLOOP_SIMD: case EXEC_OMP_PARALLEL_MASTER: case EXEC_OMP_PARALLEL_MASTER_TASKLOOP: case EXEC_OMP_PARALLEL_MASTER_TASKLOOP_SIMD: case EXEC_OMP_PARALLEL_SECTIONS: case EXEC_OMP_PARALLEL_WORKSHARE: case EXEC_OMP_SCAN: + case EXEC_OMP_SCOPE: case EXEC_OMP_SECTIONS: case EXEC_OMP_SIMD: case EXEC_OMP_SINGLE: diff --git a/gcc/fortran/frontend-passes.c b/gcc/fortran/frontend-passes.c index 996dcc2..145bff5 100644 --- a/gcc/fortran/frontend-passes.c +++ b/gcc/fortran/frontend-passes.c @@ -5556,6 +5556,9 @@ gfc_code_walker (gfc_code **c, walk_code_fn_t codefn, walk_expr_fn_t exprfn, case EXEC_OMP_PARALLEL_DO: case EXEC_OMP_PARALLEL_DO_SIMD: case EXEC_OMP_PARALLEL_LOOP: + case EXEC_OMP_PARALLEL_MASKED: + case EXEC_OMP_PARALLEL_MASKED_TASKLOOP: + case EXEC_OMP_PARALLEL_MASKED_TASKLOOP_SIMD: case EXEC_OMP_PARALLEL_MASTER: case EXEC_OMP_PARALLEL_MASTER_TASKLOOP: case EXEC_OMP_PARALLEL_MASTER_TASKLOOP_SIMD: diff --git a/gcc/fortran/gfortran.h b/gcc/fortran/gfortran.h index 921aed9..a7d82ae 100644 --- a/gcc/fortran/gfortran.h +++ b/gcc/fortran/gfortran.h @@ -275,7 +275,13 @@ enum gfc_statement ST_OMP_PARALLEL_LOOP, ST_OMP_END_PARALLEL_LOOP, ST_OMP_TEAMS_LOOP, ST_OMP_END_TEAMS_LOOP, ST_OMP_TARGET_PARALLEL_LOOP, ST_OMP_END_TARGET_PARALLEL_LOOP, ST_OMP_TARGET_TEAMS_LOOP, - ST_OMP_END_TARGET_TEAMS_LOOP, ST_NONE + ST_OMP_END_TARGET_TEAMS_LOOP, ST_OMP_MASKED, ST_OMP_END_MASKED, + ST_OMP_PARALLEL_MASKED, ST_OMP_END_PARALLEL_MASKED, + ST_OMP_PARALLEL_MASKED_TASKLOOP, ST_OMP_END_PARALLEL_MASKED_TASKLOOP, + ST_OMP_PARALLEL_MASKED_TASKLOOP_SIMD, + ST_OMP_END_PARALLEL_MASKED_TASKLOOP_SIMD, ST_OMP_MASKED_TASKLOOP, + ST_OMP_END_MASKED_TASKLOOP, ST_OMP_MASKED_TASKLOOP_SIMD, + ST_OMP_END_MASKED_TASKLOOP_SIMD, ST_OMP_SCOPE, ST_OMP_END_SCOPE, ST_NONE }; /* Types of interfaces that we can have. Assignment interfaces are @@ -1362,6 +1368,7 @@ enum gfc_omp_default_sharing enum gfc_omp_proc_bind_kind { OMP_PROC_BIND_UNKNOWN, + OMP_PROC_BIND_PRIMARY, OMP_PROC_BIND_MASTER, OMP_PROC_BIND_SPREAD, OMP_PROC_BIND_CLOSE @@ -1465,6 +1472,7 @@ typedef struct gfc_omp_clauses struct gfc_expr *device; struct gfc_expr *thread_limit; struct gfc_expr *grainsize; + struct gfc_expr *filter; struct gfc_expr *hint; struct gfc_expr *num_tasks; struct gfc_expr *priority; @@ -2757,7 +2765,10 @@ enum gfc_exec_op EXEC_OMP_PARALLEL_MASTER, EXEC_OMP_PARALLEL_MASTER_TASKLOOP, EXEC_OMP_PARALLEL_MASTER_TASKLOOP_SIMD, EXEC_OMP_MASTER_TASKLOOP, EXEC_OMP_MASTER_TASKLOOP_SIMD, EXEC_OMP_LOOP, EXEC_OMP_PARALLEL_LOOP, - EXEC_OMP_TEAMS_LOOP, EXEC_OMP_TARGET_PARALLEL_LOOP, EXEC_OMP_TARGET_TEAMS_LOOP + EXEC_OMP_TEAMS_LOOP, EXEC_OMP_TARGET_PARALLEL_LOOP, + EXEC_OMP_TARGET_TEAMS_LOOP, EXEC_OMP_MASKED, EXEC_OMP_PARALLEL_MASKED, + EXEC_OMP_PARALLEL_MASKED_TASKLOOP, EXEC_OMP_PARALLEL_MASKED_TASKLOOP_SIMD, + EXEC_OMP_MASKED_TASKLOOP, EXEC_OMP_MASKED_TASKLOOP_SIMD, EXEC_OMP_SCOPE }; typedef struct gfc_code diff --git a/gcc/fortran/intrinsic.texi b/gcc/fortran/intrinsic.texi index e56c40a..81c5298 100644 --- a/gcc/fortran/intrinsic.texi +++ b/gcc/fortran/intrinsic.texi @@ -15277,8 +15277,9 @@ with the following options: @code{-fno-unsafe-math-optimizations @section OpenMP Modules @code{OMP_LIB} and @code{OMP_LIB_KINDS} @table @asis @item @emph{Standard}: -OpenMP Application Program Interface v4.5 and -OpenMP Application Program Interface v5.0 (partially supported). +OpenMP Application Program Interface v4.5, +OpenMP Application Program Interface v5.0 (partially supported) and +OpenMP Application Program Interface v5.1 (partially supported). @end table The OpenMP Fortran runtime library routines are provided both in @@ -15341,6 +15342,7 @@ kind @code{omp_proc_bind_kind}: @table @asis @item @code{omp_proc_bind_false} @item @code{omp_proc_bind_true} +@item @code{omp_proc_bind_primary} @item @code{omp_proc_bind_master} @item @code{omp_proc_bind_close} @item @code{omp_proc_bind_spread} diff --git a/gcc/fortran/iso-c-binding.def b/gcc/fortran/iso-c-binding.def index 8bf69ef..e65c750 100644 --- a/gcc/fortran/iso-c-binding.def +++ b/gcc/fortran/iso-c-binding.def @@ -114,9 +114,14 @@ NAMED_REALCST (ISOCBINDING_DOUBLE, "c_double", \ get_real_kind_from_node (double_type_node), GFC_STD_F2003) NAMED_REALCST (ISOCBINDING_LONG_DOUBLE, "c_long_double", \ get_real_kind_from_node (long_double_type_node), GFC_STD_F2003) + +/* GNU Extension. Note that the equivalence here is specifically to + the IEEE 128-bit type __float128; if that does not map onto a type + otherwise supported by the Fortran front end, get_real_kind_from_node + will reject it as unsupported. */ NAMED_REALCST (ISOCBINDING_FLOAT128, "c_float128", \ - gfc_float128_type_node == NULL_TREE \ - ? -4 : get_real_kind_from_node (gfc_float128_type_node), \ + (float128_type_node == NULL_TREE \ + ? -4 : get_real_kind_from_node (float128_type_node)), \ GFC_STD_GNU) NAMED_CMPXCST (ISOCBINDING_FLOAT_COMPLEX, "c_float_complex", \ get_real_kind_from_node (float_type_node), GFC_STD_F2003) @@ -124,9 +129,11 @@ NAMED_CMPXCST (ISOCBINDING_DOUBLE_COMPLEX, "c_double_complex", \ get_real_kind_from_node (double_type_node), GFC_STD_F2003) NAMED_CMPXCST (ISOCBINDING_LONG_DOUBLE_COMPLEX, "c_long_double_complex", \ get_real_kind_from_node (long_double_type_node), GFC_STD_F2003) + +/* GNU Extension. Similar issues to c_float128 above. */ NAMED_CMPXCST (ISOCBINDING_FLOAT128_COMPLEX, "c_float128_complex", \ - gfc_float128_type_node == NULL_TREE \ - ? -4 : get_real_kind_from_node (gfc_float128_type_node), \ + (float128_type_node == NULL_TREE \ + ? -4 : get_real_kind_from_node (float128_type_node)), \ GFC_STD_GNU) NAMED_LOGCST (ISOCBINDING_BOOL, "c_bool", \ diff --git a/gcc/fortran/match.c b/gcc/fortran/match.c index b110548..16502da 100644 --- a/gcc/fortran/match.c +++ b/gcc/fortran/match.c @@ -3855,7 +3855,7 @@ sync_statement (gfc_statement st) for (;;) { - m = gfc_match (" stat = %v", &tmp); + m = gfc_match (" stat = %e", &tmp); if (m == MATCH_ERROR) goto syntax; if (m == MATCH_YES) @@ -3875,7 +3875,7 @@ sync_statement (gfc_statement st) break; } - m = gfc_match (" errmsg = %v", &tmp); + m = gfc_match (" errmsg = %e", &tmp); if (m == MATCH_ERROR) goto syntax; if (m == MATCH_YES) diff --git a/gcc/fortran/match.h b/gcc/fortran/match.h index bb1f34f..5127b4b 100644 --- a/gcc/fortran/match.h +++ b/gcc/fortran/match.h @@ -169,21 +169,29 @@ match gfc_match_omp_do (void); match gfc_match_omp_do_simd (void); match gfc_match_omp_loop (void); match gfc_match_omp_flush (void); +match gfc_match_omp_masked (void); +match gfc_match_omp_masked_taskloop (void); +match gfc_match_omp_masked_taskloop_simd (void); match gfc_match_omp_master (void); match gfc_match_omp_master_taskloop (void); match gfc_match_omp_master_taskloop_simd (void); +match gfc_match_omp_nothing (void); match gfc_match_omp_ordered (void); match gfc_match_omp_ordered_depend (void); match gfc_match_omp_parallel (void); match gfc_match_omp_parallel_do (void); match gfc_match_omp_parallel_do_simd (void); match gfc_match_omp_parallel_loop (void); +match gfc_match_omp_parallel_masked (void); +match gfc_match_omp_parallel_masked_taskloop (void); +match gfc_match_omp_parallel_masked_taskloop_simd (void); match gfc_match_omp_parallel_master (void); match gfc_match_omp_parallel_master_taskloop (void); match gfc_match_omp_parallel_master_taskloop_simd (void); match gfc_match_omp_parallel_sections (void); match gfc_match_omp_parallel_workshare (void); match gfc_match_omp_requires (void); +match gfc_match_omp_scope (void); match gfc_match_omp_scan (void); match gfc_match_omp_sections (void); match gfc_match_omp_simd (void); diff --git a/gcc/fortran/openmp.c b/gcc/fortran/openmp.c index 520a435..fd219dc 100644 --- a/gcc/fortran/openmp.c +++ b/gcc/fortran/openmp.c @@ -847,6 +847,7 @@ enum omp_mask1 OMP_CLAUSE_DETACH, /* OpenMP 5.0. */ OMP_CLAUSE_AFFINITY, /* OpenMP 5.0. */ OMP_CLAUSE_BIND, /* OpenMP 5.0. */ + OMP_CLAUSE_FILTER, /* OpenMP 5.1. */ OMP_CLAUSE_NOWAIT, /* This must come last. */ OMP_MASK1_LAST @@ -1772,6 +1773,10 @@ gfc_match_omp_clauses (gfc_omp_clauses **cp, const omp_mask mask, } break; case 'f': + if ((mask & OMP_CLAUSE_FILTER) + && c->filter == NULL + && gfc_match ("filter ( %e )", &c->filter) == MATCH_YES) + continue; if ((mask & OMP_CLAUSE_FINAL) && c->final_expr == NULL && gfc_match ("final ( %e )", &c->final_expr) == MATCH_YES) @@ -2231,7 +2236,10 @@ gfc_match_omp_clauses (gfc_omp_clauses **cp, const omp_mask mask, if ((mask & OMP_CLAUSE_PROC_BIND) && c->proc_bind == OMP_PROC_BIND_UNKNOWN) { - if (gfc_match ("proc_bind ( master )") == MATCH_YES) + /* Primary is new and master is deprecated in OpenMP 5.1. */ + if (gfc_match ("proc_bind ( primary )") == MATCH_YES) + c->proc_bind = OMP_PROC_BIND_MASTER; + else if (gfc_match ("proc_bind ( master )") == MATCH_YES) c->proc_bind = OMP_PROC_BIND_MASTER; else if (gfc_match ("proc_bind ( spread )") == MATCH_YES) c->proc_bind = OMP_PROC_BIND_SPREAD; @@ -3142,6 +3150,8 @@ cleanup: #define OMP_LOOP_CLAUSES \ (omp_mask (OMP_CLAUSE_BIND) | OMP_CLAUSE_COLLAPSE | OMP_CLAUSE_ORDER \ | OMP_CLAUSE_PRIVATE | OMP_CLAUSE_LASTPRIVATE | OMP_CLAUSE_REDUCTION) +#define OMP_SCOPE_CLAUSES \ + (omp_mask (OMP_CLAUSE_PRIVATE) | OMP_CLAUSE_REDUCTION) #define OMP_SECTIONS_CLAUSES \ (omp_mask (OMP_CLAUSE_PRIVATE) | OMP_CLAUSE_FIRSTPRIVATE \ | OMP_CLAUSE_LASTPRIVATE | OMP_CLAUSE_REDUCTION) @@ -3196,6 +3206,8 @@ cleanup: #define OMP_ATOMIC_CLAUSES \ (omp_mask (OMP_CLAUSE_ATOMIC) | OMP_CLAUSE_CAPTURE | OMP_CLAUSE_HINT \ | OMP_CLAUSE_MEMORDER) +#define OMP_MASKED_CLAUSES \ + (omp_mask (OMP_CLAUSE_FILTER)) static match @@ -4155,6 +4167,31 @@ gfc_match_omp_parallel_do_simd (void) match +gfc_match_omp_parallel_masked (void) +{ + return match_omp (EXEC_OMP_PARALLEL_MASKED, + OMP_PARALLEL_CLAUSES | OMP_MASKED_CLAUSES); +} + +match +gfc_match_omp_parallel_masked_taskloop (void) +{ + return match_omp (EXEC_OMP_PARALLEL_MASKED_TASKLOOP, + (OMP_PARALLEL_CLAUSES | OMP_MASKED_CLAUSES + | OMP_TASKLOOP_CLAUSES) + & ~(omp_mask (OMP_CLAUSE_IN_REDUCTION))); +} + +match +gfc_match_omp_parallel_masked_taskloop_simd (void) +{ + return match_omp (EXEC_OMP_PARALLEL_MASKED_TASKLOOP_SIMD, + (OMP_PARALLEL_CLAUSES | OMP_MASKED_CLAUSES + | OMP_TASKLOOP_CLAUSES | OMP_SIMD_CLAUSES) + & ~(omp_mask (OMP_CLAUSE_IN_REDUCTION))); +} + +match gfc_match_omp_parallel_master (void) { return match_omp (EXEC_OMP_PARALLEL_MASTER, OMP_PARALLEL_CLAUSES); @@ -4453,6 +4490,13 @@ gfc_match_omp_scan (void) match +gfc_match_omp_scope (void) +{ + return match_omp (EXEC_OMP_SCOPE, OMP_SCOPE_CLAUSES); +} + + +match gfc_match_omp_sections (void) { return match_omp (EXEC_OMP_SECTIONS, OMP_SECTIONS_CLAUSES); @@ -4701,6 +4745,27 @@ gfc_match_omp_workshare (void) match +gfc_match_omp_masked (void) +{ + return match_omp (EXEC_OMP_MASKED, OMP_MASKED_CLAUSES); +} + +match +gfc_match_omp_masked_taskloop (void) +{ + return match_omp (EXEC_OMP_MASKED_TASKLOOP, + OMP_MASKED_CLAUSES | OMP_TASKLOOP_CLAUSES); +} + +match +gfc_match_omp_masked_taskloop_simd (void) +{ + return match_omp (EXEC_OMP_MASKED_TASKLOOP_SIMD, + (OMP_MASKED_CLAUSES | OMP_TASKLOOP_CLAUSES + | OMP_SIMD_CLAUSES)); +} + +match gfc_match_omp_master (void) { if (gfc_match_omp_eos () != MATCH_YES) @@ -4732,6 +4797,17 @@ gfc_match_omp_ordered (void) return match_omp (EXEC_OMP_ORDERED, OMP_ORDERED_CLAUSES); } +match +gfc_match_omp_nothing (void) +{ + if (gfc_match_omp_eos () != MATCH_YES) + { + gfc_error ("Unexpected junk after $OMP NOTHING statement at %C"); + return MATCH_ERROR; + } + /* Will use ST_NONE; therefore, no EXEC_OMP_ is needed. */ + return MATCH_YES; +} match gfc_match_omp_ordered_depend (void) @@ -4919,7 +4995,11 @@ gfc_match_omp_cancellation_point (void) gfc_omp_clauses *c; enum gfc_omp_cancel_kind kind = gfc_match_omp_cancel_kind (); if (kind == OMP_CANCEL_UNKNOWN) - return MATCH_ERROR; + { + gfc_error ("Expected construct-type PARALLEL, SECTIONS, DO or TASKGROUP " + "in $OMP CANCELLATION POINT statement at %C"); + return MATCH_ERROR; + } if (gfc_match_omp_eos () != MATCH_YES) { gfc_error ("Unexpected junk after $OMP CANCELLATION POINT statement " @@ -4942,7 +5022,10 @@ gfc_match_omp_end_nowait (void) nowait = true; if (gfc_match_omp_eos () != MATCH_YES) { - gfc_error ("Unexpected junk after NOWAIT clause at %C"); + if (nowait) + gfc_error ("Unexpected junk after NOWAIT clause at %C"); + else + gfc_error ("Unexpected junk at %C"); return MATCH_ERROR; } new_st.op = EXEC_OMP_END_NOWAIT; @@ -5251,6 +5334,7 @@ resolve_omp_clauses (gfc_code *code, gfc_omp_clauses *omp_clauses, case EXEC_OMP_PARALLEL: case EXEC_OMP_PARALLEL_DO: + case EXEC_OMP_PARALLEL_MASKED: case EXEC_OMP_PARALLEL_MASTER: case EXEC_OMP_PARALLEL_SECTIONS: case EXEC_OMP_PARALLEL_WORKSHARE: @@ -5265,10 +5349,12 @@ resolve_omp_clauses (gfc_code *code, gfc_omp_clauses *omp_clauses, ok = ifc == OMP_IF_PARALLEL || ifc == OMP_IF_SIMD; break; + case EXEC_OMP_PARALLEL_MASKED_TASKLOOP: case EXEC_OMP_PARALLEL_MASTER_TASKLOOP: ok = ifc == OMP_IF_PARALLEL || ifc == OMP_IF_TASKLOOP; break; + case EXEC_OMP_PARALLEL_MASKED_TASKLOOP_SIMD: case EXEC_OMP_PARALLEL_MASTER_TASKLOOP_SIMD: ok = (ifc == OMP_IF_PARALLEL || ifc == OMP_IF_TASKLOOP @@ -5287,11 +5373,13 @@ resolve_omp_clauses (gfc_code *code, gfc_omp_clauses *omp_clauses, break; case EXEC_OMP_TASKLOOP: + case EXEC_OMP_MASKED_TASKLOOP: case EXEC_OMP_MASTER_TASKLOOP: ok = ifc == OMP_IF_TASKLOOP; break; case EXEC_OMP_TASKLOOP_SIMD: + case EXEC_OMP_MASKED_TASKLOOP_SIMD: case EXEC_OMP_MASTER_TASKLOOP_SIMD: ok = ifc == OMP_IF_TASKLOOP || ifc == OMP_IF_SIMD; break; @@ -6057,9 +6145,13 @@ resolve_omp_clauses (gfc_code *code, gfc_omp_clauses *omp_clauses, && (code->op == EXEC_OMP_LOOP || code->op == EXEC_OMP_TASKLOOP || code->op == EXEC_OMP_TASKLOOP_SIMD + || code->op == EXEC_OMP_MASKED_TASKLOOP + || code->op == EXEC_OMP_MASKED_TASKLOOP_SIMD || code->op == EXEC_OMP_MASTER_TASKLOOP || code->op == EXEC_OMP_MASTER_TASKLOOP_SIMD || code->op == EXEC_OMP_PARALLEL_LOOP + || code->op == EXEC_OMP_PARALLEL_MASKED_TASKLOOP + || code->op == EXEC_OMP_PARALLEL_MASKED_TASKLOOP_SIMD || code->op == EXEC_OMP_PARALLEL_MASTER_TASKLOOP || code->op == EXEC_OMP_PARALLEL_MASTER_TASKLOOP_SIMD || code->op == EXEC_OMP_TARGET_PARALLEL_LOOP @@ -6319,6 +6411,8 @@ resolve_omp_clauses (gfc_code *code, gfc_omp_clauses *omp_clauses, resolve_positive_int_expr (omp_clauses->num_teams, "NUM_TEAMS"); if (omp_clauses->device) resolve_nonnegative_int_expr (omp_clauses->device, "DEVICE"); + if (omp_clauses->filter) + resolve_nonnegative_int_expr (omp_clauses->filter, "FILTER"); if (omp_clauses->hint) { resolve_scalar_int_expr (omp_clauses->hint, "HINT"); @@ -6981,8 +7075,12 @@ gfc_resolve_omp_parallel_blocks (gfc_code *code, gfc_namespace *ns) case EXEC_OMP_DISTRIBUTE_PARALLEL_DO_SIMD: case EXEC_OMP_PARALLEL_DO: case EXEC_OMP_PARALLEL_DO_SIMD: + case EXEC_OMP_PARALLEL_MASKED_TASKLOOP: + case EXEC_OMP_PARALLEL_MASKED_TASKLOOP_SIMD: case EXEC_OMP_PARALLEL_MASTER_TASKLOOP: case EXEC_OMP_PARALLEL_MASTER_TASKLOOP_SIMD: + case EXEC_OMP_MASKED_TASKLOOP: + case EXEC_OMP_MASKED_TASKLOOP_SIMD: case EXEC_OMP_MASTER_TASKLOOP: case EXEC_OMP_MASTER_TASKLOOP_SIMD: case EXEC_OMP_TARGET_PARALLEL_DO: @@ -7130,6 +7228,13 @@ resolve_omp_do (gfc_code *code) is_simd = true; break; case EXEC_OMP_PARALLEL_LOOP: name = "!$OMP PARALLEL LOOP"; break; + case EXEC_OMP_PARALLEL_MASKED_TASKLOOP: + name = "!$OMP PARALLEL MASKED TASKLOOP"; + break; + case EXEC_OMP_PARALLEL_MASKED_TASKLOOP_SIMD: + name = "!$OMP PARALLEL MASKED TASKLOOP SIMD"; + is_simd = true; + break; case EXEC_OMP_PARALLEL_MASTER_TASKLOOP: name = "!$OMP PARALLEL MASTER TASKLOOP"; break; @@ -7137,6 +7242,11 @@ resolve_omp_do (gfc_code *code) name = "!$OMP PARALLEL MASTER TASKLOOP SIMD"; is_simd = true; break; + case EXEC_OMP_MASKED_TASKLOOP: name = "!$OMP MASKED TASKLOOP"; break; + case EXEC_OMP_MASKED_TASKLOOP_SIMD: + name = "!$OMP MASKED TASKLOOP SIMD"; + is_simd = true; + break; case EXEC_OMP_MASTER_TASKLOOP: name = "!$OMP MASTER TASKLOOP"; break; case EXEC_OMP_MASTER_TASKLOOP_SIMD: name = "!$OMP MASTER TASKLOOP SIMD"; @@ -7299,6 +7409,12 @@ omp_code_to_statement (gfc_code *code) { case EXEC_OMP_PARALLEL: return ST_OMP_PARALLEL; + case EXEC_OMP_PARALLEL_MASKED: + return ST_OMP_PARALLEL_MASKED; + case EXEC_OMP_PARALLEL_MASKED_TASKLOOP: + return ST_OMP_PARALLEL_MASKED_TASKLOOP; + case EXEC_OMP_PARALLEL_MASKED_TASKLOOP_SIMD: + return ST_OMP_PARALLEL_MASKED_TASKLOOP_SIMD; case EXEC_OMP_PARALLEL_MASTER: return ST_OMP_PARALLEL_MASTER; case EXEC_OMP_PARALLEL_MASTER_TASKLOOP: @@ -7313,6 +7429,12 @@ omp_code_to_statement (gfc_code *code) return ST_OMP_ORDERED; case EXEC_OMP_CRITICAL: return ST_OMP_CRITICAL; + case EXEC_OMP_MASKED: + return ST_OMP_MASKED; + case EXEC_OMP_MASKED_TASKLOOP: + return ST_OMP_MASKED_TASKLOOP; + case EXEC_OMP_MASKED_TASKLOOP_SIMD: + return ST_OMP_MASKED_TASKLOOP_SIMD; case EXEC_OMP_MASTER: return ST_OMP_MASTER; case EXEC_OMP_MASTER_TASKLOOP: @@ -7353,6 +7475,8 @@ omp_code_to_statement (gfc_code *code) return ST_OMP_DO_SIMD; case EXEC_OMP_SCAN: return ST_OMP_SCAN; + case EXEC_OMP_SCOPE: + return ST_OMP_SCOPE; case EXEC_OMP_SIMD: return ST_OMP_SIMD; case EXEC_OMP_TARGET: @@ -7819,8 +7943,12 @@ gfc_resolve_omp_directive (gfc_code *code, gfc_namespace *ns) case EXEC_OMP_PARALLEL_DO: case EXEC_OMP_PARALLEL_DO_SIMD: case EXEC_OMP_PARALLEL_LOOP: + case EXEC_OMP_PARALLEL_MASKED_TASKLOOP: + case EXEC_OMP_PARALLEL_MASKED_TASKLOOP_SIMD: case EXEC_OMP_PARALLEL_MASTER_TASKLOOP: case EXEC_OMP_PARALLEL_MASTER_TASKLOOP_SIMD: + case EXEC_OMP_MASKED_TASKLOOP: + case EXEC_OMP_MASKED_TASKLOOP_SIMD: case EXEC_OMP_MASTER_TASKLOOP: case EXEC_OMP_MASTER_TASKLOOP_SIMD: case EXEC_OMP_SIMD: @@ -7843,10 +7971,13 @@ gfc_resolve_omp_directive (gfc_code *code, gfc_namespace *ns) resolve_omp_do (code); break; case EXEC_OMP_CANCEL: + case EXEC_OMP_MASKED: case EXEC_OMP_PARALLEL_WORKSHARE: case EXEC_OMP_PARALLEL: + case EXEC_OMP_PARALLEL_MASKED: case EXEC_OMP_PARALLEL_MASTER: case EXEC_OMP_PARALLEL_SECTIONS: + case EXEC_OMP_SCOPE: case EXEC_OMP_SECTIONS: case EXEC_OMP_SINGLE: case EXEC_OMP_TARGET: diff --git a/gcc/fortran/parse.c b/gcc/fortran/parse.c index 6d7845e..d004732 100644 --- a/gcc/fortran/parse.c +++ b/gcc/fortran/parse.c @@ -920,6 +920,11 @@ decode_omp_directive (void) matchs ("end do simd", gfc_match_omp_end_nowait, ST_OMP_END_DO_SIMD); matcho ("end do", gfc_match_omp_end_nowait, ST_OMP_END_DO); matchs ("end simd", gfc_match_omp_eos_error, ST_OMP_END_SIMD); + matcho ("end masked taskloop simd", gfc_match_omp_eos_error, + ST_OMP_END_MASKED_TASKLOOP_SIMD); + matcho ("end masked taskloop", gfc_match_omp_eos_error, + ST_OMP_END_MASKED_TASKLOOP); + matcho ("end masked", gfc_match_omp_eos_error, ST_OMP_END_MASKED); matcho ("end master taskloop simd", gfc_match_omp_eos_error, ST_OMP_END_MASTER_TASKLOOP_SIMD); matcho ("end master taskloop", gfc_match_omp_eos_error, @@ -929,6 +934,12 @@ decode_omp_directive (void) matchs ("end parallel do simd", gfc_match_omp_eos_error, ST_OMP_END_PARALLEL_DO_SIMD); matcho ("end parallel do", gfc_match_omp_eos_error, ST_OMP_END_PARALLEL_DO); + matcho ("end parallel masked taskloop simd", gfc_match_omp_eos_error, + ST_OMP_END_PARALLEL_MASKED_TASKLOOP_SIMD); + matcho ("end parallel masked taskloop", gfc_match_omp_eos_error, + ST_OMP_END_PARALLEL_MASKED_TASKLOOP); + matcho ("end parallel masked", gfc_match_omp_eos_error, + ST_OMP_END_PARALLEL_MASKED); matcho ("end parallel master taskloop simd", gfc_match_omp_eos_error, ST_OMP_END_PARALLEL_MASTER_TASKLOOP_SIMD); matcho ("end parallel master taskloop", gfc_match_omp_eos_error, @@ -940,6 +951,7 @@ decode_omp_directive (void) matcho ("end parallel workshare", gfc_match_omp_eos_error, ST_OMP_END_PARALLEL_WORKSHARE); matcho ("end parallel", gfc_match_omp_eos_error, ST_OMP_END_PARALLEL); + matcho ("end scope", gfc_match_omp_end_nowait, ST_OMP_END_SCOPE); matcho ("end sections", gfc_match_omp_end_nowait, ST_OMP_END_SECTIONS); matcho ("end single", gfc_match_omp_end_single, ST_OMP_END_SINGLE); matcho ("end target data", gfc_match_omp_eos_error, ST_OMP_END_TARGET_DATA); @@ -982,12 +994,20 @@ decode_omp_directive (void) matcho ("flush", gfc_match_omp_flush, ST_OMP_FLUSH); break; case 'm': + matcho ("masked taskloop simd", gfc_match_omp_masked_taskloop_simd, + ST_OMP_MASKED_TASKLOOP_SIMD); + matcho ("masked taskloop", gfc_match_omp_masked_taskloop, + ST_OMP_MASKED_TASKLOOP); + matcho ("masked", gfc_match_omp_masked, ST_OMP_MASKED); matcho ("master taskloop simd", gfc_match_omp_master_taskloop_simd, ST_OMP_MASTER_TASKLOOP_SIMD); matcho ("master taskloop", gfc_match_omp_master_taskloop, ST_OMP_MASTER_TASKLOOP); matcho ("master", gfc_match_omp_master, ST_OMP_MASTER); break; + case 'n': + matcho ("nothing", gfc_match_omp_nothing, ST_NONE); + break; case 'l': matcho ("loop", gfc_match_omp_loop, ST_OMP_LOOP); break; @@ -1009,6 +1029,14 @@ decode_omp_directive (void) matcho ("parallel do", gfc_match_omp_parallel_do, ST_OMP_PARALLEL_DO); matcho ("parallel loop", gfc_match_omp_parallel_loop, ST_OMP_PARALLEL_LOOP); + matcho ("parallel masked taskloop simd", + gfc_match_omp_parallel_masked_taskloop_simd, + ST_OMP_PARALLEL_MASKED_TASKLOOP_SIMD); + matcho ("parallel masked taskloop", + gfc_match_omp_parallel_masked_taskloop, + ST_OMP_PARALLEL_MASKED_TASKLOOP); + matcho ("parallel masked", gfc_match_omp_parallel_masked, + ST_OMP_PARALLEL_MASKED); matcho ("parallel master taskloop simd", gfc_match_omp_parallel_master_taskloop_simd, ST_OMP_PARALLEL_MASTER_TASKLOOP_SIMD); @@ -1028,6 +1056,7 @@ decode_omp_directive (void) break; case 's': matcho ("scan", gfc_match_omp_scan, ST_OMP_SCAN); + matcho ("scope", gfc_match_omp_scope, ST_OMP_SCOPE); matcho ("sections", gfc_match_omp_sections, ST_OMP_SECTIONS); matcho ("section", gfc_match_omp_eos_error, ST_OMP_SECTION); matcho ("single", gfc_match_omp_single, ST_OMP_SINGLE); @@ -1639,12 +1668,16 @@ next_statement (void) #define case_exec_markers case ST_DO: case ST_FORALL_BLOCK: \ case ST_IF_BLOCK: case ST_BLOCK: case ST_ASSOCIATE: \ case ST_WHERE_BLOCK: case ST_SELECT_CASE: case ST_SELECT_TYPE: \ - case ST_SELECT_RANK: case ST_OMP_PARALLEL: case ST_OMP_PARALLEL_MASTER: \ + case ST_SELECT_RANK: case ST_OMP_PARALLEL: case ST_OMP_PARALLEL_MASKED: \ + case ST_OMP_PARALLEL_MASKED_TASKLOOP: \ + case ST_OMP_PARALLEL_MASKED_TASKLOOP_SIMD: case ST_OMP_PARALLEL_MASTER: \ case ST_OMP_PARALLEL_MASTER_TASKLOOP: \ case ST_OMP_PARALLEL_MASTER_TASKLOOP_SIMD: \ case ST_OMP_PARALLEL_SECTIONS: case ST_OMP_SECTIONS: case ST_OMP_ORDERED: \ - case ST_OMP_CRITICAL: case ST_OMP_MASTER: case ST_OMP_MASTER_TASKLOOP: \ - case ST_OMP_MASTER_TASKLOOP_SIMD: case ST_OMP_SINGLE: \ + case ST_OMP_CRITICAL: case ST_OMP_MASKED: case ST_OMP_MASKED_TASKLOOP: \ + case ST_OMP_MASKED_TASKLOOP_SIMD: \ + case ST_OMP_MASTER: case ST_OMP_MASTER_TASKLOOP: \ + case ST_OMP_MASTER_TASKLOOP_SIMD: case ST_OMP_SCOPE: case ST_OMP_SINGLE: \ case ST_OMP_DO: case ST_OMP_PARALLEL_DO: case ST_OMP_ATOMIC: \ case ST_OMP_WORKSHARE: case ST_OMP_PARALLEL_WORKSHARE: \ case ST_OMP_TASK: case ST_OMP_TASKGROUP: case ST_OMP_SIMD: \ @@ -2376,6 +2409,15 @@ gfc_ascii_statement (gfc_statement st) case ST_OMP_END_LOOP: p = "!$OMP END LOOP"; break; + case ST_OMP_END_MASKED: + p = "!$OMP END MASKED"; + break; + case ST_OMP_END_MASKED_TASKLOOP: + p = "!$OMP END MASKED TASKLOOP"; + break; + case ST_OMP_END_MASKED_TASKLOOP_SIMD: + p = "!$OMP END MASKED TASKLOOP SIMD"; + break; case ST_OMP_END_MASTER: p = "!$OMP END MASTER"; break; @@ -2400,6 +2442,15 @@ gfc_ascii_statement (gfc_statement st) case ST_OMP_END_PARALLEL_LOOP: p = "!$OMP END PARALLEL LOOP"; break; + case ST_OMP_END_PARALLEL_MASKED: + p = "!$OMP END PARALLEL MASKED"; + break; + case ST_OMP_END_PARALLEL_MASKED_TASKLOOP: + p = "!$OMP END PARALLEL MASKED TASKLOOP"; + break; + case ST_OMP_END_PARALLEL_MASKED_TASKLOOP_SIMD: + p = "!$OMP END PARALLEL MASKED TASKLOOP SIMD"; + break; case ST_OMP_END_PARALLEL_MASTER: p = "!$OMP END PARALLEL MASTER"; break; @@ -2499,6 +2550,15 @@ gfc_ascii_statement (gfc_statement st) case ST_OMP_LOOP: p = "!$OMP LOOP"; break; + case ST_OMP_MASKED: + p = "!$OMP MASKED"; + break; + case ST_OMP_MASKED_TASKLOOP: + p = "!$OMP MASKED TASKLOOP"; + break; + case ST_OMP_MASKED_TASKLOOP_SIMD: + p = "!$OMP MASKED TASKLOOP SIMD"; + break; case ST_OMP_MASTER: p = "!$OMP MASTER"; break; @@ -2524,6 +2584,15 @@ gfc_ascii_statement (gfc_statement st) case ST_OMP_PARALLEL_DO_SIMD: p = "!$OMP PARALLEL DO SIMD"; break; + case ST_OMP_PARALLEL_MASKED: + p = "!$OMP PARALLEL MASKED"; + break; + case ST_OMP_PARALLEL_MASKED_TASKLOOP: + p = "!$OMP PARALLEL MASKED TASKLOOP"; + break; + case ST_OMP_PARALLEL_MASKED_TASKLOOP_SIMD: + p = "!$OMP PARALLEL MASKED TASKLOOP SIMD"; + break; case ST_OMP_PARALLEL_MASTER: p = "!$OMP PARALLEL MASTER"; break; @@ -2545,6 +2614,9 @@ gfc_ascii_statement (gfc_statement st) case ST_OMP_SCAN: p = "!$OMP SCAN"; break; + case ST_OMP_SCOPE: + p = "!$OMP SCOPE"; + break; case ST_OMP_SECTIONS: p = "!$OMP SECTIONS"; break; @@ -5127,10 +5199,20 @@ parse_omp_do (gfc_statement omp_st) break; case ST_OMP_TASKLOOP: omp_end_st = ST_OMP_END_TASKLOOP; break; case ST_OMP_TASKLOOP_SIMD: omp_end_st = ST_OMP_END_TASKLOOP_SIMD; break; + case ST_OMP_MASKED_TASKLOOP: omp_end_st = ST_OMP_END_MASKED_TASKLOOP; break; + case ST_OMP_MASKED_TASKLOOP_SIMD: + omp_end_st = ST_OMP_END_MASKED_TASKLOOP_SIMD; + break; case ST_OMP_MASTER_TASKLOOP: omp_end_st = ST_OMP_END_MASTER_TASKLOOP; break; case ST_OMP_MASTER_TASKLOOP_SIMD: omp_end_st = ST_OMP_END_MASTER_TASKLOOP_SIMD; break; + case ST_OMP_PARALLEL_MASKED_TASKLOOP: + omp_end_st = ST_OMP_END_PARALLEL_MASKED_TASKLOOP; + break; + case ST_OMP_PARALLEL_MASKED_TASKLOOP_SIMD: + omp_end_st = ST_OMP_END_PARALLEL_MASKED_TASKLOOP_SIMD; + break; case ST_OMP_PARALLEL_MASTER_TASKLOOP: omp_end_st = ST_OMP_END_PARALLEL_MASTER_TASKLOOP; break; @@ -5380,12 +5462,18 @@ parse_omp_structured_block (gfc_statement omp_st, bool workshare_stmts_only) case ST_OMP_PARALLEL: omp_end_st = ST_OMP_END_PARALLEL; break; + case ST_OMP_PARALLEL_MASKED: + omp_end_st = ST_OMP_END_PARALLEL_MASKED; + break; case ST_OMP_PARALLEL_MASTER: omp_end_st = ST_OMP_END_PARALLEL_MASTER; break; case ST_OMP_PARALLEL_SECTIONS: omp_end_st = ST_OMP_END_PARALLEL_SECTIONS; break; + case ST_OMP_SCOPE: + omp_end_st = ST_OMP_END_SCOPE; + break; case ST_OMP_SECTIONS: omp_end_st = ST_OMP_END_SECTIONS; break; @@ -5395,6 +5483,9 @@ parse_omp_structured_block (gfc_statement omp_st, bool workshare_stmts_only) case ST_OMP_CRITICAL: omp_end_st = ST_OMP_END_CRITICAL; break; + case ST_OMP_MASKED: + omp_end_st = ST_OMP_END_MASKED; + break; case ST_OMP_MASTER: omp_end_st = ST_OMP_END_MASTER; break; @@ -5477,6 +5568,7 @@ parse_omp_structured_block (gfc_statement omp_st, bool workshare_stmts_only) break; case ST_OMP_PARALLEL: + case ST_OMP_PARALLEL_MASKED: case ST_OMP_PARALLEL_MASTER: case ST_OMP_PARALLEL_SECTIONS: parse_omp_structured_block (st, false); @@ -5679,12 +5771,15 @@ parse_executable (gfc_statement st) break; case ST_OMP_PARALLEL: + case ST_OMP_PARALLEL_MASKED: case ST_OMP_PARALLEL_MASTER: case ST_OMP_PARALLEL_SECTIONS: - case ST_OMP_SECTIONS: case ST_OMP_ORDERED: case ST_OMP_CRITICAL: + case ST_OMP_MASKED: case ST_OMP_MASTER: + case ST_OMP_SCOPE: + case ST_OMP_SECTIONS: case ST_OMP_SINGLE: case ST_OMP_TARGET: case ST_OMP_TARGET_DATA: @@ -5711,8 +5806,12 @@ parse_executable (gfc_statement st) case ST_OMP_PARALLEL_DO: case ST_OMP_PARALLEL_DO_SIMD: case ST_OMP_PARALLEL_LOOP: + case ST_OMP_PARALLEL_MASKED_TASKLOOP: + case ST_OMP_PARALLEL_MASKED_TASKLOOP_SIMD: case ST_OMP_PARALLEL_MASTER_TASKLOOP: case ST_OMP_PARALLEL_MASTER_TASKLOOP_SIMD: + case ST_OMP_MASKED_TASKLOOP: + case ST_OMP_MASKED_TASKLOOP_SIMD: case ST_OMP_MASTER_TASKLOOP: case ST_OMP_MASTER_TASKLOOP_SIMD: case ST_OMP_SIMD: diff --git a/gcc/fortran/resolve.c b/gcc/fortran/resolve.c index 5923646..117062b 100644 --- a/gcc/fortran/resolve.c +++ b/gcc/fortran/resolve.c @@ -10236,19 +10236,27 @@ resolve_sync (gfc_code *code) /* Check STAT. */ gfc_resolve_expr (code->expr2); - if (code->expr2 - && (code->expr2->ts.type != BT_INTEGER || code->expr2->rank != 0 - || code->expr2->expr_type != EXPR_VARIABLE)) - gfc_error ("STAT= argument at %L must be a scalar INTEGER variable", - &code->expr2->where); + if (code->expr2) + { + if (code->expr2->ts.type != BT_INTEGER || code->expr2->rank != 0) + gfc_error ("STAT= argument at %L must be a scalar INTEGER variable", + &code->expr2->where); + else + gfc_check_vardef_context (code->expr2, false, false, false, + _("STAT variable")); + } /* Check ERRMSG. */ gfc_resolve_expr (code->expr3); - if (code->expr3 - && (code->expr3->ts.type != BT_CHARACTER || code->expr3->rank != 0 - || code->expr3->expr_type != EXPR_VARIABLE)) - gfc_error ("ERRMSG= argument at %L must be a scalar CHARACTER variable", - &code->expr3->where); + if (code->expr3) + { + if (code->expr3->ts.type != BT_CHARACTER || code->expr3->rank != 0) + gfc_error ("ERRMSG= argument at %L must be a scalar CHARACTER variable", + &code->expr3->where); + else + gfc_check_vardef_context (code->expr3, false, false, false, + _("ERRMSG variable")); + } } @@ -10810,6 +10818,9 @@ gfc_resolve_blocks (gfc_code *b, gfc_namespace *ns) case EXEC_OMP_DO: case EXEC_OMP_DO_SIMD: case EXEC_OMP_LOOP: + case EXEC_OMP_MASKED: + case EXEC_OMP_MASKED_TASKLOOP: + case EXEC_OMP_MASKED_TASKLOOP_SIMD: case EXEC_OMP_MASTER: case EXEC_OMP_MASTER_TASKLOOP: case EXEC_OMP_MASTER_TASKLOOP_SIMD: @@ -10818,6 +10829,9 @@ gfc_resolve_blocks (gfc_code *b, gfc_namespace *ns) case EXEC_OMP_PARALLEL_DO: case EXEC_OMP_PARALLEL_DO_SIMD: case EXEC_OMP_PARALLEL_LOOP: + case EXEC_OMP_PARALLEL_MASKED: + case EXEC_OMP_PARALLEL_MASKED_TASKLOOP: + case EXEC_OMP_PARALLEL_MASKED_TASKLOOP_SIMD: case EXEC_OMP_PARALLEL_MASTER: case EXEC_OMP_PARALLEL_MASTER_TASKLOOP: case EXEC_OMP_PARALLEL_MASTER_TASKLOOP_SIMD: @@ -10825,6 +10839,7 @@ gfc_resolve_blocks (gfc_code *b, gfc_namespace *ns) case EXEC_OMP_PARALLEL_WORKSHARE: case EXEC_OMP_SECTIONS: case EXEC_OMP_SIMD: + case EXEC_OMP_SCOPE: case EXEC_OMP_SINGLE: case EXEC_OMP_TARGET: case EXEC_OMP_TARGET_DATA: @@ -11785,6 +11800,9 @@ gfc_resolve_code (gfc_code *code, gfc_namespace *ns) case EXEC_OMP_PARALLEL: case EXEC_OMP_PARALLEL_DO: case EXEC_OMP_PARALLEL_DO_SIMD: + case EXEC_OMP_PARALLEL_MASKED: + case EXEC_OMP_PARALLEL_MASKED_TASKLOOP: + case EXEC_OMP_PARALLEL_MASKED_TASKLOOP_SIMD: case EXEC_OMP_PARALLEL_MASTER: case EXEC_OMP_PARALLEL_MASTER_TASKLOOP: case EXEC_OMP_PARALLEL_MASTER_TASKLOOP_SIMD: @@ -12240,8 +12258,12 @@ start: case EXEC_OMP_MASTER: case EXEC_OMP_MASTER_TASKLOOP: case EXEC_OMP_MASTER_TASKLOOP_SIMD: + case EXEC_OMP_MASKED: + case EXEC_OMP_MASKED_TASKLOOP: + case EXEC_OMP_MASKED_TASKLOOP_SIMD: case EXEC_OMP_ORDERED: case EXEC_OMP_SCAN: + case EXEC_OMP_SCOPE: case EXEC_OMP_SECTIONS: case EXEC_OMP_SIMD: case EXEC_OMP_SINGLE: @@ -12281,6 +12303,9 @@ start: case EXEC_OMP_PARALLEL_DO: case EXEC_OMP_PARALLEL_DO_SIMD: case EXEC_OMP_PARALLEL_LOOP: + case EXEC_OMP_PARALLEL_MASKED: + case EXEC_OMP_PARALLEL_MASKED_TASKLOOP: + case EXEC_OMP_PARALLEL_MASKED_TASKLOOP_SIMD: case EXEC_OMP_PARALLEL_MASTER: case EXEC_OMP_PARALLEL_MASTER_TASKLOOP: case EXEC_OMP_PARALLEL_MASTER_TASKLOOP_SIMD: diff --git a/gcc/fortran/st.c b/gcc/fortran/st.c index 6ae1df6..7d87709 100644 --- a/gcc/fortran/st.c +++ b/gcc/fortran/st.c @@ -227,19 +227,26 @@ gfc_free_statement (gfc_code *p) case EXEC_OMP_DO_SIMD: case EXEC_OMP_LOOP: case EXEC_OMP_END_SINGLE: + case EXEC_OMP_MASKED_TASKLOOP: + case EXEC_OMP_MASKED_TASKLOOP_SIMD: case EXEC_OMP_MASTER_TASKLOOP: case EXEC_OMP_MASTER_TASKLOOP_SIMD: case EXEC_OMP_ORDERED: + case EXEC_OMP_MASKED: case EXEC_OMP_PARALLEL: case EXEC_OMP_PARALLEL_DO: case EXEC_OMP_PARALLEL_DO_SIMD: case EXEC_OMP_PARALLEL_LOOP: + case EXEC_OMP_PARALLEL_MASKED: + case EXEC_OMP_PARALLEL_MASKED_TASKLOOP: + case EXEC_OMP_PARALLEL_MASKED_TASKLOOP_SIMD: case EXEC_OMP_PARALLEL_MASTER: case EXEC_OMP_PARALLEL_MASTER_TASKLOOP: case EXEC_OMP_PARALLEL_MASTER_TASKLOOP_SIMD: case EXEC_OMP_PARALLEL_SECTIONS: case EXEC_OMP_PARALLEL_WORKSHARE: case EXEC_OMP_SCAN: + case EXEC_OMP_SCOPE: case EXEC_OMP_SECTIONS: case EXEC_OMP_SIMD: case EXEC_OMP_SINGLE: diff --git a/gcc/fortran/trans-common.c b/gcc/fortran/trans-common.c index a11cf4c..7bcf18d 100644 --- a/gcc/fortran/trans-common.c +++ b/gcc/fortran/trans-common.c @@ -759,10 +759,11 @@ create_common (gfc_common_head *com, segment_info *head, bool saw_equiv) else gfc_add_decl_to_function (var_decl); - SET_DECL_VALUE_EXPR (var_decl, - fold_build3_loc (input_location, COMPONENT_REF, - TREE_TYPE (s->field), - decl, s->field, NULL_TREE)); + tree comp = build3_loc (input_location, COMPONENT_REF, + TREE_TYPE (s->field), decl, s->field, NULL_TREE); + if (TREE_THIS_VOLATILE (s->field)) + TREE_THIS_VOLATILE (comp) = 1; + SET_DECL_VALUE_EXPR (var_decl, comp); DECL_HAS_VALUE_EXPR_P (var_decl) = 1; GFC_DECL_COMMON_OR_EQUIV (var_decl) = 1; diff --git a/gcc/fortran/trans-openmp.c b/gcc/fortran/trans-openmp.c index ac3f5f3..e0a0014 100644 --- a/gcc/fortran/trans-openmp.c +++ b/gcc/fortran/trans-openmp.c @@ -3865,6 +3865,9 @@ gfc_trans_omp_clauses (stmtblock_t *block, gfc_omp_clauses *clauses, c = build_omp_clause (gfc_get_location (&where), OMP_CLAUSE_PROC_BIND); switch (clauses->proc_bind) { + case OMP_PROC_BIND_PRIMARY: + OMP_CLAUSE_PROC_BIND_KIND (c) = OMP_CLAUSE_PROC_BIND_PRIMARY; + break; case OMP_PROC_BIND_MASTER: OMP_CLAUSE_PROC_BIND_KIND (c) = OMP_CLAUSE_PROC_BIND_MASTER; break; @@ -4044,6 +4047,21 @@ gfc_trans_omp_clauses (stmtblock_t *block, gfc_omp_clauses *clauses, omp_clauses = gfc_trans_add_clause (c, omp_clauses); } + if (clauses->filter) + { + tree filter; + + gfc_init_se (&se, NULL); + gfc_conv_expr (&se, clauses->filter); + gfc_add_block_to_block (block, &se.pre); + filter = gfc_evaluate_now (se.expr, block); + gfc_add_block_to_block (block, &se.post); + + c = build_omp_clause (gfc_get_location (&where), OMP_CLAUSE_FILTER); + OMP_CLAUSE_FILTER_EXPR (c) = filter; + omp_clauses = gfc_trans_add_clause (c, omp_clauses); + } + if (clauses->hint) { tree hint; @@ -5387,6 +5405,26 @@ gfc_trans_omp_master (gfc_code *code) } static tree +gfc_trans_omp_masked (gfc_code *code, gfc_omp_clauses *clauses) +{ + stmtblock_t block; + tree body = gfc_trans_code (code->block->next); + if (IS_EMPTY_STMT (body)) + return body; + if (!clauses) + clauses = code->ext.omp_clauses; + gfc_start_block (&block); + tree omp_clauses = gfc_trans_omp_clauses (&block, clauses, code->loc); + tree stmt = make_node (OMP_MASKED); + TREE_TYPE (stmt) = void_type_node; + OMP_MASKED_BODY (stmt) = body; + OMP_MASKED_CLAUSES (stmt) = omp_clauses; + gfc_add_expr_to_block (&block, stmt); + return gfc_finish_block (&block); +} + + +static tree gfc_trans_omp_ordered (gfc_code *code) { if (!flag_openmp) @@ -5429,6 +5467,7 @@ enum GFC_OMP_SPLIT_TEAMS, GFC_OMP_SPLIT_TARGET, GFC_OMP_SPLIT_TASKLOOP, + GFC_OMP_SPLIT_MASKED, GFC_OMP_SPLIT_NUM }; @@ -5440,7 +5479,8 @@ enum GFC_OMP_MASK_DISTRIBUTE = (1 << GFC_OMP_SPLIT_DISTRIBUTE), GFC_OMP_MASK_TEAMS = (1 << GFC_OMP_SPLIT_TEAMS), GFC_OMP_MASK_TARGET = (1 << GFC_OMP_SPLIT_TARGET), - GFC_OMP_MASK_TASKLOOP = (1 << GFC_OMP_SPLIT_TASKLOOP) + GFC_OMP_MASK_TASKLOOP = (1 << GFC_OMP_SPLIT_TASKLOOP), + GFC_OMP_MASK_MASKED = (1 << GFC_OMP_SPLIT_MASKED) }; /* If a var is in lastprivate/firstprivate/reduction but not in a @@ -5629,10 +5669,24 @@ gfc_split_omp_clauses (gfc_code *code, mask = GFC_OMP_MASK_PARALLEL | GFC_OMP_MASK_DO | GFC_OMP_MASK_SIMD; innermost = GFC_OMP_SPLIT_SIMD; break; + case EXEC_OMP_PARALLEL_MASKED: + mask = GFC_OMP_MASK_PARALLEL | GFC_OMP_MASK_MASKED; + innermost = GFC_OMP_SPLIT_MASKED; + break; + case EXEC_OMP_PARALLEL_MASKED_TASKLOOP: + mask = (GFC_OMP_MASK_PARALLEL | GFC_OMP_MASK_MASKED + | GFC_OMP_MASK_TASKLOOP | GFC_OMP_MASK_SIMD); + innermost = GFC_OMP_SPLIT_TASKLOOP; + break; case EXEC_OMP_PARALLEL_MASTER_TASKLOOP: mask = GFC_OMP_MASK_PARALLEL | GFC_OMP_MASK_TASKLOOP | GFC_OMP_MASK_SIMD; innermost = GFC_OMP_SPLIT_TASKLOOP; break; + case EXEC_OMP_PARALLEL_MASKED_TASKLOOP_SIMD: + mask = (GFC_OMP_MASK_PARALLEL | GFC_OMP_MASK_MASKED + | GFC_OMP_MASK_TASKLOOP | GFC_OMP_MASK_SIMD); + innermost = GFC_OMP_SPLIT_SIMD; + break; case EXEC_OMP_PARALLEL_MASTER_TASKLOOP_SIMD: mask = GFC_OMP_MASK_PARALLEL | GFC_OMP_MASK_TASKLOOP | GFC_OMP_MASK_SIMD; innermost = GFC_OMP_SPLIT_SIMD; @@ -5689,10 +5743,18 @@ gfc_split_omp_clauses (gfc_code *code, mask = GFC_OMP_MASK_TARGET | GFC_OMP_MASK_TEAMS | GFC_OMP_MASK_DO; innermost = GFC_OMP_SPLIT_DO; break; + case EXEC_OMP_MASKED_TASKLOOP: + mask = GFC_OMP_SPLIT_MASKED | GFC_OMP_SPLIT_TASKLOOP; + innermost = GFC_OMP_SPLIT_TASKLOOP; + break; case EXEC_OMP_MASTER_TASKLOOP: case EXEC_OMP_TASKLOOP: innermost = GFC_OMP_SPLIT_TASKLOOP; break; + case EXEC_OMP_MASKED_TASKLOOP_SIMD: + mask = GFC_OMP_MASK_MASKED | GFC_OMP_MASK_TASKLOOP | GFC_OMP_MASK_SIMD; + innermost = GFC_OMP_SPLIT_SIMD; + break; case EXEC_OMP_MASTER_TASKLOOP_SIMD: case EXEC_OMP_TASKLOOP_SIMD: mask = GFC_OMP_MASK_TASKLOOP | GFC_OMP_MASK_SIMD; @@ -5811,6 +5873,8 @@ gfc_split_omp_clauses (gfc_code *code, clausesa[GFC_OMP_SPLIT_PARALLEL].if_expr = code->ext.omp_clauses->if_expr; } + if (mask & GFC_OMP_MASK_MASKED) + clausesa[GFC_OMP_SPLIT_MASKED].filter = code->ext.omp_clauses->filter; if ((mask & GFC_OMP_MASK_DO) && !is_loop) { /* First the clauses that are unique to some constructs. */ @@ -5893,16 +5957,18 @@ gfc_split_omp_clauses (gfc_code *code, clausesa[GFC_OMP_SPLIT_TASKLOOP].collapse = code->ext.omp_clauses->collapse; } - /* Private clause is supported on all constructs, - it is enough to put it on the innermost one. For + /* Private clause is supported on all constructs but master/masked, + it is enough to put it on the innermost one except for master/masked. For !$ omp parallel do put it on parallel though, as that's what we did for OpenMP 3.1. */ - clausesa[innermost == GFC_OMP_SPLIT_DO && !is_loop + clausesa[((innermost == GFC_OMP_SPLIT_DO && !is_loop) + || code->op == EXEC_OMP_PARALLEL_MASTER + || code->op == EXEC_OMP_PARALLEL_MASKED) ? (int) GFC_OMP_SPLIT_PARALLEL : innermost].lists[OMP_LIST_PRIVATE] = code->ext.omp_clauses->lists[OMP_LIST_PRIVATE]; /* Firstprivate clause is supported on all constructs but - simd. Put it on the outermost of those and duplicate + simd and masked/master. Put it on the outermost of those and duplicate on parallel and teams. */ if (mask & GFC_OMP_MASK_TARGET) clausesa[GFC_OMP_SPLIT_TARGET].lists[OMP_LIST_FIRSTPRIVATE] @@ -6199,6 +6265,24 @@ gfc_trans_omp_parallel_workshare (gfc_code *code) } static tree +gfc_trans_omp_scope (gfc_code *code) +{ + stmtblock_t block; + tree body = gfc_trans_code (code->block->next); + if (IS_EMPTY_STMT (body)) + return body; + gfc_start_block (&block); + tree omp_clauses = gfc_trans_omp_clauses (&block, code->ext.omp_clauses, + code->loc); + tree stmt = make_node (OMP_SCOPE); + TREE_TYPE (stmt) = void_type_node; + OMP_SCOPE_BODY (stmt) = body; + OMP_SCOPE_CLAUSES (stmt) = omp_clauses; + gfc_add_expr_to_block (&block, stmt); + return gfc_finish_block (&block); +} + +static tree gfc_trans_omp_sections (gfc_code *code, gfc_omp_clauses *clauses) { stmtblock_t block, body; @@ -6585,43 +6669,66 @@ gfc_trans_omp_taskloop (gfc_code *code, gfc_exec_op op) } static tree -gfc_trans_omp_master_taskloop (gfc_code *code, gfc_exec_op op) +gfc_trans_omp_master_masked_taskloop (gfc_code *code, gfc_exec_op op) { + gfc_omp_clauses clausesa[GFC_OMP_SPLIT_NUM]; stmtblock_t block; tree stmt; - gfc_start_block (&block); + if (op != EXEC_OMP_MASTER_TASKLOOP_SIMD + && code->op != EXEC_OMP_MASTER_TASKLOOP) + gfc_split_omp_clauses (code, clausesa); + pushlevel (); - if (op == EXEC_OMP_MASTER_TASKLOOP_SIMD) + if (op == EXEC_OMP_MASKED_TASKLOOP_SIMD + || op == EXEC_OMP_MASTER_TASKLOOP_SIMD) stmt = gfc_trans_omp_taskloop (code, EXEC_OMP_TASKLOOP_SIMD); else { - gfc_omp_clauses clausesa[GFC_OMP_SPLIT_NUM]; - gcc_assert (op == EXEC_OMP_MASTER_TASKLOOP); - if (op != code->op) - gfc_split_omp_clauses (code, clausesa); + gcc_assert (op == EXEC_OMP_MASKED_TASKLOOP + || op == EXEC_OMP_MASTER_TASKLOOP); stmt = gfc_trans_omp_do (code, EXEC_OMP_TASKLOOP, NULL, - op != code->op + code->op != EXEC_OMP_MASTER_TASKLOOP ? &clausesa[GFC_OMP_SPLIT_TASKLOOP] : code->ext.omp_clauses, NULL); - if (op != code->op) - gfc_free_split_omp_clauses (code, clausesa); } if (TREE_CODE (stmt) != BIND_EXPR) stmt = build3_v (BIND_EXPR, NULL, stmt, poplevel (1, 0)); else poplevel (0, 0); - stmt = build1_v (OMP_MASTER, stmt); - gfc_add_expr_to_block (&block, stmt); + gfc_start_block (&block); + if (op == EXEC_OMP_MASKED_TASKLOOP || op == EXEC_OMP_MASKED_TASKLOOP_SIMD) + { + tree clauses = gfc_trans_omp_clauses (&block, + &clausesa[GFC_OMP_SPLIT_MASKED], + code->loc); + tree msk = make_node (OMP_MASKED); + TREE_TYPE (msk) = void_type_node; + OMP_MASKED_BODY (msk) = stmt; + OMP_MASKED_CLAUSES (msk) = clauses; + OMP_MASKED_COMBINED (msk) = 1; + gfc_add_expr_to_block (&block, msk); + } + else + { + gcc_assert (op == EXEC_OMP_MASTER_TASKLOOP + || op == EXEC_OMP_MASTER_TASKLOOP_SIMD); + stmt = build1_v (OMP_MASTER, stmt); + gfc_add_expr_to_block (&block, stmt); + } + if (op != EXEC_OMP_MASTER_TASKLOOP_SIMD + && code->op != EXEC_OMP_MASTER_TASKLOOP) + gfc_free_split_omp_clauses (code, clausesa); return gfc_finish_block (&block); } static tree -gfc_trans_omp_parallel_master (gfc_code *code) +gfc_trans_omp_parallel_master_masked (gfc_code *code) { stmtblock_t block; tree stmt, omp_clauses; gfc_omp_clauses clausesa[GFC_OMP_SPLIT_NUM]; + bool parallel_combined = false; if (code->op != EXEC_OMP_PARALLEL_MASTER) gfc_split_omp_clauses (code, clausesa); @@ -6632,19 +6739,33 @@ gfc_trans_omp_parallel_master (gfc_code *code) ? code->ext.omp_clauses : &clausesa[GFC_OMP_SPLIT_PARALLEL], code->loc); - if (code->op != EXEC_OMP_PARALLEL_MASTER) - gfc_free_split_omp_clauses (code, clausesa); pushlevel (); if (code->op == EXEC_OMP_PARALLEL_MASTER) stmt = gfc_trans_omp_master (code); + else if (code->op == EXEC_OMP_PARALLEL_MASKED) + stmt = gfc_trans_omp_masked (code, &clausesa[GFC_OMP_SPLIT_MASKED]); else { - gcc_assert (code->op == EXEC_OMP_PARALLEL_MASTER_TASKLOOP - || code->op == EXEC_OMP_PARALLEL_MASTER_TASKLOOP_SIMD); - gfc_exec_op op = (code->op == EXEC_OMP_PARALLEL_MASTER_TASKLOOP - ? EXEC_OMP_MASTER_TASKLOOP - : EXEC_OMP_MASTER_TASKLOOP_SIMD); - stmt = gfc_trans_omp_master_taskloop (code, op); + gfc_exec_op op; + switch (code->op) + { + case EXEC_OMP_PARALLEL_MASKED_TASKLOOP: + op = EXEC_OMP_MASKED_TASKLOOP; + break; + case EXEC_OMP_PARALLEL_MASKED_TASKLOOP_SIMD: + op = EXEC_OMP_MASKED_TASKLOOP_SIMD; + break; + case EXEC_OMP_PARALLEL_MASTER_TASKLOOP: + op = EXEC_OMP_MASTER_TASKLOOP; + break; + case EXEC_OMP_PARALLEL_MASTER_TASKLOOP_SIMD: + op = EXEC_OMP_MASTER_TASKLOOP_SIMD; + break; + default: + gcc_unreachable (); + } + stmt = gfc_trans_omp_master_masked_taskloop (code, op); + parallel_combined = true; } if (TREE_CODE (stmt) != BIND_EXPR) stmt = build3_v (BIND_EXPR, NULL, stmt, poplevel (1, 0)); @@ -6652,8 +6773,19 @@ gfc_trans_omp_parallel_master (gfc_code *code) poplevel (0, 0); stmt = build2_loc (gfc_get_location (&code->loc), OMP_PARALLEL, void_type_node, stmt, omp_clauses); - OMP_PARALLEL_COMBINED (stmt) = 1; + /* masked does have just filter clause, but during gimplification + isn't represented by a gimplification omp context, so for + !$omp parallel masked don't set OMP_PARALLEL_COMBINED, + so that + !$omp parallel masked + !$omp taskloop simd lastprivate (x) + isn't confused with + !$omp parallel masked taskloop simd lastprivate (x) */ + if (parallel_combined) + OMP_PARALLEL_COMBINED (stmt) = 1; gfc_add_expr_to_block (&block, stmt); + if (code->op != EXEC_OMP_PARALLEL_MASTER) + gfc_free_split_omp_clauses (code, clausesa); return gfc_finish_block (&block); } @@ -6966,11 +7098,15 @@ gfc_trans_omp_directive (gfc_code *code) return gfc_trans_omp_do_simd (code, NULL, NULL, NULL_TREE); case EXEC_OMP_FLUSH: return gfc_trans_omp_flush (code); + case EXEC_OMP_MASKED: + return gfc_trans_omp_masked (code, NULL); case EXEC_OMP_MASTER: return gfc_trans_omp_master (code); + case EXEC_OMP_MASKED_TASKLOOP: + case EXEC_OMP_MASKED_TASKLOOP_SIMD: case EXEC_OMP_MASTER_TASKLOOP: case EXEC_OMP_MASTER_TASKLOOP_SIMD: - return gfc_trans_omp_master_taskloop (code, code->op); + return gfc_trans_omp_master_masked_taskloop (code, code->op); case EXEC_OMP_ORDERED: return gfc_trans_omp_ordered (code); case EXEC_OMP_PARALLEL: @@ -6981,14 +7117,19 @@ gfc_trans_omp_directive (gfc_code *code) return gfc_trans_omp_parallel_do (code, true, NULL, NULL); case EXEC_OMP_PARALLEL_DO_SIMD: return gfc_trans_omp_parallel_do_simd (code, NULL, NULL); + case EXEC_OMP_PARALLEL_MASKED: + case EXEC_OMP_PARALLEL_MASKED_TASKLOOP: + case EXEC_OMP_PARALLEL_MASKED_TASKLOOP_SIMD: case EXEC_OMP_PARALLEL_MASTER: case EXEC_OMP_PARALLEL_MASTER_TASKLOOP: case EXEC_OMP_PARALLEL_MASTER_TASKLOOP_SIMD: - return gfc_trans_omp_parallel_master (code); + return gfc_trans_omp_parallel_master_masked (code); case EXEC_OMP_PARALLEL_SECTIONS: return gfc_trans_omp_parallel_sections (code); case EXEC_OMP_PARALLEL_WORKSHARE: return gfc_trans_omp_parallel_workshare (code); + case EXEC_OMP_SCOPE: + return gfc_trans_omp_scope (code); case EXEC_OMP_SECTIONS: return gfc_trans_omp_sections (code, code->ext.omp_clauses); case EXEC_OMP_SINGLE: diff --git a/gcc/fortran/trans-stmt.c b/gcc/fortran/trans-stmt.c index 7cbdef7..11df186 100644 --- a/gcc/fortran/trans-stmt.c +++ b/gcc/fortran/trans-stmt.c @@ -1226,7 +1226,8 @@ gfc_trans_sync (gfc_code *code, gfc_exec_op type) if (code->expr2) { - gcc_assert (code->expr2->expr_type == EXPR_VARIABLE); + gcc_assert (code->expr2->expr_type == EXPR_VARIABLE + || code->expr2->expr_type == EXPR_FUNCTION); gfc_init_se (&argse, NULL); gfc_conv_expr_val (&argse, code->expr2); stat = argse.expr; @@ -1236,7 +1237,8 @@ gfc_trans_sync (gfc_code *code, gfc_exec_op type) if (code->expr3 && flag_coarray == GFC_FCOARRAY_LIB) { - gcc_assert (code->expr3->expr_type == EXPR_VARIABLE); + gcc_assert (code->expr3->expr_type == EXPR_VARIABLE + || code->expr3->expr_type == EXPR_FUNCTION); gfc_init_se (&argse, NULL); argse.want_pointer = 1; gfc_conv_expr (&argse, code->expr3); diff --git a/gcc/fortran/trans-types.c b/gcc/fortran/trans-types.c index 50fda43..1c78a90 100644 --- a/gcc/fortran/trans-types.c +++ b/gcc/fortran/trans-types.c @@ -446,7 +446,7 @@ gfc_init_kinds (void) if (!targetm.scalar_mode_supported_p (mode)) continue; - /* Only let float, double, long double and __float128 go through. + /* Only let float, double, long double and TFmode go through. Runtime support for others is not provided, so they would be useless. */ if (!targetm.libgcc_floating_mode_supported_p (mode)) @@ -471,7 +471,14 @@ gfc_init_kinds (void) We round up so as to handle IA-64 __floatreg (RFmode), which is an 82 bit type. Not to be confused with __float80 (XFmode), which is an 80 bit type also supported by IA-64. So XFmode should come out - to be kind=10, and RFmode should come out to be kind=11. Egads. */ + to be kind=10, and RFmode should come out to be kind=11. Egads. + + TODO: The kind calculation has to be modified to support all + three 128-bit floating-point modes on PowerPC as IFmode, KFmode, + and TFmode since the following line would all map to kind=16. + However, currently only float, double, long double, and TFmode + reach this code. + */ kind = (GET_MODE_PRECISION (mode) + 7) / 8; @@ -851,6 +858,7 @@ gfc_build_real_type (gfc_real_info *info) info->c_long_double = 1; if (mode_precision != LONG_DOUBLE_TYPE_SIZE && mode_precision == 128) { + /* TODO: see PR101835. */ info->c_float128 = 1; gfc_real16_is_float128 = true; } diff --git a/gcc/fortran/trans.c b/gcc/fortran/trans.c index 275d6a2..80b724d0 100644 --- a/gcc/fortran/trans.c +++ b/gcc/fortran/trans.c @@ -2156,6 +2156,9 @@ trans_code (gfc_code * code, tree cond) case EXEC_OMP_DO_SIMD: case EXEC_OMP_LOOP: case EXEC_OMP_FLUSH: + case EXEC_OMP_MASKED: + case EXEC_OMP_MASKED_TASKLOOP: + case EXEC_OMP_MASKED_TASKLOOP_SIMD: case EXEC_OMP_MASTER: case EXEC_OMP_MASTER_TASKLOOP: case EXEC_OMP_MASTER_TASKLOOP_SIMD: @@ -2164,11 +2167,15 @@ trans_code (gfc_code * code, tree cond) case EXEC_OMP_PARALLEL_DO: case EXEC_OMP_PARALLEL_DO_SIMD: case EXEC_OMP_PARALLEL_LOOP: + case EXEC_OMP_PARALLEL_MASKED: + case EXEC_OMP_PARALLEL_MASKED_TASKLOOP: + case EXEC_OMP_PARALLEL_MASKED_TASKLOOP_SIMD: case EXEC_OMP_PARALLEL_MASTER: case EXEC_OMP_PARALLEL_MASTER_TASKLOOP: case EXEC_OMP_PARALLEL_MASTER_TASKLOOP_SIMD: case EXEC_OMP_PARALLEL_SECTIONS: case EXEC_OMP_PARALLEL_WORKSHARE: + case EXEC_OMP_SCOPE: case EXEC_OMP_SECTIONS: case EXEC_OMP_SIMD: case EXEC_OMP_SINGLE: diff --git a/gcc/ggc-common.c b/gcc/ggc-common.c index 357bda1..32ba5be 100644 --- a/gcc/ggc-common.c +++ b/gcc/ggc-common.c @@ -31,9 +31,6 @@ along with GCC; see the file COPYING3. If not see #include "plugin.h" #include "options.h" -/* When set, ggc_collect will do collection. */ -bool ggc_force_collect; - /* When true, protect the contents of the identifier hash table. */ bool ggc_protect_identifiers = true; @@ -965,12 +962,9 @@ dump_ggc_loc_statistics () if (! GATHER_STATISTICS) return; - ggc_force_collect = true; - ggc_collect (); + ggc_collect (GGC_COLLECT_FORCE); ggc_mem_desc.dump (GGC_ORIGIN); - - ggc_force_collect = false; } /* Record ALLOCATED and OVERHEAD bytes to descriptor NAME:LINE (FUNCTION). */ diff --git a/gcc/ggc-internal.h b/gcc/ggc-internal.h index 39850cd..4dcfb4c 100644 --- a/gcc/ggc-internal.h +++ b/gcc/ggc-internal.h @@ -88,9 +88,6 @@ extern void ggc_pch_read (FILE *, void *); /* Allocation and collection. */ -/* When set, ggc_collect will do collection. */ -extern bool ggc_force_collect; - extern void ggc_record_overhead (size_t, size_t, void * FINAL_MEM_STAT_DECL); extern void ggc_free_overhead (void *); diff --git a/gcc/ggc-page.c b/gcc/ggc-page.c index 1b09f0d..1c49643 100644 --- a/gcc/ggc-page.c +++ b/gcc/ggc-page.c @@ -2184,7 +2184,7 @@ validate_free_objects (void) /* Top level mark-and-sweep routine. */ void -ggc_collect (void) +ggc_collect (enum ggc_collect mode) { /* Avoid frequent unnecessary work by skipping collection if the total allocations haven't expanded much since the last @@ -2196,7 +2196,8 @@ ggc_collect (void) memory_block_pool::trim (); float min_expand = allocated_last_gc * param_ggc_min_expand / 100; - if (G.allocated < allocated_last_gc + min_expand && !ggc_force_collect) + if (mode == GGC_COLLECT_HEURISTIC + && G.allocated < allocated_last_gc + min_expand) return; timevar_push (TV_GC); diff --git a/gcc/ggc-tests.c b/gcc/ggc-tests.c index 4ee9550..e83f701 100644 --- a/gcc/ggc-tests.c +++ b/gcc/ggc-tests.c @@ -22,21 +22,10 @@ along with GCC; see the file COPYING3. If not see #include "coretypes.h" #include "tree-core.h" #include "tree.h" -#include "ggc-internal.h" /* (for ggc_force_collect). */ #include "selftest.h" #if CHECKING_P -/* A helper function for writing ggc tests. */ - -void -selftest::forcibly_ggc_collect () -{ - ggc_force_collect = true; - ggc_collect (); - ggc_force_collect = false; -} - /* The various GTY markers must be outside of a namespace to be seen by gengtype, so we don't put this file within the selftest namespace. */ @@ -58,7 +47,7 @@ test_basic_struct () root_test_struct = ggc_cleared_alloc <test_struct> (); root_test_struct->other = ggc_cleared_alloc <test_struct> (); - selftest::forcibly_ggc_collect (); + ggc_collect (GGC_COLLECT_FORCE); ASSERT_TRUE (ggc_marked_p (root_test_struct)); ASSERT_TRUE (ggc_marked_p (root_test_struct->other)); @@ -88,7 +77,7 @@ test_length () for (int i = 0; i < count; i++) root_test_of_length->elem[i] = ggc_cleared_alloc <test_of_length> (); - selftest::forcibly_ggc_collect (); + ggc_collect (GGC_COLLECT_FORCE); ASSERT_TRUE (ggc_marked_p (root_test_of_length)); for (int i = 0; i < count; i++) @@ -162,7 +151,7 @@ test_union () test_struct *referenced_by_other = ggc_cleared_alloc <test_struct> (); other->m_ptr = referenced_by_other; - selftest::forcibly_ggc_collect (); + ggc_collect (GGC_COLLECT_FORCE); ASSERT_TRUE (ggc_marked_p (root_test_of_union_1)); ASSERT_TRUE (ggc_marked_p (ts)); @@ -203,7 +192,7 @@ test_finalization () test_struct_with_dtor::dtor_call_count = 0; - selftest::forcibly_ggc_collect (); + ggc_collect (GGC_COLLECT_FORCE); /* Verify that the destructor was run for each instance. */ ASSERT_EQ (count, test_struct_with_dtor::dtor_call_count); @@ -221,7 +210,7 @@ test_deletable_global () test_of_deletable = ggc_cleared_alloc <test_struct> (); ASSERT_TRUE (test_of_deletable != NULL); - selftest::forcibly_ggc_collect (); + ggc_collect (GGC_COLLECT_FORCE); ASSERT_EQ (NULL, test_of_deletable); } @@ -294,7 +283,7 @@ test_inheritance () test_some_subclass_as_base_ptr = new some_subclass (); test_some_other_subclass_as_base_ptr = new some_other_subclass (); - selftest::forcibly_ggc_collect (); + ggc_collect (GGC_COLLECT_FORCE); /* Verify that the roots and everything referenced by them got marked (both for fields in the base class and those in subclasses). */ @@ -373,7 +362,7 @@ test_chain_next () tail_node = new_node; } - selftest::forcibly_ggc_collect (); + ggc_collect (GGC_COLLECT_FORCE); /* If we got here, we survived. */ @@ -440,7 +429,7 @@ test_user_struct () num_calls_to_user_gt_ggc_mx = 0; - selftest::forcibly_ggc_collect (); + ggc_collect (GGC_COLLECT_FORCE); ASSERT_TRUE (ggc_marked_p (root_user_struct_ptr)); ASSERT_TRUE (ggc_marked_p (referenced)); @@ -458,7 +447,7 @@ test_tree_marking () { dummy_unittesting_tree = build_int_cst (integer_type_node, 1066); - selftest::forcibly_ggc_collect (); + ggc_collect (GGC_COLLECT_FORCE); ASSERT_TRUE (ggc_marked_p (dummy_unittesting_tree)); } @@ -263,7 +263,11 @@ extern const char *ggc_alloc_string (const char *contents, int length /* Invoke the collector. Garbage collection occurs only when this function is called, not during allocations. */ -extern void ggc_collect (void); +enum ggc_collect { + GGC_COLLECT_HEURISTIC, + GGC_COLLECT_FORCE +}; +extern void ggc_collect (enum ggc_collect mode = GGC_COLLECT_HEURISTIC); /* Return unused memory pages to the system. */ extern void ggc_trim (void); diff --git a/gcc/gimple-low.c b/gcc/gimple-low.c index fa7d4de..7e39c22 100644 --- a/gcc/gimple-low.c +++ b/gcc/gimple-low.c @@ -329,11 +329,13 @@ lower_stmt (gimple_stmt_iterator *gsi, struct lower_data *data) case GIMPLE_LABEL: case GIMPLE_EH_MUST_NOT_THROW: case GIMPLE_OMP_FOR: + case GIMPLE_OMP_SCOPE: case GIMPLE_OMP_SECTIONS: case GIMPLE_OMP_SECTIONS_SWITCH: case GIMPLE_OMP_SECTION: case GIMPLE_OMP_SINGLE: case GIMPLE_OMP_MASTER: + case GIMPLE_OMP_MASKED: case GIMPLE_OMP_TASKGROUP: case GIMPLE_OMP_ORDERED: case GIMPLE_OMP_SCAN: diff --git a/gcc/gimple-pretty-print.c b/gcc/gimple-pretty-print.c index d6e63d6..53e7759 100644 --- a/gcc/gimple-pretty-print.c +++ b/gcc/gimple-pretty-print.c @@ -1658,6 +1658,64 @@ dump_gimple_omp_taskgroup (pretty_printer *buffer, const gimple *gs, } } +/* Dump a GIMPLE_OMP_MASKED tuple on the pretty_printer BUFFER. */ + +static void +dump_gimple_omp_masked (pretty_printer *buffer, const gimple *gs, + int spc, dump_flags_t flags) +{ + if (flags & TDF_RAW) + { + dump_gimple_fmt (buffer, spc, flags, "%G <%+BODY <%S>%nCLAUSES <", gs, + gimple_omp_body (gs)); + dump_omp_clauses (buffer, gimple_omp_masked_clauses (gs), spc, flags); + dump_gimple_fmt (buffer, spc, flags, " >"); + } + else + { + pp_string (buffer, "#pragma omp masked"); + dump_omp_clauses (buffer, gimple_omp_masked_clauses (gs), spc, flags); + if (!gimple_seq_empty_p (gimple_omp_body (gs))) + { + newline_and_indent (buffer, spc + 2); + pp_left_brace (buffer); + pp_newline (buffer); + dump_gimple_seq (buffer, gimple_omp_body (gs), spc + 4, flags); + newline_and_indent (buffer, spc + 2); + pp_right_brace (buffer); + } + } +} + +/* Dump a GIMPLE_OMP_SCOPE tuple on the pretty_printer BUFFER. */ + +static void +dump_gimple_omp_scope (pretty_printer *buffer, const gimple *gs, + int spc, dump_flags_t flags) +{ + if (flags & TDF_RAW) + { + dump_gimple_fmt (buffer, spc, flags, "%G <%+BODY <%S>%nCLAUSES <", gs, + gimple_omp_body (gs)); + dump_omp_clauses (buffer, gimple_omp_scope_clauses (gs), spc, flags); + dump_gimple_fmt (buffer, spc, flags, " >"); + } + else + { + pp_string (buffer, "#pragma omp scope"); + dump_omp_clauses (buffer, gimple_omp_scope_clauses (gs), spc, flags); + if (!gimple_seq_empty_p (gimple_omp_body (gs))) + { + newline_and_indent (buffer, spc + 2); + pp_left_brace (buffer); + pp_newline (buffer); + dump_gimple_seq (buffer, gimple_omp_body (gs), spc + 4, flags); + newline_and_indent (buffer, spc + 2); + pp_right_brace (buffer); + } + } +} + /* Dump a GIMPLE_OMP_TARGET tuple on the pretty_printer BUFFER. */ static void @@ -2722,6 +2780,14 @@ pp_gimple_stmt_1 (pretty_printer *buffer, const gimple *gs, int spc, dump_gimple_omp_taskgroup (buffer, gs, spc, flags); break; + case GIMPLE_OMP_MASKED: + dump_gimple_omp_masked (buffer, gs, spc, flags); + break; + + case GIMPLE_OMP_SCOPE: + dump_gimple_omp_scope (buffer, gs, spc, flags); + break; + case GIMPLE_OMP_MASTER: case GIMPLE_OMP_SECTION: dump_gimple_omp_block (buffer, gs, spc, flags); diff --git a/gcc/gimple-range-cache.cc b/gcc/gimple-range-cache.cc index 91541f1..4138d05 100644 --- a/gcc/gimple-range-cache.cc +++ b/gcc/gimple-range-cache.cc @@ -30,6 +30,9 @@ along with GCC; see the file COPYING3. If not see #include "gimple-range.h" #include "tree-cfg.h" +#define DEBUG_RANGE_CACHE (dump_file && (param_evrp_mode & EVRP_MODE_CACHE) \ + == EVRP_MODE_CACHE) + // During contructor, allocate the vector of ssa_names. non_null_ref::non_null_ref () diff --git a/gcc/gimple-range-cache.h b/gcc/gimple-range-cache.h index 1e77c9b..3b55673 100644 --- a/gcc/gimple-range-cache.h +++ b/gcc/gimple-range-cache.h @@ -103,7 +103,6 @@ public: bool get_non_stale_global_range (irange &r, tree name); void set_global_range (tree name, const irange &r); - bool enable_new_values (bool state); non_null_ref m_non_null; gori_compute m_gori; diff --git a/gcc/gimple-range-fold.cc b/gcc/gimple-range-fold.cc index d3e3e14..94dd042 100644 --- a/gcc/gimple-range-fold.cc +++ b/gcc/gimple-range-fold.cc @@ -42,9 +42,7 @@ along with GCC; see the file COPYING3. If not see #include "range.h" #include "value-query.h" #include "range-op.h" -#include "gimple-range-fold.h" -#include "gimple-range-edge.h" -#include "gimple-range-gori.h" +#include "gimple-range.h" // Construct a fur_source, and set the m_query field. fur_source::fur_source (range_query *q) diff --git a/gcc/gimple-range-gori.cc b/gcc/gimple-range-gori.cc index c124b3c..f788295 100644 --- a/gcc/gimple-range-gori.cc +++ b/gcc/gimple-range-gori.cc @@ -634,11 +634,13 @@ debug (gori_map &g) // Construct a gori_compute object. -gori_compute::gori_compute () +gori_compute::gori_compute () : tracer ("GORI ") { // Create a boolean_type true and false range. m_bool_zero = int_range<2> (boolean_false_node, boolean_false_node); m_bool_one = int_range<2> (boolean_true_node, boolean_true_node); + if (dump_file && (param_evrp_mode & EVRP_MODE_GORI)) + tracer.enable_trace (); } // Given the switch S, return an evaluation in R for NAME when the lhs @@ -712,29 +714,43 @@ gori_compute::compute_operand_range (irange &r, gimple *stmt, if (!op1_in_chain && !op2_in_chain) return false; + bool res; // Process logicals as they have special handling. if (is_gimple_logical_p (stmt)) { + unsigned idx; + if ((idx = tracer.header ("compute_operand "))) + { + print_generic_expr (dump_file, name, TDF_SLIM); + fprintf (dump_file, " with LHS = "); + lhs.dump (dump_file); + fprintf (dump_file, " at stmt "); + print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM); + } + int_range_max op1_trange, op1_frange; int_range_max op2_trange, op2_frange; compute_logical_operands (op1_trange, op1_frange, stmt, lhs, name, src, op1, op1_in_chain); compute_logical_operands (op2_trange, op2_frange, stmt, lhs, name, src, op2, op2_in_chain); - return logical_combine (r, gimple_expr_code (stmt), lhs, - op1_trange, op1_frange, op2_trange, op2_frange); + res = logical_combine (r, gimple_expr_code (stmt), lhs, + op1_trange, op1_frange, op2_trange, op2_frange); + if (idx) + tracer.trailer (idx, "compute_operand", res, name, r); } - // Follow the appropriate operands now. - if (op1_in_chain && op2_in_chain) - return compute_operand1_and_operand2_range (r, stmt, lhs, name, src); - if (op1_in_chain) - return compute_operand1_range (r, stmt, lhs, name, src); - if (op2_in_chain) - return compute_operand2_range (r, stmt, lhs, name, src); + else if (op1_in_chain && op2_in_chain) + res = compute_operand1_and_operand2_range (r, stmt, lhs, name, src); + else if (op1_in_chain) + res = compute_operand1_range (r, stmt, lhs, name, src); + else if (op2_in_chain) + res = compute_operand2_range (r, stmt, lhs, name, src); + else + gcc_unreachable (); // If neither operand is derived, this statement tells us nothing. - return false; + return res; } @@ -767,6 +783,38 @@ gori_compute::logical_combine (irange &r, enum tree_code code, && op2_true.varying_p () && op2_false.varying_p ()) return false; + unsigned idx; + if ((idx = tracer.header ("logical_combine"))) + { + switch (code) + { + case TRUTH_OR_EXPR: + case BIT_IOR_EXPR: + fprintf (dump_file, " || "); + break; + case TRUTH_AND_EXPR: + case BIT_AND_EXPR: + fprintf (dump_file, " && "); + break; + default: + break; + } + fprintf (dump_file, " with LHS = "); + lhs.dump (dump_file); + fputc ('\n', dump_file); + + tracer.print (idx, "op1_true = "); + op1_true.dump (dump_file); + fprintf (dump_file, " op1_false = "); + op1_false.dump (dump_file); + fputc ('\n', dump_file); + tracer.print (idx, "op2_true = "); + op2_true.dump (dump_file); + fprintf (dump_file, " op2_false = "); + op2_false.dump (dump_file); + fputc ('\n', dump_file); + } + // This is not a simple fold of a logical expression, rather it // determines ranges which flow through the logical expression. // @@ -804,6 +852,7 @@ gori_compute::logical_combine (irange &r, enum tree_code code, // would be lost. if (!range_is_either_true_or_false (lhs)) { + bool res; int_range_max r1; if (logical_combine (r1, code, m_bool_zero, op1_true, op1_false, op2_true, op2_false) @@ -811,9 +860,12 @@ gori_compute::logical_combine (irange &r, enum tree_code code, op2_true, op2_false)) { r.union_ (r1); - return true; + res = true; } - return false; + else + res = false; + if (idx) + tracer.trailer (idx, "logical_combine", res, NULL_TREE, r); } switch (code) @@ -873,6 +925,8 @@ gori_compute::logical_combine (irange &r, enum tree_code code, gcc_unreachable (); } + if (idx) + tracer.trailer (idx, "logical_combine", true, NULL_TREE, r); return true; } @@ -895,6 +949,13 @@ gori_compute::compute_logical_operands (irange &true_range, irange &false_range, // use its known value on entry to the block. src.get_operand (true_range, name); false_range = true_range; + unsigned idx; + if ((idx = tracer.header ("logical_operand"))) + { + print_generic_expr (dump_file, op, TDF_SLIM); + fprintf (dump_file, " not in computation chain. Queried.\n"); + tracer.trailer (idx, "logical_operand", true, NULL_TREE, true_range); + } return; } @@ -958,15 +1019,43 @@ gori_compute::compute_operand1_range (irange &r, gimple *stmt, return false; } + unsigned idx; + if ((idx = tracer.header ("compute op 1 ("))) + { + print_generic_expr (dump_file, op1, TDF_SLIM); + fprintf (dump_file, ") at "); + print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM); + tracer.print (idx, "LHS ="); + lhs.dump (dump_file); + if (op2 && TREE_CODE (op2) == SSA_NAME) + { + fprintf (dump_file, ", "); + print_generic_expr (dump_file, op2, TDF_SLIM); + fprintf (dump_file, " = "); + op2_range.dump (dump_file); + } + fprintf (dump_file, "\n"); + tracer.print (idx, "Computes "); + print_generic_expr (dump_file, op1, TDF_SLIM); + fprintf (dump_file, " = "); + r.dump (dump_file); + fprintf (dump_file, " intersect Known range : "); + op1_range.dump (dump_file); + fputc ('\n', dump_file); + } // Intersect the calculated result with the known result and return if done. if (op1 == name) { r.intersect (op1_range); + if (idx) + tracer.trailer (idx, "produces ", true, name, r); return true; } // If the calculation continues, we're using op1_range as the new LHS. op1_range.intersect (r); + if (idx) + tracer.trailer (idx, "produces ", true, op1, op1_range); gimple *src_stmt = SSA_NAME_DEF_STMT (op1); gcc_checking_assert (src_stmt); @@ -995,15 +1084,43 @@ gori_compute::compute_operand2_range (irange &r, gimple *stmt, if (!gimple_range_calc_op2 (r, stmt, lhs, op1_range)) return false; + unsigned idx; + if ((idx = tracer.header ("compute op 2 ("))) + { + print_generic_expr (dump_file, op2, TDF_SLIM); + fprintf (dump_file, ") at "); + print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM); + tracer.print (idx, "LHS = "); + lhs.dump (dump_file); + if (TREE_CODE (op1) == SSA_NAME) + { + fprintf (dump_file, ", "); + print_generic_expr (dump_file, op1, TDF_SLIM); + fprintf (dump_file, " = "); + op1_range.dump (dump_file); + } + fprintf (dump_file, "\n"); + tracer.print (idx, "Computes "); + print_generic_expr (dump_file, op2, TDF_SLIM); + fprintf (dump_file, " = "); + r.dump (dump_file); + fprintf (dump_file, " intersect Known range : "); + op2_range.dump (dump_file); + fputc ('\n', dump_file); + } // Intersect the calculated result with the known result and return if done. if (op2 == name) { r.intersect (op2_range); + if (idx) + tracer.trailer (idx, " produces ", true, NULL_TREE, r); return true; } // If the calculation continues, we're using op2_range as the new LHS. op2_range.intersect (r); + if (idx) + tracer.trailer (idx, " produces ", true, op2, op2_range); gimple *src_stmt = SSA_NAME_DEF_STMT (op2); gcc_checking_assert (src_stmt); // gcc_checking_assert (!is_import_p (op2, find.bb)); @@ -1095,6 +1212,7 @@ gori_compute::outgoing_edge_range_p (irange &r, edge e, tree name, range_query &q) { int_range_max lhs; + unsigned idx; gcc_checking_assert (gimple_range_ssa_p (name)); // Determine if there is an outgoing edge. @@ -1122,7 +1240,15 @@ gori_compute::outgoing_edge_range_p (irange &r, edge e, tree name, // If NAME can be calculated on the edge, use that. if (is_export_p (name, e->src)) { - if (compute_operand_range (r, stmt, lhs, name, src)) + bool res; + if ((idx = tracer.header ("outgoing_edge"))) + { + fprintf (dump_file, " for "); + print_generic_expr (dump_file, name, TDF_SLIM); + fprintf (dump_file, " on edge %d->%d\n", + e->src->index, e->dest->index); + } + if ((res = compute_operand_range (r, stmt, lhs, name, src))) { // Sometimes compatible types get interchanged. See PR97360. // Make sure we are returning the type of the thing we asked for. @@ -1132,28 +1258,26 @@ gori_compute::outgoing_edge_range_p (irange &r, edge e, tree name, TREE_TYPE (name))); range_cast (r, TREE_TYPE (name)); } - return true; } + if (idx) + tracer.trailer (idx, "outgoing_edge", res, name, r); + return res; } // If NAME isn't exported, check if it can be recomputed. else if (may_recompute_p (name, e)) { gimple *def_stmt = SSA_NAME_DEF_STMT (name); - if (dump_file && (dump_flags & TDF_DETAILS)) + if ((idx = tracer.header ("recomputation"))) { - fprintf (dump_file, "recomputation attempt on edge %d->%d for ", + fprintf (dump_file, " attempt on edge %d->%d for ", e->src->index, e->dest->index); - print_generic_expr (dump_file, name, TDF_SLIM); + print_gimple_stmt (dump_file, def_stmt, 0, TDF_SLIM); } // Simply calculate DEF_STMT on edge E using the range query Q. fold_range (r, def_stmt, e, &q); - if (dump_file && (dump_flags & TDF_DETAILS)) - { - fprintf (dump_file, " : Calculated :"); - r.dump (dump_file); - fputc ('\n', dump_file); - } + if (idx) + tracer.trailer (idx, "recomputation", true, name, r); return true; } return false; diff --git a/gcc/gimple-range-gori.h b/gcc/gimple-range-gori.h index ad83324..688468c 100644 --- a/gcc/gimple-range-gori.h +++ b/gcc/gimple-range-gori.h @@ -180,6 +180,7 @@ private: int_range<2> m_bool_one; // Boolean true cached. gimple_outgoing_range outgoing; // Edge values for COND_EXPR & SWITCH_EXPR. + range_tracer tracer; }; // These routines provide a GIMPLE interface to the range-ops code. diff --git a/gcc/gimple-range-trace.cc b/gcc/gimple-range-trace.cc new file mode 100644 index 0000000..1feb978 --- /dev/null +++ b/gcc/gimple-range-trace.cc @@ -0,0 +1,206 @@ +/* Code for GIMPLE range trace and debugging related routines. + Copyright (C) 2019-2021 Free Software Foundation, Inc. + Contributed by Andrew MacLeod <amacleod@redhat.com> + and Aldy Hernandez <aldyh@redhat.com>. + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 3, or (at your option) +any later version. + +GCC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +<http://www.gnu.org/licenses/>. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "backend.h" +#include "tree.h" +#include "gimple.h" +#include "ssa.h" +#include "gimple-pretty-print.h" +#include "gimple-iterator.h" +#include "tree-cfg.h" +#include "fold-const.h" +#include "tree-cfg.h" +#include "cfgloop.h" +#include "tree-scalar-evolution.h" +#include "gimple-range.h" + + +// Breakpoint to trap at a specific index. From GDB, this provides a simple +// place to put a breakpoint to stop at a given trace line. +// ie. b range_tracer::breakpoint if index == 45678 + +void +range_tracer::breakpoint (unsigned index ATTRIBUTE_UNUSED) +{ +} + +// Construct a range_tracer with component NAME. + +range_tracer::range_tracer (const char *name) +{ + gcc_checking_assert (strlen(name) < name_len -1); + strcpy (component, name); + indent = 0; + tracing = false; +} + +// This routine does the initial line spacing/indenting for a trace. +// If BLANKS is false, then IDX is printed, otherwise spaces. + +void +range_tracer::print_prefix (unsigned idx, bool blanks) +{ + // Print counter index as well as INDENT spaces. + if (!blanks) + fprintf (dump_file, "%-7u ", idx); + else + fprintf (dump_file, " "); + fprintf (dump_file, "%s ", component); + unsigned x; + for (x = 0; x< indent; x++) + fputc (' ', dump_file); + +} +// If dumping, return the next call index and print the prefix for the next +// output line. If not, retrurn 0. +// Counter is static to monotonically increase across the compilation unit. + +unsigned +range_tracer::do_header (const char *str) +{ + static unsigned trace_count = 0; + + unsigned idx = ++trace_count; + print_prefix (idx, false); + fprintf (dump_file, "%s", str); + indent += bump; + breakpoint (idx); + return idx; +} + +// Print a line without starting or ending a trace. + +void +range_tracer::print (unsigned counter, const char *str) +{ + print_prefix (counter, true); + fprintf (dump_file, "%s", str); +} + +// End a trace and print the CALLER, NAME, and RESULT and range R, + +void +range_tracer::trailer (unsigned counter, const char *caller, bool result, + tree name, const irange &r) +{ + gcc_checking_assert (tracing && counter != 0); + + indent -= bump; + print_prefix (counter, true); + fputs(result ? "TRUE : " : "FALSE : ", dump_file); + fprintf (dump_file, "(%u) ", counter); + fputs (caller, dump_file); + fputs (" (",dump_file); + if (name) + print_generic_expr (dump_file, name, TDF_SLIM); + fputs (") ",dump_file); + if (result) + { + r.dump (dump_file); + fputc('\n', dump_file); + } + else + fputc('\n', dump_file); +} + +// ========================================= +// Debugging helpers. +// ========================================= + +// Query all statements in the IL to precalculate computable ranges in RANGER. + +static DEBUG_FUNCTION void +debug_seed_ranger (gimple_ranger &ranger) +{ + // Recalculate SCEV to make sure the dump lists everything. + if (scev_initialized_p ()) + { + scev_finalize (); + scev_initialize (); + } + + basic_block bb; + int_range_max r; + gimple_stmt_iterator gsi; + FOR_EACH_BB_FN (bb, cfun) + for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi)) + { + gimple *stmt = gsi_stmt (gsi); + + if (is_gimple_debug (stmt)) + continue; + + ranger.range_of_stmt (r, stmt); + } +} + +// Dump all that ranger knows for the current function. + +DEBUG_FUNCTION void +dump_ranger (FILE *out) +{ + gimple_ranger ranger; + debug_seed_ranger (ranger); + ranger.dump (out); +} + +DEBUG_FUNCTION void +debug_ranger () +{ + dump_ranger (stderr); +} + +// Dump all that ranger knows on a path of BBs. +// +// Note that the blocks are in reverse order, thus the exit block is +// path[0]. + +DEBUG_FUNCTION void +dump_ranger (FILE *dump_file, const vec<basic_block> &path) +{ + if (path.length () == 0) + { + fprintf (dump_file, "empty\n"); + return; + } + + gimple_ranger ranger; + debug_seed_ranger (ranger); + + unsigned i = path.length (); + do + { + i--; + ranger.dump_bb (dump_file, path[i]); + } + while (i > 0); +} + +DEBUG_FUNCTION void +debug_ranger (const vec<basic_block> &path) +{ + dump_ranger (stderr, path); +} + +#include "gimple-range-tests.cc" diff --git a/gcc/gimple-range-trace.h b/gcc/gimple-range-trace.h new file mode 100644 index 0000000..d2d1a8b --- /dev/null +++ b/gcc/gimple-range-trace.h @@ -0,0 +1,61 @@ +/* Header file for the GIMPLE range tracing/debugging facilties. + Copyright (C) 2021 Free Software Foundation, Inc. + Contributed by Andrew MacLeod <amacleod@redhat.com> + and Aldy Hernandez <aldyh@redhat.com>. + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 3, or (at your option) any later +version. + +GCC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +<http://www.gnu.org/licenses/>. */ + +#ifndef GCC_GIMPLE_RANGE_TRACE_H +#define GCC_GIMPLE_RANGE_TRACE_H + +// This class manages range tracing for the ranger and gori components. +// Tracing will provide a unique integer index whenever a new trace +// is started. This can be used to identify where a calculation has gone wrong. + +class range_tracer +{ +public: + range_tracer (const char *name = ""); + unsigned header (const char *str); + void trailer (unsigned counter, const char *caller, bool result, tree name, + const irange &r); + void print (unsigned counter, const char *str); + inline void enable_trace () { tracing = true; } + inline void disable_trace () { tracing = false; } + virtual void breakpoint (unsigned index); +private: + unsigned do_header (const char *str); + void print_prefix (unsigned idx, bool blanks); + static const unsigned bump = 2; + unsigned indent; + static const unsigned name_len = 100; + char component[name_len]; + bool tracing; +}; + + +// If tracing is enabled, start a new trace header, returning the trace index. +// Otherwise return 0. + +inline unsigned +range_tracer::header (const char *str) +{ + if (tracing) + return do_header (str); + return 0; +} +#endif // GCC_GIMPLE_RANGE_TRACE_H diff --git a/gcc/gimple-range.cc b/gcc/gimple-range.cc index b210787..60b7d3a 100644 --- a/gcc/gimple-range.cc +++ b/gcc/gimple-range.cc @@ -35,46 +35,61 @@ along with GCC; see the file COPYING3. If not see #include "tree-scalar-evolution.h" #include "gimple-range.h" -gimple_ranger::gimple_ranger () +gimple_ranger::gimple_ranger () : tracer ("") { // If the cache has a relation oracle, use it. m_oracle = m_cache.oracle (); + if (dump_file && (param_evrp_mode & EVRP_MODE_TRACE)) + tracer.enable_trace (); } bool gimple_ranger::range_of_expr (irange &r, tree expr, gimple *stmt) { + unsigned idx; if (!gimple_range_ssa_p (expr)) return get_tree_range (r, expr, stmt); + if ((idx = tracer.header ("range_of_expr("))) + { + print_generic_expr (dump_file, expr, TDF_SLIM); + fputs (")", dump_file); + if (stmt) + { + fputs (" at stmt ", dump_file); + print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM); + } + else + fputs ("\n", dump_file); + } + // If there is no statement, just get the global value. if (!stmt) { if (!m_cache.get_global_range (r, expr)) r = gimple_range_global (expr); - return true; } - // For a debug stmt, pick the best value currently available, do not // trigger new value calculations. PR 100781. - if (is_gimple_debug (stmt)) + else if (is_gimple_debug (stmt)) + m_cache.range_of_expr (r, expr, stmt); + else { - m_cache.range_of_expr (r, expr, stmt); - return true; - } - basic_block bb = gimple_bb (stmt); - gimple *def_stmt = SSA_NAME_DEF_STMT (expr); + basic_block bb = gimple_bb (stmt); + gimple *def_stmt = SSA_NAME_DEF_STMT (expr); - // If name is defined in this block, try to get an range from S. - if (def_stmt && gimple_bb (def_stmt) == bb) - { - range_of_stmt (r, def_stmt, expr); - m_cache.m_non_null.adjust_range (r, expr, bb, true); + // If name is defined in this block, try to get an range from S. + if (def_stmt && gimple_bb (def_stmt) == bb) + { + range_of_stmt (r, def_stmt, expr); + m_cache.m_non_null.adjust_range (r, expr, bb, true); + } + // Otherwise OP comes from outside this block, use range on entry. + else + range_on_entry (r, bb, expr); } - else - // Otherwise OP comes from outside this block, use range on entry. - range_on_entry (r, bb, expr); - + if (idx) + tracer.trailer (idx, "range_of_expr", true, expr, r); return true; } @@ -86,6 +101,13 @@ gimple_ranger::range_on_entry (irange &r, basic_block bb, tree name) int_range_max entry_range; gcc_checking_assert (gimple_range_ssa_p (name)); + unsigned idx; + if ((idx = tracer.header ("range_on_entry ("))) + { + print_generic_expr (dump_file, name, TDF_SLIM); + fprintf (dump_file, ") to BB %d\n", bb->index); + } + // Start with any known range range_of_stmt (r, SSA_NAME_DEF_STMT (name), name); @@ -94,6 +116,9 @@ gimple_ranger::range_on_entry (irange &r, basic_block bb, tree name) r.intersect (entry_range); m_cache.m_non_null.adjust_range (r, name, bb, true); + + if (idx) + tracer.trailer (idx, "range_on_entry", true, name, r); } // Calculate the range for NAME at the end of block BB and return it in R. @@ -106,6 +131,13 @@ gimple_ranger::range_on_exit (irange &r, basic_block bb, tree name) gcc_checking_assert (bb != EXIT_BLOCK_PTR_FOR_FN (cfun)); gcc_checking_assert (gimple_range_ssa_p (name)); + unsigned idx; + if ((idx = tracer.header ("range_on_exit ("))) + { + print_generic_expr (dump_file, name, TDF_SLIM); + fprintf (dump_file, ") from BB %d\n", bb->index); + } + gimple *s = SSA_NAME_DEF_STMT (name); basic_block def_bb = gimple_bb (s); // If this is not the definition block, get the range on the last stmt in @@ -119,6 +151,9 @@ gimple_ranger::range_on_exit (irange &r, basic_block bb, tree name) range_on_entry (r, bb, name); gcc_checking_assert (r.undefined_p () || range_compatible_p (r.type (), TREE_TYPE (name))); + + if (idx) + tracer.trailer (idx, "range_on_exit", true, name, r); } // Calculate a range for NAME on edge E and return it in R. @@ -133,6 +168,13 @@ gimple_ranger::range_on_edge (irange &r, edge e, tree name) if (!gimple_range_ssa_p (name)) return range_of_expr (r, name); + unsigned idx; + if ((idx = tracer.header ("range_on_edge ("))) + { + print_generic_expr (dump_file, name, TDF_SLIM); + fprintf (dump_file, ") on edge %d->%d\n", e->src->index, e->dest->index); + } + range_on_exit (r, e->src, name); gcc_checking_assert (r.undefined_p () || range_compatible_p (r.type(), TREE_TYPE (name))); @@ -141,6 +183,8 @@ gimple_ranger::range_on_edge (irange &r, edge e, tree name) if (m_cache.range_on_edge (edge_range, e, name)) r.intersect (edge_range); + if (idx) + tracer.trailer (idx, "range_on_edge", true, name, r); return true; } @@ -163,33 +207,50 @@ gimple_ranger::fold_range_internal (irange &r, gimple *s, tree name) bool gimple_ranger::range_of_stmt (irange &r, gimple *s, tree name) { + bool res; r.set_undefined (); + unsigned idx; + if ((idx = tracer.header ("range_of_stmt ("))) + { + if (name) + print_generic_expr (dump_file, name, TDF_SLIM); + fputs (") at stmt ", dump_file); + print_gimple_stmt (dump_file, s, 0, TDF_SLIM); + } + if (!name) name = gimple_get_lhs (s); // If no name, simply call the base routine. if (!name) - return fold_range_internal (r, s, NULL_TREE); - - if (!gimple_range_ssa_p (name)) - return false; - + res = fold_range_internal (r, s, NULL_TREE); + else if (!gimple_range_ssa_p (name)) + res = false; // Check if the stmt has already been processed, and is not stale. - if (m_cache.get_non_stale_global_range (r, name)) - return true; - - // Otherwise calculate a new value. - int_range_max tmp; - fold_range_internal (tmp, s, name); - - // Combine the new value with the old value. This is required because - // the way value propagation works, when the IL changes on the fly we - // can sometimes get different results. See PR 97741. - r.intersect (tmp); - m_cache.set_global_range (name, r); + else if (m_cache.get_non_stale_global_range (r, name)) + { + if (idx) + tracer.trailer (idx, " cached", true, name, r); + return true; + } + else + { + // Otherwise calculate a new value. + int_range_max tmp; + fold_range_internal (tmp, s, name); + + // Combine the new value with the old value. This is required because + // the way value propagation works, when the IL changes on the fly we + // can sometimes get different results. See PR 97741. + r.intersect (tmp); + m_cache.set_global_range (name, r); + res = true; + } - return true; + if (idx) + tracer.trailer (idx, "range_of_stmt", res, name, r); + return res; } // This routine will export whatever global ranges are known to GCC @@ -243,7 +304,7 @@ gimple_ranger::dump_bb (FILE *f, basic_block bb) unsigned x; edge_iterator ei; edge e; - int_range_max range; + int_range_max range, tmp_range; fprintf (f, "\n=========== BB %d ============\n", bb->index); m_cache.dump_bb (f, bb); @@ -282,10 +343,9 @@ gimple_ranger::dump_bb (FILE *f, basic_block bb) // the on entry cache for either end of the edge is // set. if ((s && bb == gimple_bb (s)) || - m_cache.block_range (range, bb, name, false) || - m_cache.block_range (range, e->dest, name, false)) + m_cache.block_range (tmp_range, bb, name, false) || + m_cache.block_range (tmp_range, e->dest, name, false)) { - m_cache.range_on_edge (range, e, name); if (!range.varying_p ()) { fprintf (f, "%d->%d ", e->src->index, @@ -321,182 +381,12 @@ gimple_ranger::dump (FILE *f) m_cache.dump (f); } -// trace_ranger implementation. - - -trace_ranger::trace_ranger () -{ - indent = 0; - trace_count = 0; -} - -// If dumping, return true and print the prefix for the next output line. - -bool -trace_ranger::dumping (unsigned counter, bool trailing) -{ - if (dump_file && (dump_flags & TDF_DETAILS)) - { - // Print counter index as well as INDENT spaces. - if (!trailing) - fprintf (dump_file, " %-7u ", counter); - else - fprintf (dump_file, " "); - unsigned x; - for (x = 0; x< indent; x++) - fputc (' ', dump_file); - return true; - } - return false; -} - -// After calling a routine, if dumping, print the CALLER, NAME, and RESULT, -// returning RESULT. - -bool -trace_ranger::trailer (unsigned counter, const char *caller, bool result, - tree name, const irange &r) -{ - if (dumping (counter, true)) - { - indent -= bump; - fputs(result ? "TRUE : " : "FALSE : ", dump_file); - fprintf (dump_file, "(%u) ", counter); - fputs (caller, dump_file); - fputs (" (",dump_file); - if (name) - print_generic_expr (dump_file, name, TDF_SLIM); - fputs (") ",dump_file); - if (result) - { - r.dump (dump_file); - fputc('\n', dump_file); - } - else - fputc('\n', dump_file); - // Marks the end of a request. - if (indent == 0) - fputc('\n', dump_file); - } - return result; -} - -// Tracing version of range_on_edge. Call it with printing wrappers. - -bool -trace_ranger::range_on_edge (irange &r, edge e, tree name) -{ - unsigned idx = ++trace_count; - if (dumping (idx)) - { - fprintf (dump_file, "range_on_edge ("); - print_generic_expr (dump_file, name, TDF_SLIM); - fprintf (dump_file, ") on edge %d->%d\n", e->src->index, e->dest->index); - indent += bump; - } - - bool res = gimple_ranger::range_on_edge (r, e, name); - trailer (idx, "range_on_edge", true, name, r); - return res; -} - -// Tracing version of range_on_entry. Call it with printing wrappers. - -void -trace_ranger::range_on_entry (irange &r, basic_block bb, tree name) -{ - unsigned idx = ++trace_count; - if (dumping (idx)) - { - fprintf (dump_file, "range_on_entry ("); - print_generic_expr (dump_file, name, TDF_SLIM); - fprintf (dump_file, ") to BB %d\n", bb->index); - indent += bump; - } - - gimple_ranger::range_on_entry (r, bb, name); - - trailer (idx, "range_on_entry", true, name, r); -} - -// Tracing version of range_on_exit. Call it with printing wrappers. - -void -trace_ranger::range_on_exit (irange &r, basic_block bb, tree name) -{ - unsigned idx = ++trace_count; - if (dumping (idx)) - { - fprintf (dump_file, "range_on_exit ("); - print_generic_expr (dump_file, name, TDF_SLIM); - fprintf (dump_file, ") from BB %d\n", bb->index); - indent += bump; - } - - gimple_ranger::range_on_exit (r, bb, name); - - trailer (idx, "range_on_exit", true, name, r); -} - -// Tracing version of range_of_stmt. Call it with printing wrappers. - -bool -trace_ranger::range_of_stmt (irange &r, gimple *s, tree name) -{ - bool res; - unsigned idx = ++trace_count; - if (dumping (idx)) - { - fprintf (dump_file, "range_of_stmt ("); - if (name) - print_generic_expr (dump_file, name, TDF_SLIM); - fputs (") at stmt ", dump_file); - print_gimple_stmt (dump_file, s, 0, TDF_SLIM); - indent += bump; - } - - res = gimple_ranger::range_of_stmt (r, s, name); - - return trailer (idx, "range_of_stmt", res, name, r); -} - -// Tracing version of range_of_expr. Call it with printing wrappers. - -bool -trace_ranger::range_of_expr (irange &r, tree name, gimple *s) -{ - bool res; - unsigned idx = ++trace_count; - if (dumping (idx)) - { - fprintf (dump_file, "range_of_expr("); - print_generic_expr (dump_file, name, TDF_SLIM); - fputs (")", dump_file); - if (s) - { - fputs (" at stmt ", dump_file); - print_gimple_stmt (dump_file, s, 0, TDF_SLIM); - } - else - fputs ("\n", dump_file); - indent += bump; - } - - res = gimple_ranger::range_of_expr (r, name, s); - - return trailer (idx, "range_of_expr", res, name, r); -} - gimple_ranger * enable_ranger (struct function *fun) { gimple_ranger *r; - if (param_evrp_mode & EVRP_MODE_TRACE) - r = new trace_ranger; - else - r = new gimple_ranger; - + r = new gimple_ranger; fun->x_range_query = r; return r; @@ -509,84 +399,3 @@ disable_ranger (struct function *fun) fun->x_range_query = &global_ranges; } - -// ========================================= -// Debugging helpers. -// ========================================= - -// Query all statements in the IL to precalculate computable ranges in RANGER. - -static DEBUG_FUNCTION void -debug_seed_ranger (gimple_ranger &ranger) -{ - // Recalculate SCEV to make sure the dump lists everything. - if (scev_initialized_p ()) - { - scev_finalize (); - scev_initialize (); - } - - basic_block bb; - int_range_max r; - gimple_stmt_iterator gsi; - FOR_EACH_BB_FN (bb, cfun) - for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi)) - { - gimple *stmt = gsi_stmt (gsi); - - if (is_gimple_debug (stmt)) - continue; - - ranger.range_of_stmt (r, stmt); - } -} - -// Dump all that ranger knows for the current function. - -DEBUG_FUNCTION void -dump_ranger (FILE *out) -{ - gimple_ranger ranger; - debug_seed_ranger (ranger); - ranger.dump (out); -} - -DEBUG_FUNCTION void -debug_ranger () -{ - dump_ranger (stderr); -} - -// Dump all that ranger knows on a path of BBs. -// -// Note that the blocks are in reverse order, thus the exit block is -// path[0]. - -DEBUG_FUNCTION void -dump_ranger (FILE *dump_file, const vec<basic_block> &path) -{ - if (path.length () == 0) - { - fprintf (dump_file, "empty\n"); - return; - } - - gimple_ranger ranger; - debug_seed_ranger (ranger); - - unsigned i = path.length (); - do - { - i--; - ranger.dump_bb (dump_file, path[i]); - } - while (i > 0); -} - -DEBUG_FUNCTION void -debug_ranger (const vec<basic_block> &path) -{ - dump_ranger (stderr, path); -} - -#include "gimple-range-tests.cc" diff --git a/gcc/gimple-range.h b/gcc/gimple-range.h index aa62039..41845b1 100644 --- a/gcc/gimple-range.h +++ b/gcc/gimple-range.h @@ -22,10 +22,10 @@ along with GCC; see the file COPYING3. If not see #ifndef GCC_GIMPLE_RANGE_H #define GCC_GIMPLE_RANGE_H - #include "range.h" #include "value-query.h" #include "range-op.h" +#include "gimple-range-trace.h" #include "gimple-range-edge.h" #include "gimple-range-fold.h" #include "gimple-range-gori.h" @@ -43,7 +43,6 @@ along with GCC; see the file COPYING3. If not see // type is not supported, then false is returned. Non-statement // related methods return whatever the current global value is. - class gimple_ranger : public range_query { public: @@ -51,8 +50,8 @@ public: virtual bool range_of_stmt (irange &r, gimple *, tree name = NULL) OVERRIDE; virtual bool range_of_expr (irange &r, tree name, gimple * = NULL) OVERRIDE; virtual bool range_on_edge (irange &r, edge e, tree name) OVERRIDE; - virtual void range_on_entry (irange &r, basic_block bb, tree name); - virtual void range_on_exit (irange &r, basic_block bb, tree name); + void range_on_entry (irange &r, basic_block bb, tree name); + void range_on_exit (irange &r, basic_block bb, tree name); void export_global_ranges (); inline gori_compute &gori () { return m_cache.m_gori; } virtual void dump (FILE *f) OVERRIDE; @@ -60,34 +59,9 @@ public: protected: bool fold_range_internal (irange &r, gimple *s, tree name); ranger_cache m_cache; + range_tracer tracer; }; - -// This class overloads the ranger routines to provide tracing facilties -// Entry and exit values to each of the APIs is placed in the dumpfile. - -class trace_ranger : public gimple_ranger -{ -public: - trace_ranger (); - virtual bool range_of_stmt (irange &r, gimple *s, tree name = NULL_TREE); - virtual bool range_of_expr (irange &r, tree name, gimple *s = NULL); - virtual bool range_on_edge (irange &r, edge e, tree name); - virtual void range_on_entry (irange &r, basic_block bb, tree name); - virtual void range_on_exit (irange &r, basic_block bb, tree name); -private: - static const unsigned bump = 2; - unsigned indent; - unsigned trace_count; // Current trace index count. - - bool dumping (unsigned counter, bool trailing = false); - bool trailer (unsigned counter, const char *caller, bool result, tree name, - const irange &r); -}; - -// Flag to enable debugging the various internal Caches. -#define DEBUG_RANGE_CACHE (dump_file && (param_evrp_mode & EVRP_MODE_DEBUG)) - extern gimple_ranger *enable_ranger (struct function *); extern void disable_ranger (struct function *); diff --git a/gcc/gimple-ssa-warn-access.cc b/gcc/gimple-ssa-warn-access.cc index a4559dd..f3efe56 100644 --- a/gcc/gimple-ssa-warn-access.cc +++ b/gcc/gimple-ssa-warn-access.cc @@ -20,6 +20,7 @@ along with GCC; see the file COPYING3. If not see <http://www.gnu.org/licenses/>. */ +#define INCLUDE_STRING #include "config.h" #include "system.h" #include "coretypes.h" @@ -36,6 +37,7 @@ #include "fold-const.h" #include "gimple-fold.h" #include "gimple-iterator.h" +#include "langhooks.h" #include "tree-dfa.h" #include "tree-ssa.h" #include "tree-cfg.h" @@ -50,14 +52,6 @@ #include "demangle.h" #include "pointer-query.h" -/* Return true if STMT has an associated location. */ - -static inline location_t -has_location (const gimple *stmt) -{ - return gimple_has_location (stmt); -} - /* Return true if tree node X has an associated location. */ static inline location_t @@ -1177,7 +1171,7 @@ warn_for_access (location_t loc, tree func, tree expr, int opt, /* Helper to set RANGE to the range of BOUND if it's nonnull, bounded by BNDRNG if nonnull and valid. */ -void +static void get_size_range (tree bound, tree range[2], const offset_int bndrng[2]) { if (bound) @@ -1782,9 +1776,14 @@ new_delete_mismatch_p (tree new_decl, tree delete_decl) /* valid_new_delete_pair_p() returns a conservative result (currently it only handles global operators). A true result is reliable but - a false result doesn't necessarily mean the operators don't match. */ - if (valid_new_delete_pair_p (new_name, delete_name)) + a false result doesn't necessarily mean the operators don't match + unless CERTAIN is set. */ + bool certain; + if (valid_new_delete_pair_p (new_name, delete_name, &certain)) return false; + /* CERTAIN is set when the negative result is certain. */ + if (certain) + return true; /* For anything not handled by valid_new_delete_pair_p() such as member operators compare the individual demangled components of the mangled @@ -2100,14 +2099,14 @@ warn_dealloc_offset (location_t loc, gimple *call, const access_ref &aref) form of C++ operatorn new. */ static void -maybe_emit_free_warning (gcall *call) +maybe_check_dealloc_call (gcall *call) { tree fndecl = gimple_call_fndecl (call); if (!fndecl) return; unsigned argno = fndecl_dealloc_argno (fndecl); - if ((unsigned) gimple_call_num_args (call) <= argno) + if ((unsigned) call_nargs (call) <= argno) return; tree ptr = gimple_call_arg (call, argno); @@ -2241,9 +2240,9 @@ const pass_data pass_data_waccess = { class pass_waccess : public gimple_opt_pass { public: - pass_waccess (gcc::context *ctxt) - : gimple_opt_pass (pass_data_waccess, ctxt), m_ranger () - { } + pass_waccess (gcc::context *); + + ~pass_waccess (); opt_pass *clone () { return new pass_waccess (m_ctxt); } @@ -2253,6 +2252,9 @@ class pass_waccess : public gimple_opt_pass /* Check a call to a built-in function. */ bool check_builtin (gcall *); + /* Check a call to an ordinary function. */ + bool check_call (gcall *); + /* Check statements in a basic block. */ void check (basic_block); @@ -2260,9 +2262,35 @@ class pass_waccess : public gimple_opt_pass void check (gcall *); private: + /* Not copyable or assignable. */ + pass_waccess (pass_waccess &) = delete; + void operator= (pass_waccess &) = delete; + + /* A pointer_query object and its cache to store information about + pointers and their targets in. */ + pointer_query ptr_qry; + pointer_query::cache_type var_cache; + gimple_ranger *m_ranger; }; +/* Construct the pass. */ + +pass_waccess::pass_waccess (gcc::context *ctxt) + : gimple_opt_pass (pass_data_waccess, ctxt), + ptr_qry (m_ranger, &var_cache), + var_cache (), + m_ranger () +{ +} + +/* Release pointer_query cache. */ + +pass_waccess::~pass_waccess () +{ + ptr_qry.flush_cache (); +} + /* Return true when any checks performed by the pass are enabled. */ bool @@ -2273,12 +2301,256 @@ pass_waccess::gate (function *) || warn_mismatched_new_delete); } +/* Initialize ALLOC_OBJECT_SIZE_LIMIT based on the -Walloc-size-larger-than= + setting if the option is specified, or to the maximum object size if it + is not. Return the initialized value. */ + +static tree +alloc_max_size (void) +{ + HOST_WIDE_INT limit = warn_alloc_size_limit; + if (limit == HOST_WIDE_INT_MAX) + limit = tree_to_shwi (TYPE_MAX_VALUE (ptrdiff_type_node)); + + return build_int_cst (size_type_node, limit); +} + +/* Diagnose a call EXP to function FN decorated with attribute alloc_size + whose argument numbers given by IDX with values given by ARGS exceed + the maximum object size or cause an unsigned oveflow (wrapping) when + multiplied. FN is null when EXP is a call via a function pointer. + When ARGS[0] is null the function does nothing. ARGS[1] may be null + for functions like malloc, and non-null for those like calloc that + are decorated with a two-argument attribute alloc_size. */ + +void +maybe_warn_alloc_args_overflow (gimple *stmt, const tree args[2], + const int idx[2]) +{ + /* The range each of the (up to) two arguments is known to be in. */ + tree argrange[2][2] = { { NULL_TREE, NULL_TREE }, { NULL_TREE, NULL_TREE } }; + + /* Maximum object size set by -Walloc-size-larger-than= or SIZE_MAX / 2. */ + tree maxobjsize = alloc_max_size (); + + location_t loc = get_location (stmt); + + tree fn = gimple_call_fndecl (stmt); + tree fntype = fn ? TREE_TYPE (fn) : gimple_call_fntype (stmt); + bool warned = false; + + /* Validate each argument individually. */ + for (unsigned i = 0; i != 2 && args[i]; ++i) + { + if (TREE_CODE (args[i]) == INTEGER_CST) + { + argrange[i][0] = args[i]; + argrange[i][1] = args[i]; + + if (tree_int_cst_lt (args[i], integer_zero_node)) + { + warned = warning_at (loc, OPT_Walloc_size_larger_than_, + "argument %i value %qE is negative", + idx[i] + 1, args[i]); + } + else if (integer_zerop (args[i])) + { + /* Avoid issuing -Walloc-zero for allocation functions other + than __builtin_alloca that are declared with attribute + returns_nonnull because there's no portability risk. This + avoids warning for such calls to libiberty's xmalloc and + friends. + Also avoid issuing the warning for calls to function named + "alloca". */ + if (fn && fndecl_built_in_p (fn, BUILT_IN_ALLOCA) + ? IDENTIFIER_LENGTH (DECL_NAME (fn)) != 6 + : !lookup_attribute ("returns_nonnull", + TYPE_ATTRIBUTES (fntype))) + warned = warning_at (loc, OPT_Walloc_zero, + "argument %i value is zero", + idx[i] + 1); + } + else if (tree_int_cst_lt (maxobjsize, args[i])) + { + /* G++ emits calls to ::operator new[](SIZE_MAX) in C++98 + mode and with -fno-exceptions as a way to indicate array + size overflow. There's no good way to detect C++98 here + so avoid diagnosing these calls for all C++ modes. */ + if (i == 0 + && fn + && !args[1] + && lang_GNU_CXX () + && DECL_IS_OPERATOR_NEW_P (fn) + && integer_all_onesp (args[i])) + continue; + + warned = warning_at (loc, OPT_Walloc_size_larger_than_, + "argument %i value %qE exceeds " + "maximum object size %E", + idx[i] + 1, args[i], maxobjsize); + } + } + else if (TREE_CODE (args[i]) == SSA_NAME + && get_size_range (args[i], argrange[i])) + { + /* Verify that the argument's range is not negative (including + upper bound of zero). */ + if (tree_int_cst_lt (argrange[i][0], integer_zero_node) + && tree_int_cst_le (argrange[i][1], integer_zero_node)) + { + warned = warning_at (loc, OPT_Walloc_size_larger_than_, + "argument %i range [%E, %E] is negative", + idx[i] + 1, + argrange[i][0], argrange[i][1]); + } + else if (tree_int_cst_lt (maxobjsize, argrange[i][0])) + { + warned = warning_at (loc, OPT_Walloc_size_larger_than_, + "argument %i range [%E, %E] exceeds " + "maximum object size %E", + idx[i] + 1, + argrange[i][0], argrange[i][1], + maxobjsize); + } + } + } + + if (!argrange[0]) + return; + + /* For a two-argument alloc_size, validate the product of the two + arguments if both of their values or ranges are known. */ + if (!warned && tree_fits_uhwi_p (argrange[0][0]) + && argrange[1][0] && tree_fits_uhwi_p (argrange[1][0]) + && !integer_onep (argrange[0][0]) + && !integer_onep (argrange[1][0])) + { + /* Check for overflow in the product of a function decorated with + attribute alloc_size (X, Y). */ + unsigned szprec = TYPE_PRECISION (size_type_node); + wide_int x = wi::to_wide (argrange[0][0], szprec); + wide_int y = wi::to_wide (argrange[1][0], szprec); + + wi::overflow_type vflow; + wide_int prod = wi::umul (x, y, &vflow); + + if (vflow) + warned = warning_at (loc, OPT_Walloc_size_larger_than_, + "product %<%E * %E%> of arguments %i and %i " + "exceeds %<SIZE_MAX%>", + argrange[0][0], argrange[1][0], + idx[0] + 1, idx[1] + 1); + else if (wi::ltu_p (wi::to_wide (maxobjsize, szprec), prod)) + warned = warning_at (loc, OPT_Walloc_size_larger_than_, + "product %<%E * %E%> of arguments %i and %i " + "exceeds maximum object size %E", + argrange[0][0], argrange[1][0], + idx[0] + 1, idx[1] + 1, + maxobjsize); + + if (warned) + { + /* Print the full range of each of the two arguments to make + it clear when it is, in fact, in a range and not constant. */ + if (argrange[0][0] != argrange [0][1]) + inform (loc, "argument %i in the range [%E, %E]", + idx[0] + 1, argrange[0][0], argrange[0][1]); + if (argrange[1][0] != argrange [1][1]) + inform (loc, "argument %i in the range [%E, %E]", + idx[1] + 1, argrange[1][0], argrange[1][1]); + } + } + + if (warned && fn) + { + location_t fnloc = DECL_SOURCE_LOCATION (fn); + + if (DECL_IS_UNDECLARED_BUILTIN (fn)) + inform (loc, + "in a call to built-in allocation function %qD", fn); + else + inform (fnloc, + "in a call to allocation function %qD declared here", fn); + } +} + +/* Check a call to an alloca function for an excessive size. */ + +static void +check_alloca (gimple *stmt) +{ + if ((warn_vla_limit >= HOST_WIDE_INT_MAX + && warn_alloc_size_limit < warn_vla_limit) + || (warn_alloca_limit >= HOST_WIDE_INT_MAX + && warn_alloc_size_limit < warn_alloca_limit)) + { + /* -Walloca-larger-than and -Wvla-larger-than settings of less + than HWI_MAX override the more general -Walloc-size-larger-than + so unless either of the former options is smaller than the last + one (wchich would imply that the call was already checked), check + the alloca arguments for overflow. */ + const tree alloc_args[] = { call_arg (stmt, 0), NULL_TREE }; + const int idx[] = { 0, -1 }; + maybe_warn_alloc_args_overflow (stmt, alloc_args, idx); + } +} + +/* Check a call to an allocation function for an excessive size. */ + +static void +check_alloc_size_call (gimple *stmt) +{ + if (gimple_call_num_args (stmt) < 1) + /* Avoid invalid calls to functions without a prototype. */ + return; + + tree fndecl = gimple_call_fndecl (stmt); + if (fndecl && gimple_call_builtin_p (stmt, BUILT_IN_NORMAL)) + { + /* Alloca is handled separately. */ + switch (DECL_FUNCTION_CODE (fndecl)) + { + case BUILT_IN_ALLOCA: + case BUILT_IN_ALLOCA_WITH_ALIGN: + case BUILT_IN_ALLOCA_WITH_ALIGN_AND_MAX: + return; + default: + break; + } + } + + tree fntype = gimple_call_fntype (stmt); + tree fntypeattrs = TYPE_ATTRIBUTES (fntype); + + tree alloc_size = lookup_attribute ("alloc_size", fntypeattrs); + if (!alloc_size) + return; + + /* Extract attribute alloc_size from the type of the called expression + (which could be a function or a function pointer) and if set, store + the indices of the corresponding arguments in ALLOC_IDX, and then + the actual argument(s) at those indices in ALLOC_ARGS. */ + int idx[2] = { -1, -1 }; + tree alloc_args[] = { NULL_TREE, NULL_TREE }; + + tree args = TREE_VALUE (alloc_size); + idx[0] = TREE_INT_CST_LOW (TREE_VALUE (args)) - 1; + alloc_args[0] = call_arg (stmt, idx[0]); + if (TREE_CHAIN (args)) + { + idx[1] = TREE_INT_CST_LOW (TREE_VALUE (TREE_CHAIN (args))) - 1; + alloc_args[1] = call_arg (stmt, idx[1]); + } + + maybe_warn_alloc_args_overflow (stmt, alloc_args, idx); +} + /* Check a call STMT to strcat() for overflow and warn if it does. */ static void check_strcat (gimple *stmt) { - if (!warn_stringop_overflow) + if (!warn_stringop_overflow && !warn_stringop_overread) return; tree dest = call_arg (stmt, 0); @@ -2303,7 +2575,7 @@ check_strcat (gimple *stmt) static void check_strncat (gimple *stmt) { - if (!warn_stringop_overflow) + if (!warn_stringop_overflow && !warn_stringop_overread) return; tree dest = call_arg (stmt, 0); @@ -2532,6 +2804,12 @@ pass_waccess::check_builtin (gcall *stmt) switch (DECL_FUNCTION_CODE (callee)) { + case BUILT_IN_ALLOCA: + case BUILT_IN_ALLOCA_WITH_ALIGN: + case BUILT_IN_ALLOCA_WITH_ALIGN_AND_MAX: + check_alloca (stmt); + return true; + case BUILT_IN_GETTEXT: case BUILT_IN_PUTS: case BUILT_IN_PUTS_UNLOCKED: @@ -2634,16 +2912,384 @@ pass_waccess::check_builtin (gcall *stmt) return true; } +/* Returns the type of the argument ARGNO to function with type FNTYPE + or null when the typoe cannot be determined or no such argument exists. */ + +static tree +fntype_argno_type (tree fntype, unsigned argno) +{ + if (!prototype_p (fntype)) + return NULL_TREE; + + tree argtype; + function_args_iterator it; + FOREACH_FUNCTION_ARGS (fntype, argtype, it) + if (argno-- == 0) + return argtype; + + return NULL_TREE; +} + +/* Helper to append the "human readable" attribute access specification + described by ACCESS to the array ATTRSTR with size STRSIZE. Used in + diagnostics. */ + +static inline void +append_attrname (const std::pair<int, attr_access> &access, + char *attrstr, size_t strsize) +{ + if (access.second.internal_p) + return; + + tree str = access.second.to_external_string (); + gcc_assert (strsize >= (size_t) TREE_STRING_LENGTH (str)); + strcpy (attrstr, TREE_STRING_POINTER (str)); +} + +/* Iterate over attribute access read-only, read-write, and write-only + arguments and diagnose past-the-end accesses and related problems + in the function call EXP. */ + +static void +maybe_warn_rdwr_sizes (rdwr_map *rwm, tree fndecl, tree fntype, gimple *stmt) +{ + auto_diagnostic_group adg; + + /* Set if a warning has been issued for any argument (used to decide + whether to emit an informational note at the end). */ + opt_code opt_warned = no_warning; + + /* A string describing the attributes that the warnings issued by this + function apply to. Used to print one informational note per function + call, rather than one per warning. That reduces clutter. */ + char attrstr[80]; + attrstr[0] = 0; + + for (rdwr_map::iterator it = rwm->begin (); it != rwm->end (); ++it) + { + std::pair<int, attr_access> access = *it; + + /* Get the function call arguments corresponding to the attribute's + positional arguments. When both arguments have been specified + there will be two entries in *RWM, one for each. They are + cross-referenced by their respective argument numbers in + ACCESS.PTRARG and ACCESS.SIZARG. */ + const int ptridx = access.second.ptrarg; + const int sizidx = access.second.sizarg; + + gcc_assert (ptridx != -1); + gcc_assert (access.first == ptridx || access.first == sizidx); + + /* The pointer is set to null for the entry corresponding to + the size argument. Skip it. It's handled when the entry + corresponding to the pointer argument comes up. */ + if (!access.second.ptr) + continue; + + tree ptrtype = fntype_argno_type (fntype, ptridx); + tree argtype = TREE_TYPE (ptrtype); + + /* The size of the access by the call. */ + tree access_size; + if (sizidx == -1) + { + /* If only the pointer attribute operand was specified and + not size, set SIZE to the greater of MINSIZE or size of + one element of the pointed to type to detect smaller + objects (null pointers are diagnosed in this case only + if the pointer is also declared with attribute nonnull. */ + if (access.second.minsize + && access.second.minsize != HOST_WIDE_INT_M1U) + access_size = build_int_cstu (sizetype, access.second.minsize); + else + access_size = size_one_node; + } + else + access_size = rwm->get (sizidx)->size; + + /* Format the value or range to avoid an explosion of messages. */ + char sizstr[80]; + tree sizrng[2] = { size_zero_node, build_all_ones_cst (sizetype) }; + if (get_size_range (access_size, sizrng, true)) + { + char *s0 = print_generic_expr_to_str (sizrng[0]); + if (tree_int_cst_equal (sizrng[0], sizrng[1])) + { + gcc_checking_assert (strlen (s0) < sizeof sizstr); + strcpy (sizstr, s0); + } + else + { + char *s1 = print_generic_expr_to_str (sizrng[1]); + gcc_checking_assert (strlen (s0) + strlen (s1) + < sizeof sizstr - 4); + sprintf (sizstr, "[%s, %s]", s0, s1); + free (s1); + } + free (s0); + } + else + *sizstr = '\0'; + + /* Set if a warning has been issued for the current argument. */ + opt_code arg_warned = no_warning; + location_t loc = get_location (stmt); + tree ptr = access.second.ptr; + if (*sizstr + && tree_int_cst_sgn (sizrng[0]) < 0 + && tree_int_cst_sgn (sizrng[1]) < 0) + { + /* Warn about negative sizes. */ + if (access.second.internal_p) + { + const std::string argtypestr + = access.second.array_as_string (ptrtype); + + if (warning_at (loc, OPT_Wstringop_overflow_, + "bound argument %i value %s is " + "negative for a variable length array " + "argument %i of type %s", + sizidx + 1, sizstr, + ptridx + 1, argtypestr.c_str ())) + arg_warned = OPT_Wstringop_overflow_; + } + else if (warning_at (loc, OPT_Wstringop_overflow_, + "argument %i value %s is negative", + sizidx + 1, sizstr)) + arg_warned = OPT_Wstringop_overflow_; + + if (arg_warned != no_warning) + { + append_attrname (access, attrstr, sizeof attrstr); + /* Remember a warning has been issued and avoid warning + again below for the same attribute. */ + opt_warned = arg_warned; + continue; + } + } + + if (tree_int_cst_sgn (sizrng[0]) >= 0) + { + if (COMPLETE_TYPE_P (argtype)) + { + /* Multiply ACCESS_SIZE by the size of the type the pointer + argument points to. If it's incomplete the size is used + as is. */ + if (tree argsize = TYPE_SIZE_UNIT (argtype)) + if (TREE_CODE (argsize) == INTEGER_CST) + { + const int prec = TYPE_PRECISION (sizetype); + wide_int minsize = wi::to_wide (sizrng[0], prec); + minsize *= wi::to_wide (argsize, prec); + access_size = wide_int_to_tree (sizetype, minsize); + } + } + } + else + access_size = NULL_TREE; + + if (integer_zerop (ptr)) + { + if (sizidx >= 0 && tree_int_cst_sgn (sizrng[0]) > 0) + { + /* Warn about null pointers with positive sizes. This is + different from also declaring the pointer argument with + attribute nonnull when the function accepts null pointers + only when the corresponding size is zero. */ + if (access.second.internal_p) + { + const std::string argtypestr + = access.second.array_as_string (ptrtype); + + if (warning_at (loc, OPT_Wnonnull, + "argument %i of variable length " + "array %s is null but " + "the corresponding bound argument " + "%i value is %s", + ptridx + 1, argtypestr.c_str (), + sizidx + 1, sizstr)) + arg_warned = OPT_Wnonnull; + } + else if (warning_at (loc, OPT_Wnonnull, + "argument %i is null but " + "the corresponding size argument " + "%i value is %s", + ptridx + 1, sizidx + 1, sizstr)) + arg_warned = OPT_Wnonnull; + } + else if (access_size && access.second.static_p) + { + /* Warn about null pointers for [static N] array arguments + but do not warn for ordinary (i.e., nonstatic) arrays. */ + if (warning_at (loc, OPT_Wnonnull, + "argument %i to %<%T[static %E]%> " + "is null where non-null expected", + ptridx + 1, argtype, access_size)) + arg_warned = OPT_Wnonnull; + } + + if (arg_warned != no_warning) + { + append_attrname (access, attrstr, sizeof attrstr); + /* Remember a warning has been issued and avoid warning + again below for the same attribute. */ + opt_warned = OPT_Wnonnull; + continue; + } + } + + access_data data (ptr, access.second.mode, NULL_TREE, false, + NULL_TREE, false); + access_ref* const pobj = (access.second.mode == access_write_only + ? &data.dst : &data.src); + tree objsize = compute_objsize (ptr, 1, pobj); + + /* The size of the destination or source object. */ + tree dstsize = NULL_TREE, srcsize = NULL_TREE; + if (access.second.mode == access_read_only + || access.second.mode == access_none) + { + /* For a read-only argument there is no destination. For + no access, set the source as well and differentiate via + the access flag below. */ + srcsize = objsize; + if (access.second.mode == access_read_only + || access.second.mode == access_none) + { + /* For a read-only attribute there is no destination so + clear OBJSIZE. This emits "reading N bytes" kind of + diagnostics instead of the "writing N bytes" kind, + unless MODE is none. */ + objsize = NULL_TREE; + } + } + else + dstsize = objsize; + + /* Clear the no-warning bit in case it was set by check_access + in a prior iteration so that accesses via different arguments + are diagnosed. */ + suppress_warning (stmt, OPT_Wstringop_overflow_, false); + access_mode mode = data.mode; + if (mode == access_deferred) + mode = TYPE_READONLY (argtype) ? access_read_only : access_read_write; + check_access (stmt, access_size, /*maxread=*/ NULL_TREE, srcsize, + dstsize, mode, &data); + + if (warning_suppressed_p (stmt, OPT_Wstringop_overflow_)) + opt_warned = OPT_Wstringop_overflow_; + if (opt_warned != no_warning) + { + if (access.second.internal_p) + inform (loc, "referencing argument %u of type %qT", + ptridx + 1, ptrtype); + else + /* If check_access issued a warning above, append the relevant + attribute to the string. */ + append_attrname (access, attrstr, sizeof attrstr); + } + } + + if (*attrstr) + { + if (fndecl) + inform (get_location (fndecl), + "in a call to function %qD declared with attribute %qs", + fndecl, attrstr); + else + inform (get_location (stmt), + "in a call with type %qT and attribute %qs", + fntype, attrstr); + } + else if (opt_warned != no_warning) + { + if (fndecl) + inform (get_location (fndecl), + "in a call to function %qD", fndecl); + else + inform (get_location (stmt), + "in a call with type %qT", fntype); + } + + /* Set the bit in case if was cleared and not set above. */ + if (opt_warned != no_warning) + suppress_warning (stmt, opt_warned); +} + +/* Check call STMT to an ordinary (non-built-in) function for invalid + accesses. Return true if a call has been handled. */ + +bool +pass_waccess::check_call (gcall *stmt) +{ + tree fntype = gimple_call_fntype (stmt); + if (!fntype) + return false; + + tree fntypeattrs = TYPE_ATTRIBUTES (fntype); + if (!fntypeattrs) + return false; + + /* Map of attribute accewss specifications for function arguments. */ + rdwr_map rdwr_idx; + init_attr_rdwr_indices (&rdwr_idx, fntypeattrs); + + unsigned nargs = call_nargs (stmt); + for (unsigned i = 0; i != nargs; ++i) + { + tree arg = call_arg (stmt, i); + + /* Save the actual argument that corresponds to the access attribute + operand for later processing. */ + if (attr_access *access = rdwr_idx.get (i)) + { + if (POINTER_TYPE_P (TREE_TYPE (arg))) + { + access->ptr = arg; + // A nonnull ACCESS->SIZE contains VLA bounds. */ + } + else + { + access->size = arg; + gcc_assert (access->ptr == NULL_TREE); + } + } + } + + /* Check attribute access arguments. */ + tree fndecl = gimple_call_fndecl (stmt); + maybe_warn_rdwr_sizes (&rdwr_idx, fndecl, fntype, stmt); + + check_alloc_size_call (stmt); + return true; +} + +/* Check arguments in a call STMT for attribute nonstring. */ + +static void +check_nonstring_args (gcall *stmt) +{ + tree fndecl = gimple_call_fndecl (stmt); + + /* Detect passing non-string arguments to functions expecting + nul-terminated strings. */ + maybe_warn_nonstring_arg (fndecl, stmt); +} + /* Check call STMT for invalid accesses. */ void pass_waccess::check (gcall *stmt) { - if (gimple_call_builtin_p (stmt, BUILT_IN_NORMAL) - && check_builtin (stmt)) - return; + if (gimple_call_builtin_p (stmt, BUILT_IN_NORMAL)) + check_builtin (stmt); - maybe_emit_free_warning (stmt); + if (is_gimple_call (stmt)) + check_call (stmt); + + maybe_check_dealloc_call (stmt); + + check_nonstring_args (stmt); } /* Check basic block BB for invalid accesses. */ @@ -2664,6 +3310,8 @@ pass_waccess::check (basic_block bb) unsigned pass_waccess::execute (function *fun) { + m_ranger = enable_ranger (fun); + basic_block bb; FOR_EACH_BB_FN (bb, fun) check (bb); diff --git a/gcc/gimple-ssa-warn-access.h b/gcc/gimple-ssa-warn-access.h index 8b33ecb..1cd3a28 100644 --- a/gcc/gimple-ssa-warn-access.h +++ b/gcc/gimple-ssa-warn-access.h @@ -31,7 +31,9 @@ extern void warn_string_no_nul (location_t, tree, const char *, tree, tree, tree = NULL_TREE, bool = false, const wide_int[2] = NULL); extern tree unterminated_array (tree, tree * = NULL, bool * = NULL); -extern void get_size_range (tree, tree[2], const offset_int[2]); + +extern bool maybe_warn_nonstring_arg (tree, gimple *); +extern bool maybe_warn_nonstring_arg (tree, tree); class access_data; extern bool maybe_warn_for_bound (opt_code, location_t, gimple *, tree, diff --git a/gcc/gimple-ssa-warn-restrict.c b/gcc/gimple-ssa-warn-restrict.c index 404acb0..d1df9ca 100644 --- a/gcc/gimple-ssa-warn-restrict.c +++ b/gcc/gimple-ssa-warn-restrict.c @@ -29,6 +29,7 @@ #include "pointer-query.h" #include "ssa.h" #include "gimple-pretty-print.h" +#include "gimple-ssa-warn-access.h" #include "gimple-ssa-warn-restrict.h" #include "diagnostic-core.h" #include "fold-const.h" diff --git a/gcc/gimple-walk.c b/gcc/gimple-walk.c index 18884c4..e15fd469 100644 --- a/gcc/gimple-walk.c +++ b/gcc/gimple-walk.c @@ -682,12 +682,14 @@ walk_gimple_stmt (gimple_stmt_iterator *gsi, walk_stmt_fn callback_stmt, /* FALL THROUGH. */ case GIMPLE_OMP_CRITICAL: case GIMPLE_OMP_MASTER: + case GIMPLE_OMP_MASKED: case GIMPLE_OMP_TASKGROUP: case GIMPLE_OMP_ORDERED: case GIMPLE_OMP_SCAN: case GIMPLE_OMP_SECTION: case GIMPLE_OMP_PARALLEL: case GIMPLE_OMP_TASK: + case GIMPLE_OMP_SCOPE: case GIMPLE_OMP_SECTIONS: case GIMPLE_OMP_SINGLE: case GIMPLE_OMP_TARGET: diff --git a/gcc/gimple.c b/gcc/gimple.c index 383da98..4e2653c 100644 --- a/gcc/gimple.c +++ b/gcc/gimple.c @@ -1038,6 +1038,21 @@ gimple_build_omp_master (gimple_seq body) return p; } +/* Build a GIMPLE_OMP_MASKED statement. + + BODY is the sequence of statements to be executed by the selected thread(s). */ + +gimple * +gimple_build_omp_masked (gimple_seq body, tree clauses) +{ + gimple *p = gimple_alloc (GIMPLE_OMP_MASKED, 0); + gimple_omp_masked_set_clauses (p, clauses); + if (body) + gimple_omp_set_body (p, body); + + return p; +} + /* Build a GIMPLE_OMP_TASKGROUP statement. BODY is the sequence of statements to be executed by the taskgroup @@ -1170,6 +1185,24 @@ gimple_build_omp_single (gimple_seq body, tree clauses) } +/* Build a GIMPLE_OMP_SCOPE statement. + + BODY is the sequence of statements that will be executed once. + CLAUSES are any of the OMP scope construct's clauses: private, reduction, + nowait. */ + +gimple * +gimple_build_omp_scope (gimple_seq body, tree clauses) +{ + gimple *p = gimple_alloc (GIMPLE_OMP_SCOPE, 0); + gimple_omp_scope_set_clauses (p, clauses); + if (body) + gimple_omp_set_body (p, body); + + return p; +} + + /* Build a GIMPLE_OMP_TARGET statement. BODY is the sequence of statements that will be executed. @@ -2005,6 +2038,11 @@ gimple_copy (gimple *stmt) } goto copy_omp_body; + case GIMPLE_OMP_SCOPE: + t = unshare_expr (gimple_omp_scope_clauses (stmt)); + gimple_omp_scope_set_clauses (copy, t); + goto copy_omp_body; + case GIMPLE_OMP_TARGET: { gomp_target *omp_target_stmt = as_a <gomp_target *> (stmt); @@ -2031,6 +2069,11 @@ gimple_copy (gimple *stmt) gimple_omp_set_body (copy, new_seq); break; + case GIMPLE_OMP_MASKED: + t = unshare_expr (gimple_omp_masked_clauses (stmt)); + gimple_omp_masked_set_clauses (copy, t); + goto copy_omp_body; + case GIMPLE_TRANSACTION: new_seq = gimple_seq_copy (gimple_transaction_body ( as_a <gtransaction *> (stmt))); diff --git a/gcc/gimple.def b/gcc/gimple.def index 0ac0cf7..193b250 100644 --- a/gcc/gimple.def +++ b/gcc/gimple.def @@ -279,6 +279,10 @@ DEFGSCODE(GIMPLE_OMP_FOR, "gimple_omp_for", GSS_OMP_FOR) BODY is the sequence of statements to execute in the master section. */ DEFGSCODE(GIMPLE_OMP_MASTER, "gimple_omp_master", GSS_OMP) +/* GIMPLE_OMP_MASKED <BODY, CLAUSES> represents #pragma omp masked. + BODY is the sequence of statements to execute in the masked section. */ +DEFGSCODE(GIMPLE_OMP_MASKED, "gimple_omp_masked", GSS_OMP_SINGLE_LAYOUT) + /* GIMPLE_OMP_TASKGROUP <BODY, CLAUSES> represents #pragma omp taskgroup. BODY is the sequence of statements inside the taskgroup section. CLAUSES is an OMP_CLAUSE chain holding the associated clauses. */ @@ -336,6 +340,11 @@ DEFGSCODE(GIMPLE_OMP_RETURN, "gimple_omp_return", GSS_OMP_ATOMIC_STORE_LAYOUT) CLAUSES is an OMP_CLAUSE chain holding the associated clauses. */ DEFGSCODE(GIMPLE_OMP_SCAN, "gimple_omp_scan", GSS_OMP_SINGLE_LAYOUT) +/* GIMPLE_OMP_SCOPE <BODY, CLAUSES> represents #pragma omp scope + BODY is the sequence of statements inside the single section. + CLAUSES is an OMP_CLAUSE chain holding the associated clauses. */ +DEFGSCODE(GIMPLE_OMP_SCOPE, "gimple_omp_scope", GSS_OMP_SINGLE_LAYOUT) + /* OMP_SECTION <BODY> represents #pragma omp section. BODY is the sequence of statements in the section body. */ DEFGSCODE(GIMPLE_OMP_SECTION, "gimple_omp_section", GSS_OMP) diff --git a/gcc/gimple.h b/gcc/gimple.h index 31d7dd0..479a1c7 100644 --- a/gcc/gimple.h +++ b/gcc/gimple.h @@ -742,7 +742,7 @@ struct GTY((tag("GSS_OMP_CONTINUE"))) }; /* GIMPLE_OMP_SINGLE, GIMPLE_OMP_ORDERED, GIMPLE_OMP_TASKGROUP, - GIMPLE_OMP_SCAN. */ + GIMPLE_OMP_SCAN, GIMPLE_OMP_MASKED, GIMPLE_OMP_SCOPE. */ struct GTY((tag("GSS_OMP_SINGLE_LAYOUT"))) gimple_statement_omp_single_layout : public gimple_statement_omp @@ -1559,7 +1559,9 @@ gomp_parallel *gimple_build_omp_parallel (gimple_seq, tree, tree, tree); gomp_task *gimple_build_omp_task (gimple_seq, tree, tree, tree, tree, tree, tree); gimple *gimple_build_omp_section (gimple_seq); +gimple *gimple_build_omp_scope (gimple_seq, tree); gimple *gimple_build_omp_master (gimple_seq); +gimple *gimple_build_omp_masked (gimple_seq, tree); gimple *gimple_build_omp_taskgroup (gimple_seq, tree); gomp_continue *gimple_build_omp_continue (tree, tree); gomp_ordered *gimple_build_omp_ordered (gimple_seq, tree); @@ -1836,11 +1838,13 @@ gimple_has_substatements (gimple *g) case GIMPLE_TRY: case GIMPLE_OMP_FOR: case GIMPLE_OMP_MASTER: + case GIMPLE_OMP_MASKED: case GIMPLE_OMP_TASKGROUP: case GIMPLE_OMP_ORDERED: case GIMPLE_OMP_SECTION: case GIMPLE_OMP_PARALLEL: case GIMPLE_OMP_TASK: + case GIMPLE_OMP_SCOPE: case GIMPLE_OMP_SECTIONS: case GIMPLE_OMP_SINGLE: case GIMPLE_OMP_TARGET: @@ -5205,6 +5209,74 @@ gimple_omp_taskgroup_set_clauses (gimple *gs, tree clauses) } +/* Return the clauses associated with OMP_MASKED statement GS. */ + +static inline tree +gimple_omp_masked_clauses (const gimple *gs) +{ + GIMPLE_CHECK (gs, GIMPLE_OMP_MASKED); + return + static_cast <const gimple_statement_omp_single_layout *> (gs)->clauses; +} + + +/* Return a pointer to the clauses associated with OMP masked statement + GS. */ + +static inline tree * +gimple_omp_masked_clauses_ptr (gimple *gs) +{ + GIMPLE_CHECK (gs, GIMPLE_OMP_MASKED); + return &static_cast <gimple_statement_omp_single_layout *> (gs)->clauses; +} + + +/* Set CLAUSES to be the clauses associated with OMP masked statement + GS. */ + +static inline void +gimple_omp_masked_set_clauses (gimple *gs, tree clauses) +{ + GIMPLE_CHECK (gs, GIMPLE_OMP_MASKED); + static_cast <gimple_statement_omp_single_layout *> (gs)->clauses + = clauses; +} + + +/* Return the clauses associated with OMP_SCOPE statement GS. */ + +static inline tree +gimple_omp_scope_clauses (const gimple *gs) +{ + GIMPLE_CHECK (gs, GIMPLE_OMP_SCOPE); + return + static_cast <const gimple_statement_omp_single_layout *> (gs)->clauses; +} + + +/* Return a pointer to the clauses associated with OMP scope statement + GS. */ + +static inline tree * +gimple_omp_scope_clauses_ptr (gimple *gs) +{ + GIMPLE_CHECK (gs, GIMPLE_OMP_SCOPE); + return &static_cast <gimple_statement_omp_single_layout *> (gs)->clauses; +} + + +/* Set CLAUSES to be the clauses associated with OMP scope statement + GS. */ + +static inline void +gimple_omp_scope_set_clauses (gimple *gs, tree clauses) +{ + GIMPLE_CHECK (gs, GIMPLE_OMP_SCOPE); + static_cast <gimple_statement_omp_single_layout *> (gs)->clauses + = clauses; +} + + /* Return the kind of the OMP_FOR statemement G. */ static inline int @@ -6491,8 +6563,10 @@ gimple_return_set_retval (greturn *gs, tree retval) case GIMPLE_OMP_SINGLE: \ case GIMPLE_OMP_TARGET: \ case GIMPLE_OMP_TEAMS: \ + case GIMPLE_OMP_SCOPE: \ case GIMPLE_OMP_SECTION: \ case GIMPLE_OMP_MASTER: \ + case GIMPLE_OMP_MASKED: \ case GIMPLE_OMP_TASKGROUP: \ case GIMPLE_OMP_ORDERED: \ case GIMPLE_OMP_CRITICAL: \ diff --git a/gcc/gimplify.c b/gcc/gimplify.c index 21ff32e..070d0e4 100644 --- a/gcc/gimplify.c +++ b/gcc/gimplify.c @@ -5628,10 +5628,12 @@ is_gimple_stmt (tree t) case OMP_LOOP: case OACC_LOOP: case OMP_SCAN: + case OMP_SCOPE: case OMP_SECTIONS: case OMP_SECTION: case OMP_SINGLE: case OMP_MASTER: + case OMP_MASKED: case OMP_TASKGROUP: case OMP_ORDERED: case OMP_CRITICAL: @@ -8865,7 +8867,7 @@ gimplify_scan_omp_clauses (tree *list_p, gimple_seq *pre_p, case OMP_CLAUSE_REDUCTION: if (OMP_CLAUSE_REDUCTION_TASK (c)) { - if (region_type == ORT_WORKSHARE) + if (region_type == ORT_WORKSHARE || code == OMP_SCOPE) { if (nowait == -1) nowait = omp_find_clause (*list_p, @@ -8884,8 +8886,8 @@ gimplify_scan_omp_clauses (tree *list_p, gimple_seq *pre_p, { error_at (OMP_CLAUSE_LOCATION (c), "invalid %<task%> reduction modifier on construct " - "other than %<parallel%>, %qs or %<sections%>", - lang_GNU_Fortran () ? "do" : "for"); + "other than %<parallel%>, %qs, %<sections%> or " + "%<scope%>", lang_GNU_Fortran () ? "do" : "for"); OMP_CLAUSE_REDUCTION_TASK (c) = 0; } } @@ -8916,6 +8918,12 @@ gimplify_scan_omp_clauses (tree *list_p, gimple_seq *pre_p, "%qs construct", "taskloop"); OMP_CLAUSE_REDUCTION_INSCAN (c) = 0; break; + case OMP_SCOPE: + error_at (OMP_CLAUSE_LOCATION (c), + "%<inscan%> %<reduction%> clause on " + "%qs construct", "scope"); + OMP_CLAUSE_REDUCTION_INSCAN (c) = 0; + break; default: break; } @@ -10102,6 +10110,7 @@ gimplify_scan_omp_clauses (tree *list_p, gimple_seq *pre_p, case OMP_CLAUSE_PRIORITY: case OMP_CLAUSE_GRAINSIZE: case OMP_CLAUSE_NUM_TASKS: + case OMP_CLAUSE_FILTER: case OMP_CLAUSE_HINT: case OMP_CLAUSE_ASYNC: case OMP_CLAUSE_WAIT: @@ -10110,9 +10119,20 @@ gimplify_scan_omp_clauses (tree *list_p, gimple_seq *pre_p, case OMP_CLAUSE_VECTOR_LENGTH: case OMP_CLAUSE_WORKER: case OMP_CLAUSE_VECTOR: - if (gimplify_expr (&OMP_CLAUSE_OPERAND (c, 0), pre_p, NULL, - is_gimple_val, fb_rvalue) == GS_ERROR) - remove = true; + if (OMP_CLAUSE_OPERAND (c, 0) + && !is_gimple_min_invariant (OMP_CLAUSE_OPERAND (c, 0))) + { + if (error_operand_p (OMP_CLAUSE_OPERAND (c, 0))) + { + remove = true; + break; + } + /* All these clauses care about value, not a particular decl, + so try to force it into a SSA_NAME or fresh temporary. */ + OMP_CLAUSE_OPERAND (c, 0) + = get_initialized_tmp_var (OMP_CLAUSE_OPERAND (c, 0), + pre_p, NULL, true); + } break; case OMP_CLAUSE_GANG: @@ -10440,6 +10460,7 @@ omp_find_stores_stmt (gimple_stmt_iterator *gsi_p, case GIMPLE_OMP_TASK: case GIMPLE_OMP_SECTIONS: case GIMPLE_OMP_SINGLE: + case GIMPLE_OMP_SCOPE: case GIMPLE_OMP_TARGET: case GIMPLE_OMP_TEAMS: case GIMPLE_OMP_CRITICAL: @@ -11222,6 +11243,7 @@ gimplify_adjust_omp_clauses (gimple_seq *pre_p, gimple_seq body, tree *list_p, case OMP_CLAUSE_NOGROUP: case OMP_CLAUSE_THREADS: case OMP_CLAUSE_SIMD: + case OMP_CLAUSE_FILTER: case OMP_CLAUSE_HINT: case OMP_CLAUSE_DEFAULTMAP: case OMP_CLAUSE_ORDER: @@ -13361,6 +13383,9 @@ gimplify_omp_workshare (tree *expr_p, gimple_seq *pre_p) case OMP_SINGLE: ort = ORT_WORKSHARE; break; + case OMP_SCOPE: + ort = ORT_TASKGROUP; + break; case OMP_TARGET: ort = OMP_TARGET_COMBINED (expr) ? ORT_COMBINED_TARGET : ORT_TARGET; break; @@ -13473,6 +13498,9 @@ gimplify_omp_workshare (tree *expr_p, gimple_seq *pre_p) case OMP_SINGLE: stmt = gimple_build_omp_single (body, OMP_CLAUSES (expr)); break; + case OMP_SCOPE: + stmt = gimple_build_omp_scope (body, OMP_CLAUSES (expr)); + break; case OMP_TARGET: stmt = gimple_build_omp_target (body, GF_OMP_TARGET_KIND_REGION, OMP_CLAUSES (expr)); @@ -14745,6 +14773,7 @@ gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p, case OACC_KERNELS: case OACC_PARALLEL: case OACC_SERIAL: + case OMP_SCOPE: case OMP_SECTIONS: case OMP_SINGLE: case OMP_TARGET: @@ -14766,6 +14795,7 @@ gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p, case OMP_SECTION: case OMP_MASTER: + case OMP_MASKED: case OMP_ORDERED: case OMP_CRITICAL: case OMP_SCAN: @@ -14788,6 +14818,15 @@ gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p, case OMP_ORDERED: g = gimplify_omp_ordered (*expr_p, body); break; + case OMP_MASKED: + gimplify_scan_omp_clauses (&OMP_MASKED_CLAUSES (*expr_p), + pre_p, ORT_WORKSHARE, OMP_MASKED); + gimplify_adjust_omp_clauses (pre_p, body, + &OMP_MASKED_CLAUSES (*expr_p), + OMP_MASKED); + g = gimple_build_omp_masked (body, + OMP_MASKED_CLAUSES (*expr_p)); + break; case OMP_CRITICAL: gimplify_scan_omp_clauses (&OMP_CRITICAL_CLAUSES (*expr_p), pre_p, ORT_WORKSHARE, OMP_CRITICAL); @@ -15161,13 +15200,15 @@ gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p, && code != OMP_FOR && code != OACC_LOOP && code != OMP_MASTER + && code != OMP_MASKED && code != OMP_TASKGROUP && code != OMP_ORDERED && code != OMP_PARALLEL && code != OMP_SCAN && code != OMP_SECTIONS && code != OMP_SECTION - && code != OMP_SINGLE); + && code != OMP_SINGLE + && code != OMP_SCOPE); } #endif diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE index b983fda..950f179 100644 --- a/gcc/go/gofrontend/MERGE +++ b/gcc/go/gofrontend/MERGE @@ -1,4 +1,4 @@ -d5d51242efc432fa62d4e9b141b01c280af32d19 +77bc32767b61feb6499ca7921e96b356603517dc The first line of this file holds the git revision number of the last merge done from the gofrontend repository. diff --git a/gcc/go/gofrontend/expressions.cc b/gcc/go/gofrontend/expressions.cc index f462b0e..8d4d168 100644 --- a/gcc/go/gofrontend/expressions.cc +++ b/gcc/go/gofrontend/expressions.cc @@ -408,7 +408,14 @@ Expression::convert_type_to_interface(Type* lhs_type, Expression* rhs, { // We are assigning a non-pointer value to the interface; the // interface gets a copy of the value in the heap if it escapes. - if (rhs->is_constant()) + + // An exception is &global if global is notinheap, which is a + // pointer value but not a direct-iface type and we can't simply + // take its address. + bool is_address = (rhs->unary_expression() != NULL + && rhs->unary_expression()->op() == OPERATOR_AND); + + if (rhs->is_constant() && !is_address) obj = Expression::make_unary(OPERATOR_AND, rhs, location); else { @@ -11202,12 +11209,23 @@ Call_expression::do_lower(Gogo* gogo, Named_object* function, { Location loc = this->location(); + if (this->is_error_expression()) + return Expression::make_error(loc); + // A type cast can look like a function call. if (this->fn_->is_type_expression() && this->args_ != NULL && this->args_->size() == 1) - return Expression::make_cast(this->fn_->type(), this->args_->front(), - loc); + { + if (this->expected_result_count_ != 0 + && this->expected_result_count_ != 1) + { + this->report_error(_("type conversion result count mismatch")); + return Expression::make_error(loc); + } + return Expression::make_cast(this->fn_->type(), this->args_->front(), + loc); + } // Because do_type will return an error type and thus prevent future // errors, check for that case now to ensure that the error gets @@ -11320,6 +11338,7 @@ Call_expression::do_lower(Gogo* gogo, Named_object* function, // We always pass a pointer when calling a method, except for // direct interface types when calling a value method. if (!first_arg->type()->is_error() + && first_arg->type()->points_to() == NULL && !first_arg->type()->is_direct_iface_type()) { first_arg = Expression::make_unary(OPERATOR_AND, first_arg, loc); @@ -18619,12 +18638,20 @@ Interface_mtable_expression::do_get_backend(Translate_context* context) else m = st->method_function(p->name(), &is_ambiguous); go_assert(m != NULL); - Named_object* no = - (this->is_pointer_ - && this->type_->is_direct_iface_type() - && m->is_value_method() - ? m->iface_stub_object() - : m->named_object()); + + // See the comment in Type::method_constructor. + bool use_direct_iface_stub = false; + if (m->is_value_method() + && this->is_pointer_ + && this->type_->is_direct_iface_type()) + use_direct_iface_stub = true; + if (!m->is_value_method() + && this->is_pointer_ + && !this->type_->in_heap()) + use_direct_iface_stub = true; + Named_object* no = (use_direct_iface_stub + ? m->iface_stub_object() + : m->named_object()); go_assert(no->is_function() || no->is_function_declaration()); diff --git a/gcc/go/gofrontend/types.cc b/gcc/go/gofrontend/types.cc index 0c44186..e76600d 100644 --- a/gcc/go/gofrontend/types.cc +++ b/gcc/go/gofrontend/types.cc @@ -2464,8 +2464,16 @@ Type::is_direct_iface_type() const bool Type::is_direct_iface_type_helper(Unordered_set(const Type*)* visited) const { - if (this->points_to() != NULL - || this->channel_type() != NULL + if (this->points_to() != NULL) + { + // Pointers to notinheap types must be stored indirectly. See + // https://golang.org/issue/42076. + if (!this->points_to()->in_heap()) + return false; + return true; + } + + if (this->channel_type() != NULL || this->function_type() != NULL || this->map_type() != NULL) return true; @@ -3597,10 +3605,36 @@ Type::method_constructor(Gogo*, Type* method_type, vals->push_back(Expression::make_unary(OPERATOR_AND, s, bloc)); } - bool use_direct_iface_stub = - this->points_to() != NULL - && this->points_to()->is_direct_iface_type() - && m->is_value_method(); + // The direct_iface_stub dereferences the value stored in the + // interface when calling the method. + // + // We need this for a value method if this type is a pointer to a + // direct-iface type. For example, if we have "type C chan int" and M + // is a value method on C, then since a channel is a direct-iface type + // M expects a value of type C. We are generating the method table + // for *C, so the value stored in the interface is *C. We have to + // call the direct-iface stub to dereference *C to get C to pass to M. + // + // We also need this for a pointer method if the pointer itself is not + // a direct-iface type, as arises for notinheap types. In this case + // we have "type NIH ..." where NIH is go:notinheap. Since NIH is + // notinheap, *NIH is a pointer type that is not a direct-iface type, + // so the value stored in the interface is actually **NIH. The method + // expects *NIH, so we have to call the direct-iface stub to + // dereference **NIH to get *NIH to pass to M. (This case doesn't + // arise for value methods because pointer types can't have methods, + // so there is no such thing as a value method for type *NIH.) + + bool use_direct_iface_stub = false; + if (m->is_value_method() + && this->points_to() != NULL + && this->points_to()->is_direct_iface_type()) + use_direct_iface_stub = true; + if (!m->is_value_method() + && this->points_to() != NULL + && !this->is_direct_iface_type()) + use_direct_iface_stub = true; + Named_object* no = (use_direct_iface_stub ? m->iface_stub_object() : (m->needs_stub_method() @@ -10902,6 +10936,20 @@ Named_type::do_needs_key_update() return ret; } +// Return whether this type is permitted in the heap. +bool +Named_type::do_in_heap() const +{ + if (!this->in_heap_) + return false; + if (this->seen_) + return true; + this->seen_ = true; + bool ret = this->type_->in_heap(); + this->seen_ = false; + return ret; +} + // Return a hash code. This is used for method lookup. We simply // hash on the name itself. @@ -11434,7 +11482,7 @@ Type::finalize_methods(Gogo* gogo, const Type* type, Location location, *all_methods = NULL; } Type::build_stub_methods(gogo, type, *all_methods, location); - if (type->is_direct_iface_type()) + if (type->is_direct_iface_type() || !type->in_heap()) Type::build_direct_iface_stub_methods(gogo, type, *all_methods, location); } @@ -11814,12 +11862,23 @@ Type::build_direct_iface_stub_methods(Gogo* gogo, const Type* type, if (methods == NULL) return; + bool is_direct_iface = type->is_direct_iface_type(); + bool in_heap = type->in_heap(); for (Methods::const_iterator p = methods->begin(); p != methods->end(); ++p) { Method* m = p->second; - if (!m->is_value_method()) + + // We need a direct-iface stub for a value method for a + // direct-iface type, and for a pointer method for a not-in-heap + // type. + bool need_stub = false; + if (is_direct_iface && m->is_value_method()) + need_stub = true; + if (!in_heap && !m->is_value_method()) + need_stub = true; + if (!need_stub) continue; Type* receiver_type = const_cast<Type*>(type); diff --git a/gcc/go/gofrontend/types.h b/gcc/go/gofrontend/types.h index f2880f9..ca1ab49 100644 --- a/gcc/go/gofrontend/types.h +++ b/gcc/go/gofrontend/types.h @@ -3605,8 +3605,7 @@ class Named_type : public Type do_needs_key_update(); bool - do_in_heap() const - { return this->in_heap_ && this->type_->in_heap(); } + do_in_heap() const; unsigned int do_hash_for_method(Gogo*, int) const; diff --git a/gcc/haifa-sched.c b/gcc/haifa-sched.c index 26d1127..e14051f 100644 --- a/gcc/haifa-sched.c +++ b/gcc/haifa-sched.c @@ -2538,7 +2538,7 @@ model_set_excess_costs (rtx_insn **insns, int count) enum rfs_decision { RFS_LIVE_RANGE_SHRINK1, RFS_LIVE_RANGE_SHRINK2, RFS_SCHED_GROUP, RFS_PRESSURE_DELAY, RFS_PRESSURE_TICK, - RFS_FEEDS_BACKTRACK_INSN, RFS_PRIORITY, RFS_SPECULATION, + RFS_FEEDS_BACKTRACK_INSN, RFS_PRIORITY, RFS_AUTOPREF, RFS_SPECULATION, RFS_SCHED_RANK, RFS_LAST_INSN, RFS_PRESSURE_INDEX, RFS_DEP_COUNT, RFS_TIE, RFS_FUSION, RFS_COST, RFS_N }; @@ -2546,7 +2546,7 @@ enum rfs_decision { static const char *rfs_str[RFS_N] = { "RFS_LIVE_RANGE_SHRINK1", "RFS_LIVE_RANGE_SHRINK2", "RFS_SCHED_GROUP", "RFS_PRESSURE_DELAY", "RFS_PRESSURE_TICK", - "RFS_FEEDS_BACKTRACK_INSN", "RFS_PRIORITY", "RFS_SPECULATION", + "RFS_FEEDS_BACKTRACK_INSN", "RFS_PRIORITY", "RFS_AUTOPREF", "RFS_SPECULATION", "RFS_SCHED_RANK", "RFS_LAST_INSN", "RFS_PRESSURE_INDEX", "RFS_DEP_COUNT", "RFS_TIE", "RFS_FUSION", "RFS_COST" }; @@ -2715,7 +2715,7 @@ rank_for_schedule (const void *x, const void *y) { int autopref = autopref_rank_for_schedule (tmp, tmp2); if (autopref != 0) - return autopref; + return rfs_result (RFS_AUTOPREF, autopref, tmp, tmp2); } /* Prefer speculative insn with greater dependencies weakness. */ @@ -3155,9 +3155,11 @@ advance_state (state_t state) HAIFA_INLINE static void advance_one_cycle (void) { + int i; + advance_state (curr_state); - if (sched_verbose >= 4) - fprintf (sched_dump, ";;\tAdvance the current state.\n"); + for (i = 4; i <= sched_verbose; ++i) + fprintf (sched_dump, ";;\tAdvance the current state: %d.\n", clock_var); } /* Update register pressure after scheduling INSN. */ @@ -5683,9 +5685,16 @@ autopref_rank_for_schedule (const rtx_insn *insn1, const rtx_insn *insn2) int irrel2 = data2->status == AUTOPREF_MULTIPASS_DATA_IRRELEVANT; if (!irrel1 && !irrel2) + /* Sort memory references from lowest offset to the largest. */ r = data1->offset - data2->offset; - else + else if (write) + /* Schedule "irrelevant" insns before memory stores to resolve + as many producer dependencies of stores as possible. */ r = irrel2 - irrel1; + else + /* Schedule "irrelevant" insns after memory reads to avoid breaking + memory read sequences. */ + r = irrel1 - irrel2; } return r; diff --git a/gcc/hash-map-tests.c b/gcc/hash-map-tests.c index 5b6b192..257f2be 100644 --- a/gcc/hash-map-tests.c +++ b/gcc/hash-map-tests.c @@ -278,6 +278,156 @@ test_map_of_type_with_ctor_and_dtor () ASSERT_TRUE (val_t::ndefault + val_t::ncopy == val_t::ndtor); } + + + /* Verify basic construction and destruction of Value objects. */ + { + /* Configure, arbitrary. */ + const size_t N_init = 0; + const int N_elem = 28; + + void *a[N_elem]; + for (size_t i = 0; i < N_elem; ++i) + a[i] = &a[i]; + + val_t::ndefault = 0; + val_t::ncopy = 0; + val_t::nassign = 0; + val_t::ndtor = 0; + Map m (N_init); + ASSERT_EQ (val_t::ndefault + + val_t::ncopy + + val_t::nassign + + val_t::ndtor, 0); + + for (int i = 0; i < N_elem; ++i) + { + m.get_or_insert (a[i]); + ASSERT_EQ (val_t::ndefault, 1 + i); + ASSERT_EQ (val_t::ncopy, 0); + ASSERT_EQ (val_t::nassign, 0); + ASSERT_EQ (val_t::ndtor, i); + + m.remove (a[i]); + ASSERT_EQ (val_t::ndefault, 1 + i); + ASSERT_EQ (val_t::ncopy, 0); + ASSERT_EQ (val_t::nassign, 0); + ASSERT_EQ (val_t::ndtor, 1 + i); + } + } +} + +/* Verify aspects of 'hash_table::expand'. */ + +static void +test_map_of_type_with_ctor_and_dtor_expand (bool remove_some_inline) +{ + /* Configure, so that hash table expansion triggers a few times. */ + const size_t N_init = 0; + const int N_elem = 70; + size_t expand_c_expected = 4; + size_t expand_c = 0; + + void *a[N_elem]; + for (size_t i = 0; i < N_elem; ++i) + a[i] = &a[i]; + + typedef hash_map <void *, val_t> Map; + + /* Note that we are starting with a fresh 'Map'. Even if an existing one has + been cleared out completely, there remain 'deleted' elements, and these + would disturb the following logic, where we don't have access to the + actual 'm_n_deleted' value. */ + size_t m_n_deleted = 0; + + val_t::ndefault = 0; + val_t::ncopy = 0; + val_t::nassign = 0; + val_t::ndtor = 0; + Map m (N_init); + + /* In the following, in particular related to 'expand', we're adapting from + the internal logic of 'hash_table', glossing over "some details" not + relevant for this testing here. */ + + /* Per 'hash_table::hash_table'. */ + size_t m_size; + { + unsigned int size_prime_index_ = hash_table_higher_prime_index (N_init); + m_size = prime_tab[size_prime_index_].prime; + } + + int n_expand_moved = 0; + + for (int i = 0; i < N_elem; ++i) + { + size_t elts = m.elements (); + + /* Per 'hash_table::find_slot_with_hash'. */ + size_t m_n_elements = elts + m_n_deleted; + bool expand = m_size * 3 <= m_n_elements * 4; + + m.get_or_insert (a[i]); + if (expand) + { + ++expand_c; + + /* Per 'hash_table::expand'. */ + { + unsigned int nindex = hash_table_higher_prime_index (elts * 2); + m_size = prime_tab[nindex].prime; + } + m_n_deleted = 0; + + /* All non-deleted elements have been moved. */ + n_expand_moved += i; + if (remove_some_inline) + n_expand_moved -= (i + 2) / 3; + } + + ASSERT_EQ (val_t::ndefault, 1 + i); + ASSERT_EQ (val_t::ncopy, n_expand_moved); + ASSERT_EQ (val_t::nassign, 0); + if (remove_some_inline) + ASSERT_EQ (val_t::ndtor, (i + 2) / 3); + else + ASSERT_EQ (val_t::ndtor, 0); + + /* Remove some inline. This never triggers an 'expand' here, but via + 'm_n_deleted' does influence any following one. */ + if (remove_some_inline + && !(i % 3)) + { + m.remove (a[i]); + /* Per 'hash_table::remove_elt_with_hash'. */ + m_n_deleted++; + + ASSERT_EQ (val_t::ndefault, 1 + i); + ASSERT_EQ (val_t::ncopy, n_expand_moved); + ASSERT_EQ (val_t::nassign, 0); + ASSERT_EQ (val_t::ndtor, 1 + (i + 2) / 3); + } + } + ASSERT_EQ (expand_c, expand_c_expected); + + int ndefault = val_t::ndefault; + int ncopy = val_t::ncopy; + int nassign = val_t::nassign; + int ndtor = val_t::ndtor; + + for (int i = 0; i < N_elem; ++i) + { + if (remove_some_inline + && !(i % 3)) + continue; + + m.remove (a[i]); + ++ndtor; + ASSERT_EQ (val_t::ndefault, ndefault); + ASSERT_EQ (val_t::ncopy, ncopy); + ASSERT_EQ (val_t::nassign, nassign); + ASSERT_EQ (val_t::ndtor, ndtor); + } } /* Test calling empty on a hash_map that has a key type with non-zero @@ -309,6 +459,8 @@ hash_map_tests_c_tests () test_map_of_strings_to_int (); test_map_of_int_to_strings (); test_map_of_type_with_ctor_and_dtor (); + test_map_of_type_with_ctor_and_dtor_expand (false); + test_map_of_type_with_ctor_and_dtor_expand (true); test_nonzero_empty_key (); } diff --git a/gcc/ipa-icf-gimple.c b/gcc/ipa-icf-gimple.c index edf5f02..cf02626 100644 --- a/gcc/ipa-icf-gimple.c +++ b/gcc/ipa-icf-gimple.c @@ -96,6 +96,9 @@ func_checker::compare_ssa_name (const_tree t1, const_tree t2) unsigned i1 = SSA_NAME_VERSION (t1); unsigned i2 = SSA_NAME_VERSION (t2); + if (SSA_NAME_IS_DEFAULT_DEF (t1) != SSA_NAME_IS_DEFAULT_DEF (t2)) + return false; + if (m_source_ssa_names[i1] == -1) m_source_ssa_names[i1] = i2; else if (m_source_ssa_names[i1] != (int) i2) diff --git a/gcc/ipa-modref.c b/gcc/ipa-modref.c index 7b849c1..fafd804 100644 --- a/gcc/ipa-modref.c +++ b/gcc/ipa-modref.c @@ -158,6 +158,8 @@ dump_eaf_flags (FILE *out, int flags, bool newline = true) fprintf (out, " unused"); if (flags & EAF_NOT_RETURNED) fprintf (out, " not_returned"); + if (flags & EAF_NOREAD) + fprintf (out, " noread"); if (newline) fprintf (out, "\n"); } @@ -278,27 +280,46 @@ modref_summary::~modref_summary () ggc_delete (stores); } +/* All flags that are implied by the ECF_CONST functions. */ +const int implicit_const_eaf_flags = EAF_DIRECT | EAF_NOCLOBBER | EAF_NOESCAPE + | EAF_NODIRECTESCAPE | EAF_NOREAD; +/* All flags that are implied by the ECF_PURE function. */ +const int implicit_pure_eaf_flags = EAF_NOCLOBBER | EAF_NOESCAPE + | EAF_NODIRECTESCAPE; +/* All flags implied when we know we can ignore stores (i.e. when handling + call to noreturn). */ +const int ignore_stores_eaf_flags = EAF_DIRECT | EAF_NOCLOBBER | EAF_NOESCAPE + | EAF_NODIRECTESCAPE; + +/* Remove all flags from EAF_FLAGS that are implied by ECF_FLAGS and not + useful to track. If returns_void is true moreover clear + EAF_NOT_RETURNED. */ +static int +remove_useless_eaf_flags (int eaf_flags, int ecf_flags, bool returns_void) +{ + if (ecf_flags & ECF_NOVOPS) + return 0; + if (ecf_flags & ECF_CONST) + eaf_flags &= ~implicit_const_eaf_flags; + else if (ecf_flags & ECF_PURE) + eaf_flags &= ~implicit_pure_eaf_flags; + else if ((ecf_flags & ECF_NORETURN) || returns_void) + eaf_flags &= ~EAF_NOT_RETURNED; + /* Only NOCLOBBER or DIRECT flags alone are not useful (see comments + in tree-ssa-alias.c). Give up earlier. */ + if ((eaf_flags & ~(EAF_DIRECT | EAF_NOCLOBBER)) == 0) + return 0; + return eaf_flags; +} + /* Return true if FLAGS holds some useful information. */ static bool eaf_flags_useful_p (vec <eaf_flags_t> &flags, int ecf_flags) { for (unsigned i = 0; i < flags.length (); i++) - if (ecf_flags & ECF_CONST) - { - if (flags[i] & (EAF_UNUSED | EAF_NOT_RETURNED)) - return true; - } - else if (ecf_flags & ECF_PURE) - { - if (flags[i] & (EAF_UNUSED | EAF_DIRECT | EAF_NOT_RETURNED)) - return true; - } - else - { - if (flags[i]) - return true; - } + if (remove_useless_eaf_flags (flags[i], ecf_flags, false)) + return true; return false; } @@ -1320,17 +1341,35 @@ static int deref_flags (int flags, bool ignore_stores) { int ret = EAF_NODIRECTESCAPE; + /* If argument is unused just account for + the read involved in dereference. */ if (flags & EAF_UNUSED) - ret |= EAF_DIRECT | EAF_NOCLOBBER | EAF_NOESCAPE; + ret |= EAF_DIRECT | EAF_NOCLOBBER | EAF_NOESCAPE | EAF_NOT_RETURNED; else { if ((flags & EAF_NOCLOBBER) || ignore_stores) ret |= EAF_NOCLOBBER; if ((flags & EAF_NOESCAPE) || ignore_stores) ret |= EAF_NOESCAPE; + /* If the value dereferenced is not used for another load or store + we can still consider ARG as used only directly. + + Consider + + int + test (int *a) + { + return *a!=0; + } + + */ + if ((flags & (EAF_NOREAD | EAF_NOT_RETURNED | EAF_NOESCAPE | EAF_DIRECT)) + == (EAF_NOREAD | EAF_NOT_RETURNED | EAF_NOESCAPE | EAF_DIRECT) + && ((flags & EAF_NOCLOBBER) || ignore_stores)) + ret |= EAF_DIRECT; + if (flags & EAF_NOT_RETURNED) + ret |= EAF_NOT_RETURNED; } - if (flags & EAF_NOT_RETURNED) - ret |= EAF_NOT_RETURNED; return ret; } @@ -1355,7 +1394,7 @@ class modref_lattice { public: /* EAF flags of the SSA name. */ - int flags; + eaf_flags_t flags; /* DFS bookkkeeping: we don't do real dataflow yet. */ bool known; bool open; @@ -1379,8 +1418,12 @@ public: void modref_lattice::init () { - flags = EAF_DIRECT | EAF_NOCLOBBER | EAF_NOESCAPE | EAF_UNUSED - | EAF_NODIRECTESCAPE | EAF_NOT_RETURNED; + /* All flags we track. */ + int f = EAF_DIRECT | EAF_NOCLOBBER | EAF_NOESCAPE | EAF_UNUSED + | EAF_NODIRECTESCAPE | EAF_NOT_RETURNED | EAF_NOREAD; + flags = f; + /* Check that eaf_flags_t is wide enough to hold all flags. */ + gcc_checking_assert (f == flags); open = true; known = false; } @@ -1406,7 +1449,7 @@ modref_lattice::dump (FILE *out, int indent) const fprintf (out, "%*s Arg %i (%s) min flags", indent, "", escape_points[i].arg, escape_points[i].direct ? "direct" : "indirect"); - dump_eaf_flags (out, flags, false); + dump_eaf_flags (out, escape_points[i].min_flags, false); fprintf (out, " in call "); print_gimple_stmt (out, escape_points[i].call, 0); } @@ -1424,8 +1467,8 @@ modref_lattice::add_escape_point (gcall *call, int arg, int min_flags, unsigned int i; /* If we already determined flags to be bad enough, - * we do not need to record. */ - if ((flags & min_flags) == flags) + we do not need to record. */ + if ((flags & min_flags) == flags || (min_flags & EAF_UNUSED)) return false; FOR_EACH_VEC_ELT (escape_points, i, ep) @@ -1455,13 +1498,18 @@ modref_lattice::merge (int f) { if (f & EAF_UNUSED) return false; + /* Noescape implies that value also does not escape directly. + Fnspec machinery does set both so compensate for this. */ + if (f & EAF_NOESCAPE) + f |= EAF_NODIRECTESCAPE; if ((flags & f) != flags) { flags &= f; - /* Only NOCLOBBER or DIRECT flags alone are not useful (see comments - in tree-ssa-alias.c). Give up earlier. */ - if ((flags & ~(EAF_DIRECT | EAF_NOCLOBBER)) == 0) - flags = 0; + /* Prune obvoiusly useless flags; + We do not have ECF_FLAGS handy which is not big problem since + we will do final flags cleanup before producing summary. + Merging should be fast so it can work well with dataflow. */ + flags = remove_useless_eaf_flags (flags, 0, false); if (!flags) escape_points.release (); return true; @@ -1503,10 +1551,18 @@ modref_lattice::merge_deref (const modref_lattice &with, bool ignore_stores) if (!flags) return changed; for (unsigned int i = 0; i < with.escape_points.length (); i++) - changed |= add_escape_point (with.escape_points[i].call, - with.escape_points[i].arg, - with.escape_points[i].min_flags, - false); + { + int min_flags = with.escape_points[i].min_flags; + + if (with.escape_points[i].direct) + min_flags = deref_flags (min_flags, ignore_stores); + else if (ignore_stores) + min_flags |= ignore_stores_eaf_flags; + changed |= add_escape_point (with.escape_points[i].call, + with.escape_points[i].arg, + min_flags, + false); + } return changed; } @@ -1515,7 +1571,7 @@ modref_lattice::merge_deref (const modref_lattice &with, bool ignore_stores) bool modref_lattice::merge_direct_load () { - return merge (~EAF_UNUSED); + return merge (~(EAF_UNUSED | EAF_NOREAD)); } /* Merge in flags for direct store. */ @@ -1624,6 +1680,9 @@ analyze_ssa_name_flags (tree name, vec<modref_lattice> &lattice, int depth, fprintf (dump_file, "%*s Analyzing stmt: ", depth * 4, ""); print_gimple_stmt (dump_file, use_stmt, 0); } + /* If we see a direct non-debug use, clear unused bit. + All dereferneces should be accounted below using deref_flags. */ + lattice[index].merge (~EAF_UNUSED); /* Gimple return may load the return value. Returning name counts as an use by tree-ssa-structalias.c */ @@ -1634,7 +1693,7 @@ analyze_ssa_name_flags (tree name, vec<modref_lattice> &lattice, int depth, else if (memory_access_to (gimple_return_retval (ret), name)) { lattice[index].merge_direct_load (); - lattice[index].merge (~EAF_NOT_RETURNED); + lattice[index].merge (~(EAF_UNUSED | EAF_NOT_RETURNED)); } } /* Account for LHS store, arg loads and flags from callee function. */ @@ -1689,8 +1748,7 @@ analyze_ssa_name_flags (tree name, vec<modref_lattice> &lattice, int depth, int call_flags = gimple_call_arg_flags (call, i) | EAF_NOT_RETURNED; if (ignore_stores) - call_flags |= EAF_NOCLOBBER | EAF_NOESCAPE - | EAF_NODIRECTESCAPE; + call_flags |= ignore_stores_eaf_flags; if (!record_ipa) lattice[index].merge (call_flags); @@ -1882,14 +1940,12 @@ analyze_parms (modref_summary *summary, modref_summary_lto *summary_lto, analyze_ssa_name_flags (name, lattice, 0, ipa); int flags = lattice[SSA_NAME_VERSION (name)].flags; - /* For pure functions we have implicit NOCLOBBER - and NOESCAPE. */ - if (ecf_flags & ECF_PURE) - flags &= (EAF_UNUSED | EAF_DIRECT | EAF_NOT_RETURNED); - /* Only useful flags for const function are EAF_NOT_RETURNED and - EAF_UNUSED. */ - if (ecf_flags & ECF_CONST) - flags &= (EAF_UNUSED | EAF_NOT_RETURNED); + /* Eliminate useless flags so we do not end up storing unnecessary + summaries. */ + + flags = remove_useless_eaf_flags + (flags, ecf_flags, + VOID_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl)))); if (flags) { @@ -3019,7 +3075,8 @@ struct escape_map static void update_escape_summary_1 (cgraph_edge *e, - vec <vec <escape_map>> &map) + vec <vec <escape_map>> &map, + bool ignore_stores) { escape_summary *sum = escape_summaries->get (e); if (!sum) @@ -3037,6 +3094,9 @@ update_escape_summary_1 (cgraph_edge *e, continue; FOR_EACH_VEC_ELT (map[ee->parm_index], j, em) { + int min_flags = ee->min_flags; + if (ee->direct && !em->direct) + min_flags = deref_flags (min_flags, ignore_stores); struct escape_entry entry = {em->parm_index, ee->arg, ee->min_flags, ee->direct & em->direct}; @@ -3051,18 +3111,19 @@ update_escape_summary_1 (cgraph_edge *e, static void update_escape_summary (cgraph_node *node, - vec <vec <escape_map>> &map) + vec <vec <escape_map>> &map, + bool ignore_stores) { if (!escape_summaries) return; for (cgraph_edge *e = node->indirect_calls; e; e = e->next_callee) - update_escape_summary_1 (e, map); + update_escape_summary_1 (e, map, ignore_stores); for (cgraph_edge *e = node->callees; e; e = e->next_callee) { if (!e->inline_failed) - update_escape_summary (e->callee, map); + update_escape_summary (e->callee, map, ignore_stores); else - update_escape_summary_1 (e, map); + update_escape_summary_1 (e, map, ignore_stores); } } @@ -3163,7 +3224,7 @@ ipa_merge_modref_summary_after_inlining (cgraph_edge *edge) if (!ee->direct) flags = deref_flags (flags, ignore_stores); else if (ignore_stores) - flags |= EAF_NOCLOBBER | EAF_NOESCAPE | EAF_NODIRECTESCAPE; + flags |= ignore_stores_eaf_flags; flags |= ee->min_flags; to_info->arg_flags[ee->parm_index] &= flags; if (to_info->arg_flags[ee->parm_index]) @@ -3177,7 +3238,7 @@ ipa_merge_modref_summary_after_inlining (cgraph_edge *edge) if (!ee->direct) flags = deref_flags (flags, ignore_stores); else if (ignore_stores) - flags |= EAF_NOCLOBBER | EAF_NOESCAPE | EAF_NODIRECTESCAPE; + flags |= ignore_stores_eaf_flags; flags |= ee->min_flags; to_info_lto->arg_flags[ee->parm_index] &= flags; if (to_info_lto->arg_flags[ee->parm_index]) @@ -3187,7 +3248,7 @@ ipa_merge_modref_summary_after_inlining (cgraph_edge *edge) if (needed) emap[ee->arg].safe_push (entry); } - update_escape_summary (edge->callee, emap); + update_escape_summary (edge->callee, emap, ignore_stores); for (i = 0; (int)i < max_escape + 1; i++) emap[i].release (); if (sum) @@ -3660,11 +3721,13 @@ modref_merge_call_site_flags (escape_summary *sum, modref_summary_lto *cur_summary_lto, modref_summary *summary, modref_summary_lto *summary_lto, - bool ignore_stores) + tree caller, + int ecf_flags) { escape_entry *ee; unsigned int i; bool changed = false; + bool ignore_stores = ignore_stores_p (caller, ecf_flags); /* If we have no useful info to propagate. */ if ((!cur_summary || !cur_summary->arg_flags.length ()) @@ -3688,21 +3751,27 @@ modref_merge_call_site_flags (escape_summary *sum, } else if (ignore_stores) { - flags |= EAF_NOESCAPE | EAF_NOCLOBBER | EAF_NODIRECTESCAPE; - flags_lto |= EAF_NOESCAPE | EAF_NOCLOBBER | EAF_NODIRECTESCAPE; + flags |= ignore_stores_eaf_flags; + flags_lto |= ignore_stores_eaf_flags; } /* Returning the value is already accounted to at local propagation. */ flags |= ee->min_flags | EAF_NOT_RETURNED; flags_lto |= ee->min_flags | EAF_NOT_RETURNED; + /* Noescape implies that value also does not escape directly. + Fnspec machinery does set both so compensate for this. */ + if (flags & EAF_NOESCAPE) + flags |= EAF_NODIRECTESCAPE; + if (flags_lto & EAF_NOESCAPE) + flags_lto |= EAF_NODIRECTESCAPE; if (!(flags & EAF_UNUSED) && cur_summary && ee->parm_index < cur_summary->arg_flags.length ()) { int f = cur_summary->arg_flags[ee->parm_index]; if ((f & flags) != f) { - f = f & flags; - if ((f & ~(EAF_DIRECT | EAF_NOCLOBBER)) == 0) - f = 0; + f = remove_useless_eaf_flags + (f & flags, ecf_flags, + VOID_TYPE_P (TREE_TYPE (TREE_TYPE (caller)))); cur_summary->arg_flags[ee->parm_index] = f; changed = true; } @@ -3714,9 +3783,9 @@ modref_merge_call_site_flags (escape_summary *sum, int f = cur_summary_lto->arg_flags[ee->parm_index]; if ((f & flags_lto) != f) { - f = f & flags; - if ((f & ~(EAF_DIRECT | EAF_NOCLOBBER)) == 0) - f = 0; + f = remove_useless_eaf_flags + (f & flags_lto, ecf_flags, + VOID_TYPE_P (TREE_TYPE (TREE_TYPE (caller)))); cur_summary_lto->arg_flags[ee->parm_index] = f; changed = true; } @@ -3767,8 +3836,8 @@ modref_propagate_flags_in_scc (cgraph_node *component_node) changed |= modref_merge_call_site_flags (sum, cur_summary, cur_summary_lto, - NULL, NULL, ignore_stores_p (node->decl, - e->indirect_info->ecf_flags)); + NULL, NULL, + node->decl, e->indirect_info->ecf_flags); } if (!cur_summary && !cur_summary_lto) @@ -3777,12 +3846,13 @@ modref_propagate_flags_in_scc (cgraph_node *component_node) for (cgraph_edge *callee_edge = cur->callees; callee_edge; callee_edge = callee_edge->next_callee) { - int flags = flags_from_decl_or_type (callee_edge->callee->decl); + int ecf_flags = flags_from_decl_or_type + (callee_edge->callee->decl); modref_summary *callee_summary = NULL; modref_summary_lto *callee_summary_lto = NULL; struct cgraph_node *callee; - if (flags & (ECF_CONST | ECF_NOVOPS) + if (ecf_flags & (ECF_CONST | ECF_NOVOPS) || !callee_edge->inline_failed) continue; /* Get the callee and its summary. */ @@ -3819,7 +3889,7 @@ modref_propagate_flags_in_scc (cgraph_node *component_node) changed |= modref_merge_call_site_flags (sum, cur_summary, cur_summary_lto, callee_summary, callee_summary_lto, - ignore_stores_p (node->decl, flags)); + node->decl, ecf_flags); if (dump_file && changed) { if (cur_summary) diff --git a/gcc/ipa-modref.h b/gcc/ipa-modref.h index 498cc24..540fdea 100644 --- a/gcc/ipa-modref.h +++ b/gcc/ipa-modref.h @@ -21,7 +21,7 @@ along with GCC; see the file COPYING3. If not see #define IPA_MODREF_H typedef modref_tree <alias_set_type> modref_records; -typedef unsigned short eaf_flags_t; +typedef unsigned char eaf_flags_t; /* Single function summary. */ diff --git a/gcc/ipa-split.c b/gcc/ipa-split.c index 5e918ee..c68577d 100644 --- a/gcc/ipa-split.c +++ b/gcc/ipa-split.c @@ -546,8 +546,9 @@ consider_split (class split_point *current, bitmap non_ssa_vars, } } } - if (!VOID_TYPE_P (TREE_TYPE (current_function_decl))) - call_overhead += estimate_move_cost (TREE_TYPE (current_function_decl), + if (!VOID_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl)))) + call_overhead += estimate_move_cost (TREE_TYPE (TREE_TYPE + (current_function_decl)), false); if (current->split_size <= call_overhead) diff --git a/gcc/multiple_target.c b/gcc/multiple_target.c index e419265..6c05658 100644 --- a/gcc/multiple_target.c +++ b/gcc/multiple_target.c @@ -170,17 +170,20 @@ create_dispatcher_calls (struct cgraph_node *node) clone_function_name_numbered ( node->decl, "default")); - /* FIXME: copy of cgraph_node::make_local that should be cleaned up - in next stage1. */ - node->make_decl_local (); - node->set_section (NULL); - node->set_comdat_group (NULL); - node->externally_visible = false; - node->forced_by_abi = false; - node->set_section (NULL); - - DECL_ARTIFICIAL (node->decl) = 1; - node->force_output = true; + if (node->definition) + { + /* FIXME: copy of cgraph_node::make_local that should be cleaned up + in next stage1. */ + node->make_decl_local (); + node->set_section (NULL); + node->set_comdat_group (NULL); + node->externally_visible = false; + node->forced_by_abi = false; + node->set_section (NULL); + + DECL_ARTIFICIAL (node->decl) = 1; + node->force_output = true; + } } /* Return length of attribute names string, diff --git a/gcc/objc/ChangeLog b/gcc/objc/ChangeLog index bb84045..8adde0d 100644 --- a/gcc/objc/ChangeLog +++ b/gcc/objc/ChangeLog @@ -1,3 +1,11 @@ +2021-08-17 Matt Jacobson <mhjacobson@me.com> + + * objc-next-runtime-abi-02.c + (objc_next_runtime_abi_02_init): Warn about and reset + flag_objc_sjlj_exceptions regardless of flag_objc_exceptions. + (next_runtime_02_initialize): Use a checking assert that + flag_objc_sjlj_exceptions is off. + 2021-06-28 Martin Sebor <msebor@redhat.com> * objc-act.c (objc_maybe_build_modify_expr): Replace direct uses diff --git a/gcc/objc/objc-next-runtime-abi-02.c b/gcc/objc/objc-next-runtime-abi-02.c index 963d1bf..c552013 100644 --- a/gcc/objc/objc-next-runtime-abi-02.c +++ b/gcc/objc/objc-next-runtime-abi-02.c @@ -245,7 +245,7 @@ objc_next_runtime_abi_02_init (objc_runtime_hooks *rthooks) { extern_names = ggc_cleared_vec_alloc<hash> (SIZEHASHTABLE); - if (flag_objc_exceptions && flag_objc_sjlj_exceptions) + if (flag_objc_sjlj_exceptions) { inform (UNKNOWN_LOCATION, "%<-fobjc-sjlj-exceptions%> is ignored for " @@ -507,7 +507,7 @@ static void next_runtime_02_initialize (void) objc_getPropertyStruct_decl = NULL_TREE; objc_setPropertyStruct_decl = NULL_TREE; - gcc_assert (!flag_objc_sjlj_exceptions); + gcc_checking_assert (!flag_objc_sjlj_exceptions); /* Although we warn that fobjc-exceptions is required for exceptions code, we carry on and create it anyway. */ diff --git a/gcc/omp-builtins.def b/gcc/omp-builtins.def index 05b555c..b168575 100644 --- a/gcc/omp-builtins.def +++ b/gcc/omp-builtins.def @@ -422,6 +422,8 @@ DEF_GOMP_BUILTIN (BUILT_IN_GOMP_SINGLE_COPY_START, "GOMP_single_copy_start", BT_FN_PTR, ATTR_NOTHROW_LEAF_LIST) DEF_GOMP_BUILTIN (BUILT_IN_GOMP_SINGLE_COPY_END, "GOMP_single_copy_end", BT_FN_VOID_PTR, ATTR_NOTHROW_LEAF_LIST) +DEF_GOMP_BUILTIN (BUILT_IN_GOMP_SCOPE_START, "GOMP_scope_start", + BT_FN_VOID_PTR, ATTR_NOTHROW_LEAF_LIST) DEF_GOMP_BUILTIN (BUILT_IN_GOMP_OFFLOAD_REGISTER, "GOMP_offload_register_ver", BT_FN_VOID_UINT_PTR_INT_PTR, ATTR_NOTHROW_LIST) DEF_GOMP_BUILTIN (BUILT_IN_GOMP_OFFLOAD_UNREGISTER, diff --git a/gcc/omp-expand.c b/gcc/omp-expand.c index 9fd1c65..c868b8c 100644 --- a/gcc/omp-expand.c +++ b/gcc/omp-expand.c @@ -8417,7 +8417,7 @@ expand_omp_sections (struct omp_region *region) set_immediate_dominator (CDI_DOMINATORS, default_bb, l0_bb); } -/* Expand code for an OpenMP single directive. We've already expanded +/* Expand code for an OpenMP single or scope directive. We've already expanded much of the code, here we simply place the GOMP_barrier call. */ static void @@ -8430,7 +8430,8 @@ expand_omp_single (struct omp_region *region) exit_bb = region->exit; si = gsi_last_nondebug_bb (entry_bb); - gcc_assert (gimple_code (gsi_stmt (si)) == GIMPLE_OMP_SINGLE); + gcc_assert (gimple_code (gsi_stmt (si)) == GIMPLE_OMP_SINGLE + || gimple_code (gsi_stmt (si)) == GIMPLE_OMP_SCOPE); gsi_remove (&si, true); single_succ_edge (entry_bb)->flags = EDGE_FALLTHRU; @@ -8460,6 +8461,7 @@ expand_omp_synch (struct omp_region *region) si = gsi_last_nondebug_bb (entry_bb); gcc_assert (gimple_code (gsi_stmt (si)) == GIMPLE_OMP_SINGLE || gimple_code (gsi_stmt (si)) == GIMPLE_OMP_MASTER + || gimple_code (gsi_stmt (si)) == GIMPLE_OMP_MASKED || gimple_code (gsi_stmt (si)) == GIMPLE_OMP_TASKGROUP || gimple_code (gsi_stmt (si)) == GIMPLE_OMP_ORDERED || gimple_code (gsi_stmt (si)) == GIMPLE_OMP_CRITICAL @@ -9927,6 +9929,7 @@ expand_omp (struct omp_region *region) break; case GIMPLE_OMP_SINGLE: + case GIMPLE_OMP_SCOPE: expand_omp_single (region); break; @@ -9947,6 +9950,7 @@ expand_omp (struct omp_region *region) } /* FALLTHRU */ case GIMPLE_OMP_MASTER: + case GIMPLE_OMP_MASKED: case GIMPLE_OMP_TASKGROUP: case GIMPLE_OMP_CRITICAL: case GIMPLE_OMP_TEAMS: @@ -10266,6 +10270,8 @@ omp_make_gimple_edges (basic_block bb, struct omp_region **region, case GIMPLE_OMP_SINGLE: case GIMPLE_OMP_TEAMS: case GIMPLE_OMP_MASTER: + case GIMPLE_OMP_MASKED: + case GIMPLE_OMP_SCOPE: case GIMPLE_OMP_TASKGROUP: case GIMPLE_OMP_CRITICAL: case GIMPLE_OMP_SECTION: diff --git a/gcc/omp-low.c b/gcc/omp-low.c index 926087d..a0b41af 100644 --- a/gcc/omp-low.c +++ b/gcc/omp-low.c @@ -663,8 +663,15 @@ build_outer_var_ref (tree var, omp_context *ctx, { tree x; omp_context *outer = ctx->outer; - while (outer && gimple_code (outer->stmt) == GIMPLE_OMP_TASKGROUP) - outer = outer->outer; + for (; outer; outer = outer->outer) + { + if (gimple_code (outer->stmt) == GIMPLE_OMP_TASKGROUP) + continue; + if (gimple_code (outer->stmt) == GIMPLE_OMP_SCOPE + && !maybe_lookup_decl (var, outer)) + continue; + break; + } if (is_global_var (maybe_lookup_decl_in_outer_ctx (var, ctx))) x = var; @@ -1466,6 +1473,7 @@ scan_sharing_clauses (tree clauses, omp_context *ctx) case OMP_CLAUSE_NUM_WORKERS: case OMP_CLAUSE_VECTOR_LENGTH: case OMP_CLAUSE_DETACH: + case OMP_CLAUSE_FILTER: if (ctx->outer) scan_omp_op (&OMP_CLAUSE_OPERAND (c, 0), ctx->outer); break; @@ -1868,6 +1876,7 @@ scan_sharing_clauses (tree clauses, omp_context *ctx) case OMP_CLAUSE__SIMT_: case OMP_CLAUSE_IF_PRESENT: case OMP_CLAUSE_FINALIZE: + case OMP_CLAUSE_FILTER: case OMP_CLAUSE__CONDTEMP_: break; @@ -3426,6 +3435,7 @@ check_omp_nesting_restrictions (gimple *stmt, omp_context *ctx) case GIMPLE_OMP_SINGLE: case GIMPLE_OMP_ORDERED: case GIMPLE_OMP_MASTER: + case GIMPLE_OMP_MASKED: case GIMPLE_OMP_TASK: case GIMPLE_OMP_CRITICAL: if (is_gimple_call (stmt)) @@ -3436,14 +3446,15 @@ check_omp_nesting_restrictions (gimple *stmt, omp_context *ctx) error_at (gimple_location (stmt), "barrier region may not be closely nested inside " "of work-sharing, %<loop%>, %<critical%>, " - "%<ordered%>, %<master%>, explicit %<task%> or " - "%<taskloop%> region"); + "%<ordered%>, %<master%>, %<masked%>, explicit " + "%<task%> or %<taskloop%> region"); return false; } error_at (gimple_location (stmt), "work-sharing region may not be closely nested inside " "of work-sharing, %<loop%>, %<critical%>, %<ordered%>, " - "%<master%>, explicit %<task%> or %<taskloop%> region"); + "%<master%>, %<masked%>, explicit %<task%> or " + "%<taskloop%> region"); return false; case GIMPLE_OMP_PARALLEL: case GIMPLE_OMP_TEAMS: @@ -3458,6 +3469,7 @@ check_omp_nesting_restrictions (gimple *stmt, omp_context *ctx) } break; case GIMPLE_OMP_MASTER: + case GIMPLE_OMP_MASKED: for (; ctx != NULL; ctx = ctx->outer) switch (gimple_code (ctx->stmt)) { @@ -3470,9 +3482,45 @@ check_omp_nesting_restrictions (gimple *stmt, omp_context *ctx) case GIMPLE_OMP_SINGLE: case GIMPLE_OMP_TASK: error_at (gimple_location (stmt), - "%<master%> region may not be closely nested inside " + "%qs region may not be closely nested inside " "of work-sharing, %<loop%>, explicit %<task%> or " - "%<taskloop%> region"); + "%<taskloop%> region", + gimple_code (stmt) == GIMPLE_OMP_MASTER + ? "master" : "masked"); + return false; + case GIMPLE_OMP_PARALLEL: + case GIMPLE_OMP_TEAMS: + return true; + case GIMPLE_OMP_TARGET: + if (gimple_omp_target_kind (ctx->stmt) + == GF_OMP_TARGET_KIND_REGION) + return true; + break; + default: + break; + } + break; + case GIMPLE_OMP_SCOPE: + for (; ctx != NULL; ctx = ctx->outer) + switch (gimple_code (ctx->stmt)) + { + case GIMPLE_OMP_FOR: + if (gimple_omp_for_kind (ctx->stmt) != GF_OMP_FOR_KIND_FOR + && gimple_omp_for_kind (ctx->stmt) != GF_OMP_FOR_KIND_TASKLOOP) + break; + /* FALLTHRU */ + case GIMPLE_OMP_SECTIONS: + case GIMPLE_OMP_SINGLE: + case GIMPLE_OMP_TASK: + case GIMPLE_OMP_CRITICAL: + case GIMPLE_OMP_ORDERED: + case GIMPLE_OMP_MASTER: + case GIMPLE_OMP_MASKED: + error_at (gimple_location (stmt), + "%<scope%> region may not be closely nested inside " + "of work-sharing, %<loop%>, explicit %<task%>, " + "%<taskloop%>, %<critical%>, %<ordered%>, %<master%>, " + "or %<masked%> region"); return false; case GIMPLE_OMP_PARALLEL: case GIMPLE_OMP_TEAMS: @@ -3856,6 +3904,8 @@ omp_runtime_api_call (const_tree fndecl) { /* This array has 3 sections. First omp_* calls that don't have any suffixes. */ + "omp_alloc", + "omp_free", "target_alloc", "target_associate_ptr", "target_disassociate_ptr", @@ -3866,13 +3916,17 @@ omp_runtime_api_call (const_tree fndecl) NULL, /* Now omp_* calls that are available as omp_* and omp_*_. */ "capture_affinity", + "destroy_allocator", "destroy_lock", "destroy_nest_lock", "display_affinity", + "fulfill_event", "get_active_level", "get_affinity_format", "get_cancellation", + "get_default_allocator", "get_default_device", + "get_device_num", "get_dynamic", "get_initial_device", "get_level", @@ -3888,6 +3942,7 @@ omp_runtime_api_call (const_tree fndecl) "get_partition_num_places", "get_place_num", "get_proc_bind", + "get_supported_active_levels", "get_team_num", "get_thread_limit", "get_thread_num", @@ -3901,6 +3956,7 @@ omp_runtime_api_call (const_tree fndecl) "pause_resource", "pause_resource_all", "set_affinity_format", + "set_default_allocator", "set_lock", "set_nest_lock", "test_lock", @@ -3909,7 +3965,9 @@ omp_runtime_api_call (const_tree fndecl) "unset_nest_lock", NULL, /* And finally calls available as omp_*, omp_*_ and omp_*_8_. */ + "display_env", "get_ancestor_thread_num", + "init_allocator", "get_partition_place_nums", "get_place_num_procs", "get_place_proc_ids", @@ -4054,6 +4112,12 @@ scan_omp_1_stmt (gimple_stmt_iterator *gsi, bool *handled_ops_p, scan_omp_for (as_a <gomp_for *> (stmt), ctx); break; + case GIMPLE_OMP_SCOPE: + ctx = new_omp_context (stmt, ctx); + scan_sharing_clauses (gimple_omp_scope_clauses (stmt), ctx); + scan_omp (gimple_omp_body_ptr (stmt), ctx); + break; + case GIMPLE_OMP_SECTIONS: scan_omp_sections (as_a <gomp_sections *> (stmt), ctx); break; @@ -4079,6 +4143,12 @@ scan_omp_1_stmt (gimple_stmt_iterator *gsi, bool *handled_ops_p, scan_omp (gimple_omp_body_ptr (stmt), ctx); break; + case GIMPLE_OMP_MASKED: + ctx = new_omp_context (stmt, ctx); + scan_sharing_clauses (gimple_omp_masked_clauses (stmt), ctx); + scan_omp (gimple_omp_body_ptr (stmt), ctx); + break; + case GIMPLE_OMP_TASKGROUP: ctx = new_omp_context (stmt, ctx); scan_sharing_clauses (gimple_omp_taskgroup_clauses (stmt), ctx); @@ -8336,7 +8406,8 @@ maybe_add_implicit_barrier_cancel (omp_context *ctx, gimple *omp_return, gimple_seq_add_stmt (body, g); gimple_seq_add_stmt (body, gimple_build_label (fallthru_label)); } - else if (gimple_code (outer->stmt) != GIMPLE_OMP_TASKGROUP) + else if (gimple_code (outer->stmt) != GIMPLE_OMP_TASKGROUP + && gimple_code (outer->stmt) != GIMPLE_OMP_SCOPE) return; } @@ -8675,7 +8746,98 @@ lower_omp_single (gimple_stmt_iterator *gsi_p, omp_context *ctx) } -/* Expand code for an OpenMP master directive. */ +/* Lower code for an OMP scope directive. */ + +static void +lower_omp_scope (gimple_stmt_iterator *gsi_p, omp_context *ctx) +{ + tree block; + gimple *scope_stmt = gsi_stmt (*gsi_p); + gbind *bind; + gimple_seq bind_body, bind_body_tail = NULL, dlist; + gimple_seq tred_dlist = NULL; + + push_gimplify_context (); + + block = make_node (BLOCK); + bind = gimple_build_bind (NULL, NULL, block); + gsi_replace (gsi_p, bind, true); + bind_body = NULL; + dlist = NULL; + + tree rclauses + = omp_task_reductions_find_first (gimple_omp_scope_clauses (scope_stmt), + OMP_SCOPE, OMP_CLAUSE_REDUCTION); + if (rclauses) + { + tree type = build_pointer_type (pointer_sized_int_node); + tree temp = create_tmp_var (type); + tree c = build_omp_clause (UNKNOWN_LOCATION, OMP_CLAUSE__REDUCTEMP_); + OMP_CLAUSE_DECL (c) = temp; + OMP_CLAUSE_CHAIN (c) = gimple_omp_scope_clauses (scope_stmt); + gimple_omp_scope_set_clauses (scope_stmt, c); + lower_omp_task_reductions (ctx, OMP_SCOPE, + gimple_omp_scope_clauses (scope_stmt), + &bind_body, &tred_dlist); + rclauses = c; + tree fndecl = builtin_decl_explicit (BUILT_IN_GOMP_SCOPE_START); + gimple *stmt = gimple_build_call (fndecl, 1, temp); + gimple_seq_add_stmt (&bind_body, stmt); + } + + lower_rec_input_clauses (gimple_omp_scope_clauses (scope_stmt), + &bind_body, &dlist, ctx, NULL); + lower_omp (gimple_omp_body_ptr (scope_stmt), ctx); + + gimple_seq_add_stmt (&bind_body, scope_stmt); + + gimple_seq_add_seq (&bind_body, gimple_omp_body (scope_stmt)); + + gimple_omp_set_body (scope_stmt, NULL); + + gimple_seq clist = NULL; + lower_reduction_clauses (gimple_omp_scope_clauses (scope_stmt), + &bind_body, &clist, ctx); + if (clist) + { + tree fndecl = builtin_decl_explicit (BUILT_IN_GOMP_ATOMIC_START); + gcall *g = gimple_build_call (fndecl, 0); + gimple_seq_add_stmt (&bind_body, g); + gimple_seq_add_seq (&bind_body, clist); + fndecl = builtin_decl_explicit (BUILT_IN_GOMP_ATOMIC_END); + g = gimple_build_call (fndecl, 0); + gimple_seq_add_stmt (&bind_body, g); + } + + gimple_seq_add_seq (&bind_body, dlist); + + bind_body = maybe_catch_exception (bind_body); + + bool nowait = omp_find_clause (gimple_omp_scope_clauses (scope_stmt), + OMP_CLAUSE_NOWAIT) != NULL_TREE; + gimple *g = gimple_build_omp_return (nowait); + gimple_seq_add_stmt (&bind_body_tail, g); + gimple_seq_add_seq (&bind_body_tail, tred_dlist); + maybe_add_implicit_barrier_cancel (ctx, g, &bind_body_tail); + if (ctx->record_type) + { + gimple_stmt_iterator gsi = gsi_start (bind_body_tail); + tree clobber = build_clobber (ctx->record_type); + gsi_insert_after (&gsi, gimple_build_assign (ctx->sender_decl, + clobber), GSI_SAME_STMT); + } + gimple_seq_add_seq (&bind_body, bind_body_tail); + + gimple_bind_set_body (bind, bind_body); + + pop_gimplify_context (bind); + + gimple_bind_append_vars (bind, ctx->block_vars); + BLOCK_VARS (block) = ctx->block_vars; + if (BLOCK_VARS (block)) + TREE_USED (block) = 1; +} +/* Expand code for an OpenMP master or masked directive. */ static void lower_omp_master (gimple_stmt_iterator *gsi_p, omp_context *ctx) @@ -8685,9 +8847,20 @@ lower_omp_master (gimple_stmt_iterator *gsi_p, omp_context *ctx) gbind *bind; location_t loc = gimple_location (stmt); gimple_seq tseq; + tree filter = integer_zero_node; push_gimplify_context (); + if (gimple_code (stmt) == GIMPLE_OMP_MASKED) + { + filter = omp_find_clause (gimple_omp_masked_clauses (stmt), + OMP_CLAUSE_FILTER); + if (filter) + filter = fold_convert (integer_type_node, + OMP_CLAUSE_FILTER_EXPR (filter)); + else + filter = integer_zero_node; + } block = make_node (BLOCK); bind = gimple_build_bind (NULL, NULL, block); gsi_replace (gsi_p, bind, true); @@ -8695,7 +8868,7 @@ lower_omp_master (gimple_stmt_iterator *gsi_p, omp_context *ctx) bfn_decl = builtin_decl_explicit (BUILT_IN_OMP_GET_THREAD_NUM); x = build_call_expr_loc (loc, bfn_decl, 0); - x = build2 (EQ_EXPR, boolean_type_node, x, integer_zero_node); + x = build2 (EQ_EXPR, boolean_type_node, x, filter); x = build3 (COND_EXPR, void_type_node, x, NULL, build_and_jump (&lab)); tseq = NULL; gimplify_and_add (x, &tseq); @@ -8769,7 +8942,7 @@ lower_omp_task_reductions (omp_context *ctx, enum tree_code code, tree clauses, clauses = omp_task_reductions_find_first (clauses, code, ccode); if (clauses == NULL_TREE) return; - if (code == OMP_FOR || code == OMP_SECTIONS) + if (code == OMP_FOR || code == OMP_SECTIONS || code == OMP_SCOPE) { for (omp_context *outer = ctx->outer; outer; outer = outer->outer) if (gimple_code (outer->stmt) == GIMPLE_OMP_PARALLEL @@ -8778,7 +8951,8 @@ lower_omp_task_reductions (omp_context *ctx, enum tree_code code, tree clauses, cancellable = error_mark_node; break; } - else if (gimple_code (outer->stmt) != GIMPLE_OMP_TASKGROUP) + else if (gimple_code (outer->stmt) != GIMPLE_OMP_TASKGROUP + && gimple_code (outer->stmt) != GIMPLE_OMP_SCOPE) break; } tree record_type = lang_hooks.types.make_type (RECORD_TYPE); @@ -8894,11 +9068,11 @@ lower_omp_task_reductions (omp_context *ctx, enum tree_code code, tree clauses, tree lab2 = create_artificial_label (UNKNOWN_LOCATION); tree lab3 = NULL_TREE, lab7 = NULL_TREE; gimple *g; - if (code == OMP_FOR || code == OMP_SECTIONS) + if (code == OMP_FOR || code == OMP_SECTIONS || code == OMP_SCOPE) { - /* For worksharing constructs, only perform it in the master thread, - with the exception of cancelled implicit barriers - then only handle - the current thread. */ + /* For worksharing constructs or scope, only perform it in the master + thread, with the exception of cancelled implicit barriers - then only + handle the current thread. */ tree lab4 = create_artificial_label (UNKNOWN_LOCATION); t = builtin_decl_explicit (BUILT_IN_OMP_GET_THREAD_NUM); tree thr_num = create_tmp_var (integer_type_node); @@ -8913,8 +9087,10 @@ lower_omp_task_reductions (omp_context *ctx, enum tree_code code, tree clauses, lab3 = create_artificial_label (UNKNOWN_LOCATION); if (code == OMP_FOR) c = gimple_omp_for_clauses (ctx->stmt); - else /* if (code == OMP_SECTIONS) */ + else if (code == OMP_SECTIONS) c = gimple_omp_sections_clauses (ctx->stmt); + else /* if (code == OMP_SCOPE) */ + c = gimple_omp_scope_clauses (ctx->stmt); c = OMP_CLAUSE_DECL (omp_find_clause (c, OMP_CLAUSE__REDUCTEMP_)); cancellable = c; g = gimple_build_cond (NE_EXPR, c, build_zero_cst (TREE_TYPE (c)), @@ -9049,8 +9225,11 @@ lower_omp_task_reductions (omp_context *ctx, enum tree_code code, tree clauses, tree bfield = DECL_CHAIN (field); tree cond; - if (code == OMP_PARALLEL || code == OMP_FOR || code == OMP_SECTIONS) - /* In parallel or worksharing all threads unconditionally + if (code == OMP_PARALLEL + || code == OMP_FOR + || code == OMP_SECTIONS + || code == OMP_SCOPE) + /* In parallel, worksharing or scope all threads unconditionally initialize all their task reduction private variables. */ cond = boolean_true_node; else if (TREE_TYPE (ptr) == ptr_type_node) @@ -9291,6 +9470,8 @@ lower_omp_task_reductions (omp_context *ctx, enum tree_code code, tree clauses, c = gimple_omp_for_clauses (ctx->stmt); else if (code == OMP_SECTIONS) c = gimple_omp_sections_clauses (ctx->stmt); + else if (code == OMP_SCOPE) + c = gimple_omp_scope_clauses (ctx->stmt); else c = gimple_omp_taskreg_clauses (ctx->stmt); c = omp_find_clause (c, OMP_CLAUSE__REDUCTEMP_); @@ -9305,7 +9486,7 @@ lower_omp_task_reductions (omp_context *ctx, enum tree_code code, tree clauses, g = gimple_build_cond (NE_EXPR, idx, num_thr_sz, lab1, lab2); gimple_seq_add_stmt (end, g); gimple_seq_add_stmt (end, gimple_build_label (lab2)); - if (code == OMP_FOR || code == OMP_SECTIONS) + if (code == OMP_FOR || code == OMP_SECTIONS || code == OMP_SCOPE) { enum built_in_function bfn = BUILT_IN_GOMP_WORKSHARE_TASK_REDUCTION_UNREGISTER; @@ -13863,12 +14044,18 @@ lower_omp_1 (gimple_stmt_iterator *gsi_p, omp_context *ctx) ctx->cancel_label = create_artificial_label (UNKNOWN_LOCATION); lower_omp_sections (gsi_p, ctx); break; + case GIMPLE_OMP_SCOPE: + ctx = maybe_lookup_ctx (stmt); + gcc_assert (ctx); + lower_omp_scope (gsi_p, ctx); + break; case GIMPLE_OMP_SINGLE: ctx = maybe_lookup_ctx (stmt); gcc_assert (ctx); lower_omp_single (gsi_p, ctx); break; case GIMPLE_OMP_MASTER: + case GIMPLE_OMP_MASKED: ctx = maybe_lookup_ctx (stmt); gcc_assert (ctx); lower_omp_master (gsi_p, ctx); @@ -13973,6 +14160,7 @@ lower_omp_1 (gimple_stmt_iterator *gsi_p, omp_context *ctx) if (gimple_code (up->stmt) == GIMPLE_OMP_ORDERED || gimple_code (up->stmt) == GIMPLE_OMP_CRITICAL || gimple_code (up->stmt) == GIMPLE_OMP_TASKGROUP + || gimple_code (up->stmt) == GIMPLE_OMP_SCOPE || gimple_code (up->stmt) == GIMPLE_OMP_SECTION || gimple_code (up->stmt) == GIMPLE_OMP_SCAN || (gimple_code (up->stmt) == GIMPLE_OMP_TARGET @@ -14242,10 +14430,12 @@ diagnose_sb_1 (gimple_stmt_iterator *gsi_p, bool *handled_ops_p, case GIMPLE_OMP_PARALLEL: case GIMPLE_OMP_TASK: + case GIMPLE_OMP_SCOPE: case GIMPLE_OMP_SECTIONS: case GIMPLE_OMP_SINGLE: case GIMPLE_OMP_SECTION: case GIMPLE_OMP_MASTER: + case GIMPLE_OMP_MASKED: case GIMPLE_OMP_ORDERED: case GIMPLE_OMP_SCAN: case GIMPLE_OMP_CRITICAL: @@ -14303,10 +14493,12 @@ diagnose_sb_2 (gimple_stmt_iterator *gsi_p, bool *handled_ops_p, case GIMPLE_OMP_PARALLEL: case GIMPLE_OMP_TASK: + case GIMPLE_OMP_SCOPE: case GIMPLE_OMP_SECTIONS: case GIMPLE_OMP_SINGLE: case GIMPLE_OMP_SECTION: case GIMPLE_OMP_MASTER: + case GIMPLE_OMP_MASKED: case GIMPLE_OMP_ORDERED: case GIMPLE_OMP_SCAN: case GIMPLE_OMP_CRITICAL: diff --git a/gcc/omp-oacc-neuter-broadcast.cc b/gcc/omp-oacc-neuter-broadcast.cc index f855538..d48627a 100644 --- a/gcc/omp-oacc-neuter-broadcast.cc +++ b/gcc/omp-oacc-neuter-broadcast.cc @@ -538,12 +538,9 @@ typedef hash_map<tree, tree> field_map_t; typedef hash_map<tree, field_map_t *> record_field_map_t; -static GTY(()) record_field_map_t *field_map; - static void -install_var_field (tree var, tree record_type) +install_var_field (tree var, tree record_type, field_map_t *fields) { - field_map_t *fields = *field_map->get (record_type); tree name; char tmp[20]; @@ -959,9 +956,8 @@ oacc_build_component_ref (tree obj, tree field) } static tree -build_receiver_ref (tree record_type, tree var, tree receiver_decl) +build_receiver_ref (tree var, tree receiver_decl, field_map_t *fields) { - field_map_t *fields = *field_map->get (record_type); tree x = build_simple_mem_ref (receiver_decl); tree field = *fields->get (var); TREE_THIS_NOTRAP (x) = 1; @@ -970,9 +966,8 @@ build_receiver_ref (tree record_type, tree var, tree receiver_decl) } static tree -build_sender_ref (tree record_type, tree var, tree sender_decl) +build_sender_ref (tree var, tree sender_decl, field_map_t *fields) { - field_map_t *fields = *field_map->get (record_type); tree field = *fields->get (var); return oacc_build_component_ref (sender_decl, field); } @@ -1010,7 +1005,7 @@ static void worker_single_copy (basic_block from, basic_block to, hash_set<tree> *def_escapes_block, hash_set<tree> *worker_partitioned_uses, - tree record_type) + tree record_type, record_field_map_t *record_field_map) { /* If we only have virtual defs, we'll have no record type, but we still want to emit single_copy_start and (particularly) single_copy_end to act as @@ -1147,7 +1142,7 @@ worker_single_copy (basic_block from, basic_block to, gcc_assert (TREE_CODE (var) == VAR_DECL); /* If we had no record type, we will have no fields map. */ - field_map_t **fields_p = field_map->get (record_type); + field_map_t **fields_p = record_field_map->get (record_type); field_map_t *fields = fields_p ? *fields_p : NULL; if (worker_partitioned_uses->contains (var) @@ -1158,8 +1153,7 @@ worker_single_copy (basic_block from, basic_block to, /* Receive definition from shared memory block. */ - tree receiver_ref = build_receiver_ref (record_type, var, - receiver_decl); + tree receiver_ref = build_receiver_ref (var, receiver_decl, fields); gassign *recv = gimple_build_assign (neutered_def, receiver_ref); gsi_insert_after (©out_gsi, recv, GSI_CONTINUE_LINKING); @@ -1189,7 +1183,7 @@ worker_single_copy (basic_block from, basic_block to, /* Send definition to shared memory block. */ - tree sender_ref = build_sender_ref (record_type, var, sender_decl); + tree sender_ref = build_sender_ref (var, sender_decl, fields); if (TREE_CODE (var) == SSA_NAME) { @@ -1232,7 +1226,8 @@ static void neuter_worker_single (parallel_g *par, unsigned outer_mask, bitmap worker_single, bitmap vector_single, vec<propagation_set *> *prop_set, - hash_set<tree> *partitioned_var_uses) + hash_set<tree> *partitioned_var_uses, + record_field_map_t *record_field_map) { unsigned mask = outer_mask | par->mask; @@ -1322,7 +1317,8 @@ neuter_worker_single (parallel_g *par, unsigned outer_mask, if (has_defs) worker_single_copy (block, block, &def_escapes_block, - &worker_partitioned_uses, record_type); + &worker_partitioned_uses, record_type, + record_field_map); else worker_single_simple (block, block, &def_escapes_block); } @@ -1358,10 +1354,10 @@ neuter_worker_single (parallel_g *par, unsigned outer_mask, if (par->inner) neuter_worker_single (par->inner, mask, worker_single, vector_single, - prop_set, partitioned_var_uses); + prop_set, partitioned_var_uses, record_field_map); if (par->next) neuter_worker_single (par->next, outer_mask, worker_single, vector_single, - prop_set, partitioned_var_uses); + prop_set, partitioned_var_uses, record_field_map); } static int @@ -1402,13 +1398,8 @@ execute_omp_oacc_neuter_broadcast () FOR_ALL_BB_FN (bb, cfun) bb->aux = NULL; - field_map = record_field_map_t::create_ggc (40); - - vec<propagation_set *> prop_set; - prop_set.create (last_basic_block_for_fn (cfun)); - - for (int i = 0; i < last_basic_block_for_fn (cfun); i++) - prop_set.quick_push (0); + vec<propagation_set *> prop_set (vNULL); + prop_set.safe_grow_cleared (last_basic_block_for_fn (cfun), true); find_ssa_names_to_propagate (par, mask, worker_single, vector_single, &prop_set); @@ -1421,6 +1412,8 @@ execute_omp_oacc_neuter_broadcast () find_local_vars_to_propagate (par, mask, &partitioned_var_uses, &gang_private_vars, &prop_set); + record_field_map_t record_field_map; + FOR_ALL_BB_FN (bb, cfun) { propagation_set *ws_prop = prop_set[bb->index]; @@ -1441,12 +1434,16 @@ execute_omp_oacc_neuter_broadcast () field_vec.qsort (sort_by_size_then_ssa_version_or_uid); - field_map->put (record_type, field_map_t::create_ggc (17)); + field_map_t *fields = new field_map_t; + + bool existed; + existed = record_field_map.put (record_type, fields); + gcc_checking_assert (!existed); /* Insert var fields in reverse order, so the last inserted element is the first in the structure. */ for (int i = field_vec.length () - 1; i >= 0; i--) - install_var_field (field_vec[i], record_type); + install_var_field (field_vec[i], record_type, fields); layout_type (record_type); @@ -1455,10 +1452,19 @@ execute_omp_oacc_neuter_broadcast () } neuter_worker_single (par, mask, worker_single, vector_single, &prop_set, - &partitioned_var_uses); + &partitioned_var_uses, &record_field_map); + + for (auto it : record_field_map) + delete it.second; + record_field_map.empty (); + /* These are supposed to have been 'delete'd by 'neuter_worker_single'. */ + for (auto it : prop_set) + gcc_checking_assert (!it); prop_set.release (); + delete par; + /* This doesn't seem to make a difference. */ loops_state_clear (LOOP_CLOSED_SSA); diff --git a/gcc/optabs-query.c b/gcc/optabs-query.c index 05ee5f5..a6dd0fe 100644 --- a/gcc/optabs-query.c +++ b/gcc/optabs-query.c @@ -740,7 +740,8 @@ supports_vec_gather_load_p () this_fn_optabs->supports_vec_gather_load_cached = true; this_fn_optabs->supports_vec_gather_load - = supports_vec_convert_optab_p (gather_load_optab); + = (supports_vec_convert_optab_p (gather_load_optab) + || supports_vec_convert_optab_p (mask_gather_load_optab)); return this_fn_optabs->supports_vec_gather_load; } @@ -757,7 +758,8 @@ supports_vec_scatter_store_p () this_fn_optabs->supports_vec_scatter_store_cached = true; this_fn_optabs->supports_vec_scatter_store - = supports_vec_convert_optab_p (scatter_store_optab); + = (supports_vec_convert_optab_p (scatter_store_optab) + || supports_vec_convert_optab_p (mask_scatter_store_optab)); return this_fn_optabs->supports_vec_scatter_store; } @@ -806,37 +806,39 @@ control_options_for_live_patching (struct gcc_options *opts, switch (level) { case LIVE_PATCHING_INLINE_ONLY_STATIC: +#define LIVE_PATCHING_OPTION "-flive-patching=inline-only-static" if (opts_set->x_flag_ipa_cp_clone && opts->x_flag_ipa_cp_clone) error_at (loc, "%qs is incompatible with %qs", - "-fipa-cp-clone", "-flive-patching=inline-only-static"); + "-fipa-cp-clone", LIVE_PATCHING_OPTION); else opts->x_flag_ipa_cp_clone = 0; if (opts_set->x_flag_ipa_sra && opts->x_flag_ipa_sra) error_at (loc, "%qs is incompatible with %qs", - "-fipa-sra", "-flive-patching=inline-only-static"); + "-fipa-sra", LIVE_PATCHING_OPTION); else opts->x_flag_ipa_sra = 0; if (opts_set->x_flag_partial_inlining && opts->x_flag_partial_inlining) error_at (loc, "%qs is incompatible with %qs", - "-fpartial-inlining", "-flive-patching=inline-only-static"); + "-fpartial-inlining", LIVE_PATCHING_OPTION); else opts->x_flag_partial_inlining = 0; if (opts_set->x_flag_ipa_cp && opts->x_flag_ipa_cp) error_at (loc, "%qs is incompatible with %qs", - "-fipa-cp", "-flive-patching=inline-only-static"); + "-fipa-cp", LIVE_PATCHING_OPTION); else opts->x_flag_ipa_cp = 0; /* FALLTHROUGH. */ case LIVE_PATCHING_INLINE_CLONE: +#undef LIVE_PATCHING_OPTION +#define LIVE_PATCHING_OPTION "-flive-patching=inline-only-static|inline-clone" /* live patching should disable whole-program optimization. */ if (opts_set->x_flag_whole_program && opts->x_flag_whole_program) error_at (loc, "%qs is incompatible with %qs", - "-fwhole-program", - "-flive-patching=inline-only-static|inline-clone"); + "-fwhole-program", LIVE_PATCHING_OPTION); else opts->x_flag_whole_program = 0; @@ -846,71 +848,62 @@ control_options_for_live_patching (struct gcc_options *opts, if (opts_set->x_flag_ipa_pta && opts->x_flag_ipa_pta) error_at (loc, "%qs is incompatible with %qs", - "-fipa-pta", - "-flive-patching=inline-only-static|inline-clone"); + "-fipa-pta", LIVE_PATCHING_OPTION); else opts->x_flag_ipa_pta = 0; if (opts_set->x_flag_ipa_reference && opts->x_flag_ipa_reference) error_at (loc, "%qs is incompatible with %qs", - "-fipa-reference", - "-flive-patching=inline-only-static|inline-clone"); + "-fipa-reference", LIVE_PATCHING_OPTION); else opts->x_flag_ipa_reference = 0; if (opts_set->x_flag_ipa_ra && opts->x_flag_ipa_ra) error_at (loc, "%qs is incompatible with %qs", - "-fipa-ra", - "-flive-patching=inline-only-static|inline-clone"); + "-fipa-ra", LIVE_PATCHING_OPTION); else opts->x_flag_ipa_ra = 0; if (opts_set->x_flag_ipa_icf && opts->x_flag_ipa_icf) error_at (loc, "%qs is incompatible with %qs", - "-fipa-icf", - "-flive-patching=inline-only-static|inline-clone"); + "-fipa-icf", LIVE_PATCHING_OPTION); else opts->x_flag_ipa_icf = 0; if (opts_set->x_flag_ipa_icf_functions && opts->x_flag_ipa_icf_functions) error_at (loc, "%qs is incompatible with %qs", - "-fipa-icf-functions", - "-flive-patching=inline-only-static|inline-clone"); + "-fipa-icf-functions", LIVE_PATCHING_OPTION); else opts->x_flag_ipa_icf_functions = 0; if (opts_set->x_flag_ipa_icf_variables && opts->x_flag_ipa_icf_variables) error_at (loc, "%qs is incompatible with %qs", - "-fipa-icf-variables", - "-flive-patching=inline-only-static|inline-clone"); + "-fipa-icf-variables", LIVE_PATCHING_OPTION); else opts->x_flag_ipa_icf_variables = 0; if (opts_set->x_flag_ipa_bit_cp && opts->x_flag_ipa_bit_cp) error_at (loc, "%qs is incompatible with %qs", - "-fipa-bit-cp", - "-flive-patching=inline-only-static|inline-clone"); + "-fipa-bit-cp", LIVE_PATCHING_OPTION); else opts->x_flag_ipa_bit_cp = 0; if (opts_set->x_flag_ipa_vrp && opts->x_flag_ipa_vrp) error_at (loc, "%qs is incompatible with %qs", - "-fipa-vrp", - "-flive-patching=inline-only-static|inline-clone"); + "-fipa-vrp", LIVE_PATCHING_OPTION); else opts->x_flag_ipa_vrp = 0; if (opts_set->x_flag_ipa_pure_const && opts->x_flag_ipa_pure_const) error_at (loc, "%qs is incompatible with %qs", - "-fipa-pure-const", - "-flive-patching=inline-only-static|inline-clone"); + "-fipa-pure-const", LIVE_PATCHING_OPTION); else opts->x_flag_ipa_pure_const = 0; if (opts_set->x_flag_ipa_modref && opts->x_flag_ipa_modref) error_at (loc, - "%<-fipa-modref%> is incompatible with " - "%<-flive-patching=inline-only-static|inline-clone%>"); + "%<-fipa-modref%> is incompatible with %qs", + LIVE_PATCHING_OPTION); else opts->x_flag_ipa_modref = 0; @@ -920,8 +913,7 @@ control_options_for_live_patching (struct gcc_options *opts, if (opts_set->x_flag_ipa_reference_addressable && opts->x_flag_ipa_reference_addressable) error_at (loc, "%qs is incompatible with %qs", - "-fipa-reference-addressable", - "-flive-patching=inline-only-static|inline-clone"); + "-fipa-reference-addressable", LIVE_PATCHING_OPTION); else opts->x_flag_ipa_reference_addressable = 0; @@ -929,14 +921,15 @@ control_options_for_live_patching (struct gcc_options *opts, if (opts_set->x_flag_ipa_stack_alignment && opts->x_flag_ipa_stack_alignment) error_at (loc, "%qs is incompatible with %qs", - "-fipa-stack-alignment", - "-flive-patching=inline-only-static|inline-clone"); + "-fipa-stack-alignment", LIVE_PATCHING_OPTION); else opts->x_flag_ipa_stack_alignment = 0; break; default: gcc_unreachable (); } + +#undef LIVE_PATCHING_OPTION } /* --help option argument if set. */ diff --git a/gcc/params.opt b/gcc/params.opt index aa2fb40..f926488 100644 --- a/gcc/params.opt +++ b/gcc/params.opt @@ -132,7 +132,7 @@ Maximum number of basic blocks before EVRP uses a sparse cache. -param=evrp-mode= Common Joined Var(param_evrp_mode) Enum(evrp_mode) Init(EVRP_MODE_RVRP_ONLY) Param Optimization ---param=evrp-mode=[legacy|ranger|legacy-first|ranger-first|ranger-trace|ranger-debug|trace|debug] Specifies the mode Early VRP should operate in. +--param=evrp-mode=[legacy|ranger|legacy-first|ranger-first|trace|gori|cache|tracegori|debug] Specifies the mode Early VRP should operate in. Enum Name(evrp_mode) Type(enum evrp_mode) UnknownError(unknown evrp mode %qs) @@ -150,13 +150,16 @@ EnumValue Enum(evrp_mode) String(ranger-first) Value(EVRP_MODE_RVRP_FIRST) EnumValue -Enum(evrp_mode) String(ranger-trace) Value(EVRP_MODE_RVRP_TRACE) +Enum(evrp_mode) String(trace) Value(EVRP_MODE_TRACE) EnumValue -Enum(evrp_mode) String(ranger-debug) Value(EVRP_MODE_RVRP_DEBUG) +Enum(evrp_mode) String(cache) Value(EVRP_MODE_CACHE) EnumValue -Enum(evrp_mode) String(trace) Value(EVRP_MODE_TRACE) +Enum(evrp_mode) String(gori) Value(EVRP_MODE_GORI) + +EnumValue +Enum(evrp_mode) String(tracegori) Value(EVRP_MODE_TRACE_GORI) EnumValue Enum(evrp_mode) String(debug) Value(EVRP_MODE_DEBUG) @@ -1010,19 +1013,6 @@ Maximum depth of DFS walk used by modref escape analysis. Common Joined UInteger Var(param_modref_max_escape_points) Init(256) Param Optimization Maximum number of escape points tracked by modref per SSA-name. --param=threader-mode= -Common Joined Var(param_threader_mode) Enum(threader_mode) Init(THREADER_MODE_RANGER) Param Optimization ---param=threader-mode=[legacy|ranger] Specifies the mode the backwards threader should run in. - -Enum -Name(threader_mode) Type(enum threader_mode) UnknownError(unknown threader mode %qs) - -EnumValue -Enum(threader_mode) String(legacy) Value(THREADER_MODE_LEGACY) - -EnumValue -Enum(threader_mode) String(ranger) Value(THREADER_MODE_RANGER) - -param=tm-max-aggregate-size= Common Joined UInteger Var(param_tm_max_aggregate_size) Init(9) Param Optimization Size in bytes after which thread-local aggregates should be instrumented with the logging functions instead of save/restore pairs. diff --git a/gcc/pointer-query.cc b/gcc/pointer-query.cc index bc7cac0..99caf78 100644 --- a/gcc/pointer-query.cc +++ b/gcc/pointer-query.cc @@ -22,58 +22,21 @@ #include "system.h" #include "coretypes.h" #include "backend.h" -#include "target.h" -#include "rtl.h" #include "tree.h" -#include "memmodel.h" #include "gimple.h" -#include "predict.h" -#include "tm_p.h" #include "stringpool.h" #include "tree-vrp.h" -#include "tree-ssanames.h" -#include "expmed.h" -#include "optabs.h" -#include "emit-rtl.h" -#include "recog.h" #include "diagnostic-core.h" -#include "alias.h" #include "fold-const.h" -#include "fold-const-call.h" -#include "gimple-ssa-warn-restrict.h" -#include "stor-layout.h" -#include "calls.h" -#include "varasm.h" #include "tree-object-size.h" #include "tree-ssa-strlen.h" -#include "realmpfr.h" -#include "cfgrtl.h" -#include "except.h" -#include "dojump.h" -#include "explow.h" -#include "stmt.h" -#include "expr.h" -#include "libfuncs.h" -#include "output.h" -#include "typeclass.h" #include "langhooks.h" -#include "value-prof.h" -#include "builtins.h" #include "stringpool.h" #include "attribs.h" -#include "asan.h" -#include "internal-fn.h" -#include "case-cfn-macros.h" #include "gimple-fold.h" #include "intl.h" -#include "tree-dfa.h" -#include "gimple-iterator.h" -#include "gimple-ssa.h" -#include "tree-ssa-live.h" -#include "tree-outof-ssa.h" #include "attr-fnspec.h" #include "gimple-range.h" - #include "pointer-query.h" static bool compute_objsize_r (tree, int, access_ref *, ssa_name_limit_t &, @@ -311,6 +274,164 @@ gimple_call_return_array (gimple *stmt, offset_int offrng[2], bool *past_end, return NULL_TREE; } +/* Return true when EXP's range can be determined and set RANGE[] to it + after adjusting it if necessary to make EXP a represents a valid size + of object, or a valid size argument to an allocation function declared + with attribute alloc_size (whose argument may be signed), or to a string + manipulation function like memset. + When ALLOW_ZERO is set in FLAGS, allow returning a range of [0, 0] for + a size in an anti-range [1, N] where N > PTRDIFF_MAX. A zero range is + a (nearly) invalid argument to allocation functions like malloc but it + is a valid argument to functions like memset. + When USE_LARGEST is set in FLAGS set RANGE to the largest valid subrange + in a multi-range, otherwise to the smallest valid subrange. */ + +bool +get_size_range (range_query *query, tree exp, gimple *stmt, tree range[2], + int flags /* = 0 */) +{ + if (!exp) + return false; + + if (tree_fits_uhwi_p (exp)) + { + /* EXP is a constant. */ + range[0] = range[1] = exp; + return true; + } + + tree exptype = TREE_TYPE (exp); + bool integral = INTEGRAL_TYPE_P (exptype); + + wide_int min, max; + enum value_range_kind range_type; + + if (!query) + query = get_global_range_query (); + + if (integral) + { + value_range vr; + + query->range_of_expr (vr, exp, stmt); + + if (vr.undefined_p ()) + vr.set_varying (TREE_TYPE (exp)); + range_type = vr.kind (); + min = wi::to_wide (vr.min ()); + max = wi::to_wide (vr.max ()); + } + else + range_type = VR_VARYING; + + if (range_type == VR_VARYING) + { + if (integral) + { + /* Use the full range of the type of the expression when + no value range information is available. */ + range[0] = TYPE_MIN_VALUE (exptype); + range[1] = TYPE_MAX_VALUE (exptype); + return true; + } + + range[0] = NULL_TREE; + range[1] = NULL_TREE; + return false; + } + + unsigned expprec = TYPE_PRECISION (exptype); + + bool signed_p = !TYPE_UNSIGNED (exptype); + + if (range_type == VR_ANTI_RANGE) + { + if (signed_p) + { + if (wi::les_p (max, 0)) + { + /* EXP is not in a strictly negative range. That means + it must be in some (not necessarily strictly) positive + range which includes zero. Since in signed to unsigned + conversions negative values end up converted to large + positive values, and otherwise they are not valid sizes, + the resulting range is in both cases [0, TYPE_MAX]. */ + min = wi::zero (expprec); + max = wi::to_wide (TYPE_MAX_VALUE (exptype)); + } + else if (wi::les_p (min - 1, 0)) + { + /* EXP is not in a negative-positive range. That means EXP + is either negative, or greater than max. Since negative + sizes are invalid make the range [MAX + 1, TYPE_MAX]. */ + min = max + 1; + max = wi::to_wide (TYPE_MAX_VALUE (exptype)); + } + else + { + max = min - 1; + min = wi::zero (expprec); + } + } + else + { + wide_int maxsize = wi::to_wide (max_object_size ()); + min = wide_int::from (min, maxsize.get_precision (), UNSIGNED); + max = wide_int::from (max, maxsize.get_precision (), UNSIGNED); + if (wi::eq_p (0, min - 1)) + { + /* EXP is unsigned and not in the range [1, MAX]. That means + it's either zero or greater than MAX. Even though 0 would + normally be detected by -Walloc-zero, unless ALLOW_ZERO + is set, set the range to [MAX, TYPE_MAX] so that when MAX + is greater than the limit the whole range is diagnosed. */ + wide_int maxsize = wi::to_wide (max_object_size ()); + if (flags & SR_ALLOW_ZERO) + { + if (wi::leu_p (maxsize, max + 1) + || !(flags & SR_USE_LARGEST)) + min = max = wi::zero (expprec); + else + { + min = max + 1; + max = wi::to_wide (TYPE_MAX_VALUE (exptype)); + } + } + else + { + min = max + 1; + max = wi::to_wide (TYPE_MAX_VALUE (exptype)); + } + } + else if ((flags & SR_USE_LARGEST) + && wi::ltu_p (max + 1, maxsize)) + { + /* When USE_LARGEST is set and the larger of the two subranges + is a valid size, use it... */ + min = max + 1; + max = maxsize; + } + else + { + /* ...otherwise use the smaller subrange. */ + max = min - 1; + min = wi::zero (expprec); + } + } + } + + range[0] = wide_int_to_tree (exptype, min); + range[1] = wide_int_to_tree (exptype, max); + + return true; +} + +bool +get_size_range (tree exp, tree range[2], int flags /* = 0 */) +{ + return get_size_range (/*query=*/NULL, exp, /*stmt=*/NULL, range, flags); +} + /* If STMT is a call to an allocation function, returns the constant maximum size of the object allocated by the call represented as sizetype. If nonnull, sets RNG1[] to the range of the size. diff --git a/gcc/pointer-query.h b/gcc/pointer-query.h index 8bd538a..eb7e90d 100644 --- a/gcc/pointer-query.h +++ b/gcc/pointer-query.h @@ -230,6 +230,17 @@ struct access_data access_mode mode; }; +enum size_range_flags + { + /* Set to consider zero a valid range. */ + SR_ALLOW_ZERO = 1, + /* Set to use the largest subrange of a set of ranges as opposed + to the smallest. */ + SR_USE_LARGEST = 2 + }; +extern bool get_size_range (tree, tree[2], int = 0); +extern bool get_size_range (range_query *, tree, gimple *, tree[2], int = 0); + class range_query; extern tree gimple_call_alloc_size (gimple *, wide_int[2] = NULL, range_query * = NULL); diff --git a/gcc/range-op.cc b/gcc/range-op.cc index eb66e12..56eccf4 100644 --- a/gcc/range-op.cc +++ b/gcc/range-op.cc @@ -3642,6 +3642,12 @@ operator_abs::op1_range (irange &r, tree type, r.union_ (int_range<1> (type, -positives.upper_bound (i), -positives.lower_bound (i))); + // With flag_wrapv, -TYPE_MIN_VALUE = TYPE_MIN_VALUE which is + // unrepresentable. Add -TYPE_MIN_VALUE in this case. + wide_int min_value = wi::min_value (TYPE_PRECISION (type), TYPE_SIGN (type)); + wide_int lb = lhs.lower_bound (); + if (!TYPE_OVERFLOW_UNDEFINED (type) && wi::eq_p (lb, min_value)) + r.union_ (int_range<2> (type, lb, lb)); return true; } diff --git a/gcc/read-rtl-function.c b/gcc/read-rtl-function.c index ca580d3..941d1e1 100644 --- a/gcc/read-rtl-function.c +++ b/gcc/read-rtl-function.c @@ -1861,7 +1861,7 @@ test_loading_labels () /* Ensure that label names read from a dump are GC-managed and are found through the insn. */ - forcibly_ggc_collect (); + ggc_collect (GGC_COLLECT_FORCE); ASSERT_TRUE (ggc_marked_p (insn_200)); ASSERT_TRUE (ggc_marked_p (LABEL_NAME (insn_200))); } @@ -830,6 +830,9 @@ struct GTY(()) rtvec_def { #define CONST_DOUBLE_AS_FLOAT_P(X) \ (GET_CODE (X) == CONST_DOUBLE && GET_MODE (X) != VOIDmode) +/* Predicate yielding nonzero iff X is an rtx for a constant vector. */ +#define CONST_VECTOR_P(X) (GET_CODE (X) == CONST_VECTOR) + /* Predicate yielding nonzero iff X is a label insn. */ #define LABEL_P(X) (GET_CODE (X) == CODE_LABEL) diff --git a/gcc/selftest-run-tests.c b/gcc/selftest-run-tests.c index 1b5583e..6a8f291 100644 --- a/gcc/selftest-run-tests.c +++ b/gcc/selftest-run-tests.c @@ -128,7 +128,7 @@ selftest::run_tests () issues. For example, if any GC-managed items have buggy (or missing) finalizers, this last collection will ensure that things that were failed to be finalized can be detected by valgrind. */ - forcibly_ggc_collect (); + ggc_collect (GGC_COLLECT_FORCE); /* Finished running tests; the test_runner dtor will print a summary. */ } diff --git a/gcc/selftest.h b/gcc/selftest.h index 80459d6..58d8d38 100644 --- a/gcc/selftest.h +++ b/gcc/selftest.h @@ -190,11 +190,6 @@ for_each_line_table_case (void (*testcase) (const line_table_case &)); extern char *read_file (const location &loc, const char *path); -/* A helper function for writing tests that interact with the - garbage collector. */ - -extern void forcibly_ggc_collect (); - /* Convert a path relative to SRCDIR/gcc/testsuite/selftests to a real path (either absolute, or relative to pwd). The result should be freed by the caller. */ diff --git a/gcc/symtab.c b/gcc/symtab.c index 8c4cb70..c7ea8ec 100644 --- a/gcc/symtab.c +++ b/gcc/symtab.c @@ -1959,6 +1959,8 @@ symtab_node::noninterposable_alias (void) /* If aliases aren't supported by the assembler, fail. */ if (!TARGET_SUPPORTS_ALIASES) return NULL; + else if (lookup_attribute ("target_clones", DECL_ATTRIBUTES (node->decl))) + return NULL; /* Otherwise create a new one. */ new_decl = copy_node (node->decl); diff --git a/gcc/target.def b/gcc/target.def index 2652d8c..b302042 100644 --- a/gcc/target.def +++ b/gcc/target.def @@ -7090,6 +7090,18 @@ DEFHOOK void, (void), NULL) +DEFHOOK +(gcov_type_size, + "Returns the gcov type size in bits. This type is used for example for\n\ +counters incremented by profiling and code-coverage events. The default\n\ +value is 64, if the type size of long long is greater than 32, otherwise the\n\ +default value is 32. A 64-bit type is recommended to avoid overflows of the\n\ +counters. If the @option{-fprofile-update=atomic} is used, then the\n\ +counters are incremented using atomic operations. Targets not supporting\n\ +64-bit atomic operations may override the default value and request a 32-bit\n\ +type.", + HOST_WIDE_INT, (void), default_gcov_type_size) + /* Close the 'struct gcc_target' definition. */ HOOK_VECTOR_END (C90_EMPTY_HACK) diff --git a/gcc/targhooks.c b/gcc/targhooks.c index eb51909..c9b5208 100644 --- a/gcc/targhooks.c +++ b/gcc/targhooks.c @@ -2654,4 +2654,11 @@ default_memtag_untagged_pointer (rtx tagged_pointer, rtx target) return untagged_base; } +/* The default implementation of TARGET_GCOV_TYPE_SIZE. */ +HOST_WIDE_INT +default_gcov_type_size (void) +{ + return TYPE_PRECISION (long_long_integer_type_node) > 32 ? 64 : 32; +} + #include "gt-targhooks.h" diff --git a/gcc/targhooks.h b/gcc/targhooks.h index f92e102..92d5199 100644 --- a/gcc/targhooks.h +++ b/gcc/targhooks.h @@ -302,4 +302,6 @@ extern rtx default_memtag_set_tag (rtx, rtx, rtx); extern rtx default_memtag_extract_tag (rtx, rtx); extern rtx default_memtag_untagged_pointer (rtx, rtx); +extern HOST_WIDE_INT default_gcov_type_size (void); + #endif /* GCC_TARGHOOKS_H */ diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index d0d2584..e5dcd4a 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,404 @@ +2021-08-17 Martin Sebor <msebor@redhat.com> + + PR middle-end/101854 + * gcc.dg/attr-alloc_size-5.c: Adjust optimization to -O1. + * gcc.dg/attr-alloc_size-7.c: Use #pragmas to adjust optimization. + * gcc.dg/attr-alloc_size-8.c: Adjust optimization to -O1. + * gcc.dg/Wstringop-overflow-72.c: New test. + +2021-08-17 Jakub Jelinek <jakub@redhat.com> + + PR c++/101539 + * g++.dg/cpp2a/is-corresponding-member1.C: New test. + * g++.dg/cpp2a/is-corresponding-member2.C: New test. + * g++.dg/cpp2a/is-corresponding-member3.C: New test. + * g++.dg/cpp2a/is-corresponding-member4.C: New test. + * g++.dg/cpp2a/is-corresponding-member5.C: New test. + * g++.dg/cpp2a/is-corresponding-member6.C: New test. + * g++.dg/cpp2a/is-corresponding-member7.C: New test. + * g++.dg/cpp2a/is-corresponding-member8.C: New test. + * g++.dg/cpp2a/is-layout-compatible1.C: New test. + * g++.dg/cpp2a/is-layout-compatible2.C: New test. + * g++.dg/cpp2a/is-layout-compatible3.C: New test. + +2021-08-17 Thomas Schwinge <thomas@codesourcery.com> + + * gcc.dg/pr78213.c: Restore testing. + +2021-08-17 Roger Sayle <roger@nextmovesoftware.com> + + * gcc.dg/tree-ssa/ssa-ccp-40.c: New test case. + +2021-08-17 Roger Sayle <roger@nextmovesoftware.com> + + * gcc.dg/fold-ior-5.c: New test case. + +2021-08-17 Tobias Burnus <tobias@codesourcery.com> + + * gfortran.dg/gomp/scan-1.f90: + * gfortran.dg/gomp/cancel-1.f90: New test. + * gfortran.dg/gomp/cancel-4.f90: New test. + * gfortran.dg/gomp/loop-4.f90: New test. + * gfortran.dg/gomp/nesting-1.f90: New test. + * gfortran.dg/gomp/nesting-2.f90: New test. + * gfortran.dg/gomp/nesting-3.f90: New test. + * gfortran.dg/gomp/nowait-1.f90: New test. + * gfortran.dg/gomp/reduction-task-1.f90: New test. + * gfortran.dg/gomp/reduction-task-2.f90: New test. + * gfortran.dg/gomp/reduction-task-2a.f90: New test. + * gfortran.dg/gomp/reduction-task-3.f90: New test. + * gfortran.dg/gomp/scope-1.f90: New test. + * gfortran.dg/gomp/scope-2.f90: New test. + +2021-08-17 Andrew MacLeod <amacleod@redhat.com> + + PR tree-optimization/101938 + * gcc.dg/pr101938.c: New test. + +2021-08-17 Richard Biener <rguenther@suse.de> + + PR tree-optimization/101868 + * gcc.dg/lto/pr101868_0.c: New testcase. + * gcc.dg/lto/pr101868_1.c: Likewise. + * gcc.dg/lto/pr101868_2.c: Likewise. + * gcc.dg/lto/pr101868_3.c: Likewise. + +2021-08-17 Jakub Jelinek <jakub@redhat.com> + + * c-c++-common/gomp/nesting-2.c (foo): Add scope and masked + construct tests. + * c-c++-common/gomp/scan-1.c (f3): Add scope construct test.. + * c-c++-common/gomp/cancel-1.c (f2): Add scope and masked + construct tests. + * c-c++-common/gomp/reduction-task-2.c (bar): Add scope construct + test. Adjust diagnostics for the addition of scope. + * c-c++-common/gomp/loop-1.c (f5): Add master, masked and scope + construct tests. + * c-c++-common/gomp/clause-dups-1.c (f1): Add scope construct test. + * gcc.dg/gomp/nesting-1.c (f1, f2, f3): Add scope construct tests. + * c-c++-common/gomp/scope-1.c: New test. + * c-c++-common/gomp/scope-2.c: New test. + * g++.dg/gomp/attrs-1.C (bar): Add scope construct tests. + * g++.dg/gomp/attrs-2.C (bar): Likewise. + * gfortran.dg/gomp/reduction4.f90: Adjust expected diagnostics. + * gfortran.dg/gomp/reduction7.f90: Likewise. + +2021-08-17 Jakub Jelinek <jakub@redhat.com> + + * c-c++-common/cpp/va-opt-5.c: New test. + * c-c++-common/cpp/va-opt-6.c: New test. + +2021-08-17 Richard Biener <rguenther@suse.de> + + PR tree-optimization/101925 + * gcc.dg/sso-16.c: New testcase. + +2021-08-17 liuhongt <hongtao.liu@intel.com> + + * gcc.target/i386/pr82460-2.c: Adjust testcase by adding + --param=vect-epilogues-nomask=0 + +2021-08-16 liuhongt <hongtao.liu@intel.com> + + PR target/101930 + * gcc.target/i386/pr101930.c: New test. + +2021-08-16 Martin Liska <mliska@suse.cz> + + PR ipa/100600 + * gcc.dg/ipa/pr100600.c: New test. + +2021-08-16 liuhongt <hongtao.liu@intel.com> + + PR target/101846 + * gcc.target/i386/pr101846-2.c: New test. + * gcc.target/i386/pr101846-3.c: New test. + * gcc.target/i386/pr101846-4.c: New test. + +2021-08-16 Tobias Burnus <tobias@codesourcery.com> + + * gfortran.dg/gomp/masked-1.f90: New test. + * gfortran.dg/gomp/masked-2.f90: New test. + * gfortran.dg/gomp/masked-3.f90: New test. + * gfortran.dg/gomp/masked-combined-1.f90: New test. + * gfortran.dg/gomp/masked-combined-2.f90: New test. + +2021-08-15 Harald Anlauf <anlauf@gmx.de> + + PR fortran/99351 + * gfortran.dg/coarray_sync.f90: New test. + * gfortran.dg/coarray_3.f90: Adjust error messages. + +2021-08-14 Martin Sebor <msebor@redhat.com> + + PR middle-end/101791 + * g++.dg/warn/Wmismatched-new-delete-6.C: New test. + * g++.dg/warn/Wmismatched-new-delete-7.C: New test. + +2021-08-14 Jakub Jelinek <jakub@redhat.com> + + PR target/101896 + * gcc.target/i386/avx512f-pr101896.c: New test. + +2021-08-13 Martin Sebor <msebor@redhat.com> + + PR middle-end/101734 + * gcc.dg/uninit-42.c: New test. + +2021-08-13 Martin Liska <mliska@suse.cz> + + PR ipa/101261 + * gcc.target/i386/pr101261.c: New test. + +2021-08-13 Jan Hubicka <hubicka@ucw.cz> + + * gcc.dg/tree-ssa/modref-6.c: Update. + +2021-08-13 prathamesh.kulkarni <prathamesh.kulkarni@linaro.org> + + * gcc.target/arm/simd/pr98435.c: Add dg-require-effective-target + arm_softfp_ok. + +2021-08-12 Jakub Jelinek <jakub@redhat.com> + + * c-c++-common/gomp/clauses-1.c (bar): Add tests for combined masked + constructs with clauses. + * c-c++-common/gomp/clauses-5.c (foo): Add testcase for filter clause. + * c-c++-common/gomp/clause-dups-1.c (f1): Likewise. + * c-c++-common/gomp/masked-1.c: New test. + * c-c++-common/gomp/masked-2.c: New test. + * c-c++-common/gomp/masked-combined-1.c: New test. + * c-c++-common/gomp/masked-combined-2.c: New test. + * c-c++-common/goacc/uninit-if-clause.c: Remove xfails. + * g++.dg/gomp/block-11.C: New test. + * g++.dg/gomp/tpl-masked-1.C: New test. + * g++.dg/gomp/attrs-1.C (bar): Add tests for masked construct and + combined masked constructs with clauses in attribute syntax. + * g++.dg/gomp/attrs-2.C (bar): Likewise. + * gcc.dg/gomp/nesting-1.c (f1, f2): Add tests for masked construct + nesting. + * gfortran.dg/goacc/host_data-tree.f95: Allow also SSA_NAMEs in if + clause. + * gfortran.dg/goacc/kernels-tree.f95: Likewise. + +2021-08-12 Jakub Jelinek <jakub@redhat.com> + + PR preprocessor/101638 + * gcc.dg/cpp/pr101638.c: New test. + +2021-08-12 Michael Meissner <meissner@linux.ibm.com> + + * gcc.target/powerpc/fold-vec-load-builtin_vec_xl-char.c: Fix + typo in regular expression. + * gcc.target/powerpc/fold-vec-load-builtin_vec_xl-double.c: + Likewise. + * gcc.target/powerpc/fold-vec-load-builtin_vec_xl-float.c: + Likewise. + * gcc.target/powerpc/fold-vec-load-builtin_vec_xl-int.c: + Likewise. + * gcc.target/powerpc/fold-vec-load-builtin_vec_xl-longlong.c: + Likewise. + * gcc.target/powerpc/fold-vec-load-builtin_vec_xl-short.c: + Likewise. + +2021-08-12 Sergei Trofimovich <siarheit@google.com> + + PR c++/101219 + * g++.dg/warn/pr101219.C: New test. + +2021-08-12 Martin Uecker <muecker@gwdg.de> + + PR c/101838 + * gcc.dg/vla-stexp-2.c: New test. + +2021-08-12 Aldy Hernandez <aldyh@redhat.com> + + * gcc.dg/tree-ssa/ssa-dom-thread-7.c: Remove call into the legacy + code and adjust for ranger threader. + +2021-08-12 Tobias Burnus <tobias@codesourcery.com> + + * c-c++-common/gomp/pr61486-2.c: Duplicate one proc_bind(master) + testcase and test proc_bind(primary) instead. + * gfortran.dg/gomp/affinity-1.f90: Likewise. + +2021-08-12 Hans-Peter Nilsson <hp@axis.com> + + * gfortran.dg/PR82376.f90: Robustify match. + +2021-08-12 Jakub Jelinek <jakub@redhat.com> + + PR target/101860 + * gcc.target/i386/avx512f-pr101860.c: New test. + +2021-08-12 Jakub Jelinek <jakub@redhat.com> + + * g++.dg/gomp/attrs-12.C: New test. + +2021-08-12 Jakub Jelinek <jakub@redhat.com> + + * g++.dg/gomp/attrs-11.C: Add new tests. + +2021-08-12 Jakub Jelinek <jakub@redhat.com> + + PR c++/99429 + PR c++/94162 + * g++.dg/cpp2a/spaceship-synth11.C: New test. + * g++.dg/cpp2a/spaceship-synth-neg6.C: New test. + +2021-08-12 Jakub Jelinek <jakub@redhat.com> + + * g++.dg/gomp/attrs-11.C: Adjust expected diagnostics. + +2021-08-12 Jakub Jelinek <jakub@redhat.com> + + * g++.dg/lookup/strong-using.C: Add test using [[gnu::strong]] + as well. + * g++.dg/lookup/strong-using2.C: Likewise. + * g++.dg/cpp0x/gen-attrs-58.C: Move alignas(int) before + using namespace. + * g++.dg/cpp0x/gen-attrs-59.C: Move alignas(X) before + using namespace, add tests for alignas before semicolon. + * g++.dg/cpp0x/gen-attrs-76.C: Remove xfails. Add test for + C++11 attributes on using directive before semicolon. + +2021-08-12 liuhongt <hongtao.liu@intel.com> + + PR target/101846 + * gcc.target/i386/pr101846-1.c: New test. + +2021-08-12 Patrick Palka <ppalka@redhat.com> + + PR c++/101663 + * g++.dg/cpp2a/construct_at.h: New convenience header file that + defines minimal implementations of std::construct_at/destroy_at, + split out from ... + * g++.dg/cpp2a/constexpr-new5.C: ... here. + * g++.dg/cpp2a/constexpr-new6.C: Use the header. + * g++.dg/cpp2a/constexpr-new14.C: Likewise. + * g++.dg/cpp2a/constexpr-new20.C: New test. + +2021-08-11 Patrick Palka <ppalka@redhat.com> + + PR c++/101725 + DR 2082 + * g++.dg/DRs/dr2082.C: New test. + * g++.dg/cpp2a/concepts-uneval4.C: New test. + +2021-08-11 Jakub Jelinek <jakub@redhat.com> + + PR c++/101786 + * g++.dg/cpp2a/constinit16.C: New test. + +2021-08-11 Patrick Palka <ppalka@redhat.com> + + PR c++/79501 + * g++.dg/cpp1z/class-deduction98.C: New test. + +2021-08-11 Patrick Palka <ppalka@redhat.com> + + PR c++/89062 + * g++.dg/cpp1z/class-deduction97.C: New test. + +2021-08-11 Richard Biener <rguenther@suse.de> + + * gcc.dg/lto/pr48622_1.c: Provide non-LTO definition + of ashift_qi_1. + +2021-08-11 Jan Hubicka <jh@suse.cz> + + * c-c++-common/modref-dse.c: New test. + +2021-08-11 Richard Biener <rguenther@suse.de> + + PR middle-end/101858 + * gcc.dg/pr101858.c: New testcase. + +2021-08-11 prathamesh.kulkarni <prathamesh.kulkarni@linaro.org> + + PR target/66791 + * gcc.target/arm/pr51534.c: Adjust test. + +2021-08-11 liuhongt <hongtao.liu@intel.com> + + PR target/98309 + * gcc.target/i386/pr98309-1.c: New test. + * gcc.target/i386/pr98309-2.c: New test. + +2021-08-11 Hans-Peter Nilsson <hp@axis.com> + + PR middle-end/101674 + * gcc.dg/uninit-pred-9_b.c: Xfail for cris-*-* too. + +2021-08-10 Tobias Burnus <tobias@codesourcery.com> + + PR libfortran/101305 + PR fortran/101660 + PR testsuite/101847 + * lib/gfortran.exp (gfortran_init): Remove -I$specpath/libgfortran + from the string used to set GFORTRAN_UNDER_TEST. + +2021-08-10 H.J. Lu <hjl.tools@gmail.com> + + PR tree-optimization/101809 + * gcc.target/i386/pr88531-1a.c: Enable for all targets. + +2021-08-10 Jakub Jelinek <jakub@redhat.com> + + PR target/80355 + * gcc.target/i386/avx512f-pr80355-2.c: New test. + +2021-08-10 Jakub Jelinek <jakub@redhat.com> + + PR target/80355 + * gcc.target/i386/avx512f-pr80355-1.c: New test. + +2021-08-10 Jakub Jelinek <jakub@redhat.com> + + * g++.dg/gomp/attrs-1.C (bar): Add missing semicolon after + [[omp::directive (threadprivate (t2))]]. Add tests with + if/while/switch after parallel in attribute syntax. + (corge): Add missing omp:: before directive. + * g++.dg/gomp/attrs-2.C (bar): Add missing semicolon after + [[omp::directive (threadprivate (t2))]]. + * g++.dg/gomp/attrs-10.C: New test. + * g++.dg/gomp/attrs-11.C: New test. + +2021-08-10 Hongyu Wang <hongyu.wang@intel.com> + + * gcc.target/i386/amxbf16-dpbf16ps-2.c: Fix typos. + +2021-08-10 Richard Biener <rguenther@suse.de> + + PR middle-end/101824 + * gcc.dg/tree-ssa/pr101824.c: New testcase. + +2021-08-10 Martin Uecker <muecker@gwdg.de> + + PR c/29970 + * gcc.dg/vla-stexp-1.c: New test. + +2021-08-10 H.J. Lu <hjl.tools@gmail.com> + + PR target/101804 + * gcc.target/i386/avx2-gather-2.c: Pass -march=skylake instead + of "-mavx2 -mtune=skylake". Scan vpcmpeqd. + +2021-08-10 liuhongt <hongtao.liu@intel.com> + + * gcc.target/i386/cond_op_shift_d-1.c: New test. + * gcc.target/i386/cond_op_shift_d-2.c: New test. + * gcc.target/i386/cond_op_shift_q-1.c: New test. + * gcc.target/i386/cond_op_shift_q-2.c: New test. + * gcc.target/i386/cond_op_shift_ud-1.c: New test. + * gcc.target/i386/cond_op_shift_ud-2.c: New test. + * gcc.target/i386/cond_op_shift_uq-1.c: New test. + * gcc.target/i386/cond_op_shift_uq-2.c: New test. + * gcc.target/i386/cond_op_shift_uw-1.c: New test. + * gcc.target/i386/cond_op_shift_uw-2.c: New test. + * gcc.target/i386/cond_op_shift_w-1.c: New test. + * gcc.target/i386/cond_op_shift_w-2.c: New test. + 2021-08-09 Andrew MacLeod <amacleod@redhat.com> * gcc.dg/pr101741.c: New. diff --git a/gcc/testsuite/c-c++-common/cpp/va-opt-5.c b/gcc/testsuite/c-c++-common/cpp/va-opt-5.c new file mode 100644 index 0000000..b687ced --- /dev/null +++ b/gcc/testsuite/c-c++-common/cpp/va-opt-5.c @@ -0,0 +1,67 @@ +/* { dg-do run } */ +/* { dg-options "-std=gnu99" { target c } } */ +/* { dg-options "-std=c++20" { target c++ } } */ + +#define lparen ( +#define a0 fooa0 +#define a1 fooa1 a0 +#define a2 fooa2 a1 +#define a3 fooa3 a2 +#define a() b lparen ) +#define b() c lparen ) +#define c() d lparen ) +#define g h +#define i(j) j +#define f(...) #__VA_OPT__(g i(0)) +#define k(x,...) # __VA_OPT__(x) #x #__VA_OPT__(__VA_ARGS__) +#define l(x,...) #__VA_OPT__(a1 x) +#define m(x,...) "a()" #__VA_OPT__(a3 __VA_ARGS__ x ## __VA_ARGS__ ## x ## c a3) "a()" +#define n(x,...) = #__VA_OPT__(a3 __VA_ARGS__ x ## __VA_ARGS__ ## x ## c a3) #x #__VA_OPT__(a0 __VA_ARGS__ x ## __VA_ARGS__ ## x ## c a0) ; +#define o(x, ...) #__VA_OPT__(x##x x##x) +#define p(x, ...) #__VA_OPT__(_Pragma ("foobar")) +#define q(...) #__VA_OPT__(/* foo */x/* bar */) +const char *v1 = f(); +const char *v2 = f(123); +const char *v3 = k(1); +const char *v4 = k(1, 2, 3 ); +const char *v5 = l(a()); +const char *v6 = l(a1 a(), 1); +const char *v7 = m(); +const char *v8 = m(,); +const char *v9 = m(,a3); +const char *v10 = m(a3,a(),a0); +const char *v11 n() +const char *v12 n(,) +const char *v13 n(,a0) +const char *v14 n(a0, a(),a0) +const char *v15 = o(, 0); +const char *v16 = p(0); +const char *v17 = p(0, 1); +const char *v18 = q(); +const char *v19 = q(1); + +int +main () +{ + if (__builtin_strcmp (v1, "") + || __builtin_strcmp (v2, "g i(0)") + || __builtin_strcmp (v3, "1") + || __builtin_strcmp (v4, "112, 3") + || __builtin_strcmp (v5, "") + || __builtin_strcmp (v6, "a1 fooa1 fooa0 b ( )") + || __builtin_strcmp (v7, "a()a()") + || __builtin_strcmp (v8, "a()a()") + || __builtin_strcmp (v9, "a()a3 fooa3 fooa2 fooa1 fooa0 a3c a3a()") + || __builtin_strcmp (v10, "a()a3 b ( ),fooa0 a3a(),a0a3c a3a()") + || __builtin_strcmp (v11, "") + || __builtin_strcmp (v12, "") + || __builtin_strcmp (v13, "a3 fooa0 a0c a3a0 fooa0 a0c a0") + || __builtin_strcmp (v14, "a3 b ( ),fooa0 a0a(),a0a0c a3a0a0 b ( ),fooa0 a0a(),a0a0c a0") + || __builtin_strcmp (v15, "") + || __builtin_strcmp (v16, "") + || __builtin_strcmp (v17, "_Pragma (\"foobar\")") + || __builtin_strcmp (v18, "") + || __builtin_strcmp (v19, "x")) + __builtin_abort (); + return 0; +} diff --git a/gcc/testsuite/c-c++-common/cpp/va-opt-6.c b/gcc/testsuite/c-c++-common/cpp/va-opt-6.c new file mode 100644 index 0000000..8a7761b --- /dev/null +++ b/gcc/testsuite/c-c++-common/cpp/va-opt-6.c @@ -0,0 +1,17 @@ +/* { dg-do preprocess } */ +/* { dg-options "-std=gnu99" { target c } } */ +/* { dg-options "-std=c++20" { target c++ } } */ + +#define a "" +#define b(...) a ## #__VA_OPT__(1) /* { dg-error "pasting \"a\" and \"\"\"\" does not give a valid preprocessing token" } */ +#define c(...) a ## #__VA_OPT__(1) /* { dg-error "pasting \"a\" and \"\"1\"\" does not give a valid preprocessing token" } */ +#define d(...) #__VA_OPT__(1) ## ! +#define e(...) #__VA_OPT__(1) ## ! +#define f(...) #__VA_OPT__(. ## !) +#define g(...) #__VA_OPT__(. ## !) +b() +c(1) +d( ) /* { dg-error "pasting \"\"\"\" and \"!\" does not give a valid preprocessing token" } */ +e( 1 ) /* { dg-error "pasting \"\"1\"\" and \"!\" does not give a valid preprocessing token" } */ +f() +g(0) /* { dg-error "pasting \".\" and \"!\" does not give a valid preprocessing token" } */ diff --git a/gcc/testsuite/c-c++-common/goacc/uninit-if-clause.c b/gcc/testsuite/c-c++-common/goacc/uninit-if-clause.c index 7f78d72..683ac1b 100644 --- a/gcc/testsuite/c-c++-common/goacc/uninit-if-clause.c +++ b/gcc/testsuite/c-c++-common/goacc/uninit-if-clause.c @@ -1,6 +1,5 @@ /* { dg-do compile } */ /* { dg-additional-options "-Wuninitialized" } */ -/* { dg-excess-errors "PR70392" { xfail c++ } } */ #include <stdbool.h> @@ -14,25 +13,25 @@ main (void) #pragma acc parallel if(l) /* { dg-warning "is used uninitialized" } */ ; - #pragma acc parallel if(b) /* { dg-warning "is used uninitialized" "" { xfail c++ } } */ + #pragma acc parallel if(b) /* { dg-warning "is used uninitialized" } */ ; #pragma acc kernels if(l2) /* { dg-warning "is used uninitialized" } */ ; - #pragma acc kernels if(b2) /* { dg-warning "is used uninitialized" "" { xfail c++ } } */ + #pragma acc kernels if(b2) /* { dg-warning "is used uninitialized" } */ ; #pragma acc data if(l3) /* { dg-warning "is used uninitialized" } */ ; - #pragma acc data if(b3) /* { dg-warning "is used uninitialized" "" { xfail c++ } } */ + #pragma acc data if(b3) /* { dg-warning "is used uninitialized" } */ ; #pragma acc update if(l4) self(i) /* { dg-warning "is used uninitialized" } */ ; - #pragma acc update if(b4) self(i2) /* { dg-warning "is used uninitialized" "" { xfail c++ } } */ + #pragma acc update if(b4) self(i2) /* { dg-warning "is used uninitialized" } */ ; } diff --git a/gcc/testsuite/c-c++-common/gomp/cancel-1.c b/gcc/testsuite/c-c++-common/gomp/cancel-1.c index 5255dd3..5d68cd3 100644 --- a/gcc/testsuite/c-c++-common/gomp/cancel-1.c +++ b/gcc/testsuite/c-c++-common/gomp/cancel-1.c @@ -39,6 +39,28 @@ f2 (void) #pragma omp cancellation point sections /* { dg-error "not closely nested inside" } */ #pragma omp cancellation point taskgroup /* { dg-error "not closely nested inside" } */ } + #pragma omp masked + { + #pragma omp cancel parallel /* { dg-error "not closely nested inside" } */ + #pragma omp cancel for /* { dg-error "not closely nested inside" } */ + #pragma omp cancel sections /* { dg-error "not closely nested inside" } */ + #pragma omp cancel taskgroup /* { dg-error "not closely nested inside" } */ + #pragma omp cancellation point parallel /* { dg-error "not closely nested inside" } */ + #pragma omp cancellation point for /* { dg-error "not closely nested inside" } */ + #pragma omp cancellation point sections /* { dg-error "not closely nested inside" } */ + #pragma omp cancellation point taskgroup /* { dg-error "not closely nested inside" } */ + } + #pragma omp scope + { + #pragma omp cancel parallel /* { dg-error "not closely nested inside" } */ + #pragma omp cancel for /* { dg-error "not closely nested inside" } */ + #pragma omp cancel sections /* { dg-error "not closely nested inside" } */ + #pragma omp cancel taskgroup /* { dg-error "not closely nested inside" } */ + #pragma omp cancellation point parallel /* { dg-error "not closely nested inside" } */ + #pragma omp cancellation point for /* { dg-error "not closely nested inside" } */ + #pragma omp cancellation point sections /* { dg-error "not closely nested inside" } */ + #pragma omp cancellation point taskgroup /* { dg-error "not closely nested inside" } */ + } #pragma omp single { #pragma omp cancel parallel /* { dg-error "not closely nested inside" } */ diff --git a/gcc/testsuite/c-c++-common/gomp/clause-dups-1.c b/gcc/testsuite/c-c++-common/gomp/clause-dups-1.c index 3dde058..604caf0 100644 --- a/gcc/testsuite/c-c++-common/gomp/clause-dups-1.c +++ b/gcc/testsuite/c-c++-common/gomp/clause-dups-1.c @@ -203,7 +203,10 @@ f1 (int *p) i = p[0]++; #pragma omp atomic capture hint(0) hint (0) /* { dg-error "too many 'hint' clauses" } */ i = p[0]++; - + #pragma omp masked filter (0) filter (0) /* { dg-error "too many 'filter' clauses" } */ + f0 (); + #pragma omp scope nowait nowait /* { dg-error "too many 'nowait' clauses" } */ + ; } #pragma omp declare simd simdlen (4) simdlen (4) /* { dg-error "too many 'simdlen' clauses" } */ diff --git a/gcc/testsuite/c-c++-common/gomp/clauses-1.c b/gcc/testsuite/c-c++-common/gomp/clauses-1.c index 682442af..378c7bf 100644 --- a/gcc/testsuite/c-c++-common/gomp/clauses-1.c +++ b/gcc/testsuite/c-c++-common/gomp/clauses-1.c @@ -273,6 +273,10 @@ bar (int d, int m, int i1, int i2, int i3, int p, int *idp, int s, private (p) firstprivate (f) if (parallel: i2) default(shared) shared(s) reduction(+:r) \ num_threads (nth) proc_bind(spread) copyin(t) allocate (f) ; + #pragma omp parallel masked \ + private (p) firstprivate (f) if (parallel: i2) default(shared) shared(s) reduction(+:r) \ + num_threads (nth) proc_bind(spread) copyin(t) allocate (f) filter (d) + ; #pragma omp taskgroup task_reduction (+:r2) allocate (r2) #pragma omp master taskloop \ private (p) firstprivate (f) lastprivate (l) shared (s) default(shared) grainsize (g) collapse(1) untied if(taskloop: i1) final(fi) mergeable priority (pp) \ @@ -280,23 +284,47 @@ bar (int d, int m, int i1, int i2, int i3, int p, int *idp, int s, for (int i = 0; i < 64; i++) ll++; #pragma omp taskgroup task_reduction (+:r2) allocate (r2) + #pragma omp masked taskloop \ + private (p) firstprivate (f) lastprivate (l) shared (s) default(shared) grainsize (g) collapse(1) untied if(taskloop: i1) final(fi) mergeable priority (pp) \ + reduction(default, +:r) in_reduction(+:r2) allocate (f) filter (d) + for (int i = 0; i < 64; i++) + ll++; + #pragma omp taskgroup task_reduction (+:r2) allocate (r2) #pragma omp master taskloop simd \ private (p) firstprivate (f) lastprivate (l) shared (s) default(shared) grainsize (g) collapse(1) untied if(taskloop: i1) if(simd: i2) final(fi) mergeable priority (pp) \ safelen(8) simdlen(4) linear(ll: 1) aligned(q: 32) reduction(default, +:r) in_reduction(+:r2) nontemporal(ntm) \ order(concurrent) allocate (f) for (int i = 0; i < 64; i++) ll++; + #pragma omp taskgroup task_reduction (+:r2) allocate (r2) + #pragma omp masked taskloop simd \ + private (p) firstprivate (f) lastprivate (l) shared (s) default(shared) grainsize (g) collapse(1) untied if(taskloop: i1) if(simd: i2) final(fi) mergeable priority (pp) \ + safelen(8) simdlen(4) linear(ll: 1) aligned(q: 32) reduction(default, +:r) in_reduction(+:r2) nontemporal(ntm) \ + order(concurrent) allocate (f) filter (d) + for (int i = 0; i < 64; i++) + ll++; #pragma omp parallel master taskloop \ private (p) firstprivate (f) lastprivate (l) shared (s) default(shared) grainsize (g) collapse(1) untied if(taskloop: i1) final(fi) mergeable priority (pp) \ reduction(default, +:r) if (parallel: i2) num_threads (nth) proc_bind(spread) copyin(t) allocate (f) for (int i = 0; i < 64; i++) ll++; + #pragma omp parallel masked taskloop \ + private (p) firstprivate (f) lastprivate (l) shared (s) default(shared) grainsize (g) collapse(1) untied if(taskloop: i1) final(fi) mergeable priority (pp) \ + reduction(default, +:r) if (parallel: i2) num_threads (nth) proc_bind(spread) copyin(t) allocate (f) filter (d) + for (int i = 0; i < 64; i++) + ll++; #pragma omp parallel master taskloop simd \ private (p) firstprivate (f) lastprivate (l) shared (s) default(shared) grainsize (g) collapse(1) untied if(taskloop: i1) if(simd: i2) final(fi) mergeable priority (pp) \ safelen(8) simdlen(4) linear(ll: 1) aligned(q: 32) reduction(default, +:r) nontemporal(ntm) if (parallel: i2) num_threads (nth) proc_bind(spread) copyin(t) \ order(concurrent) allocate (f) for (int i = 0; i < 64; i++) ll++; + #pragma omp parallel masked taskloop simd \ + private (p) firstprivate (f) lastprivate (l) shared (s) default(shared) grainsize (g) collapse(1) untied if(taskloop: i1) if(simd: i2) final(fi) mergeable priority (pp) \ + safelen(8) simdlen(4) linear(ll: 1) aligned(q: 32) reduction(default, +:r) nontemporal(ntm) if (parallel: i2) num_threads (nth) proc_bind(spread) copyin(t) \ + order(concurrent) allocate (f) filter (d) + for (int i = 0; i < 64; i++) + ll++; #pragma omp taskgroup task_reduction (+:r2) allocate (r2) #pragma omp master taskloop \ private (p) firstprivate (f) lastprivate (l) shared (s) default(shared) num_tasks (nta) collapse(1) untied if(i1) final(fi) mergeable priority (pp) \ @@ -304,23 +332,47 @@ bar (int d, int m, int i1, int i2, int i3, int p, int *idp, int s, for (int i = 0; i < 64; i++) ll++; #pragma omp taskgroup task_reduction (+:r2) allocate (r2) + #pragma omp mastked taskloop \ + private (p) firstprivate (f) lastprivate (l) shared (s) default(shared) num_tasks (nta) collapse(1) untied if(i1) final(fi) mergeable priority (pp) \ + reduction(default, +:r) in_reduction(+:r2) filter (d) + for (int i = 0; i < 64; i++) + ll++; + #pragma omp taskgroup task_reduction (+:r2) allocate (r2) #pragma omp master taskloop simd \ private (p) firstprivate (f) lastprivate (l) shared (s) default(shared) num_tasks (nta) collapse(1) untied if(i1) final(fi) mergeable priority (pp) \ safelen(8) simdlen(4) linear(ll: 1) aligned(q: 32) reduction(default, +:r) in_reduction(+:r2) nontemporal(ntm) \ order(concurrent) allocate (f) for (int i = 0; i < 64; i++) ll++; + #pragma omp taskgroup task_reduction (+:r2) allocate (r2) + #pragma omp masked taskloop simd \ + private (p) firstprivate (f) lastprivate (l) shared (s) default(shared) num_tasks (nta) collapse(1) untied if(i1) final(fi) mergeable priority (pp) \ + safelen(8) simdlen(4) linear(ll: 1) aligned(q: 32) reduction(default, +:r) in_reduction(+:r2) nontemporal(ntm) \ + order(concurrent) allocate (f) filter (d) + for (int i = 0; i < 64; i++) + ll++; #pragma omp parallel master taskloop \ private (p) firstprivate (f) lastprivate (l) shared (s) default(shared) num_tasks (nta) collapse(1) untied if(i1) final(fi) mergeable priority (pp) \ reduction(default, +:r) num_threads (nth) proc_bind(spread) copyin(t) allocate (f) for (int i = 0; i < 64; i++) ll++; + #pragma omp parallel masked taskloop \ + private (p) firstprivate (f) lastprivate (l) shared (s) default(shared) num_tasks (nta) collapse(1) untied if(i1) final(fi) mergeable priority (pp) \ + reduction(default, +:r) num_threads (nth) proc_bind(spread) copyin(t) allocate (f) filter (d) + for (int i = 0; i < 64; i++) + ll++; #pragma omp parallel master taskloop simd \ private (p) firstprivate (f) lastprivate (l) shared (s) default(shared) num_tasks (nta) collapse(1) untied if(i1) final(fi) mergeable priority (pp) \ safelen(8) simdlen(4) linear(ll: 1) aligned(q: 32) reduction(default, +:r) nontemporal(ntm) num_threads (nth) proc_bind(spread) copyin(t) \ order(concurrent) allocate (f) for (int i = 0; i < 64; i++) ll++; + #pragma omp parallel masked taskloop simd \ + private (p) firstprivate (f) lastprivate (l) shared (s) default(shared) num_tasks (nta) collapse(1) untied if(i1) final(fi) mergeable priority (pp) \ + safelen(8) simdlen(4) linear(ll: 1) aligned(q: 32) reduction(default, +:r) nontemporal(ntm) num_threads (nth) proc_bind(spread) copyin(t) \ + order(concurrent) allocate (f) filter (d) + for (int i = 0; i < 64; i++) + ll++; #pragma omp loop bind(thread) order(concurrent) \ private (p) lastprivate (l) collapse(1) reduction(+:r) for (l = 0; l < 64; ++l) diff --git a/gcc/testsuite/c-c++-common/gomp/clauses-5.c b/gcc/testsuite/c-c++-common/gomp/clauses-5.c index 35e16f0..87e53a9 100644 --- a/gcc/testsuite/c-c++-common/gomp/clauses-5.c +++ b/gcc/testsuite/c-c++-common/gomp/clauses-5.c @@ -49,4 +49,6 @@ foo (int *p) ; #pragma omp critical (baz) hint (2, 3) /* { dg-error "expected" } */ ; + #pragma omp masked filter (3, 4) /* { dg-error "expected" } */ + ; } diff --git a/gcc/testsuite/c-c++-common/gomp/loop-1.c b/gcc/testsuite/c-c++-common/gomp/loop-1.c index 4fb995c..3454fa8 100644 --- a/gcc/testsuite/c-c++-common/gomp/loop-1.c +++ b/gcc/testsuite/c-c++-common/gomp/loop-1.c @@ -183,6 +183,24 @@ f5 (int *a) } #pragma omp loop for (i = 0; i < 64; i++) + { + #pragma omp master /* { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a 'loop' region" } */ + foo (); + } + #pragma omp loop + for (i = 0; i < 64; i++) + { + #pragma omp masked /* { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a 'loop' region" } */ + foo (); + } + #pragma omp loop + for (i = 0; i < 64; i++) + { + #pragma omp scope /* { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a 'loop' region" } */ + foo (); + } + #pragma omp loop + for (i = 0; i < 64; i++) a[i] += omp_get_thread_num (); /* { dg-error "OpenMP runtime API call '\[^\n\r]*omp_get_thread_num\[^\n\r]*' in a region with 'order\\(concurrent\\)' clause" } */ #pragma omp loop for (i = 0; i < 64; i++) diff --git a/gcc/testsuite/c-c++-common/gomp/masked-1.c b/gcc/testsuite/c-c++-common/gomp/masked-1.c new file mode 100644 index 0000000..36c2e49 --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/masked-1.c @@ -0,0 +1,23 @@ +void bar (void); + +void +foo (int x, int *a) +{ + #pragma omp masked + bar (); + #pragma omp masked filter (0) + bar (); + #pragma omp masked filter (7) + bar (); + #pragma omp masked filter (x) + bar (); + #pragma omp masked taskloop simd filter (x) grainsize (12) simdlen (4) + for (int i = 0; i < 128; i++) + a[i] = i; + #pragma omp parallel masked filter (x) firstprivate (x) + bar (); + #pragma omp masked + #pragma omp masked filter (0) + #pragma omp masked filter (x) + ; +} diff --git a/gcc/testsuite/c-c++-common/gomp/masked-2.c b/gcc/testsuite/c-c++-common/gomp/masked-2.c new file mode 100644 index 0000000..7230c82 --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/masked-2.c @@ -0,0 +1,11 @@ +void bar (void); +struct S { int s; }; + +void +foo (float f, struct S s) +{ + #pragma omp masked filter (0.0) /* { dg-error "integral|integer" } */ + bar (); + #pragma omp masked filter (s) /* { dg-error "integral|integer" } */ + bar (); +} diff --git a/gcc/testsuite/c-c++-common/gomp/masked-combined-1.c b/gcc/testsuite/c-c++-common/gomp/masked-combined-1.c new file mode 100644 index 0000000..0b3ff58 --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/masked-combined-1.c @@ -0,0 +1,37 @@ +void bar (int *); + +void +foo (int *a, int f) +{ + int i, j, k, u = 0, v = 0, w = 0, x = 0, y = 0, z = 0; + #pragma omp parallel masked default(none) private (k) filter (f) firstprivate (f) + bar (&k); + #pragma omp parallel masked default(none) private (k) + bar (&k); + #pragma omp parallel default(none) firstprivate(a, f) shared(x, y, z) + { + #pragma omp masked taskloop reduction (+:x) default(none) firstprivate(a) filter (f) + for (i = 0; i < 64; i++) + x += a[i]; + #pragma omp masked taskloop simd reduction (+:y) default(none) firstprivate(a) private (i) filter (f) + for (i = 0; i < 64; i++) + y += a[i]; + #pragma omp masked taskloop simd reduction (+:y) default(none) firstprivate(a) private (i) + for (i = 0; i < 64; i++) + y += a[i]; + #pragma omp masked taskloop simd collapse(2) reduction (+:z) default(none) firstprivate(a) private (i, j) filter (f) + for (j = 0; j < 1; j++) + for (i = 0; i < 64; ++i) + z += a[i]; + } + #pragma omp parallel masked taskloop reduction (+:u) default(none) firstprivate(a, f) filter (f) + for (i = 0; i < 64; i++) + u += a[i]; + #pragma omp parallel masked taskloop simd reduction (+:v) default(none) firstprivate(a, f) filter (f) + for (i = 0; i < 64; i++) + v += a[i]; + #pragma omp parallel masked taskloop simd collapse(2) reduction (+:w) default(none) firstprivate(a, f) filter (f) + for (j = 0; j < 1; j++) + for (i = 0; i < 64; ++i) + w += a[i]; +} diff --git a/gcc/testsuite/c-c++-common/gomp/masked-combined-2.c b/gcc/testsuite/c-c++-common/gomp/masked-combined-2.c new file mode 100644 index 0000000..1d63969 --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/masked-combined-2.c @@ -0,0 +1,13 @@ +void +foo (int *a) +{ + int i, r = 0, s = 0; + #pragma omp taskgroup task_reduction(+:r) + #pragma omp parallel masked taskloop in_reduction(+:r) /* { dg-error "'in_reduction' is not valid for '#pragma omp parallel masked taskloop'" } */ + for (i = 0; i < 64; i++) + r += a[i]; + #pragma omp taskgroup task_reduction(+:s) + #pragma omp parallel masked taskloop simd in_reduction(+:s) /* { dg-error "'in_reduction' is not valid for '#pragma omp parallel masked taskloop simd'" } */ + for (i = 0; i < 64; i++) + s += a[i]; +} diff --git a/gcc/testsuite/c-c++-common/gomp/nesting-2.c b/gcc/testsuite/c-c++-common/gomp/nesting-2.c index 7a03430..420cfd3 100644 --- a/gcc/testsuite/c-c++-common/gomp/nesting-2.c +++ b/gcc/testsuite/c-c++-common/gomp/nesting-2.c @@ -19,6 +19,10 @@ foo (void) #pragma omp barrier /* { dg-error "region may not be closely nested inside of" } */ #pragma omp master /* { dg-error "region may not be closely nested inside of" } */ ; + #pragma omp masked /* { dg-error "region may not be closely nested inside of" } */ + ; + #pragma omp scope /* { dg-error "region may not be closely nested inside of" } */ + ; #pragma omp ordered /* { dg-error "region may not be closely nested inside of" } */ ; #pragma omp ordered threads /* { dg-error "region may not be closely nested inside of" } */ @@ -55,6 +59,10 @@ foo (void) #pragma omp barrier #pragma omp master ; + #pragma omp masked + ; + #pragma omp scope + ; #pragma omp ordered /* { dg-error ".ordered. region must be closely nested inside a loop region with an .ordered. clause" } */ ; #pragma omp ordered threads /* { dg-error ".ordered. region must be closely nested inside a loop region with an .ordered. clause" } */ @@ -89,6 +97,10 @@ foo (void) #pragma omp barrier #pragma omp master ; + #pragma omp masked + ; + #pragma omp scope + ; #pragma omp ordered /* { dg-error ".ordered. region must be closely nested inside a loop region with an .ordered. clause" } */ ; #pragma omp ordered threads /* { dg-error ".ordered. region must be closely nested inside a loop region with an .ordered. clause" } */ diff --git a/gcc/testsuite/c-c++-common/gomp/nothing-1.c b/gcc/testsuite/c-c++-common/gomp/nothing-1.c new file mode 100644 index 0000000..d50c92a --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/nothing-1.c @@ -0,0 +1,37 @@ +#pragma omp nothing + +struct S +{ + #pragma omp nothing + int s; +}; + +int +foo (int i) +{ + #pragma omp nothing + if (0) + #pragma omp nothing + i++; + if (1) + ; + else + #pragma omp nothing + i++; + switch (0) + #pragma omp nothing + { + default: + break; + } + while (0) + #pragma omp nothing + i++; + for (; 0;) + #pragma omp nothing + i++; + lab: + #pragma omp nothing + i++; + return i; +} diff --git a/gcc/testsuite/c-c++-common/gomp/pr61486-2.c b/gcc/testsuite/c-c++-common/gomp/pr61486-2.c index 4a68023..c86fd91 100644 --- a/gcc/testsuite/c-c++-common/gomp/pr61486-2.c +++ b/gcc/testsuite/c-c++-common/gomp/pr61486-2.c @@ -216,6 +216,19 @@ test (int n, int o, int p, int q, int r, int s, int *pp) s = i * 10; } #pragma omp target device (n + 1) if (n != 6)map(from:n) map(alloc:a[2:o-2]) + #pragma omp teams distribute parallel for simd if (n != 6)default(shared) \ + private (p) firstprivate (q) shared (n) reduction (+: r) \ + thread_limit (n * 2) dist_schedule (static, 4) num_threads (n + 4) \ + proc_bind (primary) lastprivate (s) schedule (static, 8) \ + num_teams (n + 4) safelen(16) linear(i:1) aligned (pp:4) + for (i = 0; i < 10; i++) + { + r = r + 1; + p = q; + a[2+i] = p + q; + s = i * 10; + } + #pragma omp target device (n + 1) if (n != 6)map(from:n) map(alloc:a[2:o-2]) #pragma omp teams distribute simd default(shared) \ private (p) firstprivate (q) shared (n) reduction (+: r) \ thread_limit (n * 2) dist_schedule (static, 4) collapse (2) \ diff --git a/gcc/testsuite/c-c++-common/gomp/pr63326.c b/gcc/testsuite/c-c++-common/gomp/pr63326.c index 3e62723..48ab4f6 100644 --- a/gcc/testsuite/c-c++-common/gomp/pr63326.c +++ b/gcc/testsuite/c-c++-common/gomp/pr63326.c @@ -156,64 +156,64 @@ f4 (int x) { do #pragma omp barrier /* { dg-error "may only be used in compound statements" } */ - while (0); /* { dg-error "before" "" { target c++ } } */ - } /* { dg-error "before" "" { target c++ } } */ + while (0); + } { do #pragma omp flush /* { dg-error "may only be used in compound statements" } */ - while (0); /* { dg-error "before" "" { target c++ } } */ - } /* { dg-error "before" "" { target c++ } } */ + while (0); + } { do #pragma omp taskwait /* { dg-error "may only be used in compound statements" } */ - while (0); /* { dg-error "before" "" { target c++ } } */ - } /* { dg-error "before" "" { target c++ } } */ + while (0); + } { do #pragma omp taskyield /* { dg-error "may only be used in compound statements" } */ - while (0); /* { dg-error "before" "" { target c++ } } */ - } /* { dg-error "before" "" { target c++ } } */ + while (0); + } #pragma omp parallel { do #pragma omp cancel parallel /* { dg-error "may only be used in compound statements" } */ - while (0); /* { dg-error "before" "" { target c++ } } */ - } /* { dg-error "before" "" { target c++ } } */ + while (0); + } #pragma omp parallel { do #pragma omp cancellation point parallel /* { dg-error "may only be used in compound statements" } */ - while (0); /* { dg-error "before" "" { target c++ } } */ - } /* { dg-error "before" "" { target c++ } } */ + while (0); + } #pragma omp for ordered(1) for (i = 0; i < 16; i++) { { do #pragma omp ordered depend(source) /* { dg-error "may only be used in compound statements" } */ - while (0); /* { dg-error "before" "" { target c++ } } */ - } /* { dg-error "before" "" { target c++ } } */ + while (0); + } { do #pragma omp ordered depend(sink: i-1) /* { dg-error "may only be used in compound statements" } */ - while (0); /* { dg-error "before" "" { target c++ } } */ - } /* { dg-error "before" "" { target c++ } } */ + while (0); + } } { do #pragma omp target enter data map(to:i) /* { dg-error "may only be used in compound statements" } */ - while (0); /* { dg-error "before" "" { target c++ } } */ - } /* { dg-error "before" "" { target c++ } } */ + while (0); + } { do #pragma omp target update to(i) /* { dg-error "may only be used in compound statements" } */ - while (0); /* { dg-error "before" "" { target c++ } } */ - } /* { dg-error "before" "" { target c++ } } */ + while (0); + } { do #pragma omp target exit data map(from:i) /* { dg-error "may only be used in compound statements" } */ - while (0); /* { dg-error "before" "" { target c++ } } */ - } /* { dg-error "before" "" { target c++ } } */ + while (0); + } } void diff --git a/gcc/testsuite/c-c++-common/gomp/reduction-task-2.c b/gcc/testsuite/c-c++-common/gomp/reduction-task-2.c index 1e262d3..225abed 100644 --- a/gcc/testsuite/c-c++-common/gomp/reduction-task-2.c +++ b/gcc/testsuite/c-c++-common/gomp/reduction-task-2.c @@ -14,7 +14,9 @@ bar (void) #pragma omp section foo (-3); } - #pragma omp simd reduction (task, +: v) /* { dg-error "invalid 'task' reduction modifier on construct other than 'parallel', 'for' or 'sections'" } */ + #pragma omp scope reduction (task, +: v) nowait /* { dg-error "'task' reduction modifier on a construct with a 'nowait' clause" } */ + foo (-4); + #pragma omp simd reduction (task, +: v) /* { dg-error "invalid 'task' reduction modifier on construct other than 'parallel', 'for', 'sections' or 'scope'" } */ for (i = 0; i < 64; i++) v++; #pragma omp for simd reduction (task, +: v) /* { dg-error "invalid 'task' reduction modifier on construct combined with 'simd'" } */ @@ -26,13 +28,13 @@ bar (void) #pragma omp teams distribute parallel for simd reduction (task, +: v) /* { dg-error "invalid 'task' reduction modifier on construct combined with 'simd'" } */ for (i = 0; i < 64; i++) v++; - #pragma omp taskloop reduction (task, +: v) /* { dg-error "invalid 'task' reduction modifier on construct other than 'parallel', 'for' or 'sections'" } */ + #pragma omp taskloop reduction (task, +: v) /* { dg-error "invalid 'task' reduction modifier on construct other than 'parallel', 'for', 'sections' or 'scope'" } */ for (i = 0; i < 64; i++) foo (i); #pragma omp taskloop simd reduction (task, +: v) /* { dg-error "invalid 'task' reduction modifier on construct combined with 'simd'" } */ for (i = 0; i < 64; i++) v++; - #pragma omp teams reduction (task, +: v) /* { dg-error "invalid 'task' reduction modifier on construct other than 'parallel', 'for' or 'sections'" } */ + #pragma omp teams reduction (task, +: v) /* { dg-error "invalid 'task' reduction modifier on construct other than 'parallel', 'for', 'sections' or 'scope'" } */ foo (i); #pragma omp teams distribute reduction (task, +: v) /* { dg-error "invalid 'task' reduction modifier on construct not combined with 'parallel', 'for' or 'sections'" } */ for (i = 0; i < 64; i++) diff --git a/gcc/testsuite/c-c++-common/gomp/scan-1.c b/gcc/testsuite/c-c++-common/gomp/scan-1.c index 17804e3..95b46cb 100644 --- a/gcc/testsuite/c-c++-common/gomp/scan-1.c +++ b/gcc/testsuite/c-c++-common/gomp/scan-1.c @@ -89,6 +89,8 @@ f3 (int *c, int *d) #pragma omp section ; } + #pragma omp scope reduction (inscan, +: a) /* { dg-error "'inscan' 'reduction' clause on 'scope' construct" } */ + ; #pragma omp target parallel for reduction (inscan, +: a) map (c[:64], d[:64]) /* { dg-error "'inscan' 'reduction' clause on construct other than 'for', 'simd', 'for simd', 'parallel for', 'parallel for simd'" } */ for (i = 0; i < 64; i++) { diff --git a/gcc/testsuite/c-c++-common/gomp/scope-1.c b/gcc/testsuite/c-c++-common/gomp/scope-1.c new file mode 100644 index 0000000..ab7a778 --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/scope-1.c @@ -0,0 +1,39 @@ +int r, r2, r3; + +void +foo (void) +{ + int i = 0, j = 0, k = 0; + #pragma omp scope private (i) reduction (+:r) nowait + { + i = 1; + r++; + } + #pragma omp scope private (i) reduction (task, +:r) + #pragma omp scope private (j) reduction (task, +:r2) + #pragma omp scope private (k) reduction (task, +:r3) + { + i = 1; + j = 2; + k = 3; + r++; + r2++; + r3++; + } + #pragma omp parallel + { + #pragma omp scope reduction (+:r) private (i) nowait + { + #pragma omp scope reduction (+:r2) private (j) nowait + { + #pragma omp single + { + i = 1; + j = 2; + r++; + r2++; + } + } + } + } +} diff --git a/gcc/testsuite/c-c++-common/gomp/scope-2.c b/gcc/testsuite/c-c++-common/gomp/scope-2.c new file mode 100644 index 0000000..58517be --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/scope-2.c @@ -0,0 +1,41 @@ +int r, r2, r3 = 1; +int bar (void); + +void +foo (void) +{ + int i = 0, j = 0, k = 0; + #pragma omp parallel + { + if (bar ()) + { + #pragma omp cancel parallel + } + #pragma omp scope reduction (+:r) private (i) + { + #pragma omp scope reduction (+:r2) private (j) + { + #pragma omp single nowait + { + i = 1; + j = 2; + r++; + r2++; + } + } + } + } + #pragma omp parallel + { + if (bar ()) + { + #pragma omp cancel parallel + } + #pragma omp scope reduction (task, +:r) private (i) + #pragma omp scope reduction (task, *:r3) + { + r++; + r3++; + } + } +} diff --git a/gcc/testsuite/c-c++-common/modref-dse.c b/gcc/testsuite/c-c++-common/modref-dse.c new file mode 100644 index 0000000..5f64e8f --- /dev/null +++ b/gcc/testsuite/c-c++-common/modref-dse.c @@ -0,0 +1,38 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-dse2-details" } */ +/* { dg-final { scan-tree-dump-not "Deleted dead store" "dse2" } } */ + +struct foo { unsigned long bar; }; + +unsigned y; + +static int __attribute__ ((__noinline__, __noclone__)) +wrapped (struct foo *p, int i); + +static int wrapper (struct foo *p); + +static int __attribute__ ((__noclone__)) +wrapper (struct foo *p) { + return wrapped (p, 1); +} + +static int __attribute__ ((__noinline__, __noclone__)) +dind (struct foo **pp); + +int __attribute__ ((__noclone__, __no_reorder__)) +xfn () { + struct foo x = { 0xBADC0FFE }; + struct foo *p = &x; + return dind (&p); +} + +static int __attribute__ ((__noinline__, __no_reorder__)) +wrapped (struct foo *p, int i) { + return p->bar + i == y++; +} + +static int __attribute__ ((__noinline__, __noclone__, __no_reorder__)) +dind (struct foo **pp) { + wrapper (*pp); + return 0; +} diff --git a/gcc/testsuite/g++.dg/DRs/dr2082.C b/gcc/testsuite/g++.dg/DRs/dr2082.C new file mode 100644 index 0000000..84bb23f --- /dev/null +++ b/gcc/testsuite/g++.dg/DRs/dr2082.C @@ -0,0 +1,12 @@ +// DR 2082 + +void f() { + int i; + extern void h(int x = sizeof(i)); +} + +class A { + void f(A* p = this) { } // { dg-error "this" } +}; + +int h(int a, int b = sizeof(a)); diff --git a/gcc/testsuite/g++.dg/cpp0x/gen-attrs-58.C b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-58.C index f760f56..dc01722 100644 --- a/gcc/testsuite/g++.dg/cpp0x/gen-attrs-58.C +++ b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-58.C @@ -2,4 +2,4 @@ // { dg-do compile { target c++11 } } namespace N { int i; } -using namespace N alignas(int); // { dg-warning "ignored" } +alignas(int) using namespace N; // { dg-warning "ignored" } diff --git a/gcc/testsuite/g++.dg/cpp0x/gen-attrs-59.C b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-59.C index c7839fe..9776dc3 100644 --- a/gcc/testsuite/g++.dg/cpp0x/gen-attrs-59.C +++ b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-59.C @@ -2,4 +2,11 @@ // { dg-do compile { target c++11 } } namespace N {} -using namespace N alignas(X); // { dg-error "declared" } +alignas(X) using namespace N; // { dg-error "declared" } +namespace O {} +using namespace O alignas(X); // { dg-error "expected" } +// { dg-error "declared" "" { target *-*-* } .-1 } +// { dg-warning "attribute ignored" "" { target *-*-* } .-2 } +namespace P {} +using namespace P alignas(int); // { dg-error "expected" } +// { dg-warning "attribute ignored" "" { target *-*-* } .-1 } diff --git a/gcc/testsuite/g++.dg/cpp0x/gen-attrs-76.C b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-76.C index cbda8de..72cd4b3 100644 --- a/gcc/testsuite/g++.dg/cpp0x/gen-attrs-76.C +++ b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-76.C @@ -3,6 +3,7 @@ namespace N {} namespace O { typedef int T; }; +namespace P {} void foo () @@ -11,7 +12,8 @@ foo () [[]] __extension__ asm (""); // { dg-error "expected" } __extension__ [[]] asm (""); // { dg-error "expected" } [[]] namespace M = ::N; // { dg-error "expected" } - [[]] using namespace N; // { dg-bogus "expected" "" { xfail *-*-* } } + [[]] using namespace N; // { dg-bogus "expected" } + using namespace P [[]]; // { dg-error "expected" } [[]] using O::T; // { dg-error "expected" } [[]] __label__ foo; // { dg-error "expected" } [[]] static_assert (true, ""); // { dg-error "expected" } @@ -24,7 +26,8 @@ bar () [[gnu::unused]] __extension__ asm (""); // { dg-error "expected" } __extension__ [[gnu::unused]] asm (""); // { dg-error "expected" } [[gnu::unused]] namespace M = ::N; // { dg-error "expected" } - [[gnu::unused]] using namespace N; // { dg-bogus "expected" "" { xfail *-*-* } } + [[gnu::unused]] using namespace N; // { dg-bogus "expected" } + using namespace P [[gnu::unused]]; // { dg-error "expected" } [[gnu::unused]] using O::T; // { dg-error "expected" } [[gnu::unused]] __label__ foo; // { dg-error "expected" } [[gnu::unused]] static_assert (true, ""); // { dg-error "expected" } diff --git a/gcc/testsuite/g++.dg/cpp1z/class-deduction97.C b/gcc/testsuite/g++.dg/cpp1z/class-deduction97.C new file mode 100644 index 0000000..3281868 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1z/class-deduction97.C @@ -0,0 +1,6 @@ +// PR c++/89062 +// { dg-do compile { target c++17 } } + +template<class T> struct Foo { Foo(T); }; + +Foo<int> x(Foo{1}); diff --git a/gcc/testsuite/g++.dg/cpp1z/class-deduction98.C b/gcc/testsuite/g++.dg/cpp1z/class-deduction98.C new file mode 100644 index 0000000..bee0ce4 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1z/class-deduction98.C @@ -0,0 +1,10 @@ +// PR c++/79501 +// { dg-do compile { target c++17 } } + +template<class T> +struct A { + template<class U> struct B { template<class V> B(V); }; + B(T) -> B<T>; +}; + +A<int>::B b(0); diff --git a/gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr11.C b/gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr11.C new file mode 100644 index 0000000..c4806de --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr11.C @@ -0,0 +1,29 @@ +// PR c++/101344 +// { dg-do compile { target c++20 } } + +template<class T=void> +struct A { int m; int t[2]; }; + +A a1{1, {2, 3}}; // previously rejected +A a2{1, 2, 3}; + +struct B { int x, y; }; + +template<class T=void> +struct C { int m; struct { int x, y; } t; }; + +A b1{1, {2, 3}}; // previously rejected +A b2{1, 2, 3}; + +template<class T> +struct D { T t[2]; }; + +D d1{1, 2}; +D d2{{1, 2}}; // previously rejected + +template<class T> +struct E { T t[2][2]; }; + +E e1{1, 2, 3, 4}; +E e2{{{1, 2}, {3, 4}}}; // previously rejected +E e3{{1, 2, 3, 4}}; // { dg-error "deduction|no match" } diff --git a/gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr12.C b/gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr12.C new file mode 100644 index 0000000..ebe73c1 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr12.C @@ -0,0 +1,15 @@ +// PR c++/101820 +// { dg-do compile { target c++20 } } + +struct Inner { int i = 0; }; + +template <typename T = void> +struct Outer { Inner s{}; }; + +Outer o1{ .s = {} }; // works +Outer o2{ .s = Inner{ .i = 1} }; // works +Outer o3{ .s = { .i = 1} }; // does not + +Outer o4{ .s{} }; // works +Outer o5{ .s{Inner{ .i = 1} } }; // works +Outer o6{ .s{ .i = 1} }; // does not diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-uneval4.C b/gcc/testsuite/g++.dg/cpp2a/concepts-uneval4.C new file mode 100644 index 0000000..1be27d1 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-uneval4.C @@ -0,0 +1,12 @@ +// PR c++/101725 +// { dg-do compile { target c++20 } } + +template<class T, bool V = requires (T t) { x(t); }> void f(); + +struct A { + int m; + void f(int a, int b = requires (int t) { a + m + t; }); +}; + +void g(); +static_assert(noexcept(requires { g(); })); diff --git a/gcc/testsuite/g++.dg/cpp2a/constexpr-new14.C b/gcc/testsuite/g++.dg/cpp2a/constexpr-new14.C index fd6f607..2603739 100644 --- a/gcc/testsuite/g++.dg/cpp2a/constexpr-new14.C +++ b/gcc/testsuite/g++.dg/cpp2a/constexpr-new14.C @@ -1,65 +1,7 @@ // PR c++/97195 // { dg-do compile { target c++20 } } -namespace std -{ - typedef __SIZE_TYPE__ size_t; - - template <typename T> - struct allocator - { - constexpr allocator () noexcept {} - - constexpr T *allocate (size_t n) - { return static_cast<T *> (::operator new (n * sizeof(T))); } - - constexpr void - deallocate (T *p, size_t n) - { ::operator delete (p); } - }; - - template <typename T, typename U = T &&> - U __declval (int); - template <typename T> - T __declval (long); - template <typename T> - auto declval () noexcept -> decltype (__declval<T> (0)); - - template <typename T> - struct remove_reference - { typedef T type; }; - template <typename T> - struct remove_reference<T &> - { typedef T type; }; - template <typename T> - struct remove_reference<T &&> - { typedef T type; }; - - template <typename T> - constexpr T && - forward (typename std::remove_reference<T>::type &t) noexcept - { return static_cast<T&&> (t); } - - template<typename T> - constexpr T && - forward (typename std::remove_reference<T>::type &&t) noexcept - { return static_cast<T&&> (t); } - - template <typename T, typename... A> - constexpr auto - construct_at (T *l, A &&... a) - noexcept (noexcept (::new ((void *) 0) T (std::declval<A> ()...))) - -> decltype (::new ((void *) 0) T (std::declval<A> ()...)) - { return ::new ((void *) l) T (std::forward<A> (a)...); } - - template <typename T> - constexpr inline void - destroy_at (T *l) - { l->~T (); } -} - -inline void *operator new (std::size_t, void *p) noexcept -{ return p; } +#include "construct_at.h" constexpr bool foo () diff --git a/gcc/testsuite/g++.dg/cpp2a/constexpr-new20.C b/gcc/testsuite/g++.dg/cpp2a/constexpr-new20.C new file mode 100644 index 0000000..88bc442 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/constexpr-new20.C @@ -0,0 +1,18 @@ +// PR c++/101663 +// { dg-do compile { target c++20 } } + +#include "construct_at.h" + +template <typename _Tp> struct __box { + [[no_unique_address]] _Tp _M_value; +}; + +struct Empty {}; + +constexpr bool test() { + __box<Empty> a; + std::construct_at(&a._M_value); + return true; +} + +static_assert(test()); diff --git a/gcc/testsuite/g++.dg/cpp2a/constexpr-new5.C b/gcc/testsuite/g++.dg/cpp2a/constexpr-new5.C index 2bb407a..eeaee96 100644 --- a/gcc/testsuite/g++.dg/cpp2a/constexpr-new5.C +++ b/gcc/testsuite/g++.dg/cpp2a/constexpr-new5.C @@ -1,65 +1,7 @@ // P0784R7 // { dg-do compile { target c++20 } } -namespace std -{ - typedef __SIZE_TYPE__ size_t; - - template <typename T> - struct allocator - { - constexpr allocator () noexcept {} - - constexpr T *allocate (size_t n) - { return static_cast<T *> (::operator new (n * sizeof(T))); } - - constexpr void - deallocate (T *p, size_t n) - { ::operator delete (p); } - }; - - template <typename T, typename U = T &&> - U __declval (int); - template <typename T> - T __declval (long); - template <typename T> - auto declval () noexcept -> decltype (__declval<T> (0)); - - template <typename T> - struct remove_reference - { typedef T type; }; - template <typename T> - struct remove_reference<T &> - { typedef T type; }; - template <typename T> - struct remove_reference<T &&> - { typedef T type; }; - - template <typename T> - constexpr T && - forward (typename std::remove_reference<T>::type &t) noexcept - { return static_cast<T&&> (t); } - - template<typename T> - constexpr T && - forward (typename std::remove_reference<T>::type &&t) noexcept - { return static_cast<T&&> (t); } - - template <typename T, typename... A> - constexpr auto - construct_at (T *l, A &&... a) - noexcept (noexcept (::new ((void *) 0) T (std::declval<A> ()...))) - -> decltype (::new ((void *) 0) T (std::declval<A> ()...)) - { return ::new ((void *) l) T (std::forward<A> (a)...); } - - template <typename T> - constexpr inline void - destroy_at (T *l) - { l->~T (); } -} - -inline void *operator new (std::size_t, void *p) noexcept -{ return p; } +#include "construct_at.h" constexpr bool foo () diff --git a/gcc/testsuite/g++.dg/cpp2a/constexpr-new6.C b/gcc/testsuite/g++.dg/cpp2a/constexpr-new6.C index d51bdbb..eeaee96 100644 --- a/gcc/testsuite/g++.dg/cpp2a/constexpr-new6.C +++ b/gcc/testsuite/g++.dg/cpp2a/constexpr-new6.C @@ -1,69 +1,7 @@ // P0784R7 // { dg-do compile { target c++20 } } -namespace std -{ - inline namespace _8 { } - namespace _8 { - - typedef __SIZE_TYPE__ size_t; - - template <typename T> - struct allocator - { - constexpr allocator () noexcept {} - - constexpr T *allocate (size_t n) - { return static_cast<T *> (::operator new (n * sizeof(T))); } - - constexpr void - deallocate (T *p, size_t n) - { ::operator delete (p); } - }; - - template <typename T, typename U = T &&> - U __declval (int); - template <typename T> - T __declval (long); - template <typename T> - auto declval () noexcept -> decltype (__declval<T> (0)); - - template <typename T> - struct remove_reference - { typedef T type; }; - template <typename T> - struct remove_reference<T &> - { typedef T type; }; - template <typename T> - struct remove_reference<T &&> - { typedef T type; }; - - template <typename T> - constexpr T && - forward (typename std::remove_reference<T>::type &t) noexcept - { return static_cast<T&&> (t); } - - template<typename T> - constexpr T && - forward (typename std::remove_reference<T>::type &&t) noexcept - { return static_cast<T&&> (t); } - - template <typename T, typename... A> - constexpr auto - construct_at (T *l, A &&... a) - noexcept (noexcept (::new ((void *) 0) T (std::declval<A> ()...))) - -> decltype (::new ((void *) 0) T (std::declval<A> ()...)) - { return ::new ((void *) l) T (std::forward<A> (a)...); } - - template <typename T> - constexpr inline void - destroy_at (T *l) - { l->~T (); } - } -} - -inline void *operator new (std::size_t, void *p) noexcept -{ return p; } +#include "construct_at.h" constexpr bool foo () diff --git a/gcc/testsuite/g++.dg/cpp2a/constinit16.C b/gcc/testsuite/g++.dg/cpp2a/constinit16.C new file mode 100644 index 0000000..dda81d5 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/constinit16.C @@ -0,0 +1,21 @@ +// PR c++/101786 +// { dg-do compile { target c++20 } } +// { dg-add-options tls } +// { dg-require-alias "" } +// { dg-require-effective-target tls_runtime } +// { dg-final { scan-assembler-not "_ZTH17mythreadlocalvar1" } } +// { dg-final { scan-assembler "_ZTH17mythreadlocalvar2" } } +// { dg-final { scan-assembler-not "_ZTH17mythreadlocalvar3" } } +// { dg-final { scan-assembler "_ZTH17mythreadlocalvar4" } } + +extern thread_local constinit int mythreadlocalvar1; +struct S; +extern thread_local constinit S mythreadlocalvar2; +struct T { int t; }; +extern thread_local constinit T mythreadlocalvar3; +struct U { int u; ~U (); }; +extern thread_local constinit U mythreadlocalvar4; +int foo () { return mythreadlocalvar1; } +S *bar () { return &mythreadlocalvar2; } +T *baz () { return &mythreadlocalvar3; } +U *qux () { return &mythreadlocalvar4; } diff --git a/gcc/testsuite/g++.dg/cpp2a/construct_at.h b/gcc/testsuite/g++.dg/cpp2a/construct_at.h new file mode 100644 index 0000000..27e92cb --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/construct_at.h @@ -0,0 +1,62 @@ +// A minimal conforming implementation of std::construct_at/destroy_at, +// used by some C++20 constexpr tests to avoid including all of <memory>. + +namespace std +{ + typedef __SIZE_TYPE__ size_t; + + template <typename T> + struct allocator + { + constexpr allocator () noexcept {} + + constexpr T *allocate (size_t n) + { return static_cast<T *> (::operator new (n * sizeof(T))); } + + constexpr void + deallocate (T *p, size_t n) + { ::operator delete (p); } + }; + + template <typename T, typename U = T &&> + U __declval (int); + template <typename T> + T __declval (long); + template <typename T> + auto declval () noexcept -> decltype (__declval<T> (0)); + + template <typename T> + struct remove_reference + { typedef T type; }; + template <typename T> + struct remove_reference<T &> + { typedef T type; }; + template <typename T> + struct remove_reference<T &&> + { typedef T type; }; + + template <typename T> + constexpr T && + forward (typename std::remove_reference<T>::type &t) noexcept + { return static_cast<T&&> (t); } + + template<typename T> + constexpr T && + forward (typename std::remove_reference<T>::type &&t) noexcept + { return static_cast<T&&> (t); } + + template <typename T, typename... A> + constexpr auto + construct_at (T *l, A &&... a) + noexcept (noexcept (::new ((void *) 0) T (std::declval<A> ()...))) + -> decltype (::new ((void *) 0) T (std::declval<A> ()...)) + { return ::new ((void *) l) T (std::forward<A> (a)...); } + + template <typename T> + constexpr inline void + destroy_at (T *l) + { l->~T (); } +} + +inline void *operator new (std::size_t, void *p) noexcept +{ return p; } diff --git a/gcc/testsuite/g++.dg/cpp2a/is-corresponding-member1.C b/gcc/testsuite/g++.dg/cpp2a/is-corresponding-member1.C new file mode 100644 index 0000000..dd14c44 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/is-corresponding-member1.C @@ -0,0 +1,61 @@ +// P0466R5 +// { dg-do compile { target c++20 } } + +namespace std +{ +template <class S1, class S2, class M1, class M2> +constexpr bool +is_corresponding_member (M1 S1::*m1, M2 S2::*m2) noexcept +{ + return __builtin_is_corresponding_member (m1, m2); +} +} + +struct A { int a; }; +struct B { const int b; }; +struct C { int a; unsigned int b; int f; A c; int : 0; int d; double e; }; +struct D { const int x; unsigned int y; int g; B z; int u; double w; }; +struct E { int a; [[no_unique_address]] int b; }; +struct F { int c; const int d; }; +struct G { double a; int b; double c; }; +struct H { const volatile double d; int e : 16; double f; }; +struct I { const double g; int h : 15; const double i; }; +struct J : public A {}; +struct K {}; +struct L : public K, public B {}; +union U { int a; }; +struct V { void foo () {}; }; +struct W { int a; private: int b; public: int c; }; +struct Z : public A, public B {}; + +static_assert (std::is_corresponding_member (&A::a, &A::a)); +static_assert (std::is_corresponding_member (&A::a, &B::b)); +static_assert (std::is_corresponding_member (&C::a, &D::x)); +static_assert (std::is_corresponding_member (&C::b, &D::y)); +static_assert (std::is_corresponding_member (&C::f, &D::g)); +static_assert (std::is_corresponding_member (&C::c, &D::z)); +static_assert (!std::is_corresponding_member (&C::d, &D::u)); +static_assert (!std::is_corresponding_member (&C::e, &D::w)); +static_assert (!std::is_corresponding_member (&C::f, &D::x)); +static_assert (!std::is_corresponding_member (&C::a, &D::g)); +static_assert (std::is_corresponding_member (&E::a, &F::c)); +static_assert (!std::is_corresponding_member (&E::b, &F::d)); +static_assert (std::is_corresponding_member (&G::a, &H::d)); +static_assert (!std::is_corresponding_member (&G::c, &H::f)); +static_assert (std::is_corresponding_member (&H::d, &I::g)); +static_assert (!std::is_corresponding_member (&H::f, &I::i)); +static_assert (std::is_corresponding_member (&J::a, &B::b)); +static_assert (std::is_corresponding_member<J, B, int, const int> (&J::a, &B::b)); +static_assert (std::is_corresponding_member (&J::a, &L::b)); +static_assert (std::is_corresponding_member<J, L, int, const int> (&J::a, &L::b)); +static_assert (std::is_corresponding_member (&L::b, &B::b)); +static_assert (std::is_corresponding_member<L, B, const int, const int> (&L::b, &B::b)); +static_assert (!std::is_corresponding_member (&U::a, &U::a)); +static_assert (!std::is_corresponding_member (&A::a, (int A::*) nullptr)); +static_assert (!std::is_corresponding_member ((int A::*) nullptr, &A::a)); +static_assert (!std::is_corresponding_member ((int A::*) nullptr, (int A::*) nullptr)); +static_assert (!std::is_corresponding_member (&V::foo, &V::foo)); +static_assert (!std::is_corresponding_member (&W::a, &W::a)); +static_assert (!std::is_corresponding_member (&W::c, &W::c)); +static_assert (std::is_corresponding_member (&Z::a, &Z::b)); +static_assert (!std::is_corresponding_member<Z, Z, int, const int> (&Z::a, &Z::b)); diff --git a/gcc/testsuite/g++.dg/cpp2a/is-corresponding-member2.C b/gcc/testsuite/g++.dg/cpp2a/is-corresponding-member2.C new file mode 100644 index 0000000..1cedbcb --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/is-corresponding-member2.C @@ -0,0 +1,158 @@ +// P0466R5 +// { dg-do run { target c++20 } } + +namespace std +{ +template <class S1, class S2, class M1, class M2> +constexpr bool +is_corresponding_member (M1 S1::*m1, M2 S2::*m2) noexcept +{ + return __builtin_is_corresponding_member (m1, m2); +} +} + +struct A { int a; }; +struct B { const int b; }; +struct C { int a; unsigned int b; int f; A c; int : 0; int d; double e; }; +struct D { const int x; unsigned int y; int g; B z; int u; double w; }; +struct E { int a; [[no_unique_address]] int b; }; +struct F { int c; const int d; }; +struct G { double a; int b; double c; }; +struct H { const volatile double d; int e : 16; double f; }; +struct I { const double g; int h : 15; const double i; }; +struct J : public A {}; +struct K {}; +struct L : public K, public B {}; +union U { int a; }; +struct V { void foo () {}; }; +struct W { int a; private: int b; public: int c; }; +struct Z : public A, public B {}; + +int +main () +{ + auto t1 = &A::a; + auto t2 = &A::a; + if (!std::is_corresponding_member (t1, t2)) + __builtin_abort (); + auto t3 = &A::a; + auto t4 = &B::b; + if (!std::is_corresponding_member (t3, t4)) + __builtin_abort (); + auto t5 = &C::a; + auto t6 = &D::x; + if (!std::is_corresponding_member (t5, t6)) + __builtin_abort (); + auto t9 = &C::b; + auto t10 = &D::y; + if (!std::is_corresponding_member (t9, t10)) + __builtin_abort (); + auto t11 = &C::f; + auto t12 = &D::g; + if (!std::is_corresponding_member (t11, t12)) + __builtin_abort (); + auto t13 = &C::c; + auto t14 = &D::z; + if (!std::is_corresponding_member (t13, t14)) + __builtin_abort (); + auto t15 = &C::d; + auto t16 = &D::u; + if (std::is_corresponding_member (t15, t16)) + __builtin_abort (); + auto t17 = &C::e; + auto t18 = &D::w; + if (std::is_corresponding_member (t17, t18)) + __builtin_abort (); + auto t19 = &C::f; + auto t20 = &D::x; + if (std::is_corresponding_member (t19, t20)) + __builtin_abort (); + auto t21 = &C::a; + auto t22 = &D::g; + if (std::is_corresponding_member (t21, t22)) + __builtin_abort (); + auto t23 = &E::a; + auto t24 = &F::c; + if (!std::is_corresponding_member (t23, t24)) + __builtin_abort (); + auto t25 = &E::b; + auto t26 = &F::d; + if (std::is_corresponding_member (t25, t26)) + __builtin_abort (); + auto t27 = &G::a; + auto t28 = &H::d; + if (!std::is_corresponding_member (t27, t28)) + __builtin_abort (); + auto t29 = &G::c; + auto t30 = &H::f; + if (std::is_corresponding_member (t29, t30)) + __builtin_abort (); + auto t31 = &H::d; + auto t32 = &I::g; + if (!std::is_corresponding_member (t31, t32)) + __builtin_abort (); + auto t33 = &H::f; + auto t34 = &I::i; + if (std::is_corresponding_member (t33, t34)) + __builtin_abort (); + auto t35 = &J::a; + auto t36 = &B::b; + if (!std::is_corresponding_member (t35, t36)) + __builtin_abort (); + int J::*t37 = &J::a; + const int B::*t38 = &B::b; + if (!std::is_corresponding_member (t37, t38)) + __builtin_abort (); + auto t39 = &J::a; + auto t40 = &L::b; + if (!std::is_corresponding_member (t39, t40)) + __builtin_abort (); + int J::*t41 = &J::a; + const int L::*t42 = &L::b; + if (!std::is_corresponding_member (t41, t42)) + __builtin_abort (); + auto t43 = &L::b; + auto t44 = &B::b; + if (!std::is_corresponding_member (t43, t44)) + __builtin_abort (); + const int L::*t45 = &L::b; + const int B::*t46 = &B::b; + if (!std::is_corresponding_member (t45, t46)) + __builtin_abort (); + auto t47 = &U::a; + auto t48 = &U::a; + if (std::is_corresponding_member (t47, t48)) + __builtin_abort (); + auto t49 = &A::a; + auto t50 = (int A::*) nullptr; + if (std::is_corresponding_member (t49, t50)) + __builtin_abort (); + auto t51 = (int A::*) nullptr; + auto t52 = &A::a; + if (std::is_corresponding_member (t51, t52)) + __builtin_abort (); + auto t53 = (int A::*) nullptr; + auto t54 = (int A::*) nullptr; + if (std::is_corresponding_member (t53, t54)) + __builtin_abort (); + auto t55 = &V::foo; + auto t56 = &V::foo; + if (std::is_corresponding_member (t55, t56)) + __builtin_abort (); + auto t57 = &W::a; + auto t58 = &W::a; + if (std::is_corresponding_member (t57, t58)) + __builtin_abort (); + auto t59 = &W::c; + auto t60 = &W::c; + if (std::is_corresponding_member (t59, t60)) + __builtin_abort (); + auto t61 = &Z::a; + auto t62 = &Z::b; + if (!std::is_corresponding_member (t61, t62)) + __builtin_abort (); + int Z::*t63 = &Z::a; + const int Z::*t64 = &Z::b; + if (std::is_corresponding_member (t63, t64)) + __builtin_abort (); +} diff --git a/gcc/testsuite/g++.dg/cpp2a/is-corresponding-member3.C b/gcc/testsuite/g++.dg/cpp2a/is-corresponding-member3.C new file mode 100644 index 0000000..1ff510c --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/is-corresponding-member3.C @@ -0,0 +1,14 @@ +// P0466R5 +// { dg-do compile { target c++20 } } + +struct A { int a; }; +struct B; + +bool a = __builtin_is_corresponding_member (); // { dg-error "needs two arguments" } +bool b = __builtin_is_corresponding_member (&A::a); // { dg-error "needs two arguments" } +bool c = __builtin_is_corresponding_member (&A::a, &A::a, &A::a); // { dg-error "needs two arguments" } +bool d = __builtin_is_corresponding_member (&A::a, 1); // { dg-error "argument is not pointer to member" } +bool e = __builtin_is_corresponding_member (1.0, &A::a); // { dg-error "argument is not pointer to member" } +bool f = __builtin_is_corresponding_member (1, A{}); // { dg-error "argument is not pointer to member" } +bool g = __builtin_is_corresponding_member (&A::a, (int B::*) nullptr); // { dg-error "invalid use of incomplete type" } +bool h = __builtin_is_corresponding_member ((int B::*) nullptr, &A::a); // { dg-error "invalid use of incomplete type" } diff --git a/gcc/testsuite/g++.dg/cpp2a/is-corresponding-member4.C b/gcc/testsuite/g++.dg/cpp2a/is-corresponding-member4.C new file mode 100644 index 0000000..6b74090 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/is-corresponding-member4.C @@ -0,0 +1,25 @@ +// P0466R5 +// { dg-do compile { target c++20 } } + +namespace std +{ +template <class S1, class S2, class M1, class M2> +constexpr bool +is_corresponding_member (M1 S1::*m1, M2 S2::*m2) noexcept +{ + return __builtin_is_corresponding_member (m1, m2); // { dg-error "invalid use of incomplete type 'struct B'" } +} +} + +struct A { int a; }; +struct B; +constexpr int B::*n = nullptr; +constexpr auto a = std::is_corresponding_member (&A::a, n); // { dg-error "invalid use of incomplete type 'struct B'" } +constexpr auto b = std::is_corresponding_member (n, &A::a); // { dg-error "invalid use of incomplete type 'struct B'" } + +void +foo (int B::*m) +{ + std::is_corresponding_member (&A::a, m); + std::is_corresponding_member (m, &A::a); +} diff --git a/gcc/testsuite/g++.dg/cpp2a/is-corresponding-member5.C b/gcc/testsuite/g++.dg/cpp2a/is-corresponding-member5.C new file mode 100644 index 0000000..b956309 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/is-corresponding-member5.C @@ -0,0 +1,95 @@ +// P0466R5 +// { dg-do run { target c++20 } } + +namespace std +{ +template <class S1, class S2, class M1, class M2> +constexpr bool +is_corresponding_member (M1 S1::*m1, M2 S2::*m2) noexcept +{ + return __builtin_is_corresponding_member (m1, m2); +} +} + +struct S {}; +struct T {}; +struct I { int a; }; +struct alignas(16) J { const int b; }; +struct K { char b; char s[15]; I c; short d; }; +struct L { char d; char t[15]; J e; short f; }; +struct U { int a0; [[no_unique_address]] S a1; [[no_unique_address]] S a2; [[no_unique_address]] S a3; short a4; }; +struct V { int b0; [[no_unique_address]] S b1; [[no_unique_address]] T b2; [[no_unique_address]] S b3; short b4; }; +struct U1 { int a0; [[no_unique_address]] S a1; [[no_unique_address]] S a2; [[no_unique_address]] S a3; short a4; }; +struct V1 { int b0; [[no_unique_address]] S b1; [[no_unique_address]] T b2; [[no_unique_address]] S b3; short b4; }; +struct A { int a; union { short b; long c; }; int d; signed char e; int f; }; +struct B { const int a; union { signed long b; short c; }; volatile int d; unsigned char e; int f; }; +struct A1 { int a; union { short b; long c; }; int d; short e; int f; }; +struct B1 { const int a; union { signed long b; short c; }; volatile int d; unsigned short e; int f; }; + +static_assert (std::is_corresponding_member (&I::a, &J::b)); +static_assert (std::is_corresponding_member (&K::b, &L::d)); +static_assert (!std::is_corresponding_member (&K::c, &L::e)); +static_assert (std::is_corresponding_member (&U::a0, &V::b0)); +static_assert (!std::is_corresponding_member (&U::a4, &V::b4)); +static_assert (std::is_corresponding_member (&A::a, &B::a)); +static_assert (std::is_corresponding_member (&A::d, &B::d)); +static_assert (!std::is_corresponding_member (&A::e, &B::e)); +static_assert (!std::is_corresponding_member (&A::f, &B::f)); +static_assert (!std::is_corresponding_member (&A::a, &B::f)); +static_assert (!std::is_corresponding_member (&A::d, &B::a)); +static_assert (!std::is_corresponding_member (&A::a, &B::d)); +static_assert (!std::is_corresponding_member (&A::f, &B::a)); +static_assert (!std::is_corresponding_member (&A1::e, &B1::e)); + +int +main () +{ + auto t1 = &I::a; + auto t2 = &J::b; + if (!std::is_corresponding_member (t1, t2)) + __builtin_abort (); + auto t3 = &K::b; + auto t4 = &L::d; + if (!std::is_corresponding_member (t3, t4)) + __builtin_abort (); + auto t5 = &K::c; + auto t6 = &L::e; + if (std::is_corresponding_member (t5, t6)) + __builtin_abort (); + auto t7 = &U::a0; + auto t8 = &V::b0; + if (!std::is_corresponding_member (t7, t8)) + __builtin_abort (); + auto t9 = &U::a4; + auto t10 = &V::b4; + if (std::is_corresponding_member (t9, t10)) + __builtin_abort (); + auto t11 = &A::a; + auto t12 = &B::a; + auto t13 = &A::d; + auto t14 = &B::d; + auto t15 = &A::e; + auto t16 = &B::e; + auto t17 = &A::f; + auto t18 = &B::f; + if (!std::is_corresponding_member (t11, t12)) + __builtin_abort (); + if (!std::is_corresponding_member (t13, t14)) + __builtin_abort (); + if (std::is_corresponding_member (t15, t16)) + __builtin_abort (); + if (std::is_corresponding_member (t17, t18)) + __builtin_abort (); + if (std::is_corresponding_member (t11, t18)) + __builtin_abort (); + if (std::is_corresponding_member (t13, t12)) + __builtin_abort (); + if (std::is_corresponding_member (t11, t14)) + __builtin_abort (); + if (std::is_corresponding_member (t17, t12)) + __builtin_abort (); + auto t19 = &A1::e; + auto t20 = &B1::e; + if (std::is_corresponding_member (t19, t20)) + __builtin_abort (); +} diff --git a/gcc/testsuite/g++.dg/cpp2a/is-corresponding-member6.C b/gcc/testsuite/g++.dg/cpp2a/is-corresponding-member6.C new file mode 100644 index 0000000..e4f53bb --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/is-corresponding-member6.C @@ -0,0 +1,34 @@ +// P0466R5 +// { dg-do compile { target c++20 } } + +namespace std +{ +template <class S1, class S2, class M1, class M2> +constexpr bool +is_corresponding_member (M1 S1::*m1, M2 S2::*m2) noexcept +{ + return __builtin_is_corresponding_member (m1, m2); +} +// { dg-message "'__builtin_is_corresponding_member' not well defined for anonymous unions" "" { target *-*-* } .-2 } +} + +struct S {}; +struct T {}; +struct I { int a; }; +struct alignas(16) J { const int b; }; +struct K { char b; char s[15]; alignas(16) I c; short d; }; +struct L { char d; char t[15]; J e; short f; }; +struct U { int a0; [[no_unique_address]] S a1; [[no_unique_address]] S a2; [[no_unique_address]] S a3; short a4; }; +struct V { int b0; [[no_unique_address]] S b1; [[no_unique_address]] T b2; [[no_unique_address]] S b3; short b4; }; +struct U1 { int a0; [[no_unique_address]] S a1; [[no_unique_address]] S a2; [[no_unique_address]] S a3; short a4; }; +struct V1 { int b0; [[no_unique_address]] S b1; [[no_unique_address]] T b2; [[no_unique_address]] S b3; short b4; }; +struct A { int a; union { short b; long c; }; int d; signed char e; int f; }; +struct B { const int a; union { signed long b; short c; }; volatile int d; unsigned char e; int f; }; + +static_assert (!std::is_corresponding_member (&K::d, &L::f)); +static_assert (std::is_corresponding_member (&U::a1, &V::b1)); +static_assert (!std::is_corresponding_member (&U::a2, &V::b2)); +static_assert (!std::is_corresponding_member (&U::a3, &V::b3)); +static_assert (!std::is_corresponding_member (&U1::a3, &V1::b3)); +static_assert (!std::is_corresponding_member (&A::b, &B::c)); +constexpr auto a = std::is_corresponding_member (&A::c, &B::b); // { dg-message "required from here" } diff --git a/gcc/testsuite/g++.dg/cpp2a/is-corresponding-member7.C b/gcc/testsuite/g++.dg/cpp2a/is-corresponding-member7.C new file mode 100644 index 0000000..602ca01 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/is-corresponding-member7.C @@ -0,0 +1,71 @@ +// P0466R5 +// { dg-do run { target c++20 } } +// { dg-options "" } + +namespace std +{ +template <class S1, class S2, class M1, class M2> +constexpr bool +is_corresponding_member (M1 S1::*m1, M2 S2::*m2) noexcept +{ + return __builtin_is_corresponding_member (m1, m2); +} +} + +struct A { int a; struct { int b; short c; long d; }; int : 0; int e; }; +struct B { const signed int a; struct { int b; signed short c; signed long d; }; volatile int e; }; +struct C { int a; union { struct { short b; long c; }; long d; short e; }; signed int f; }; +struct D { int a; union { long b; short c; struct { short d; signed long e; }; }; int f; }; + +static_assert (std::is_corresponding_member (&A::a, &B::a)); +static_assert (std::is_corresponding_member (&A::b, &B::b)); +static_assert (std::is_corresponding_member (&A::c, &B::c)); +static_assert (std::is_corresponding_member (&A::d, &B::d)); +static_assert (!std::is_corresponding_member (&A::e, &B::e)); +static_assert (!std::is_corresponding_member (&A::a, &B::b)); +static_assert (!std::is_corresponding_member (&A::b, &B::a)); +static_assert (std::is_corresponding_member (&C::a, &D::a)); +static_assert (std::is_corresponding_member (&C::f, &D::f)); +static_assert (!std::is_corresponding_member (&C::a, &D::f)); +static_assert (!std::is_corresponding_member (&C::f, &D::a)); + +int +main () +{ + auto t1 = &A::a; + auto t2 = &B::a; + auto t3 = &A::b; + auto t4 = &B::b; + auto t5 = &A::c; + auto t6 = &B::c; + auto t7 = &A::d; + auto t8 = &B::d; + auto t9 = &A::e; + auto t10 = &B::e; + if (!std::is_corresponding_member (t1, t2)) + __builtin_abort (); + if (!std::is_corresponding_member (t3, t4)) + __builtin_abort (); + if (!std::is_corresponding_member (t5, t6)) + __builtin_abort (); + if (!std::is_corresponding_member (t7, t8)) + __builtin_abort (); + if (std::is_corresponding_member (t9, t10)) + __builtin_abort (); + if (std::is_corresponding_member (t1, t4)) + __builtin_abort (); + if (std::is_corresponding_member (t3, t2)) + __builtin_abort (); + auto t11 = &C::a; + auto t12 = &D::a; + auto t13 = &C::f; + auto t14 = &D::f; + if (!std::is_corresponding_member (t11, t12)) + __builtin_abort (); + if (!std::is_corresponding_member (t13, t14)) + __builtin_abort (); + if (std::is_corresponding_member (t11, t14)) + __builtin_abort (); + if (std::is_corresponding_member (t13, t12)) + __builtin_abort (); +} diff --git a/gcc/testsuite/g++.dg/cpp2a/is-corresponding-member8.C b/gcc/testsuite/g++.dg/cpp2a/is-corresponding-member8.C new file mode 100644 index 0000000..1a33908 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/is-corresponding-member8.C @@ -0,0 +1,25 @@ +// P0466R5 +// { dg-do compile { target c++20 } } +// { dg-options "" } + +namespace std +{ +template <class S1, class S2, class M1, class M2> +constexpr bool +is_corresponding_member (M1 S1::*m1, M2 S2::*m2) noexcept +{ + return __builtin_is_corresponding_member (m1, m2); +} +// { dg-message "'__builtin_is_corresponding_member' not well defined for anonymous unions" "" { target *-*-* } .-2 } +} + +struct A { int a; struct { short b; short c; long d; }; int : 0; int e; }; +struct B { const signed int a; struct alignas(16) { short b; signed short c; signed long d; }; volatile int e; }; +struct C { int a; union { struct { int b; long c; }; long d; short e; }; signed int f; }; +struct D { int a; union { long b; short c; struct { int d; signed long e; }; }; int f; }; + +static_assert (std::is_corresponding_member (&A::a, &B::a)); +static_assert (!std::is_corresponding_member (&A::b, &B::b)); +static_assert (!std::is_corresponding_member (&A::c, &B::c)); +static_assert (!std::is_corresponding_member (&A::d, &B::d)); +auto a = std::is_corresponding_member (&C::a, &D::a); // { dg-message "required from here" } diff --git a/gcc/testsuite/g++.dg/cpp2a/is-layout-compatible1.C b/gcc/testsuite/g++.dg/cpp2a/is-layout-compatible1.C new file mode 100644 index 0000000..dbc2a9a --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/is-layout-compatible1.C @@ -0,0 +1,80 @@ +// P0466R5 +// { dg-do compile { target c++20 } } + +namespace std +{ +template <typename T, T v> +struct integral_constant +{ + static constexpr T value = v; +}; + +template <typename, typename> +struct is_layout_compatible; + +template<typename T, typename U> +struct is_layout_compatible + : public integral_constant <bool, __is_layout_compatible (T, U)> +{ +}; + +template <typename T, typename U> +inline constexpr bool is_layout_compatible_v = __is_layout_compatible (T, U); +} + +struct A { int a; char b; }; +struct B { const int c; volatile char d; }; +struct C { int a : 1; int : 7; int : 0; int b : 2; }; +struct D { int : 1; int c : 7; int : 0; int : 2; }; +struct E { int f : 1; int : 7; int g : 2; }; +struct F { int a; signed char b; }; +union G { int a; long long b; signed char c; unsigned char d; int e; }; +union H { long long f; unsigned char g; int h; int i; signed char j; }; +struct I : public A {}; +struct J {}; +struct K : public J {}; +struct L {}; +struct M : public K, L { const int a; volatile char b; }; +struct N {}; +struct O : public N, M {}; +struct P { int a; private: int b; public: int c; }; +struct Q { int a; private: int b; public: int c; }; +union U1 { int a; private: int b; public: int c; }; +union U2 { int a; private: int b; public: int c; }; +struct S {}; +struct T {}; +struct W; +struct X; +enum E1 : int { E11, E12 }; +enum E2 : int { E21, E22 }; +enum E3 : long { E31, E32 }; +enum E4 { E41, E42 }; +enum E5 { E51, E52 }; + +static_assert (std::is_layout_compatible<int, const int>::value); +static_assert (std::is_layout_compatible_v<double, volatile double>); +static_assert (std::is_layout_compatible_v<A, B>); +static_assert (std::is_layout_compatible_v<C, D>); +static_assert (!std::is_layout_compatible_v<int, unsigned int>); +static_assert (!std::is_layout_compatible_v<A, F>); +static_assert (std::is_layout_compatible_v<G, H>); +static_assert (std::is_layout_compatible_v<S, T>); +static_assert (std::is_layout_compatible_v<A[3], A[3]>); +static_assert (std::is_layout_compatible_v<A[], A[]>); +static_assert (!std::is_layout_compatible_v<S[1], T[1]>); +static_assert (std::is_layout_compatible_v<W[], W[]>); +static_assert (!std::is_layout_compatible_v<W[], X[]>); +static_assert (!std::is_layout_compatible_v<D, E>); +static_assert (std::is_layout_compatible_v<void, const void>); +static_assert (std::is_layout_compatible_v<I, const A>); +static_assert (std::is_layout_compatible_v<volatile A, const I>); +static_assert (std::is_layout_compatible_v<M, A>); +static_assert (std::is_layout_compatible_v<O, M>); +static_assert (std::is_layout_compatible_v<A, O>); +static_assert (std::is_layout_compatible_v<P, P>); +static_assert (!std::is_layout_compatible_v<P, Q>); +static_assert (std::is_layout_compatible_v<U1, U1>); +static_assert (!std::is_layout_compatible_v<U1, U2>); +static_assert (std::is_layout_compatible_v<E1, E2>); +static_assert (!std::is_layout_compatible_v<E1, E3>); +static_assert (std::is_layout_compatible_v<E4, E5>); diff --git a/gcc/testsuite/g++.dg/cpp2a/is-layout-compatible2.C b/gcc/testsuite/g++.dg/cpp2a/is-layout-compatible2.C new file mode 100644 index 0000000..bf902f3 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/is-layout-compatible2.C @@ -0,0 +1,36 @@ +// P0466R5 +// { dg-do compile { target c++20 } } + +namespace std +{ +template <typename T, T v> +struct integral_constant +{ + static constexpr T value = v; +}; + +template <typename, typename> +struct is_layout_compatible; + +template<typename T, typename U> +struct is_layout_compatible + : public integral_constant <bool, __is_layout_compatible (T, U)> +{ +}; + +template <typename T, typename U> +inline constexpr bool is_layout_compatible_v = __is_layout_compatible (T, U); +} +// { dg-error "invalid use of incomplete type 'struct W'" "" { target *-*-* } .-2 } +// { dg-error "invalid use of incomplete type 'struct \[XY]'" "" { target *-*-* } .-3 } +// { dg-error "invalid use of incomplete type 'struct Z'" "" { target *-*-* } .-4 } + +struct W; +struct X; +struct Y; +struct Z; +struct A {}; + +auto a = std::is_layout_compatible_v<W, W>; +auto b = std::is_layout_compatible_v<X, Y>; +auto c = std::is_layout_compatible_v<A, Z>; diff --git a/gcc/testsuite/g++.dg/cpp2a/is-layout-compatible3.C b/gcc/testsuite/g++.dg/cpp2a/is-layout-compatible3.C new file mode 100644 index 0000000..c548587 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/is-layout-compatible3.C @@ -0,0 +1,64 @@ +// P0466R5 +// { dg-do compile { target c++20 } } + +namespace std +{ +template <typename T, T v> +struct integral_constant +{ + static constexpr T value = v; +}; + +template <typename, typename> +struct is_layout_compatible; + +template<typename T, typename U> +struct is_layout_compatible + : public integral_constant <bool, __is_layout_compatible (T, U)> +{ +}; + +template <typename T, typename U> +inline constexpr bool is_layout_compatible_v = __is_layout_compatible (T, U); +} + +// Weird cases. +struct S {}; +struct T {}; +struct I { int a; }; +struct alignas(16) J { const int b; }; +struct K { I c; int d; }; +struct L { J e; int f; }; +union M { I u; }; +union N { J v; }; +union O { int a; int b; }; +union P { int a : 1; int b : 12; }; +enum Q : int { Q1, Q2 }; +enum alignas(16) R : int { R1, R2 }; +struct U { [[no_unique_address]] S a1; [[no_unique_address]] S a2; [[no_unique_address]] S a3; }; +struct V { [[no_unique_address]] S b1; [[no_unique_address]] T b2; [[no_unique_address]] S b3; }; +struct alignas(16) A : public I {}; +struct alignas(16) B {}; +struct C : public B, public I {}; +union D { int a : 3; int b : 9; }; +struct alignas(16) E { alignas(16) int a; alignas(16) int b; }; +struct alignas(16) F { int c; alignas(16) int d; }; +union alignas(16) G { int a; alignas(16) short b; }; +union alignas(16) H { short c; int d; }; +struct A1 { int a; }; +struct B1 { signed int b; }; +struct alignas (16) C1 : public A1 {}; +struct alignas (16) D1 : public B1 {}; + +static_assert (!std::is_layout_compatible_v<I, J>); +static_assert (!std::is_layout_compatible_v<K, L>); +static_assert (!std::is_layout_compatible_v<M, N>); +static_assert (!std::is_layout_compatible_v<O, P>); +static_assert (!std::is_layout_compatible_v<P, D>); +static_assert (!std::is_layout_compatible_v<Q, R>); +static_assert (!std::is_layout_compatible_v<U, V>); +static_assert (!std::is_layout_compatible_v<A, I>); +static_assert (!std::is_layout_compatible_v<C, I>); +static_assert (std::is_layout_compatible_v<E, F>); +static_assert (std::is_layout_compatible_v<G, H>); +static_assert (std::is_layout_compatible_v<C1, D1>); diff --git a/gcc/testsuite/g++.dg/cpp2a/nontype-class49.C b/gcc/testsuite/g++.dg/cpp2a/nontype-class49.C new file mode 100644 index 0000000..c83e407 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/nontype-class49.C @@ -0,0 +1,8 @@ +// PR c++/101883 +// { dg-do compile { target c++20 } } + +template<class T> struct C { constexpr C(int) { } }; +explicit C(int) -> C<int>; + +template<C c> struct X { }; +X<1> x; // { dg-error "deduction|no match" } diff --git a/gcc/testsuite/g++.dg/cpp2a/spaceship-synth-neg6.C b/gcc/testsuite/g++.dg/cpp2a/spaceship-synth-neg6.C new file mode 100644 index 0000000..d3f95e1 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/spaceship-synth-neg6.C @@ -0,0 +1,11 @@ +// PR c++/94162 +// { dg-do compile { target c++20 } } + +#include <compare> + +struct S { + int a; // { dg-error "three-way comparison of 'S::a' has type 'std::strong_ordering', which does not convert to 'int\\*'" } + int *operator<=>(const S&) const = default; +}; + +bool b = S{} < S{}; // { dg-error "use of deleted function 'constexpr int\\* S::operator<=>\\\(const S&\\\) const'" } diff --git a/gcc/testsuite/g++.dg/cpp2a/spaceship-synth11.C b/gcc/testsuite/g++.dg/cpp2a/spaceship-synth11.C new file mode 100644 index 0000000..37c8157 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/spaceship-synth11.C @@ -0,0 +1,29 @@ +// PR c++/99429 +// { dg-do compile { target c++20 } } + +namespace std { +struct strong_ordering { + int _v; + constexpr strong_ordering (int v) :_v(v) {} + constexpr operator int (void) const { return _v; } + static const strong_ordering less; + static const strong_ordering equal; + static const strong_ordering greater; +}; +constexpr strong_ordering strong_ordering::less = -1; +constexpr strong_ordering strong_ordering::equal = 0; +constexpr strong_ordering strong_ordering::greater = 1; +} + +template <unsigned long N> +struct duration { + static constexpr const long period = N; + constexpr duration (void) = default; + constexpr duration (const duration& d) = default; + constexpr bool operator== (const duration& d) const = default; + constexpr bool operator<=> (const duration& d) const = default; + long _d; +}; + +using nanoseconds = duration<1>; +using microseconds = duration<nanoseconds::period * 1000>; diff --git a/gcc/testsuite/g++.dg/gomp/attrs-1.C b/gcc/testsuite/g++.dg/gomp/attrs-1.C index 6bbdcac..435d54f 100644 --- a/gcc/testsuite/g++.dg/gomp/attrs-1.C +++ b/gcc/testsuite/g++.dg/gomp/attrs-1.C @@ -111,6 +111,7 @@ void bar (int d, int m, int i1, int i2, int i3, int p, int *idp, int s, int nte, int tl, int nth, int g, int nta, int fi, int pp, int *q, int *dd, int ntm) { + [[omp::directive (nothing)]]; [[omp::directive (for simd private (p) firstprivate (f) lastprivate (l) linear (ll:1) reduction(+:r) schedule(static, 4) collapse(1) nowait safelen(8) simdlen(4) aligned(q: 32) nontemporal(ntm) if(i1) order(concurrent) allocate (f))]] @@ -348,6 +349,10 @@ bar (int d, int m, int i1, int i2, int i3, int p, int *idp, int s, private (p) firstprivate (f) if (parallel: i2) default(shared) shared(s) reduction(+:r) num_threads (nth) proc_bind(spread) copyin(t) allocate (f))]] ; + [[omp::directive (parallel masked + private (p) firstprivate (f) if (parallel: i2) default(shared) shared(s) reduction(+:r) + num_threads (nth) proc_bind(spread) copyin(t) allocate (f) filter (d))]] + ; [[omp::directive (parallel private (p) firstprivate (f) if (parallel: i2) default(shared) shared(s) reduction(+:r) num_threads (nth) proc_bind(spread) copyin(t) allocate (f))]] @@ -358,7 +363,15 @@ bar (int d, int m, int i1, int i2, int i3, int p, int *idp, int s, reduction(default, +:r) in_reduction(+:r2) allocate (f)))]] for (int i = 0; i < 64; i++) ll++; + [[omp::sequence (directive (taskgroup task_reduction (+:r2) allocate (r2)), + omp::directive (masked taskloop + private (p) firstprivate (f) lastprivate (l) shared (s) default(shared) grainsize (g) collapse(1) untied if(taskloop: i1) final(fi) mergeable priority (pp) + reduction(default, +:r) in_reduction(+:r2) allocate (f) filter (d)))]] + for (int i = 0; i < 64; i++) + ll++; [[omp::directive (master)]]; + [[omp::directive (masked)]]; + [[omp::directive (masked filter (d))]]; [[omp::sequence (omp::directive (taskgroup task_reduction (+:r2) allocate (r2)), directive (master taskloop simd private (p) firstprivate (f) lastprivate (l) shared (s) default(shared) grainsize (g) collapse(1) untied if(taskloop: i1) if(simd: i2) final(fi) mergeable priority (pp) @@ -366,23 +379,47 @@ bar (int d, int m, int i1, int i2, int i3, int p, int *idp, int s, order(concurrent) allocate (f)))]] for (int i = 0; i < 64; i++) ll++; + [[omp::sequence (omp::directive (taskgroup task_reduction (+:r2) allocate (r2)), + directive (masked taskloop simd + private (p) firstprivate (f) lastprivate (l) shared (s) default(shared) grainsize (g) collapse(1) untied if(taskloop: i1) if(simd: i2) final(fi) mergeable priority (pp) + safelen(8) simdlen(4) linear(ll: 1) aligned(q: 32) reduction(default, +:r) in_reduction(+:r2) nontemporal(ntm) + order(concurrent) allocate (f) filter (d)))]] + for (int i = 0; i < 64; i++) + ll++; [[omp::directive (parallel master taskloop private (p) firstprivate (f) lastprivate (l) shared (s) default(shared) grainsize (g) collapse(1) untied if(taskloop: i1) final(fi) mergeable priority (pp) reduction(default, +:r) if (parallel: i2) num_threads (nth) proc_bind(spread) copyin(t) allocate (f))]] for (int i = 0; i < 64; i++) ll++; + [[omp::directive (parallel masked taskloop + private (p) firstprivate (f) lastprivate (l) shared (s) default(shared) grainsize (g) collapse(1) untied if(taskloop: i1) final(fi) mergeable priority (pp) + reduction(default, +:r) if (parallel: i2) num_threads (nth) proc_bind(spread) copyin(t) allocate (f) filter (d))]] + for (int i = 0; i < 64; i++) + ll++; [[omp::directive (parallel master taskloop simd private (p) firstprivate (f) lastprivate (l) shared (s) default(shared) grainsize (g) collapse(1) untied if(taskloop: i1) if(simd: i2) final(fi) mergeable priority (pp) safelen(8) simdlen(4) linear(ll: 1) aligned(q: 32) reduction(default, +:r) nontemporal(ntm) if (parallel: i2) num_threads (nth) proc_bind(spread) copyin(t) order(concurrent) allocate (f))]] for (int i = 0; i < 64; i++) ll++; + [[omp::directive (parallel masked taskloop simd + private (p) firstprivate (f) lastprivate (l) shared (s) default(shared) grainsize (g) collapse(1) untied if(taskloop: i1) if(simd: i2) final(fi) mergeable priority (pp) + safelen(8) simdlen(4) linear(ll: 1) aligned(q: 32) reduction(default, +:r) nontemporal(ntm) if (parallel: i2) num_threads (nth) proc_bind(spread) copyin(t) + order(concurrent) allocate (f) filter (d))]] + for (int i = 0; i < 64; i++) + ll++; [[omp::sequence (directive (taskgroup task_reduction (+:r2) allocate (r2)), directive (master taskloop private (p) firstprivate (f) lastprivate (l) shared (s) default(shared) num_tasks (nta) collapse(1) untied if(i1) final(fi) mergeable priority (pp) reduction(default, +:r) in_reduction(+:r2)))]] for (int i = 0; i < 64; i++) ll++; + [[omp::sequence (directive (taskgroup task_reduction (+:r2) allocate (r2)), + directive (masked taskloop + private (p) firstprivate (f) lastprivate (l) shared (s) default(shared) num_tasks (nta) collapse(1) untied if(i1) final(fi) mergeable priority (pp) + reduction(default, +:r) in_reduction(+:r2) filter (d)))]] + for (int i = 0; i < 64; i++) + ll++; [[omp::sequence (omp::directive (taskgroup task_reduction (+:r2) allocate (r2)), omp::directive (master taskloop simd private (p) firstprivate (f) lastprivate (l) shared (s) default(shared) num_tasks (nta) collapse(1) untied if(i1) final(fi) mergeable priority (pp) @@ -390,17 +427,35 @@ bar (int d, int m, int i1, int i2, int i3, int p, int *idp, int s, order(concurrent) allocate (f)))]] for (int i = 0; i < 64; i++) ll++; + [[omp::sequence (omp::directive (taskgroup task_reduction (+:r2) allocate (r2)), + omp::directive (masked taskloop simd + private (p) firstprivate (f) lastprivate (l) shared (s) default(shared) num_tasks (nta) collapse(1) untied if(i1) final(fi) mergeable priority (pp) + safelen(8) simdlen(4) linear(ll: 1) aligned(q: 32) reduction(default, +:r) in_reduction(+:r2) nontemporal(ntm) + order(concurrent) allocate (f) filter (d)))]] + for (int i = 0; i < 64; i++) + ll++; [[omp::directive (parallel master taskloop private (p) firstprivate (f) lastprivate (l) shared (s) default(shared) num_tasks (nta) collapse(1) untied if(i1) final(fi) mergeable priority (pp) reduction(default, +:r) num_threads (nth) proc_bind(spread) copyin(t) allocate (f))]] for (int i = 0; i < 64; i++) ll++; + [[omp::directive (parallel masked taskloop + private (p) firstprivate (f) lastprivate (l) shared (s) default(shared) num_tasks (nta) collapse(1) untied if(i1) final(fi) mergeable priority (pp) + reduction(default, +:r) num_threads (nth) proc_bind(spread) copyin(t) allocate (f) filter (d))]] + for (int i = 0; i < 64; i++) + ll++; [[omp::directive (parallel master taskloop simd private (p) firstprivate (f) lastprivate (l) shared (s) default(shared) num_tasks (nta) collapse(1) untied if(i1) final(fi) mergeable priority (pp) safelen(8) simdlen(4) linear(ll: 1) aligned(q: 32) reduction(default, +:r) nontemporal(ntm) num_threads (nth) proc_bind(spread) copyin(t) order(concurrent) allocate (f))]] for (int i = 0; i < 64; i++) ll++; + [[omp::directive (parallel masked taskloop simd + private (p) firstprivate (f) lastprivate (l) shared (s) default(shared) num_tasks (nta) collapse(1) untied if(i1) final(fi) mergeable priority (pp) + safelen(8) simdlen(4) linear(ll: 1) aligned(q: 32) reduction(default, +:r) nontemporal(ntm) num_threads (nth) proc_bind(spread) copyin(t) + order(concurrent) allocate (f) filter (d))]] + for (int i = 0; i < 64; i++) + ll++; [[omp::directive (loop bind(thread) order(concurrent) private (p) lastprivate (l) collapse(1) reduction(+:r))]] for (l = 0; l < 64; ++l) @@ -500,11 +555,23 @@ bar (int d, int m, int i1, int i2, int i3, int p, int *idp, int s, [[omp::directive (cancellation point parallel)]]; } } + [[omp::directive (scope private (p) reduction(+:r) nowait)]] + ; + [[omp::directive (scope private (p) reduction(task, +:r))]] + ; extern int t2; - [[omp::directive (threadprivate (t2))]] + [[omp::directive (threadprivate (t2))]]; extern int t2; [[omp::directive (declare reduction (dr: int: omp_out += omp_in) initializer (omp_priv = 0))]] ; + [[omp::directive (parallel)]] + if (0) + ; + [[omp::directive (parallel)]] + while (0) + ; + [[omp::directive (parallel)]] + switch (0) { case 1: break; default: break; } } void corge1 (); @@ -521,7 +588,7 @@ corge () omp::directive (declare simd simdlen(8) notinbranch)]] extern int corge3 (int l, int *p); [[omp::directive (declare simd simdlen(4) linear(l) aligned(p:4) uniform(p) inbranch), - directive (declare simd simdlen(8) notinbranch)]] + omp::directive (declare simd simdlen(8) notinbranch)]] extern int corge4 (int l, int *p); [[omp::sequence (directive (declare simd simdlen(4) linear(l) aligned(p:4) uniform(p) inbranch), omp::directive (declare simd simdlen(8) notinbranch))]] diff --git a/gcc/testsuite/g++.dg/gomp/attrs-10.C b/gcc/testsuite/g++.dg/gomp/attrs-10.C new file mode 100644 index 0000000..a78f892 --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/attrs-10.C @@ -0,0 +1,240 @@ +// { dg-do compile { target c++11 } } +// { dg-options "-fopenmp -ffat-lto-objects -fdump-tree-gimple" } + +extern "C" void abort (); + +[[omp::directive (declare simd, linear (l))]] extern int f1 (int l); +extern int f2 (int), f3 [[omp::directive (declare simd, uniform (m))]] (int m), f4 (int), z; +[[omp::directive (declare simd, linear (l), simdlen(4))]] extern int f5 [[omp::directive (declare simd uniform (l) simdlen (8) notinbranch)]] (int l); + +int +f1 (int l) +{ + return l; +} + +// { dg-final { scan-assembler-times "_ZGVbM4l__Z2f1i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVbN4l__Z2f1i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVcM4l__Z2f1i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVcN4l__Z2f1i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVdM8l__Z2f1i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVdN8l__Z2f1i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVeM16l__Z2f1i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVeN16l__Z2f1i:" 1 { target { i?86-*-* x86_64-*-* } } } } + +int +f2 (int l) +{ + return l + 1; +} + +// { dg-final { scan-assembler-not "_ZGV\[a-zA-Z0-9]__Z2f2i:" { target { i?86-*-* x86_64-*-* } } } } + +int +f3 (int l) +{ + return l + 2; +} + +// { dg-final { scan-assembler-times "_ZGVbM4u__Z2f3i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVbN4u__Z2f3i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVcM4u__Z2f3i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVcN4u__Z2f3i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVdM8u__Z2f3i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVdN8u__Z2f3i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVeM16u__Z2f3i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVeN16u__Z2f3i:" 1 { target { i?86-*-* x86_64-*-* } } } } + +int +f4 (int l) +{ + return l + 3; +} + +// { dg-final { scan-assembler-not "_ZGV\[a-zA-Z0-9]__Z2f4i:" { target { i?86-*-* x86_64-*-* } } } } + +int +f5 (int l) +{ // { dg-warning "GCC does not currently support mixed size types for 'simd' functions" "" { target aarch64*-*-* } .-1 } + return l + 4; +} + +// { dg-final { scan-assembler-times "_ZGVbM4l__Z2f5i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVbN4l__Z2f5i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVcM4l__Z2f5i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVcN4l__Z2f5i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVdM4l__Z2f5i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVdN4l__Z2f5i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVeM4l__Z2f5i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVeN4l__Z2f5i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVbN8u__Z2f5i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVcN8u__Z2f5i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVdN8u__Z2f5i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVeN8u__Z2f5i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-not "_ZGV\[bcde]M8u__Z2f5i:" { target { i?86-*-* x86_64-*-* } } } } + +[[omp::directive (declare simd, linear (l), simdlen(4), notinbranch), + omp::directive (declare simd, uniform (l), simdlen(4), inbranch)]] +int +f6 [[omp::sequence (directive (declare simd uniform (l) simdlen (8), notinbranch), + omp::directive (declare simd linear (l) simdlen (8) inbranch))]] (int l) +{ // { dg-warning "GCC does not currently support mixed size types for 'simd' functions" "" { target aarch64*-*-* } .-2 } + return l + 5; +} + +// { dg-final { scan-assembler-times "_ZGVbM4u__Z2f6i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVbN4l__Z2f6i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVbM8l__Z2f6i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVbN8u__Z2f6i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVcM4u__Z2f6i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVcN4l__Z2f6i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVcM8l__Z2f6i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVcN8u__Z2f6i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVdM4u__Z2f6i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVdN4l__Z2f6i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVdM8l__Z2f6i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVdN8u__Z2f6i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVeM4u__Z2f6i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVeN4l__Z2f6i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVeM8l__Z2f6i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVeN8u__Z2f6i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-not "_ZGV\[bcde]M4l__Z2f6i:" { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-not "_ZGV\[bcde]N4u__Z2f6i:" { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-not "_ZGV\[bcde]M8u__Z2f6i:" { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-not "_ZGV\[bcde]N8l__Z2f6i:" { target { i?86-*-* x86_64-*-* } } } } + +int +f7 (int l) +{ + return l + 6; +} + +// { dg-final { scan-assembler-not "_ZGV\[a-zA-Z0-9]__Z2f7i:" { target { i?86-*-* x86_64-*-* } } } } + +int +f8 (int l) +{ + return l + 7; +} + +// { dg-final { scan-assembler-not "_ZGV\[a-zA-Z0-9]__Z2f8i:" { target { i?86-*-* x86_64-*-* } } } } + +[[omp::sequence (omp::directive (declare variant (f7), match (construct={parallel})), + directive (declare simd uniform (l), simdlen(4)))]] +int +f9 [[omp::directive (declare simd uniform (l) simdlen (8)), + omp::directive (declare variant (f8) match (construct={parallel,for}))]] (int l) +{ // { dg-warning "GCC does not currently support mixed size types for 'simd' functions" "" { target aarch64*-*-* } .-2 } + return l + 8; +} + +// { dg-final { scan-assembler-times "_ZGVbM4u__Z2f9i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVbN4u__Z2f9i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVcM4u__Z2f9i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVcN4u__Z2f9i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVdM4u__Z2f9i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVdN4u__Z2f9i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVeM4u__Z2f9i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVeN4u__Z2f9i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVbM8u__Z2f9i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVbN8u__Z2f9i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVcM8u__Z2f9i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVcN8u__Z2f9i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVdM8u__Z2f9i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVdN8u__Z2f9i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVeM8u__Z2f9i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVeN8u__Z2f9i:" 1 { target { i?86-*-* x86_64-*-* } } } } + +int z; + +void +test () +{ + [[omp::directive (parallel)]] + if (f9 (3) != 9) + abort (); + [[omp::directive (parallel for)]] + for (int i = 0; i < 1; i++) + if (f9 (4) != 11) + abort (); + if (f9 (5) != 13) + abort (); +} + +// { dg-final { scan-tree-dump-times " = f7 \\\(3\\\);" 1 "gimple" } } +// { dg-final { scan-tree-dump-times " = f8 \\\(4\\\);" 1 "gimple" } } +// { dg-final { scan-tree-dump-times " = f9 \\\(5\\\);" 1 "gimple" } } + +template <int N> +int +f10 (int x) +{ + return x + N; +} + +template [[omp::directive (declare simd, notinbranch)]] int f10<0> (int); + +// { dg-final { scan-assembler-times "_ZGVbN4v__Z3f10ILi0EEii:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVcN4v__Z3f10ILi0EEii:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVdN8v__Z3f10ILi0EEii:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVeN16v__Z3f10ILi0EEii:" 1 { target { i?86-*-* x86_64-*-* } } } } + +template int f10<1> [[omp::directive (declare simd inbranch linear(x))]] (int x); + +// { dg-final { scan-assembler-times "_ZGVbM4l__Z3f10ILi1EEii:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVcM4l__Z3f10ILi1EEii:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVdM8l__Z3f10ILi1EEii:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVeM16l__Z3f10ILi1EEii:" 1 { target { i?86-*-* x86_64-*-* } } } } + +template <int N> +int f11 (int); + +template <> [[omp::directive (declare simd, inbranch)]] int +f11<0> (int x) +{ + return x; +} + +// { dg-final { scan-assembler-times "_ZGVbM4v__Z3f11ILi0EEii:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVcM4v__Z3f11ILi0EEii:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVdM8v__Z3f11ILi0EEii:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVeM16v__Z3f11ILi0EEii:" 1 { target { i?86-*-* x86_64-*-* } } } } + +template <> int +f11<1> [[omp::directive (declare simd, notinbranch, linear (y))]] (int y) +{ + return y; +} + +// { dg-final { scan-assembler-times "_ZGVbN4l__Z3f11ILi1EEii:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVcN4l__Z3f11ILi1EEii:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVdN8l__Z3f11ILi1EEii:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVeN16l__Z3f11ILi1EEii:" 1 { target { i?86-*-* x86_64-*-* } } } } + +struct S +{ + [[omp::sequence (directive (declare simd, inbranch, uniform (this)))]] int f12 (int x); + int f13 [[gnu::noinline, omp::directive (declare simd notinbranch uniform (this) linear (y))]] (int y) { return y; } +}; + +int +S::f12 (int x) +{ + return x; +} + +// { dg-final { scan-assembler-times "_ZGVbM4uv__ZN1S3f12Ei:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVcM4uv__ZN1S3f12Ei:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVdM8uv__ZN1S3f12Ei:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVeM16uv__ZN1S3f12Ei:" 1 { target { i?86-*-* x86_64-*-* } } } } + +// { dg-final { scan-assembler-times "_ZGVbN4ul__ZN1S3f13Ei:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVcN4ul__ZN1S3f13Ei:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVdN8ul__ZN1S3f13Ei:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVeN16ul__ZN1S3f13Ei:" 1 { target { i?86-*-* x86_64-*-* } } } } + +int +f14 (S &p, int x) +{ + return p.f13 (x); +} diff --git a/gcc/testsuite/g++.dg/gomp/attrs-11.C b/gcc/testsuite/g++.dg/gomp/attrs-11.C new file mode 100644 index 0000000..44e025e --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/attrs-11.C @@ -0,0 +1,86 @@ +// { dg-do compile { target c++11 } } +// { dg-options "-fopenmp -Wno-attributes" } + +namespace N {} +namespace O { typedef int T; }; + +void +foo () +{ + [[omp::directive (parallel)]] asm (""); // { dg-error "expected" } + [[omp::directive (parallel)]] __extension__ asm (""); // { dg-error "expected" } + __extension__ [[omp::directive (parallel)]] asm (""); // { dg-error "expected" } + [[omp::directive (parallel)]] namespace M = ::N; // { dg-error "expected" } + [[omp::directive (parallel)]] using namespace N; // { dg-error "not allowed to be specified in this context" } + [[omp::directive (parallel)]] using O::T; // { dg-error "expected" } + [[omp::directive (parallel)]] __label__ foo; // { dg-error "expected" } + [[omp::directive (parallel)]] static_assert (true, ""); // { dg-error "expected" } + [[omp::directive (parallel)]] int a = 5; // { dg-error "not allowed to be specified in this context" } + int b = 0; + [[omp::directive (parallel)]] l: b++; // { dg-error "not allowed to be specified in this context" } + switch (0) + { + [[omp::directive (parallel)]] case 6: break; // { dg-error "not allowed to be specified in this context" } + [[omp::directive (parallel)]] default: break; // { dg-error "not allowed to be specified in this context" } + } +} + +void +bar () +{ + [[omp::directive (declare simd)]] int a; // { dg-error "not allowed to be specified in this context|not immediately followed by function declaration or definition" } + [[omp::directive (declare simd)]] int b, f1 (int); // { dg-error "not allowed to be specified in this context|not immediately followed by function declaration or definition" } + [[omp::directive (declare simd)]] int f2 (int), c; // { dg-error "not immediately followed by function declaration or definition" } + int d [[omp::directive (declare simd)]]; // { dg-error "not allowed to be specified in this context" } + int f3 [[omp::directive (declare simd)]] (int), f4 [[omp::directive (declare simd)]] (int); + __extension__ [[omp::directive (declare simd)]] int f5 (int); + __extension__ int f6 [[omp::directive (declare simd, notinbranch)]] (int); + #pragma omp declare simd notinbranch + [[omp::directive (declare simd inbranch)]] int f7 (int); // { dg-error "mixing OpenMP directives with attribute and pragma syntax on the same declaration" } + [[omp::directive (declare simd notinbranch)]] + #pragma omp declare simd inbranch // { dg-error "mixing OpenMP directives with attribute and pragma syntax on the same statement" } + int f8 (int); + static int t1, t2, t3, t4; + [[omp::directive (declare simd), omp::directive (foobar)]] int f9 (int); // { dg-error "unknown OpenMP directive name" } + [[omp::directive (foobar), omp::directive (declare simd)]] int f10 (int); // { dg-error "unknown OpenMP directive name" } + [[omp::directive (threadprivate (t1)), omp::directive (declare simd)]] int f10 (int); // { dg-error "OpenMP directive other than 'declare simd' or 'declare variant' appertains to a declaration" } + [[omp::directive (declare simd), omp::directive (threadprivate (t2))]] int f11 (int); // { dg-error "OpenMP directive other than 'declare simd' or 'declare variant' appertains to a declaration" } + int f12 [[omp::directive (declare simd), omp::directive (foobar)]] (int); // { dg-error "unknown OpenMP directive name" } + int f13 [[omp::directive (foobar), omp::directive (declare simd)]] (int); // { dg-error "unknown OpenMP directive name" } + int f14 [[omp::directive (threadprivate (t3)), omp::directive (declare simd)]] (int); // { dg-error "OpenMP directive other than 'declare simd' or 'declare variant' appertains to a declaration" } + int f15 [[omp::directive (declare simd), omp::directive (threadprivate (t4))]] (int); // { dg-error "OpenMP directive other than 'declare simd' or 'declare variant' appertains to a declaration" } +} + +[[omp::directive (declare simd)]] int a; // { dg-error "not allowed to be specified in this context|not immediately followed by function declaration or definition" } +[[omp::directive (declare simd)]] int b, f16 (int); // { dg-error "not allowed to be specified in this context|not immediately followed by function declaration or definition" } +[[omp::directive (declare simd)]] int f17 (int), c; // { dg-error "not immediately followed by function declaration or definition" } +int d [[omp::directive (declare simd)]]; // { dg-error "not allowed to be specified in this context" } +int f18 [[omp::directive (declare simd)]] (int), f19 [[omp::directive (declare simd)]] (int); +__extension__ [[omp::directive (declare simd)]] int f20 (int); +__extension__ int f21 [[omp::directive (declare simd, notinbranch)]] (int); +#pragma omp declare simd notinbranch +[[omp::directive (declare simd inbranch)]] int f22 (int); // { dg-error "mixing OpenMP directives with attribute and pragma syntax on the same declaration" } +[[omp::directive (declare simd notinbranch)]] // { dg-error "'declare simd' directive not immediately followed by function declaration or definition" } +#pragma omp declare simd inbranch // { dg-error "'#pragma' is not allowed here" } +int f23 (int); +int t5, t6, t7, t8; +[[omp::directive (declare simd), omp::directive (foobar)]] int f24 (int); // { dg-error "unknown OpenMP directive name" } +[[omp::directive (foobar), omp::directive (declare simd)]] int f25 (int); // { dg-error "unknown OpenMP directive name" } +[[omp::directive (threadprivate (t5)), omp::directive (declare simd)]] int f26 (int); // { dg-error "OpenMP directive other than 'declare simd' or 'declare variant' appertains to a declaration" } +[[omp::directive (declare simd), omp::directive (threadprivate (t6))]] int f27 (int); // { dg-error "OpenMP directive other than 'declare simd' or 'declare variant' appertains to a declaration" } +int f28 [[omp::directive (declare simd), omp::directive (foobar)]] (int); // { dg-error "unknown OpenMP directive name" } +int f29 [[omp::directive (foobar), omp::directive (declare simd)]] (int); // { dg-error "unknown OpenMP directive name" } +int f30 [[omp::directive (threadprivate (t7)), omp::directive (declare simd)]] (int); // { dg-error "OpenMP directive other than 'declare simd' or 'declare variant' appertains to a declaration" } +int f31 [[omp::directive (declare simd), omp::directive (threadprivate (t8))]] (int); // { dg-error "OpenMP directive other than 'declare simd' or 'declare variant' appertains to a declaration" } + +void +baz () +{ + #pragma omp parallel + [[omp::directive (declare simd)]] extern int f32 (int); // { dg-error "mixing OpenMP directives with attribute and pragma syntax on the same statement" } + #pragma omp parallel + extern int f33 [[omp::directive (declare simd)]] (int); // { dg-error "mixing OpenMP directives with attribute and pragma syntax on the same statement" } + [[omp::directive (parallel)]] + #pragma omp declare simd // { dg-error "mixing OpenMP directives with attribute and pragma syntax on the same statement" } + extern int f34 (int); +} diff --git a/gcc/testsuite/g++.dg/gomp/attrs-12.C b/gcc/testsuite/g++.dg/gomp/attrs-12.C new file mode 100644 index 0000000..b613872 --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/attrs-12.C @@ -0,0 +1,41 @@ +// { dg-do compile { target c++11 } } + +#pragma omp declare target +#pragma omp declare target +[[omp::directive (declare target)]]; +int a; +[[omp::directive (end declare target)]]; +#pragma omp end declare target +#pragma omp end declare target +[[omp::directive (declare target)]]; +int b; +#pragma omp end declare target // { dg-error "'declare target' in attribute syntax terminated with 'end declare target' in pragma syntax" } +#pragma omp declare target +int c; +[[omp::directive (end declare target)]];// { dg-error "'declare target' in pragma syntax terminated with 'end declare target' in attribute syntax" } +#pragma omp declare target +[[omp::directive (declare target)]]; +int d; +#pragma omp end declare target // { dg-error "'declare target' in attribute syntax terminated with 'end declare target' in pragma syntax" } +#pragma omp declare target +int e; +[[omp::directive (end declare target)]];// { dg-error "'declare target' in pragma syntax terminated with 'end declare target' in attribute syntax" } +#pragma omp end declare target +[[omp::directive (declare target)]]; +[[omp::directive (declare target)]]; +int f; +#pragma omp end declare target // { dg-error "'declare target' in attribute syntax terminated with 'end declare target' in pragma syntax" } +#pragma omp declare target +int g; +[[omp::directive (end declare target)]];// { dg-error "'declare target' in pragma syntax terminated with 'end declare target' in attribute syntax" } +[[omp::directive (end declare target)]]; +[[omp::directive (declare target)]]; +#pragma omp declare target +int h; +#pragma omp end declare target +#pragma omp end declare target // { dg-error "'declare target' in attribute syntax terminated with 'end declare target' in pragma syntax" } +#pragma omp declare target +[[omp::directive (declare target)]]; +int i; +[[omp::directive (end declare target)]]; +[[omp::directive (end declare target)]];// { dg-error "'declare target' in pragma syntax terminated with 'end declare target' in attribute syntax" } diff --git a/gcc/testsuite/g++.dg/gomp/attrs-2.C b/gcc/testsuite/g++.dg/gomp/attrs-2.C index 189dc6b..bea657f 100644 --- a/gcc/testsuite/g++.dg/gomp/attrs-2.C +++ b/gcc/testsuite/g++.dg/gomp/attrs-2.C @@ -111,6 +111,7 @@ void bar (int d, int m, int i1, int i2, int i3, int p, int *idp, int s, int nte, int tl, int nth, int g, int nta, int fi, int pp, int *q, int *dd, int ntm) { + [[omp::directive (nothing)]]; [[omp::directive (for simd, private (p),firstprivate (f),lastprivate (l),linear (ll:1),reduction(+:r),schedule(static, 4),collapse(1),nowait, safelen(8),simdlen(4),aligned(q: 32),nontemporal(ntm),if(i1),order(concurrent),allocate (f))]] @@ -348,6 +349,10 @@ bar (int d, int m, int i1, int i2, int i3, int p, int *idp, int s, private (p),firstprivate (f),if (parallel: i2),default(shared),shared(s),reduction(+:r), num_threads (nth),proc_bind(spread),copyin(t),allocate (f))]] ; + [[omp::directive (parallel masked, + private (p),firstprivate (f),if (parallel: i2),default(shared),shared(s),reduction(+:r), + num_threads (nth),proc_bind(spread),copyin(t),allocate (f),filter(d))]] + ; [[omp::directive (parallel, private (p),firstprivate (f),if (parallel: i2),default(shared),shared(s),reduction(+:r), num_threads (nth),proc_bind(spread),copyin(t),allocate (f))]] @@ -358,7 +363,15 @@ bar (int d, int m, int i1, int i2, int i3, int p, int *idp, int s, reduction(default, +:r),in_reduction(+:r2),allocate (f)))]] for (int i = 0; i < 64; i++) ll++; + [[using omp:sequence (directive (taskgroup, task_reduction (+:r2),allocate (r2)), + omp::directive (masked taskloop, + private (p),firstprivate (f),lastprivate (l),shared (s),default(shared),grainsize (g),collapse(1),untied, if(taskloop: i1),final(fi),mergeable, priority (pp), + reduction(default, +:r),in_reduction(+:r2),allocate (f),filter(d)))]] + for (int i = 0; i < 64; i++) + ll++; [[using omp:directive (master)]]; + [[using omp:directive (masked)]]; + [[using omp:directive (masked,filter(d))]]; [[omp::sequence (omp::directive (taskgroup task_reduction (+:r2),allocate (r2)), directive (master taskloop simd, private (p),firstprivate (f),lastprivate (l),shared (s),default(shared),grainsize (g),collapse(1),untied,if(taskloop: i1),if(simd: i2),final(fi),mergeable,priority (pp), @@ -366,23 +379,47 @@ bar (int d, int m, int i1, int i2, int i3, int p, int *idp, int s, order(concurrent),allocate (f)))]] for (int i = 0; i < 64; i++) ll++; + [[omp::sequence (omp::directive (taskgroup task_reduction (+:r2),allocate (r2)), + directive (masked taskloop simd, + private (p),firstprivate (f),lastprivate (l),shared (s),default(shared),grainsize (g),collapse(1),untied,if(taskloop: i1),if(simd: i2),final(fi),mergeable,priority (pp), + safelen(8),simdlen(4),linear(ll: 1),aligned(q: 32),reduction(default, +:r),in_reduction(+:r2),nontemporal(ntm), + order(concurrent),allocate (f),filter(d)))]] + for (int i = 0; i < 64; i++) + ll++; [[omp::directive (parallel master taskloop, private (p),firstprivate (f),lastprivate (l),shared (s),default(shared),grainsize (g),collapse(1),untied,if(taskloop: i1),final(fi),mergeable,priority (pp), reduction(default, +:r),if (parallel: i2),num_threads (nth),proc_bind(spread),copyin(t),allocate (f))]] for (int i = 0; i < 64; i++) ll++; + [[omp::directive (parallel masked taskloop, + private (p),firstprivate (f),lastprivate (l),shared (s),default(shared),grainsize (g),collapse(1),untied,if(taskloop: i1),final(fi),mergeable,priority (pp), + reduction(default, +:r),if (parallel: i2),num_threads (nth),proc_bind(spread),copyin(t),allocate (f),filter(d))]] + for (int i = 0; i < 64; i++) + ll++; [[omp::directive (parallel master taskloop simd, private (p),firstprivate (f),lastprivate (l),shared (s),default(shared),grainsize (g),collapse(1),untied,if(taskloop: i1),if(simd: i2),final(fi),mergeable,priority (pp), safelen(8),simdlen(4),linear(ll: 1),aligned(q: 32),reduction(default, +:r),nontemporal(ntm),if (parallel: i2),num_threads (nth),proc_bind(spread),copyin(t), order(concurrent),allocate (f))]] for (int i = 0; i < 64; i++) ll++; + [[omp::directive (parallel masked taskloop simd, + private (p),firstprivate (f),lastprivate (l),shared (s),default(shared),grainsize (g),collapse(1),untied,if(taskloop: i1),if(simd: i2),final(fi),mergeable,priority (pp), + safelen(8),simdlen(4),linear(ll: 1),aligned(q: 32),reduction(default, +:r),nontemporal(ntm),if (parallel: i2),num_threads (nth),proc_bind(spread),copyin(t), + order(concurrent),allocate (f),filter(d))]] + for (int i = 0; i < 64; i++) + ll++; [[omp::sequence (directive (taskgroup,task_reduction (+:r2),allocate (r2)), directive (master taskloop, private (p),firstprivate (f),lastprivate (l),shared (s),default(shared),num_tasks (nta),collapse(1),untied,if(i1),final(fi),mergeable,priority (pp), reduction(default, +:r),in_reduction(+:r2)))]] for (int i = 0; i < 64; i++) ll++; + [[omp::sequence (directive (taskgroup,task_reduction (+:r2),allocate (r2)), + directive (masked taskloop, + private (p),firstprivate (f),lastprivate (l),shared (s),default(shared),num_tasks (nta),collapse(1),untied,if(i1),final(fi),mergeable,priority (pp), + reduction(default, +:r),in_reduction(+:r2),filter(d)))]] + for (int i = 0; i < 64; i++) + ll++; [[omp::sequence (omp::directive (taskgroup,task_reduction (+:r2),allocate (r2)), omp::directive (master taskloop simd, private (p),firstprivate (f),lastprivate (l),shared (s),default(shared),num_tasks (nta),collapse(1),untied,if(i1),final(fi),mergeable,priority (pp), @@ -390,17 +427,35 @@ bar (int d, int m, int i1, int i2, int i3, int p, int *idp, int s, order(concurrent),allocate (f)))]] for (int i = 0; i < 64; i++) ll++; + [[omp::sequence (omp::directive (taskgroup,task_reduction (+:r2),allocate (r2)), + omp::directive (masked taskloop simd, + private (p),firstprivate (f),lastprivate (l),shared (s),default(shared),num_tasks (nta),collapse(1),untied,if(i1),final(fi),mergeable,priority (pp), + safelen(8),simdlen(4),linear(ll: 1),aligned(q: 32),reduction(default, +:r),in_reduction(+:r2),nontemporal(ntm), + order(concurrent),allocate (f),filter(d)))]] + for (int i = 0; i < 64; i++) + ll++; [[omp::directive (parallel master taskloop, private (p),firstprivate (f),lastprivate (l),shared (s),default(shared),num_tasks (nta),collapse(1),untied if(i1),final(fi),mergeable priority (pp), reduction(default, +:r),num_threads (nth),proc_bind(spread),copyin(t),allocate (f))]] for (int i = 0; i < 64; i++) ll++; + [[omp::directive (parallel masked taskloop, + private (p),firstprivate (f),lastprivate (l),shared (s),default(shared),num_tasks (nta),collapse(1),untied if(i1),final(fi),mergeable priority (pp), + reduction(default, +:r),num_threads (nth),proc_bind(spread),copyin(t),allocate (f),filter(d))]] + for (int i = 0; i < 64; i++) + ll++; [[omp::directive (parallel master taskloop simd, private (p),firstprivate (f),lastprivate (l),shared (s),default(shared),num_tasks (nta),collapse(1),untied if(i1),final(fi),mergeable priority (pp), safelen(8),simdlen(4),linear(ll: 1),aligned(q: 32),reduction(default, +:r),nontemporal(ntm),num_threads (nth),proc_bind(spread),copyin(t), order(concurrent),allocate (f))]] for (int i = 0; i < 64; i++) ll++; + [[omp::directive (parallel masked taskloop simd, + private (p),firstprivate (f),lastprivate (l),shared (s),default(shared),num_tasks (nta),collapse(1),untied if(i1),final(fi),mergeable priority (pp), + safelen(8),simdlen(4),linear(ll: 1),aligned(q: 32),reduction(default, +:r),nontemporal(ntm),num_threads (nth),proc_bind(spread),copyin(t), + order(concurrent),allocate (f),filter(d))]] + for (int i = 0; i < 64; i++) + ll++; [[omp::directive (loop, bind(thread),order(concurrent), private (p),lastprivate (l),collapse(1),reduction(+:r))]] for (l = 0; l < 64; ++l) @@ -500,8 +555,12 @@ bar (int d, int m, int i1, int i2, int i3, int p, int *idp, int s, [[omp::directive (cancellation point, parallel)]]; } } + [[omp::directive (scope, private (p), reduction(+:r), nowait)]] + ; + [[using omp:directive (scope, private (p), reduction(task, +:r))]] + ; extern int t2; - [[omp::directive (threadprivate (t2))]] + [[omp::directive (threadprivate (t2))]]; extern int t2; [[omp::directive (declare reduction (dr: int: omp_out += omp_in),initializer (omp_priv = 0))]] ; diff --git a/gcc/testsuite/g++.dg/gomp/attrs-7.C b/gcc/testsuite/g++.dg/gomp/attrs-7.C index 598c32a..cf84281 100644 --- a/gcc/testsuite/g++.dg/gomp/attrs-7.C +++ b/gcc/testsuite/g++.dg/gomp/attrs-7.C @@ -11,8 +11,7 @@ foo () // { dg-error "#pragma omp section" "" { target *-*-* } .-1 } // { dg-error "#pragma omp flush" "" { target *-*-* } .-2 } [[omp::sequence (directive (flush), omp::directive (section))]]; // { dg-error "must be the only specified attribute on a statement" } - // { dg-error "#pragma omp section" "" { target *-*-* } .-1 } - // { dg-error "#pragma omp flush" "" { target *-*-* } .-2 } + // { dg-error "#pragma omp flush" "" { target *-*-* } .-1 } [[gnu::cold, omp::directive (section)]]; // { dg-error "must be the only specified attribute on a statement" } // { dg-error "#pragma omp section" "" { target *-*-* } .-1 } [[omp::directive (section)]] [[gnu::cold]]; // { dg-error "must be the only specified attribute on a statement" } diff --git a/gcc/testsuite/g++.dg/gomp/attrs-9.C b/gcc/testsuite/g++.dg/gomp/attrs-9.C index 0af556c..08cd2b1 100644 --- a/gcc/testsuite/g++.dg/gomp/attrs-9.C +++ b/gcc/testsuite/g++.dg/gomp/attrs-9.C @@ -13,3 +13,4 @@ int b, c; int d; [[omp::directive (end declare target)]]; [[omp::directive (end declare target)]]; +[[omp::directive (nothing)]]; diff --git a/gcc/testsuite/g++.dg/gomp/barrier-2.C b/gcc/testsuite/g++.dg/gomp/barrier-2.C index 1d929d2..6f3fded 100644 --- a/gcc/testsuite/g++.dg/gomp/barrier-2.C +++ b/gcc/testsuite/g++.dg/gomp/barrier-2.C @@ -9,4 +9,4 @@ void f3(bool p) { if (p) #pragma omp barrier // { dg-error "compound statements" } -} // { dg-error "" } +} diff --git a/gcc/testsuite/g++.dg/gomp/block-11.C b/gcc/testsuite/g++.dg/gomp/block-11.C index c280006..cf4b0d3 100644 --- a/gcc/testsuite/g++.dg/gomp/block-11.C +++ b/gcc/testsuite/g++.dg/gomp/block-11.C @@ -1,3 +1,21 @@ +// { dg-do compile } + +void foo() +{ + #pragma omp masked + { + goto bad1; // { dg-message "from here" } + } + + #pragma omp masked filter(1) + { + bad1: // { dg-error "jump" } + // { dg-message "exits OpenMP" "" { target *-*-* } .-1 } + return; // { dg-error "invalid exit" } + } +} + +// { dg-message "error: invalid branch to/from OpenMP structured block" "" { target *-*-* } 7 } /* PR c++/24516 */ /* { dg-do compile } */ diff --git a/gcc/testsuite/g++.dg/gomp/tpl-masked-1.C b/gcc/testsuite/g++.dg/gomp/tpl-masked-1.C new file mode 100644 index 0000000..8574861 --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/tpl-masked-1.C @@ -0,0 +1,21 @@ +// { dg-do compile } +// { dg-options "-fopenmp -fdump-tree-gimple" } + +int i; + +template <typename T> void f1 (bool p, T t) +{ + if (p) + { + #pragma omp masked filter (t) + i++; + } +} + +void f2 () +{ + f1<int> (true, 0); + f1<long> (true, 0L); +} + +// { dg-final { scan-tree-dump-times "#pragma omp masked" 2 "gimple" } } diff --git a/gcc/testsuite/g++.dg/lookup/strong-using.C b/gcc/testsuite/g++.dg/lookup/strong-using.C index 9d58fdd..2bd821e 100644 --- a/gcc/testsuite/g++.dg/lookup/strong-using.C +++ b/gcc/testsuite/g++.dg/lookup/strong-using.C @@ -8,3 +8,12 @@ namespace A using namespace B __attribute__ ((strong)); // { dg-warning "no longer supported" "" } } + +namespace C +{ + namespace D // { dg-message "inline namespace" } + { + } + + [[gnu::strong]] using namespace D; // { dg-warning "no longer supported" "" } +} diff --git a/gcc/testsuite/g++.dg/lookup/strong-using2.C b/gcc/testsuite/g++.dg/lookup/strong-using2.C index 1728494..989827c 100644 --- a/gcc/testsuite/g++.dg/lookup/strong-using2.C +++ b/gcc/testsuite/g++.dg/lookup/strong-using2.C @@ -9,3 +9,12 @@ namespace A using namespace B __attribute__ ((strong)); // { dg-bogus "no longer supported" } } + +namespace C +{ + namespace D // { dg-bogus "inline namespace" } + { + } + + [[gnu::strong]] using namespace D; // { dg-bogus "no longer supported" } +} diff --git a/gcc/testsuite/g++.dg/warn/Wmismatched-new-delete-6.C b/gcc/testsuite/g++.dg/warn/Wmismatched-new-delete-6.C new file mode 100644 index 0000000..e19d000 --- /dev/null +++ b/gcc/testsuite/g++.dg/warn/Wmismatched-new-delete-6.C @@ -0,0 +1,158 @@ +/* PR middle-end/101791 - missing warning on a mismatch between scalar + and array forms of new and delete + { dg-do compile } + { dg-options "-Wall" } */ + +typedef __SIZE_TYPE__ size_t; + +namespace std +{ +#if __cplusplus >= 201703L +enum class align_val_t: size_t { }; +#else +enum align_val_t { }; +#endif + +struct nothrow_t { }; +const nothrow_t nothrow = { }; + +} + +void* operator new (size_t); +void* operator new (size_t, std::align_val_t); +void* operator new (size_t, std::nothrow_t) throw (); +void* operator new (size_t, std::align_val_t, std::nothrow_t) throw (); + +void* operator new[] (size_t); +void* operator new[] (size_t, std::align_val_t); +void* operator new[] (size_t, std::nothrow_t) throw (); +void* operator new[] (size_t, std::align_val_t, std::nothrow_t) throw (); + +void operator delete (void*); +void operator delete (void*, size_t); +void operator delete (void*, std::align_val_t); +void operator delete (void*, size_t, std::align_val_t); +void operator delete (void*, std::nothrow_t) throw (); +void operator delete (void*, std::align_val_t, std::nothrow_t) throw (); + +void operator delete[] (void*); +void operator delete[] (void*, size_t); +void operator delete[] (void*, std::align_val_t); +void operator delete[] (void*, size_t, std::align_val_t); +void operator delete[] (void*, std::nothrow_t) throw (); +void operator delete[] (void*, std::align_val_t, std::nothrow_t) throw (); + + +void sink (void*, ...); + + +void nowarn_scalar_scalar () +{ + { + int *p = new int; + sink (p); + delete p; + } + + { + int *p = new (std::align_val_t (8)) int; + sink (p); + delete p; + } + + { + int *p = new (std::nothrow) int; + sink (p); + delete p; + } + + { + int *p = new (std::align_val_t (8), std::nothrow) int; + sink (p); + delete p; + } +} + +void nowarn_array_array () +{ + { + int *p = new int[__LINE__]; + sink (p); + delete[] p; + } + + { + int *p = new (std::align_val_t (8)) int[__LINE__]; + sink (p); + delete[] p; + } + + { + int *p = new (std::nothrow) int[__LINE__]; + sink (p); + delete[] p; + } + + { + int *p = new (std::align_val_t (8), std::nothrow) int[__LINE__]; + sink (p); + delete[] p; + } +} + + + +void nowarn_scalar_array () +{ + { + int *p = new int; // { dg-message "returned from" } + sink (p); + delete[] p; // { dg-warning "\\\[-Wmismatched-new-delete" } + } + + { + int *p = new (std::align_val_t (8)) int; + sink (p); + delete[] p; // { dg-warning "\\\[-Wmismatched-new-delete" } + } + + { + int *p = new (std::nothrow) int; + sink (p); + delete[] p; // { dg-warning "\\\[-Wmismatched-new-delete" } + } + + { + int *p = new (std::align_val_t (8), std::nothrow) int; + sink (p); + delete[] p; // { dg-warning "\\\[-Wmismatched-new-delete" } + } +} + + +void nowarn_array_scalar () +{ + { + int *p = new int[__LINE__]; + sink (p); + delete p; // { dg-warning "\\\[-Wmismatched-new-delete" } + } + + { + int *p = new (std::align_val_t (8)) int[__LINE__]; + sink (p); + delete p; // { dg-warning "\\\[-Wmismatched-new-delete" } + } + + { + int *p = new (std::nothrow) int[__LINE__]; + sink (p); + delete p; // { dg-warning "\\\[-Wmismatched-new-delete" } + } + + { + int *p = new (std::align_val_t (8), std::nothrow) int[__LINE__]; + sink (p); + delete p; // { dg-warning "\\\[-Wmismatched-new-delete" } + } +} diff --git a/gcc/testsuite/g++.dg/warn/Wmismatched-new-delete-7.C b/gcc/testsuite/g++.dg/warn/Wmismatched-new-delete-7.C new file mode 100644 index 0000000..67a5354 --- /dev/null +++ b/gcc/testsuite/g++.dg/warn/Wmismatched-new-delete-7.C @@ -0,0 +1,91 @@ +/* PR middle-end/101791 - missing warning on a mismatch between scalar + and array forms of new and delete + Verify that likely safe calls to technically mismatched member operator + new and delete are not diagnosed. This test might need to be adjusted + if it turns out the assumptions GCC makes are overly conservative. + { dg-do compile } + { dg-options "-Wall" } */ + +typedef __SIZE_TYPE__ size_t; + +namespace std +{ +#if __cplusplus >= 201703L +enum class align_val_t: size_t { }; +#else +enum align_val_t { }; +#endif + +struct nothrow_t { }; +const nothrow_t nothrow = { }; + +} + +void sink (void*, ...); + +struct X { } x; +struct Y { } y; + +struct A +{ + void* operator new (size_t); + void* operator new (size_t, std::align_val_t); + + void* operator new (size_t, X); + void* operator new (size_t, Y); + + void* operator new (size_t, std::align_val_t, X); + void* operator new (size_t, std::nothrow_t, Y); + + /* A single operator delete callable on the result of calls to any + of the operator new overloads above (this may be too optimistic). */ + void operator delete (void*); +}; + +A* nowarn_align () +{ + /* The following are likely okay given A's definition above but would + not be if A also defined an align_val_t overload of operator delete. */ + A *p = new (std::align_val_t (8)) A; + delete p; + + return new (std::align_val_t (16)) A; +} + +A* nowarn_X () +{ + /* The following are also likely okay given A's definition above but + also would not be if A also defined an overload of operator delete + for X. */ + A *p = new (x) A; + delete p; + return new (x) A; +} + +A* nowarn_Y () +{ + // Same as above. + A *p = new (y) A; + delete p; + return new (y) A; +} + + +A* nowarn_align_X () +{ + // Same as above. + A *p = new (std::align_val_t (32), x) A; + delete p; + + return new (std::align_val_t (64), x) A; +} + + +A* nowarn_nothrow_Y () +{ + // Same as above. + A *p = new (std::nothrow, y) A; + delete p; + return new (std::nothrow, y) A; +} + diff --git a/gcc/testsuite/g++.dg/warn/pr101219.C b/gcc/testsuite/g++.dg/warn/pr101219.C new file mode 100644 index 0000000..0d23d73 --- /dev/null +++ b/gcc/testsuite/g++.dg/warn/pr101219.C @@ -0,0 +1,11 @@ +/* PR c++/101219 - ICE on use of uninitialized memfun pointer + { dg-do compile } + { dg-options "-Wall" } */ + +struct S { void m(); }; + +template <int> bool f() { + void (S::*mp)(); + + return &S::m == mp; // no warning emitted here (no instantiation) +} diff --git a/gcc/testsuite/gcc.dg/Wstringop-overflow-72.c b/gcc/testsuite/gcc.dg/Wstringop-overflow-72.c new file mode 100644 index 0000000..c10773e --- /dev/null +++ b/gcc/testsuite/gcc.dg/Wstringop-overflow-72.c @@ -0,0 +1,13 @@ +/* PR middle-end/101854 - Invalid warning -Wstringop-overflow wrong argument + { dg-do compile } + { dg-options "-O2 -Wall" } */ + +struct A { int a[5]; }; + +struct A g (int*, int[6][8]); + +struct A f (void) +{ + int a[2]; + return g (a, 0); // { dg-bogus "-Wstringop-overflow" } +} diff --git a/gcc/testsuite/gcc.dg/attr-alloc_size-5.c b/gcc/testsuite/gcc.dg/attr-alloc_size-5.c index 7aa7cbf..4eea625 100644 --- a/gcc/testsuite/gcc.dg/attr-alloc_size-5.c +++ b/gcc/testsuite/gcc.dg/attr-alloc_size-5.c @@ -4,7 +4,7 @@ zero bytes. For standard allocation functions the return value is implementation-defined and so relying on it may be a source of bugs. */ /* { dg-do compile } */ -/* { dg-options "-O2 -Wall -Walloc-zero" } */ +/* { dg-options "-O1 -Wall -Walloc-zero" } */ #define SCHAR_MAX __SCHAR_MAX__ #define SCHAR_MIN (-SCHAR_MAX - 1) diff --git a/gcc/testsuite/gcc.dg/attr-alloc_size-7.c b/gcc/testsuite/gcc.dg/attr-alloc_size-7.c index 68602ec..3adde5c 100644 --- a/gcc/testsuite/gcc.dg/attr-alloc_size-7.c +++ b/gcc/testsuite/gcc.dg/attr-alloc_size-7.c @@ -4,7 +4,7 @@ of the maximum specified by -Walloc-size-larger-than=maximum. */ /* { dg-do compile } */ /* { dg-require-effective-target alloca } */ -/* { dg-options "-O2 -Wall -Walloc-size-larger-than=12345" } */ +/* { dg-options "-O1 -Wall -Walloc-size-larger-than=12345" } */ #define SIZE_MAX __SIZE_MAX__ #define MAXOBJSZ 12345 @@ -13,15 +13,40 @@ typedef __SIZE_TYPE__ size_t; void sink (void*); -static size_t maxobjsize (void) +#pragma GCC push_options +/* Verify that constant evaluation takes place even at -O0. */ +#pragma GCC optimize ("0") + +void test_cst (void *p) { - return MAXOBJSZ; + enum { max = MAXOBJSZ }; + + sink (__builtin_aligned_alloc (1, max)); + sink (__builtin_aligned_alloc (1, max + 1)); /* { dg-warning "argument 2 value .12346\[lu\]*. exceeds maximum object size 12345" } */ + + sink (__builtin_alloca (max)); + sink (__builtin_alloca (max + 2)); /* { dg-warning "argument 1 value .12347\[lu\]*. exceeds maximum object size 12345" } */ + + sink (__builtin_calloc (1, max)); + sink (__builtin_calloc (max, 1)); + + sink (__builtin_calloc (max / 2, 3)); /* { dg-warning "product .6172\[lu\]* \\* 3\[lu\]*. of arguments 1 and 2 exceeds maximum object size 12345" } */ + sink (__builtin_calloc (4, max / 3)); /* { dg-warning "product .4\[lu\]* \\* 4115\[lu\]*. of arguments 1 and 2 exceeds maximum object size 12345" } */ + + sink (__builtin_malloc (max)); + sink (__builtin_malloc (max + 3)); /* { dg-warning "argument 1 value .12348\[lu\]*. exceeds maximum object size 12345" } */ + + sink (__builtin_realloc (p, max)); + sink (__builtin_realloc (p, max + 4)); /* { dg-warning "argument 2 value .12349\[lu\]*. exceeds maximum object size 12345" } */ } -void test_var (void *p) +/* Variable evaluation needs -O1. */ +#pragma GCC pop_options + +__attribute__ ((noipa)) void test_var (void *p) { - size_t max = maxobjsize (); + size_t max = MAXOBJSZ; sink (__builtin_aligned_alloc (1, max)); sink (__builtin_aligned_alloc (1, max + 1)); /* { dg-warning "argument 2 value .12346\[lu\]*. exceeds maximum object size 12345" } */ @@ -43,7 +68,15 @@ void test_var (void *p) } -void test_range (void *p, size_t range) +/* Value range evaluation (apparently) needs -O2 here. */ +#pragma GCC optimize ("2") + +static size_t maxobjsize (void) +{ + return MAXOBJSZ; +} + +__attribute__ ((noipa)) void test_range (void *p, size_t range) { /* Make sure the variable is at least as large as the maximum object size but also make sure that it's guaranteed not to be too big to diff --git a/gcc/testsuite/gcc.dg/attr-alloc_size-8.c b/gcc/testsuite/gcc.dg/attr-alloc_size-8.c index 91d7eb5..7b47b04 100644 --- a/gcc/testsuite/gcc.dg/attr-alloc_size-8.c +++ b/gcc/testsuite/gcc.dg/attr-alloc_size-8.c @@ -4,7 +4,7 @@ two more specific options override the more general latter option. */ /* { dg-do compile } */ /* { dg-require-effective-target alloca } */ -/* { dg-options "-O2 -Walloc-size-larger-than=123 -Walloca-larger-than=234 -Wvla-larger-than=345" } */ +/* { dg-options "-O -Walloc-size-larger-than=123 -Walloca-larger-than=234 -Wvla-larger-than=345" } */ typedef __SIZE_TYPE__ size_t; diff --git a/gcc/testsuite/gcc.dg/cpp/pr101638.c b/gcc/testsuite/gcc.dg/cpp/pr101638.c new file mode 100644 index 0000000..1030473 --- /dev/null +++ b/gcc/testsuite/gcc.dg/cpp/pr101638.c @@ -0,0 +1,7 @@ +/* PR preprocessor/101638 */ +/* { dg-do preprocess } */ +/* { dg-options "-Wtraditional" } */ + +#define foo(attr) __has_attribute(attr) +#if foo(__deprecated__) +#endif diff --git a/gcc/testsuite/gcc.dg/fold-ior-5.c b/gcc/testsuite/gcc.dg/fold-ior-5.c new file mode 100644 index 0000000..8de5697 --- /dev/null +++ b/gcc/testsuite/gcc.dg/fold-ior-5.c @@ -0,0 +1,17 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-optimized" } */ + +unsigned int test_ior(unsigned char i) +{ + return (i | (i<<16)) | ((i<<24) | (i<<8)); +} + +unsigned int test_xor(unsigned char i) +{ + return (i ^ (i<<16)) ^ ((i<<24) ^ (i<<8)); +} + +/* { dg-final { scan-tree-dump-not " \\^ " "optimized" } } */ +/* { dg-final { scan-tree-dump-not " \\| " "optimized" } } */ +/* { dg-final { scan-tree-dump-times " \\* 16843009" 2 "optimized" } } */ + diff --git a/gcc/testsuite/gcc.dg/gomp/barrier-2.c b/gcc/testsuite/gcc.dg/gomp/barrier-2.c index c0d62f5..ef605a0 100644 --- a/gcc/testsuite/gcc.dg/gomp/barrier-2.c +++ b/gcc/testsuite/gcc.dg/gomp/barrier-2.c @@ -16,8 +16,7 @@ void f1(void) void f2(void) { - label: /* { dg-error "label at end of compound statement" } */ - /* { dg-warning "defined but not used" "" { target *-*-* } .-1 } */ + label: /* { dg-warning "defined but not used" } */ #pragma omp barrier /* { dg-error "may only be used in compound statements" } */ } diff --git a/gcc/testsuite/gcc.dg/gomp/declare-simd-5.c b/gcc/testsuite/gcc.dg/gomp/declare-simd-5.c index b9a4161..9397820 100644 --- a/gcc/testsuite/gcc.dg/gomp/declare-simd-5.c +++ b/gcc/testsuite/gcc.dg/gomp/declare-simd-5.c @@ -15,7 +15,7 @@ f1 (int x) lab: #pragma omp declare simd simdlen (8) aligned (b : 8 * sizeof (int)) extern int f5 (int a, int *b, int c); /* { dg-error "must be followed by function declaration or definition" } */ - x++; /* { dg-error "a label can only be part of a statement and a declaration is not a statement" "" { target *-*-* } .-1 } */ + x++; } return x; } diff --git a/gcc/testsuite/gcc.dg/gomp/declare-variant-2.c b/gcc/testsuite/gcc.dg/gomp/declare-variant-2.c index 39c2c1d..3da5dc7 100644 --- a/gcc/testsuite/gcc.dg/gomp/declare-variant-2.c +++ b/gcc/testsuite/gcc.dg/gomp/declare-variant-2.c @@ -17,7 +17,7 @@ f1 (int x) lab: #pragma omp declare variant (fn0) match (user={condition(0)}) extern int f5 (int a, int *b, int c); /* { dg-error "must be followed by function declaration or definition" } */ - x++; /* { dg-error "a label can only be part of a statement and a declaration is not a statement" "" { target *-*-* } .-1 } */ + x++; } return x; } diff --git a/gcc/testsuite/gcc.dg/gomp/nesting-1.c b/gcc/testsuite/gcc.dg/gomp/nesting-1.c index 52fcda7..ed457ce 100644 --- a/gcc/testsuite/gcc.dg/gomp/nesting-1.c +++ b/gcc/testsuite/gcc.dg/gomp/nesting-1.c @@ -19,9 +19,13 @@ f1 (void) } #pragma omp single /* { dg-error "may not be closely nested" } */ ; - #pragma omp master /* { dg-error "may not be closely nested" } */ - ; + #pragma omp master /* { dg-error "may not be closely nested" } */ + ; + #pragma omp masked /* { dg-error "may not be closely nested" } */ + ; #pragma omp barrier /* { dg-error "may not be closely nested" } */ + #pragma omp scope /* { dg-error "may not be closely nested" } */ + ; } #pragma omp sections { @@ -50,6 +54,16 @@ f1 (void) } #pragma omp sections { + #pragma omp masked /* { dg-error "may not be closely nested" } */ + ; + } + #pragma omp sections + { + #pragma omp scope /* { dg-error "may not be closely nested" } */ + ; + } + #pragma omp sections + { #pragma omp section ; } @@ -81,6 +95,15 @@ f1 (void) #pragma omp section #pragma omp master /* { dg-error "may not be closely nested" } */ ; + #pragma omp section + #pragma omp masked /* { dg-error "may not be closely nested" } */ + ; + } + #pragma omp sections + { + #pragma omp section + #pragma omp scope /* { dg-error "may not be closely nested" } */ + ; } #pragma omp single { @@ -97,7 +120,11 @@ f1 (void) ; #pragma omp master /* { dg-error "may not be closely nested" } */ ; + #pragma omp masked /* { dg-error "may not be closely nested" } */ + ; #pragma omp barrier /* { dg-error "may not be closely nested" } */ + #pragma omp scope /* { dg-error "may not be closely nested" } */ + ; } #pragma omp master { @@ -115,6 +142,27 @@ f1 (void) #pragma omp master ; #pragma omp barrier /* { dg-error "may not be closely nested" } */ + #pragma omp scope /* { dg-error "may not be closely nested" } */ + ; + } + #pragma omp masked filter (1) + { + #pragma omp for /* { dg-error "may not be closely nested" } */ + for (j = 0; j < 3; j++) + ; + #pragma omp sections /* { dg-error "may not be closely nested" } */ + { + ; + #pragma omp section + ; + } + #pragma omp single /* { dg-error "may not be closely nested" } */ + ; + #pragma omp master + ; + #pragma omp barrier /* { dg-error "may not be closely nested" } */ + #pragma omp scope /* { dg-error "may not be closely nested" } */ + ; } #pragma omp task { @@ -131,7 +179,11 @@ f1 (void) ; #pragma omp master /* { dg-error "may not be closely nested" } */ ; + #pragma omp masked /* { dg-error "may not be closely nested" } */ + ; #pragma omp barrier /* { dg-error "may not be closely nested" } */ + #pragma omp scope /* { dg-error "may not be closely nested" } */ + ; } #pragma omp parallel { @@ -148,7 +200,42 @@ f1 (void) ; #pragma omp master ; + #pragma omp masked + ; + #pragma omp barrier + #pragma omp scope + ; + #pragma omp scope + { + #pragma omp scope + ; + } + } + #pragma omp scope + { + #pragma omp for + for (j = 0; j < 3; j++) + ; + #pragma omp sections + { + ; + #pragma omp section + ; + } + #pragma omp single + ; + #pragma omp master + ; + #pragma omp masked + ; #pragma omp barrier + #pragma omp scope + ; + #pragma omp scope + { + #pragma omp scope + ; + } } } @@ -171,7 +258,11 @@ f2 (void) ; #pragma omp master ; + #pragma omp masked + ; #pragma omp barrier /* { dg-error "may not be closely nested" } */ + #pragma omp scope /* { dg-error "may not be closely nested" } */ + ; } } @@ -182,6 +273,8 @@ f3 (void) { #pragma omp ordered /* { dg-error "may not be closely nested" } */ ; + #pragma omp scope /* { dg-error "may not be closely nested" } */ + ; } } @@ -192,6 +285,8 @@ f4 (void) { #pragma omp ordered /* { dg-error "may not be closely nested" } */ ; + #pragma omp scope /* { dg-error "may not be closely nested" } */ + ; } } diff --git a/gcc/testsuite/gcc.dg/ipa/pr100600.c b/gcc/testsuite/gcc.dg/ipa/pr100600.c new file mode 100644 index 0000000..8a3d0e1 --- /dev/null +++ b/gcc/testsuite/gcc.dg/ipa/pr100600.c @@ -0,0 +1,22 @@ +/* PR ipa/100600 */ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ + +int a, b, c; +long d(long x, long e, long f, long g) { + long h, i; + for (; h < e; h++) { + i = f; + for (; i < g; i++) + c = b + a; + } + return h + i; +} + +long j(long x, long e, long y, long g) { + long h, i; + for (; h < e; h++) + for (; i < g; i++) + c = b + a; + return h + i; +} diff --git a/gcc/testsuite/gcc.dg/lto/pr101868_0.c b/gcc/testsuite/gcc.dg/lto/pr101868_0.c new file mode 100644 index 0000000..c84d19b --- /dev/null +++ b/gcc/testsuite/gcc.dg/lto/pr101868_0.c @@ -0,0 +1,33 @@ +/* { dg-lto-do run } */ +/* { dg-lto-options { "-O2 -fno-strict-aliasing -flto" } } */ + +typedef unsigned long VALUE; + +__attribute__ ((cold)) +void rb_check_type(VALUE, int); + +static VALUE +repro(VALUE dummy, VALUE hash) +{ + if (hash == 0) { + rb_check_type(hash, 1); + } + else if (*(long *)hash) { + rb_check_type(hash, 1); + } + + + return *(long *)hash; +} + +static VALUE (*that)(VALUE dummy, VALUE hash) = repro; + +int +main(int argc, char **argv) +{ + argc--; + that(0, argc); + + rb_check_type(argc, argc); + +} diff --git a/gcc/testsuite/gcc.dg/lto/pr101868_1.c b/gcc/testsuite/gcc.dg/lto/pr101868_1.c new file mode 100644 index 0000000..146c14a --- /dev/null +++ b/gcc/testsuite/gcc.dg/lto/pr101868_1.c @@ -0,0 +1,23 @@ +typedef unsigned long VALUE; + + +__attribute__ ((noreturn)) void rexc_raise(VALUE mesg); + +VALUE rb_donothing(VALUE klass); + +static void +funexpected_type(VALUE x, int xt, int t) +{ + rexc_raise(rb_donothing(0)); +} + +__attribute__ ((cold)) +void +rb_check_type(VALUE x, int t) +{ + int xt; + + if (x == 0) { + funexpected_type(x, xt, t); + } +} diff --git a/gcc/testsuite/gcc.dg/lto/pr101868_2.c b/gcc/testsuite/gcc.dg/lto/pr101868_2.c new file mode 100644 index 0000000..e6f01b2 --- /dev/null +++ b/gcc/testsuite/gcc.dg/lto/pr101868_2.c @@ -0,0 +1,11 @@ +typedef unsigned long VALUE; + +static void thing(void) {} +static void (*ptr)(void) = &thing; + +VALUE +rb_donothing(VALUE klass) +{ + ptr(); + return 0; +} diff --git a/gcc/testsuite/gcc.dg/lto/pr101868_3.c b/gcc/testsuite/gcc.dg/lto/pr101868_3.c new file mode 100644 index 0000000..6121762 --- /dev/null +++ b/gcc/testsuite/gcc.dg/lto/pr101868_3.c @@ -0,0 +1,8 @@ +typedef unsigned long VALUE; + +__attribute__((noreturn)) +void +rexc_raise(VALUE mesg) +{ + __builtin_exit(0); +} diff --git a/gcc/testsuite/gcc.dg/lto/pr48622_1.c b/gcc/testsuite/gcc.dg/lto/pr48622_1.c new file mode 100644 index 0000000..4d05bae --- /dev/null +++ b/gcc/testsuite/gcc.dg/lto/pr48622_1.c @@ -0,0 +1,6 @@ +/* { dg-options "-fno-lto" } */ + +typedef unsigned int u8 __attribute__ ((mode (QI))); +u8 ashift_qi_1 (u8) +{ +} diff --git a/gcc/testsuite/gcc.dg/pr101858.c b/gcc/testsuite/gcc.dg/pr101858.c new file mode 100644 index 0000000..61fcca6 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr101858.c @@ -0,0 +1,9 @@ +/* { dg-do compile } */ +/* { dg-options "-w" } */ + +int foo(int a) +{ + if (a < (int*)((__INTPTR_TYPE__)1 << a)) + a = 0; + return a; +} diff --git a/gcc/testsuite/gcc.dg/pr101938.c b/gcc/testsuite/gcc.dg/pr101938.c new file mode 100644 index 0000000..8277755 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr101938.c @@ -0,0 +1,28 @@ +// { dg-do run } +// { dg-require-effective-target lp64 } +// { dg-options "-O2 -fwrapv" } + +typedef long long int int64; +#define INT64CONST(x) (x##LL) +/* -9223372036854775808ULL */ +#define INT64_MIN (-INT64CONST(0x7FFFFFFFFFFFFFFF) - 1) + +static void __attribute__((noipa)) foo(int64 arg1, int64 arg2) { + int64 a1 = -arg1; + int64 a2 = (arg2 < 0) ? arg2 : -arg2; + + if (a1 > a2) { + int64 swap = arg1; + arg1 = arg2; + arg2 = swap; + } + + if (arg1 == INT64_MIN && arg2 == -1) return; + + __builtin_abort(); +} + +int main() { + foo(-1, INT64_MIN); + return 0; +} diff --git a/gcc/testsuite/gcc.dg/pr78213.c b/gcc/testsuite/gcc.dg/pr78213.c index ebc2cce..40dd3c8 100644 --- a/gcc/testsuite/gcc.dg/pr78213.c +++ b/gcc/testsuite/gcc.dg/pr78213.c @@ -1,12 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-fself-test" } */ - -/* When this test was written -fself-test took no argument, but it - has subsequently gained a mandatory argument, giving the path - to selftest support files (within the srcdir). - It's not clear how to provide this path sanely from - within DejaGnu, so for now, this test is disabled. */ -/* { dg-skip-if "" { *-*-* } } */ +/* { dg-options "-fself-test=$srcdir/selftests" } */ /* Verify that -fself-test does not fail on a non empty source. */ diff --git a/gcc/testsuite/gcc.dg/sso-16.c b/gcc/testsuite/gcc.dg/sso-16.c new file mode 100644 index 0000000..7bf8938 --- /dev/null +++ b/gcc/testsuite/gcc.dg/sso-16.c @@ -0,0 +1,100 @@ +/* { dg-do run } */ +/* { dg-require-effective-target int32plus } */ +/* { dg-options "-O3" } */ + +typedef __INT32_TYPE__ int32_t; + +#define BIG_ENDIAN __attribute__((scalar_storage_order("big-endian"))) + +/* host order version (little endian)*/ +struct _ip6_addr { + union { + char addr8[16]; + int32_t addr32[4]; + } u; +}; + +typedef struct _ip6_addr t_ip6_addr; + +struct _net_addr { + char is_v4; + union { + int32_t addr; + t_ip6_addr addr6; + } u; +}; + +typedef struct _net_addr t_net_addr; + +/* big endian version */ +struct _be_ip6_addr { + union { + char addr8[16]; + } BIG_ENDIAN u; +} BIG_ENDIAN; + +typedef struct _be_ip6_addr t_be_ip6_addr; + +struct _be_net_addr { + char is_v4; + union { + t_be_ip6_addr addr6; + int32_t addr; + } BIG_ENDIAN u; +} BIG_ENDIAN; + +typedef struct _be_net_addr t_be_net_addr; + +/* convert */ +t_be_ip6_addr be_ip6_addr(const t_ip6_addr ip6) +{ + t_be_ip6_addr rc = { + .u.addr8[0] = ip6.u.addr8[0], + .u.addr8[1] = ip6.u.addr8[1], + .u.addr8[2] = ip6.u.addr8[2], + .u.addr8[3] = ip6.u.addr8[3], + .u.addr8[4] = ip6.u.addr8[4], + .u.addr8[5] = ip6.u.addr8[5], + .u.addr8[6] = ip6.u.addr8[6], + .u.addr8[7] = ip6.u.addr8[7], + .u.addr8[8] = ip6.u.addr8[8], + .u.addr8[9] = ip6.u.addr8[9], + .u.addr8[10] = ip6.u.addr8[10], + .u.addr8[11] = ip6.u.addr8[11], + .u.addr8[12] = ip6.u.addr8[12], + .u.addr8[13] = ip6.u.addr8[13], + .u.addr8[14] = ip6.u.addr8[14], + .u.addr8[15] = ip6.u.addr8[15], + }; + return rc; +} + +t_be_net_addr __attribute__((noipa)) be_net_addr(const t_net_addr ip) +{ + t_be_net_addr rc = {.is_v4 = ip.is_v4 }; + if (ip.is_v4) { + rc.u.addr = ip.u.addr; + } else { + rc.u.addr6 = be_ip6_addr(ip.u.addr6); + } + return rc; +} + +int main(void) +{ + t_be_net_addr out = { }; + + t_net_addr in = { + .is_v4 = 0, + .u.addr6.u.addr8 = + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 } + }; + + out = be_net_addr(in); + + // actually first 4 bytes are swapped + if (in.u.addr6.u.addr8[0] != out.u.addr6.u.addr8[0]) + __builtin_abort(); + + return 0; +} diff --git a/gcc/testsuite/gcc.dg/tree-ssa/modref-6.c b/gcc/testsuite/gcc.dg/tree-ssa/modref-6.c index 8db9a1d..2d97a49 100644 --- a/gcc/testsuite/gcc.dg/tree-ssa/modref-6.c +++ b/gcc/testsuite/gcc.dg/tree-ssa/modref-6.c @@ -32,6 +32,6 @@ int test2() /* Flags for pure call. */ /* { dg-final { scan-tree-dump "parm 0 flags: direct not_returned" "modref1" } } */ /* Flags for const call. */ -/* { dg-final { scan-tree-dump "parm 0 flags: unused not_returned" "modref1" } } */ +/* { dg-final { scan-tree-dump "parm 0 flags: not_returned" "modref1" } } */ /* Overall we want to make "int a" non escaping. */ /* { dg-final { scan-tree-dump "return 42" "optimized" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr101824.c b/gcc/testsuite/gcc.dg/tree-ssa/pr101824.c new file mode 100644 index 0000000..d5987e1 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/pr101824.c @@ -0,0 +1,19 @@ +/* { dg-do compile } */ +/* { dg-options "-O3 -fdump-tree-pcom-details -fdump-tree-optimized" } */ + +int main() +{ + volatile int y; + void bar() + { + __builtin_printf ("%d", y); + } + while (y) + ; + return 0; +} + +/* Make sure the load from y is correctly interpreted as volatile, even + when going through FRAME. */ +/* { dg-final { scan-tree-dump-not "Executing predictive commoning" "pcom" } } */ +/* { dg-final { scan-tree-dump " ={v} FRAME" "optimized" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-ccp-40.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-ccp-40.c new file mode 100644 index 0000000..aa7349e1 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-ccp-40.c @@ -0,0 +1,11 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-optimized" } */ + +int foo(int x) +{ + int p = 7; + int q = p - (x & 5); + return q & 2; +} + +/* { dg-final { scan-tree-dump "return 2;" "optimized" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-7.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-7.c index 1c2d12a..5fc2145 100644 --- a/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-7.c +++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-7.c @@ -1,6 +1,5 @@ /* { dg-do compile } */ /* { dg-options "-O2 -fdump-tree-thread1-stats -fdump-tree-thread2-stats -fdump-tree-dom2-stats -fdump-tree-thread3-stats -fdump-tree-dom3-stats -fdump-tree-vrp2-stats -fno-guess-branch-probability" } */ -/* { dg-additional-options "--param=threader-mode=legacy" } */ /* Here we have the same issue as was commented in ssa-dom-thread-6.c. The PHI coming into the threader has a lot more constants, so the @@ -17,7 +16,7 @@ $ diff clean/a.c.105t.mergephi2 a.c.105t.mergephi2 basically tracking the switch index better through multiple paths. */ -/* { dg-final { scan-tree-dump "Jumps threaded: 19" "thread1" } } */ +/* { dg-final { scan-tree-dump "Jumps threaded: 18" "thread1" } } */ /* { dg-final { scan-tree-dump "Jumps threaded: 8" "thread2" } } */ /* { dg-final { scan-tree-dump-not "Jumps threaded" "dom2" } } */ diff --git a/gcc/testsuite/gcc.dg/uninit-42.c b/gcc/testsuite/gcc.dg/uninit-42.c new file mode 100644 index 0000000..efaaacd --- /dev/null +++ b/gcc/testsuite/gcc.dg/uninit-42.c @@ -0,0 +1,87 @@ +/* PR middle-end/101734 - missing warning reading from a write-only object + Verify that reading objects pointed to by arguments + declared with attribute access none or write-only is diagnosed by + -Wmaybe-uninitialized. + { dg-do compile } + { dg-options "-Wall" } */ + +#define A(mode, ...) __attribute__ ((access (mode, __VA_ARGS__))) + +void sink (void *, ...); + + +A (write_only, 1, 2) +int nowarn_wo_assign_r0 (int *p, int n) +{ + *p = n; + return *p; +} + +A (write_only, 1, 2) +int nowarn_wo_sink_r0 (int *p, int n) +{ + sink (p, p + 1, p + n); + return *p; +} + +A (write_only, 1, 2) +int warn_wo_r0 (int *p, int n) +{ + return *p; // { dg-warning "'\\*p' may be used uninitialized \\\[-Wmaybe-uninitialized" } +} + + +A (write_only, 1, 2) +int nowarn_wo_w1_r1 (int *p, int n) +{ + p[1] = n; + return p[1]; +} + +A (write_only, 1, 2) +int warn_wo_r1 (int *p, int n) +{ + return p[1]; // { dg-warning "'p\\\[1]' may be used uninitialized" } +} + + +A (write_only, 1, 2) +int nowarn_wo_rwi_rj (int *p, int n, int i, int j) +{ + p[i] = n; + return p[j]; +} + +A (write_only, 1, 2) + int warn_wo_ri (int *p, int n, int i) +{ + return p[i]; // { dg-warning " may be used uninitialized" } +} + + + +A (none, 1, 2) +int* nowarn_none_sink_return (int *p, int n) +{ + sink (p, p + 1, p + n); + return p; +} + +A (none, 1, 2) +int warn_none_r0 (int *p, int n) +{ + (void)&n; + return *p; // { dg-warning "'\\*p' may be used uninitialized" } +} + +A (none, 1, 2) +int warn_none_r1 (int *p, int n) +{ + return p[1]; // { dg-warning "'p\\\[1]' may be used uninitialized" } +} + +A (write_only, 1, 2) +int warn_none_ri (int *p, int n, int i) +{ + return p[i]; // { dg-warning " may be used uninitialized" } +} diff --git a/gcc/testsuite/gcc.dg/uninit-pred-9_b.c b/gcc/testsuite/gcc.dg/uninit-pred-9_b.c index 9383c55..8c2d28c 100644 --- a/gcc/testsuite/gcc.dg/uninit-pred-9_b.c +++ b/gcc/testsuite/gcc.dg/uninit-pred-9_b.c @@ -20,7 +20,7 @@ int foo (int n, int l, int m, int r) blah(v); /* { dg-bogus "uninitialized" "bogus warning" } */ if ( (n <= 8) && (m < 99) && (r < 19) ) - blah(v); /* { dg-bogus "uninitialized" "pr101674" { xfail powerpc64*-*-* mmix-*-* } } */ + blah(v); /* { dg-bogus "uninitialized" "pr101674" { xfail powerpc64*-*-* mmix-*-* cris-*-* } } */ return 0; } diff --git a/gcc/testsuite/gcc.dg/vla-stexp-2.c b/gcc/testsuite/gcc.dg/vla-stexp-2.c new file mode 100644 index 0000000..176f400 --- /dev/null +++ b/gcc/testsuite/gcc.dg/vla-stexp-2.c @@ -0,0 +1,33 @@ +/* PR101838 */ +/* { dg-do run } */ +/* { dg-options "-Wpedantic -O0" } */ + + +int bar0( + int (*a)[*], + int (*b)[sizeof(*a)] +); + + +int bar( + struct f { /* { dg-warning "will not be visible outside of this definition" } */ + int a[*]; } v, /* { dg-warning "variably modified type" } */ + int (*b)[sizeof(struct f)] // should not warn about zero size +); + +int foo(void) +{ + int n = 0; + return sizeof(typeof(*({ n = 10; struct foo { /* { dg-warning "braced-groups" } */ + int x[n]; /* { dg-warning "variably modified type" } */ + } x; &x; }))); +} + + +int main() +{ + if (sizeof(struct foo { int x[10]; }) != foo()) + __builtin_abort(); + + return 0; +} diff --git a/gcc/testsuite/gcc.target/arm/pr51534.c b/gcc/testsuite/gcc.target/arm/pr51534.c index 3711b45..ac7f1ea 100644 --- a/gcc/testsuite/gcc.target/arm/pr51534.c +++ b/gcc/testsuite/gcc.target/arm/pr51534.c @@ -35,29 +35,17 @@ GEN_COND_TESTS(vceq) /* Scan for expected outputs. */ /* { dg-final { scan-assembler "vcgt\.s8\[ \]+\[dD\]\[0-9\]+, \[dD\]\[0-9\]+, #0" } } */ -/* { dg-final { scan-assembler-times "vcgt\.u8\[ \]+\[dD\]\[0-9\]+, \[dD\]\[0-9\]+, \[dD\]\[0-9\]+" 2 } } */ /* { dg-final { scan-assembler "vcgt\.s16\[ \]+\[dD\]\[0-9\]+, \[dD\]\[0-9\]+, #0" } } */ -/* { dg-final { scan-assembler-times "vcgt\.u16\[ \]+\[dD\]\[0-9\]+, \[dD\]\[0-9\]+, \[dD\]\[0-9\]+" 2 } } */ /* { dg-final { scan-assembler "vcgt\.s32\[ \]+\[dD\]\[0-9\]+, \[dD\]\[0-9\]+, #0" } } */ -/* { dg-final { scan-assembler-times "vcgt\.u32\[ \]+\[dD\]\[0-9\]+, \[dD\]\[0-9\]+, \[dD\]\[0-9\]+" 2 } } */ /* { dg-final { scan-assembler "vcgt\.s8\[ \]+\[qQ\]\[0-9\]+, \[qQ\]\[0-9\]+, #0" } } */ -/* { dg-final { scan-assembler-times "vcgt\.u8\[ \]+\[qQ\]\[0-9\]+, \[qQ\]\[0-9\]+, \[qQ\]\[0-9\]+" 2 } } */ /* { dg-final { scan-assembler "vcgt\.s16\[ \]+\[qQ\]\[0-9\]+, \[qQ\]\[0-9\]+, #0" } } */ -/* { dg-final { scan-assembler-times "vcgt\.u16\[ \]+\[qQ\]\[0-9\]+, \[qQ\]\[0-9\]+, \[qQ\]\[0-9\]+" 2 } } */ /* { dg-final { scan-assembler "vcgt\.s32\[ \]+\[qQ\]\[0-9\]+, \[qQ\]\[0-9\]+, #0" } } */ -/* { dg-final { scan-assembler-times "vcgt\.u32\[ \]+\[qQ\]\[0-9\]+, \[qQ\]\[0-9\]+, \[qQ\]\[0-9\]+" 2 } } */ /* { dg-final { scan-assembler "vcge\.s8\[ \]+\[dD\]\[0-9\]+, \[dD\]\[0-9\]+, #0" } } */ -/* { dg-final { scan-assembler-times "vcge\.u8\[ \]+\[dD\]\[0-9\]+, \[dD\]\[0-9\]+, \[dD\]\[0-9\]+" 2 } } */ /* { dg-final { scan-assembler "vcge\.s16\[ \]+\[dD\]\[0-9\]+, \[dD\]\[0-9\]+, #0" } } */ -/* { dg-final { scan-assembler-times "vcge\.u16\[ \]+\[dD\]\[0-9\]+, \[dD\]\[0-9\]+, \[dD\]\[0-9\]+" 2 } } */ /* { dg-final { scan-assembler "vcge\.s32\[ \]+\[dD\]\[0-9\]+, \[dD\]\[0-9\]+, #0" } } */ -/* { dg-final { scan-assembler-times "vcge\.u32\[ \]+\[dD\]\[0-9\]+, \[dD\]\[0-9\]+, \[dD\]\[0-9\]+" 2 } } */ /* { dg-final { scan-assembler "vcge\.s8\[ \]+\[qQ\]\[0-9\]+, \[qQ\]\[0-9\]+, #0" } } */ -/* { dg-final { scan-assembler-times "vcge\.u8\[ \]+\[qQ\]\[0-9\]+, \[qQ\]\[0-9\]+, \[qQ\]\[0-9\]+" 2 } } */ /* { dg-final { scan-assembler "vcge\.s16\[ \]+\[qQ\]\[0-9\]+, \[qQ\]\[0-9\]+, #0" } } */ -/* { dg-final { scan-assembler-times "vcge\.u16\[ \]+\[qQ\]\[0-9\]+, \[qQ\]\[0-9\]+, \[qQ\]\[0-9\]+" 2 } } */ /* { dg-final { scan-assembler "vcge\.s32\[ \]+\[qQ\]\[0-9\]+, \[qQ\]\[0-9\]+, #0" } } */ -/* { dg-final { scan-assembler-times "vcge\.u32\[ \]+\[qQ\]\[0-9\]+, \[qQ\]\[0-9\]+, \[qQ\]\[0-9\]+" 2 } } */ /* { dg-final { scan-assembler "vclt\.s8\[ \]+\[dD\]\[0-9\]+, \[dD\]\[0-9\]+, #0" } } */ /* { dg-final { scan-assembler "vclt\.s16\[ \]+\[dD\]\[0-9\]+, \[dD\]\[0-9\]+, #0" } } */ /* { dg-final { scan-assembler "vclt\.s32\[ \]+\[dD\]\[0-9\]+, \[dD\]\[0-9\]+, #0" } } */ @@ -70,12 +58,14 @@ GEN_COND_TESTS(vceq) /* { dg-final { scan-assembler "vcle\.s8\[ \]+\[qQ\]\[0-9\]+, \[qQ\]\[0-9\]+, #0" } } */ /* { dg-final { scan-assembler "vcle\.s16\[ \]+\[qQ\]\[0-9\]+, \[qQ\]\[0-9\]+, #0" } } */ /* { dg-final { scan-assembler "vcle\.s32\[ \]+\[qQ\]\[0-9\]+, \[qQ\]\[0-9\]+, #0" } } */ -/* { dg-final { scan-assembler-times "vceq\.i8\[ \]+\[dD\]\[0-9\]+, \[dD\]\[0-9\]+, #0" 2 } } */ -/* { dg-final { scan-assembler-times "vceq\.i16\[ \]+\[dD\]\[0-9\]+, \[dD\]\[0-9\]+, #0" 2 } } */ -/* { dg-final { scan-assembler-times "vceq\.i32\[ \]+\[dD\]\[0-9\]+, \[dD\]\[0-9\]+, #0" 2 } } */ -/* { dg-final { scan-assembler-times "vceq\.i8\[ \]+\[qQ\]\[0-9\]+, \[qQ\]\[0-9\]+, #0" 2 } } */ -/* { dg-final { scan-assembler-times "vceq\.i16\[ \]+\[qQ\]\[0-9\]+, \[qQ\]\[0-9\]+, #0" 2 } } */ -/* { dg-final { scan-assembler-times "vceq\.i32\[ \]+\[qQ\]\[0-9\]+, \[qQ\]\[0-9\]+, #0" 2 } } */ +/* { dg-final { scan-assembler-times "vceq\.i8\[ \]+\[dD\]\[0-9\]+, \[dD\]\[0-9\]+, #0" 4 } } */ +/* { dg-final { scan-assembler-times "vceq\.i16\[ \]+\[dD\]\[0-9\]+, \[dD\]\[0-9\]+, #0" 4 } } */ +/* { dg-final { scan-assembler-times "vceq\.i32\[ \]+\[dD\]\[0-9\]+, \[dD\]\[0-9\]+, #0" 4 } } */ +/* { dg-final { scan-assembler-times "vceq\.i8\[ \]+\[qQ\]\[0-9\]+, \[qQ\]\[0-9\]+, #0" 4 } } */ +/* { dg-final { scan-assembler-times "vceq\.i16\[ \]+\[qQ\]\[0-9\]+, \[qQ\]\[0-9\]+, #0" 4 } } */ +/* { dg-final { scan-assembler-times "vceq\.i32\[ \]+\[qQ\]\[0-9\]+, \[qQ\]\[0-9\]+, #0" 4 } } */ +/* { dg-final { scan-assembler-times "vmov\.i32\[ \]+\[dD\]\[0-9\]+, #0xffffffff" 3 } } */ +/* { dg-final { scan-assembler-times "vmov\.i32\[ \]+\[qQ\]\[0-9\]+, #4294967295" 3 } } */ /* And ensure we don't have unexpected output too. */ /* { dg-final { scan-assembler-not "vc\[gl\]\[te\]\.u\[0-9\]+\[ \]+\[qQdD\]\[0-9\]+, \[qQdD\]\[0-9\]+, #0" } } */ diff --git a/gcc/testsuite/gcc.target/arm/simd/pr98435.c b/gcc/testsuite/gcc.target/arm/simd/pr98435.c index 0af8633..a4c6a1c 100644 --- a/gcc/testsuite/gcc.target/arm/simd/pr98435.c +++ b/gcc/testsuite/gcc.target/arm/simd/pr98435.c @@ -1,5 +1,6 @@ /* { dg-do compile } */ /* { dg-options "-O2 -ffast-math" } */ +/* { dg-require-effective-target arm_softfp_ok } */ /* { dg-require-effective-target arm_v8_2a_bf16_neon_ok } */ /* { dg-add-options arm_v8_2a_bf16_neon } */ /* { dg-additional-options "-mfloat-abi=softfp -march=armv8.2-a+bf16+fp16" } */ diff --git a/gcc/testsuite/gcc.target/i386/amxbf16-dpbf16ps-2.c b/gcc/testsuite/gcc.target/i386/amxbf16-dpbf16ps-2.c index 349ec58..f7002ca 100644 --- a/gcc/testsuite/gcc.target/i386/amxbf16-dpbf16ps-2.c +++ b/gcc/testsuite/gcc.target/i386/amxbf16-dpbf16ps-2.c @@ -57,7 +57,7 @@ void calc_matrix_dpbf16ps (__tile *dst, __tile *src1, __tile *src2) (make_f32(src1_buf[i * 4 * N + 4 * j + t]) * make_f32(src2_buf[j * 4 * K + 4 * k + t])) + (make_f32(src1_buf[i * 4 * N + 4 * j + t + 1]) * - make_f32(src1_buf[i * 4 * N + 4 * j + t + 1])); + make_f32(src2_buf[j * 4 * K + 4 * k + t + 1])); } } @@ -72,8 +72,8 @@ void test_amx_bf16_dpbf16ps () init_tile_config (&cfg); init_tile_reg_and_src_with_buffer (1, dst, tmp_dst_buf); - init_tile_reg_and_src_with_buffer (2, dst, tmp_dst_buf); - init_tile_reg_and_src_with_buffer (3, dst, tmp_dst_buf); + init_tile_reg_and_src_with_buffer (2, src1, tmp_dst_buf); + init_tile_reg_and_src_with_buffer (3, src2, tmp_dst_buf); calc_matrix_dpbf16ps (&dst, &src1, &src2); diff --git a/gcc/testsuite/gcc.target/i386/avx512f-pr101860.c b/gcc/testsuite/gcc.target/i386/avx512f-pr101860.c new file mode 100644 index 0000000..1aadfa2 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/avx512f-pr101860.c @@ -0,0 +1,5 @@ +/* PR target/101860 */ +/* { dg-do compile } */ +/* { dg-options "-O2 -mavx512f -mno-avx512bw" } */ + +#include "../../gcc.dg/torture/vshuf-v32hi.c" diff --git a/gcc/testsuite/gcc.target/i386/avx512f-pr101896.c b/gcc/testsuite/gcc.target/i386/avx512f-pr101896.c new file mode 100644 index 0000000..c1805cc --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/avx512f-pr101896.c @@ -0,0 +1,5 @@ +/* PR target/101896 */ +/* { dg-do compile } */ +/* { dg-options "-O2 -mavx512f -mno-avx512bw" } */ + +#include "../../gcc.dg/torture/vshuf-v64qi.c" diff --git a/gcc/testsuite/gcc.target/i386/avx512f-pr80355-1.c b/gcc/testsuite/gcc.target/i386/avx512f-pr80355-1.c new file mode 100644 index 0000000..b1ff010 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/avx512f-pr80355-1.c @@ -0,0 +1,19 @@ +/* PR target/80355 */ +/* { dg-do compile } */ +/* { dg-options "-O2 -mavx512f -mno-avx512vl -mno-avx512dq" } */ +/* { dg-final { scan-assembler "\tvshufi32x4\t" } } */ +/* { dg-final { scan-assembler "\tvshufi64x2\t" } } */ + +typedef long long V __attribute__((vector_size (64))); +typedef int W __attribute__((vector_size (64))); + +W +f0 (W x) +{ + return __builtin_shuffle (x, (W) { 8, 9, 10, 11, 12, 13, 14, 15, 0, 1, 2, 3, 4, 5, 6, 7 }); +} +V +f1 (V x) +{ + return __builtin_shuffle (x, (V) { 4, 5, 6, 7, 0, 1, 2, 3 }); +} diff --git a/gcc/testsuite/gcc.target/i386/avx512f-pr80355-2.c b/gcc/testsuite/gcc.target/i386/avx512f-pr80355-2.c new file mode 100644 index 0000000..c510b2f --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/avx512f-pr80355-2.c @@ -0,0 +1,23 @@ +/* PR target/80355 */ +/* { dg-do compile } */ +/* { dg-options "-O2 -mavx512f -mno-avx512vl -mno-avx512dq -mno-avx512bw" } */ +/* { dg-final { scan-assembler-times "\tvshufi(?:32x4|64x2)\t" 2 } } */ + +typedef short V __attribute__((vector_size (64))); +typedef char W __attribute__((vector_size (64))); + +W +f0 (W x) +{ + return __builtin_shuffle (x, (W) { 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31 }); +} + +V +f1 (V x) +{ + return __builtin_shuffle (x, (V) { 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }); +} diff --git a/gcc/testsuite/gcc.target/i386/pr101261.c b/gcc/testsuite/gcc.target/i386/pr101261.c new file mode 100644 index 0000000..d25d1a2 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr101261.c @@ -0,0 +1,11 @@ +/* PR middle-end/101261 */ +/* { dg-do compile { target fpic } } */ +/* { dg-options "-fno-semantic-interposition -fPIC" } */ +/* { dg-require-ifunc "" } */ + +void +__attribute__((target_clones("default", "avx2"))) +dt_ioppr_transform_image_colorspace() +{ + dt_ioppr_transform_image_colorspace(); +} diff --git a/gcc/testsuite/gcc.target/i386/pr101846-1.c b/gcc/testsuite/gcc.target/i386/pr101846-1.c new file mode 100644 index 0000000..40d95bd --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr101846-1.c @@ -0,0 +1,95 @@ +/* { dg-do compile } */ +/* { dg-options "-mavx512bw -mavx512vl -mavx512dq -O2" } */ +/* { dg-final { scan-assembler-not "vmov" } } */ +/* { dg-final { scan-assembler-times "vpmovzxbw" "3" } } */ +/* { dg-final { scan-assembler-times "vpmovzxwd" "3" } } */ +/* { dg-final { scan-assembler-times "vpmovzxdq" "3" } } */ + +typedef short v4hi __attribute__((vector_size (8))); +typedef short v8hi __attribute__((vector_size (16))); +typedef short v16hi __attribute__((vector_size (32))); +typedef short v32hi __attribute__((vector_size (64))); +typedef char v8qi __attribute__((vector_size (8))); +typedef char v16qi __attribute__((vector_size (16))); +typedef char v32qi __attribute__((vector_size (32))); +typedef char v64qi __attribute__((vector_size (64))); +typedef int v2si __attribute__((vector_size (8))); +typedef int v4si __attribute__((vector_size (16))); +typedef int v8si __attribute__((vector_size (32))); +typedef int v16si __attribute__((vector_size (64))); + +v32hi +foo_zxwd_512 (v16hi x) +{ + return __builtin_shufflevector (x, (v16hi) {}, + 0, 16, 1, 17, 2, 18, 3, 19, + 4, 20, 5, 21, 6, 22, 7, 23, + 8, 24, 9, 25, 10, 26, 11, 27, + 12, 28, 13, 29, 14, 30, 15, 31); +} + +v16hi +foo_zxwd_256 (v8hi x) +{ + return __builtin_shufflevector (x, (v8hi) {}, + 0, 8, 1, 9, 2, 10, 3, 11, + 4, 12, 5, 13, 6, 14, 7, 15); +} + +v8hi +foo_zxwd_128 (v4hi x) +{ + return __builtin_shufflevector (x, (v4hi) {}, 0, 4, 1, 5, 2, 6, 3, 7); +} + +v16si +foo_zxdq_512 (v8si x) +{ + return __builtin_shufflevector (x, (v8si) {}, + 0, 8, 1, 9, 2, 10, 3, 11, + 4, 12, 5, 13, 6, 14, 7, 15); +} + +v8si +foo_zxdq_256 (v4si x) +{ + return __builtin_shufflevector (x, (v4si) {}, 0, 4, 1, 5, 2, 6, 3, 7); +} + +v4si +foo_zxdq_128 (v2si x) +{ + return __builtin_shufflevector (x, (v2si) {}, 0, 2, 1, 3); +} + +v64qi +foo_zxbw_512 (v32qi x) +{ + return __builtin_shufflevector (x, (v32qi) {}, + 0, 32, 1, 33, 2, 34, 3, 35, + 4, 36, 5, 37, 6, 38, 7, 39, + 8, 40, 9, 41, 10, 42, 11, 43, + 12, 44, 13, 45, 14, 46, 15, 47, + 16, 48, 17, 49, 18, 50, 19, 51, + 20, 52, 21, 53, 22, 54, 23, 55, + 24, 56, 25, 57, 26, 58, 27, 59, + 28, 60, 29, 61, 30, 62, 31, 63); +} + +v32qi +foo_zxbw_256 (v16qi x) +{ + return __builtin_shufflevector (x, (v16qi) {}, + 0, 16, 1, 17, 2, 18, 3, 19, + 4, 20, 5, 21, 6, 22, 7, 23, + 8, 24, 9, 25, 10, 26, 11, 27, + 12, 28, 13, 29, 14, 30, 15, 31); +} + +v16qi +foo_zxbw_128 (v8qi x) +{ + return __builtin_shufflevector (x, (v8qi) {}, + 0, 8, 1, 9, 2, 10, 3, 11, + 4, 12, 5, 13, 6, 14, 7, 15); +} diff --git a/gcc/testsuite/gcc.target/i386/pr101846-2.c b/gcc/testsuite/gcc.target/i386/pr101846-2.c new file mode 100644 index 0000000..26c9ed5 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr101846-2.c @@ -0,0 +1,81 @@ +/* { dg-do compile } */ +/* { dg-options "-mavx512vl -mavx512vbmi -O2" } */ +/* { dg-final { scan-assembler-times "vpmovwb" "3" } } */ +/* { dg-final { scan-assembler-times "vpmovdw" "3" } } */ +/* { dg-final { scan-assembler-times "vpmovqd" "3" } } */ + +typedef short v4hi __attribute__((vector_size (8))); +typedef short v8hi __attribute__((vector_size (16))); +typedef short v16hi __attribute__((vector_size (32))); +typedef short v32hi __attribute__((vector_size (64))); +typedef char v8qi __attribute__((vector_size (8))); +typedef char v16qi __attribute__((vector_size (16))); +typedef char v32qi __attribute__((vector_size (32))); +typedef char v64qi __attribute__((vector_size (64))); +typedef int v2si __attribute__((vector_size (8))); +typedef int v4si __attribute__((vector_size (16))); +typedef int v8si __attribute__((vector_size (32))); +typedef int v16si __attribute__((vector_size (64))); + +v16hi +foo_dw_512 (v32hi x) +{ + return __builtin_shufflevector (x, x, + 0, 2, 4, 6, 8, 10, 12, 14, + 16, 18, 20, 22, 24, 26, 28, 30); +} + +v8hi +foo_dw_256 (v16hi x) +{ + return __builtin_shufflevector (x, x, 0, 2, 4, 6, 8, 10, 12, 14); +} + +v4hi +foo_dw_128 (v8hi x) +{ + return __builtin_shufflevector (x, x, 0, 2, 4, 6); +} + +v8si +foo_qd_512 (v16si x) +{ + return __builtin_shufflevector (x, x, 0, 2, 4, 6, 8, 10, 12, 14); +} + +v4si +foo_qd_256 (v8si x) +{ + return __builtin_shufflevector (x, x, 0, 2, 4, 6); +} + +v2si +foo_qd_128 (v4si x) +{ + return __builtin_shufflevector (x, x, 0, 2); +} + +v32qi +foo_wb_512 (v64qi x) +{ + return __builtin_shufflevector (x, x, + 0, 2, 4, 6, 8, 10, 12, 14, + 16, 18, 20, 22, 24, 26, 28, 30, + 32, 34, 36, 38, 40, 42, 44, 46, + 48, 50, 52, 54, 56, 58, 60, 62); +} + +v16qi +foo_wb_256 (v32qi x) +{ + return __builtin_shufflevector (x, x, + 0, 2, 4, 6, 8, 10, 12, 14, + 16, 18, 20, 22, 24, 26, 28, 30); +} + +v8qi +foo_wb_128 (v16qi x) +{ + return __builtin_shufflevector (x, x, + 0, 2, 4, 6, 8, 10, 12, 14); +} diff --git a/gcc/testsuite/gcc.target/i386/pr101846-3.c b/gcc/testsuite/gcc.target/i386/pr101846-3.c new file mode 100644 index 0000000..f774018 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr101846-3.c @@ -0,0 +1,73 @@ +/* { dg-do compile } */ +/* { dg-options "-mavx512vl -mavx512vbmi -O2" } */ +/* { dg-final { scan-assembler-times "vpermb" "2" } } */ +/* { dg-final { scan-assembler-times "vpermw" "2" } } */ +/* { dg-final { scan-assembler-times "vpermd" "2" } } */ + +typedef short v4hi __attribute__((vector_size (8))); +typedef short v8hi __attribute__((vector_size (16))); +typedef short v16hi __attribute__((vector_size (32))); +typedef short v32hi __attribute__((vector_size (64))); +typedef char v8qi __attribute__((vector_size (8))); +typedef char v16qi __attribute__((vector_size (16))); +typedef char v32qi __attribute__((vector_size (32))); +typedef char v64qi __attribute__((vector_size (64))); +typedef int v2si __attribute__((vector_size (8))); +typedef int v4si __attribute__((vector_size (16))); +typedef int v8si __attribute__((vector_size (32))); +typedef int v16si __attribute__((vector_size (64))); + +v32hi +foow_512 (v32hi x) +{ + return __builtin_shufflevector (x, x, + 0, 2, 4, 6, 8, 10, 12, 14, + 16, 18, 20, 22, 24, 26, 28, 30, + 16, 17, 18, 19, 20, 21, 22, 23, + 24, 25, 26, 27, 28, 29, 30, 31); +} + +v16hi +foow_256 (v16hi x) +{ + return __builtin_shufflevector (x, x, 0, 2, 4, 6, 8, 10, 12, 14, + 8, 9, 10, 11, 12, 13, 14, 15); +} + + +v16si +food_512 (v16si x) +{ + return __builtin_shufflevector (x, x, 0, 2, 4, 6, 8, 10, 12, 14, + 8, 9, 10, 11, 12, 13, 14, 15); +} + +v8si +food_256 (v8si x) +{ + return __builtin_shufflevector (x, x, 0, 2, 4, 6, 4, 5, 6, 7); +} + +v64qi +foob_512 (v64qi x) +{ + return __builtin_shufflevector (x, x, + 0, 2, 4, 6, 8, 10, 12, 14, + 16, 18, 20, 22, 24, 26, 28, 30, + 32, 34, 36, 38, 40, 42, 44, 46, + 48, 50, 52, 54, 56, 58, 60, 62, + 32, 33, 34, 35, 36, 37, 38, 39, + 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, + 56, 57, 58, 59, 60, 61, 62, 63); +} + +v32qi +foob_256 (v32qi x) +{ + return __builtin_shufflevector (x, x, + 0, 2, 4, 6, 8, 10, 12, 14, + 16, 18, 20, 22, 24, 26, 28, 30, + 16, 17, 18, 19, 20, 21, 22, 23, + 24, 25, 26, 27, 28, 29, 30, 31); +} diff --git a/gcc/testsuite/gcc.target/i386/pr101846-4.c b/gcc/testsuite/gcc.target/i386/pr101846-4.c new file mode 100644 index 0000000..2a6163c --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr101846-4.c @@ -0,0 +1,40 @@ +/* { dg-do compile } */ +/* { dg-options "-mavx512vl -mavx512vbmi -O2" } */ +/* { dg-final { scan-assembler-times "vpermi2b" "3" } } */ + +typedef char v16qi __attribute__((vector_size (16))); +typedef char v32qi __attribute__((vector_size (32))); +typedef char v64qi __attribute__((vector_size (64))); + + +v64qi +foob_512 (v64qi x, v64qi y) +{ + return __builtin_shufflevector (x, y, + 0, 2, 4, 6, 8, 10, 12, 14, + 16, 18, 20, 22, 24, 26, 28, 30, + 32, 34, 36, 38, 40, 42, 44, 46, + 48, 50, 52, 54, 56, 58, 60, 62, + 64, 65, 66, 67, 68, 69, 70, 71, + 72, 73, 74, 77, 79, 74, 72, 70, + 89, 88, 78, 86, 85, 75, 83, 82, + 112, 108, 101, 100, 86, 96, 97, 95); +} + +v32qi +foob_256 (v32qi x, v32qi y) +{ + return __builtin_shufflevector (x, y, + 0, 2, 4, 6, 8, 10, 12, 14, + 16, 18, 20, 22, 24, 26, 28, 30, + 32, 34, 36, 38, 40, 42, 44, 46, + 48, 50, 52, 54, 56, 58, 60, 62); +} + +v16qi +foob_128 (v16qi x, v16qi y) +{ + return __builtin_shufflevector (x, y, + 0, 2, 4, 6, 8, 10, 12, 14, + 16, 18, 20, 22, 24, 26, 28, 30); +} diff --git a/gcc/testsuite/gcc.target/i386/pr101930.c b/gcc/testsuite/gcc.target/i386/pr101930.c new file mode 100644 index 0000000..7207dd1 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr101930.c @@ -0,0 +1,9 @@ +/* { dg-do compile } */ +/* { dg-options "-mavx512f -O2 -mfpmath=sse -ffast-math" } */ +double a; +double +__attribute__((noipa)) +foo (int b) +{ + return __builtin_ldexp (a, b); +} diff --git a/gcc/testsuite/gcc.target/i386/pr54400.c b/gcc/testsuite/gcc.target/i386/pr54400.c index 5ed5ba0..3a45037 100644 --- a/gcc/testsuite/gcc.target/i386/pr54400.c +++ b/gcc/testsuite/gcc.target/i386/pr54400.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-O2 -msse3 -mfpmath=sse" } */ +/* { dg-options "-O2 -msse3 -mfpmath=sse -mtune-ctrl=v2df_reduction_prefer_haddpd" } */ #include <x86intrin.h> diff --git a/gcc/testsuite/gcc.target/i386/pr82460-2.c b/gcc/testsuite/gcc.target/i386/pr82460-2.c index 4a45bee..8cdfb54 100644 --- a/gcc/testsuite/gcc.target/i386/pr82460-2.c +++ b/gcc/testsuite/gcc.target/i386/pr82460-2.c @@ -1,6 +1,6 @@ /* PR target/82460 */ /* { dg-do compile } */ -/* { dg-options "-O2 -ftree-vectorize -mavx512vbmi -mprefer-vector-width=none" } */ +/* { dg-options "-O2 -ftree-vectorize -mavx512vbmi -mprefer-vector-width=none --param=vect-epilogues-nomask=0" } */ /* We want to reuse the permutation mask in the loop, so use vpermt2b rather than vpermi2b. */ /* { dg-final { scan-assembler-not {\mvpermi2b\M} } } */ diff --git a/gcc/testsuite/gcc.target/i386/pr88531-1a.c b/gcc/testsuite/gcc.target/i386/pr88531-1a.c index d1c29b2..5e4f28e 100644 --- a/gcc/testsuite/gcc.target/i386/pr88531-1a.c +++ b/gcc/testsuite/gcc.target/i386/pr88531-1a.c @@ -1,4 +1,4 @@ -/* { dg-do compile { target lp64 } } */ +/* { dg-do compile } */ /* { dg-options "-O3 -march=x86-64 -mfpmath=sse" } */ #include <stdint.h> diff --git a/gcc/testsuite/gcc.target/i386/pr94147.c b/gcc/testsuite/gcc.target/i386/pr94147.c new file mode 100644 index 0000000..8ff5c34 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr94147.c @@ -0,0 +1,22 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -msse3 -mfpmath=sse" } */ + +#include <x86intrin.h> + +double f (__m128d p) +{ + return p[0] - p[1]; +} + +double g1 (__m128d p) +{ + return p[0] + p[1]; +} + +double g2 (__m128d p) +{ + return p[1] + p[0]; +} + +/* { dg-final { scan-assembler-not "hsubpd" } } */ +/* { dg-final { scan-assembler-not "haddpd" } } */ diff --git a/gcc/testsuite/gcc.target/i386/pr98309-1.c b/gcc/testsuite/gcc.target/i386/pr98309-1.c new file mode 100644 index 0000000..3a7afb5 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr98309-1.c @@ -0,0 +1,18 @@ +/* { dg-do compile } */ +/* { dg-options "-mavx512f -O2 -mfpmath=sse -ffast-math" } */ +/* { dg-final { scan-assembler-times "vcvtsi2s\[sd\]" "2" } } */ +/* { dg-final { scan-assembler-times "vscalefs\[sd\]" "2" } } */ + +double +__attribute__((noipa)) +foo (double a, int b) +{ + return __builtin_ldexp (a, b); +} + +float +__attribute__((noipa)) +foo2 (float a, int b) +{ + return __builtin_ldexpf (a, b); +} diff --git a/gcc/testsuite/gcc.target/i386/pr98309-2.c b/gcc/testsuite/gcc.target/i386/pr98309-2.c new file mode 100644 index 0000000..ecfb916 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr98309-2.c @@ -0,0 +1,39 @@ +/* { dg-do run } */ +/* { dg-options "-mavx512f -O2 -mfpmath=sse -ffast-math" } */ +/* { dg-require-effective-target avx512f } */ + +#define AVX512F +#ifndef CHECK +#define CHECK "avx512f-helper.h" +#endif + +#include CHECK + +#include "pr98309-1.c" + +double +__attribute__((noipa, target("fpmath=387"))) +foo_i387 (double a, int b) +{ + return __builtin_ldexp (a, b); +} + +float +__attribute__((noipa, target("fpmath=387"))) +foo2_i387 (float a, int b) +{ + return __builtin_ldexpf (a, b); +} + +static void +test_512 (void) +{ + float fa = 14.5; + double da = 44.5; + int fb = 12; + int db = 8; + if (foo_i387 (da, db) != foo (da, db)) + abort (); + if (foo2_i387 (fa, fb) != foo2 (fa, fb)) + abort (); +} diff --git a/gcc/testsuite/gcc.target/powerpc/fold-vec-load-builtin_vec_xl-char.c b/gcc/testsuite/gcc.target/powerpc/fold-vec-load-builtin_vec_xl-char.c index f6eb88f..9fc24f9 100644 --- a/gcc/testsuite/gcc.target/powerpc/fold-vec-load-builtin_vec_xl-char.c +++ b/gcc/testsuite/gcc.target/powerpc/fold-vec-load-builtin_vec_xl-char.c @@ -36,4 +36,4 @@ BUILD_VAR_TEST( test10, vector unsigned char, signed long long, vector unsigned BUILD_VAR_TEST( test11, vector unsigned char, signed int, vector unsigned char); BUILD_CST_TEST( test12, vector unsigned char, 8, vector unsigned char); -/* { dg-final { scan-assembler-times {\mlxvw4x\M|\mlxvd2x\M|\mlxvx\M|\mp?lvx\M} 12 } } */ +/* { dg-final { scan-assembler-times {\mlxvw4x\M|\mlxvd2x\M|\mlxvx\M|\mp?lxv\M|\mlvx\M} 12 } } */ diff --git a/gcc/testsuite/gcc.target/powerpc/fold-vec-load-builtin_vec_xl-double.c b/gcc/testsuite/gcc.target/powerpc/fold-vec-load-builtin_vec_xl-double.c index 66d5445..770bf36 100644 --- a/gcc/testsuite/gcc.target/powerpc/fold-vec-load-builtin_vec_xl-double.c +++ b/gcc/testsuite/gcc.target/powerpc/fold-vec-load-builtin_vec_xl-double.c @@ -28,4 +28,4 @@ BUILD_VAR_TEST( test4, vector double, signed long long, vector double); BUILD_VAR_TEST( test5, vector double, signed int, vector double); BUILD_CST_TEST( test6, vector double, 12, vector double); -/* { dg-final { scan-assembler-times {\mlxvd2x\M|\mlxvx\M|\mp?lvx\M} 6 } } */ +/* { dg-final { scan-assembler-times {\mlxvd2x\M|\mlxvx\M|\mp?lxv\M|\mlvx\M} 6 } } */ diff --git a/gcc/testsuite/gcc.target/powerpc/fold-vec-load-builtin_vec_xl-float.c b/gcc/testsuite/gcc.target/powerpc/fold-vec-load-builtin_vec_xl-float.c index 7d84c20..9b35a44 100644 --- a/gcc/testsuite/gcc.target/powerpc/fold-vec-load-builtin_vec_xl-float.c +++ b/gcc/testsuite/gcc.target/powerpc/fold-vec-load-builtin_vec_xl-float.c @@ -28,4 +28,4 @@ BUILD_VAR_TEST( test4, vector float, signed long long, vector float); BUILD_VAR_TEST( test5, vector float, signed int, vector float); BUILD_CST_TEST( test6, vector float, 12, vector float); -/* { dg-final { scan-assembler-times {\mlxvw4x\M|\mlxvd2x\M|\mlxvx\M|\mp?lvx\M} 6 } } */ +/* { dg-final { scan-assembler-times {\mlxvw4x\M|\mlxvd2x\M|\mlxvx\M|\mp?lxv\M|\mlvx\M} 6 } } */ diff --git a/gcc/testsuite/gcc.target/powerpc/fold-vec-load-builtin_vec_xl-int.c b/gcc/testsuite/gcc.target/powerpc/fold-vec-load-builtin_vec_xl-int.c index c6a8226..75903a9 100644 --- a/gcc/testsuite/gcc.target/powerpc/fold-vec-load-builtin_vec_xl-int.c +++ b/gcc/testsuite/gcc.target/powerpc/fold-vec-load-builtin_vec_xl-int.c @@ -36,4 +36,4 @@ BUILD_VAR_TEST( test10, vector unsigned int, signed long long, vector unsigned i BUILD_VAR_TEST( test11, vector unsigned int, signed int, vector unsigned int); BUILD_CST_TEST( test12, vector unsigned int, 12, vector unsigned int); -/* { dg-final { scan-assembler-times {\mlxvw4x\M|\mlxvd2x\M|\mlxvx\M|\mp?lvx\M} 12 } } */ +/* { dg-final { scan-assembler-times {\mlxvw4x\M|\mlxvd2x\M|\mlxvx\M|\mp?lxv\M|\mlvx\M} 12 } } */ diff --git a/gcc/testsuite/gcc.target/powerpc/fold-vec-load-builtin_vec_xl-longlong.c b/gcc/testsuite/gcc.target/powerpc/fold-vec-load-builtin_vec_xl-longlong.c index 6f0cd73..204f738 100644 --- a/gcc/testsuite/gcc.target/powerpc/fold-vec-load-builtin_vec_xl-longlong.c +++ b/gcc/testsuite/gcc.target/powerpc/fold-vec-load-builtin_vec_xl-longlong.c @@ -36,4 +36,4 @@ BUILD_VAR_TEST( test10, vector unsigned long long, signed long long, vector uns BUILD_VAR_TEST( test11, vector unsigned long long, signed int, vector unsigned long long); BUILD_CST_TEST( test12, vector unsigned long long, 12, vector unsigned long long); -/* { dg-final { scan-assembler-times {\mlxvd2x\M|\mlxvx\M|\mp?lvx\M} 12 } } */ +/* { dg-final { scan-assembler-times {\mlxvd2x\M|\mlxvx\M|\mp?lxv\M|\mlvx\M} 12 } } */ diff --git a/gcc/testsuite/gcc.target/powerpc/fold-vec-load-builtin_vec_xl-short.c b/gcc/testsuite/gcc.target/powerpc/fold-vec-load-builtin_vec_xl-short.c index 6c270a9..1be7765 100644 --- a/gcc/testsuite/gcc.target/powerpc/fold-vec-load-builtin_vec_xl-short.c +++ b/gcc/testsuite/gcc.target/powerpc/fold-vec-load-builtin_vec_xl-short.c @@ -36,4 +36,4 @@ BUILD_VAR_TEST( test10, vector unsigned short, signed long long, vector unsigne BUILD_VAR_TEST( test11, vector unsigned short, signed int, vector unsigned short); BUILD_CST_TEST( test12, vector unsigned short, 12, vector unsigned short); -/* { dg-final { scan-assembler-times {\mlxvw4x\M|\mlxvd2x\M|\mlxvx\M|\mp?lvx\M} 12 } } */ +/* { dg-final { scan-assembler-times {\mlxvw4x\M|\mlxvd2x\M|\mlxvx\M|\mp?lxv\M|\mlvx\M} 12 } } */ diff --git a/gcc/testsuite/gfortran.dg/PR82376.f90 b/gcc/testsuite/gfortran.dg/PR82376.f90 index 07143ab..b99779c 100644 --- a/gcc/testsuite/gfortran.dg/PR82376.f90 +++ b/gcc/testsuite/gfortran.dg/PR82376.f90 @@ -2,7 +2,8 @@ ! { dg-options "-fdump-tree-original -fcheck=pointer" } ! ! Test the fix for PR82376. The pointer check was doubling up the call -! to new. The fix reduces the count of 'new' from 5 to 4. +! to new. The fix reduces the count of 'new' from 5 to 4, or to 3, when +! counting only calls. ! ! Contributed by José Rui Faustino de Sousa <jrfsousa@gmail.com> ! @@ -56,4 +57,4 @@ contains end subroutine set end program main_p -! { dg-final { scan-tree-dump-times "new" 4 "original" } } +! { dg-final { scan-tree-dump-times { new \(} 3 "original" } } diff --git a/gcc/testsuite/gfortran.dg/coarray_3.f90 b/gcc/testsuite/gfortran.dg/coarray_3.f90 index d152ce1..1c294cd 100644 --- a/gcc/testsuite/gfortran.dg/coarray_3.f90 +++ b/gcc/testsuite/gfortran.dg/coarray_3.f90 @@ -11,11 +11,11 @@ character(len=30) :: str(2) critical fkl ! { dg-error "Syntax error in CRITICAL" } end critical fkl ! { dg-error "Expecting END PROGRAM" } -sync all (stat=1) ! { dg-error "Syntax error in SYNC ALL" } +sync all (stat=1) ! { dg-error "Non-variable expression" } sync all ( stat = n,stat=k) ! { dg-error "Redundant STAT" } sync memory (errmsg=str) ! { dg-error "must be a scalar CHARACTER variable" } sync memory (errmsg=n) ! { dg-error "must be a scalar CHARACTER variable" } -sync images (*, stat=1.0) ! { dg-error "Syntax error in SYNC IMAGES" } +sync images (*, stat=1.0) ! { dg-error "must be a scalar INTEGER variable" } sync images (-1) ! { dg-error "must between 1 and num_images" } sync images (1) sync images ( [ 1 ]) diff --git a/gcc/testsuite/gfortran.dg/coarray_sync.f90 b/gcc/testsuite/gfortran.dg/coarray_sync.f90 new file mode 100644 index 0000000..f3d6be1 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/coarray_sync.f90 @@ -0,0 +1,44 @@ +! { dg-do compile } +! { dg-options "-fcoarray=lib" } +! PR fortran/99351 - ICE in gfc_finish_var_decl, at fortran/trans-decl.c:695 + +module m + character(3), parameter :: c = 'abc' + integer, parameter :: s = 42 + integer, target :: i + character(:), allocatable :: a + target :: a +contains + subroutine s1 + allocate (character(42) :: a) + sync all (stat=i) + sync all (stat=f()) + sync all (errmsg=a) + sync all (errmsg=p()) + sync all (stat=a%len) ! { dg-error "variable definition context" } + sync all (stat=s) ! { dg-error "variable definition context" } + sync all (errmsg=c) ! { dg-error "variable definition context" } + end + subroutine s2 + sync images (*, stat=i) + sync images (*, errmsg=a) + sync images (*, stat=a%len) ! { dg-error "variable definition context" } + sync images (*, stat=s) ! { dg-error "variable definition context" } + sync images (*, errmsg=c) ! { dg-error "variable definition context" } + end + subroutine s3 + sync memory (stat=i,errmsg=p()) + sync memory (stat=f(),errmsg=a) + sync memory (stat=a%len) ! { dg-error "variable definition context" } + sync memory (stat=s) ! { dg-error "variable definition context" } + sync memory (errmsg=c) ! { dg-error "variable definition context" } + end + integer function f() + pointer :: f + f => i + end function f + function p() + character(:), pointer :: p + p => a + end function p +end diff --git a/gcc/testsuite/gfortran.dg/goacc/host_data-tree.f95 b/gcc/testsuite/gfortran.dg/goacc/host_data-tree.f95 index 558e800..e575890 100644 --- a/gcc/testsuite/gfortran.dg/goacc/host_data-tree.f95 +++ b/gcc/testsuite/gfortran.dg/goacc/host_data-tree.f95 @@ -12,12 +12,12 @@ program test !$acc host_data use_device(p) if (p == 42) ! { dg-final { scan-tree-dump-times "(?n)D\\.\[0-9\]+ = \\*p == 42;$" 1 "original" } } ! { dg-final { scan-tree-dump-times "(?n)#pragma acc host_data use_device_ptr\\(p\\) if\\(D\\.\[0-9\]+\\)$" 1 "original" } } - ! { dg-final { scan-tree-dump-times "(?n)#pragma omp target oacc_host_data use_device_ptr\\(p\\) if\\(D\\.\[0-9\]+\\)$" 1 "gimple" } } + ! { dg-final { scan-tree-dump-times "(?n)#pragma omp target oacc_host_data use_device_ptr\\(p\\) if\\((?:D\\.|_)\[0-9\]+\\)$" 1 "gimple" } } !$acc end host_data !$acc host_data use_device(p) if_present if (p == 43) ! { dg-final { scan-tree-dump-times "(?n)D\\.\[0-9\]+ = \\*p == 43;$" 1 "original" } } ! { dg-final { scan-tree-dump-times "(?n)#pragma acc host_data use_device_ptr\\(p\\) if\\(D\\.\[0-9\]+\\) if_present$" 1 "original" } } - ! { dg-final { scan-tree-dump-times "(?n)#pragma omp target oacc_host_data use_device_ptr\\(if_present:p\\) if\\(D\\.\[0-9\]+\\) if_present$" 1 "gimple" } } + ! { dg-final { scan-tree-dump-times "(?n)#pragma omp target oacc_host_data use_device_ptr\\(if_present:p\\) if\\((?:D\\.|_)\[0-9\]+\\) if_present$" 1 "gimple" } } !$acc end host_data end program test diff --git a/gcc/testsuite/gfortran.dg/goacc/kernels-tree.f95 b/gcc/testsuite/gfortran.dg/goacc/kernels-tree.f95 index 63ef7e1..688ed0a 100644 --- a/gcc/testsuite/gfortran.dg/goacc/kernels-tree.f95 +++ b/gcc/testsuite/gfortran.dg/goacc/kernels-tree.f95 @@ -37,5 +37,5 @@ end program test ! { dg-final { scan-tree-dump-times "map\\(force_deviceptr:u\\)" 1 "original" } } -! { dg-final { scan-tree-dump-times {(?n)#pragma omp target oacc_data_kernels if\(D\.[0-9]+\)$} 1 "omp_oacc_kernels_decompose" } } -! { dg-final { scan-tree-dump-times {(?n)#pragma omp target oacc_parallel_kernels_gang_single num_gangs\(1\) if\(D\.[0-9]+\) async\(-1\)$} 1 "omp_oacc_kernels_decompose" } } +! { dg-final { scan-tree-dump-times {(?n)#pragma omp target oacc_data_kernels if\((?:D\.|_)[0-9]+\)$} 1 "omp_oacc_kernels_decompose" } } +! { dg-final { scan-tree-dump-times {(?n)#pragma omp target oacc_parallel_kernels_gang_single num_gangs\(1\) if\((?:D\.|_)[0-9]+\) async\(-1\)$} 1 "omp_oacc_kernels_decompose" } } diff --git a/gcc/testsuite/gfortran.dg/gomp/affinity-1.f90 b/gcc/testsuite/gfortran.dg/gomp/affinity-1.f90 index b6e20b9..cb1543b 100644 --- a/gcc/testsuite/gfortran.dg/gomp/affinity-1.f90 +++ b/gcc/testsuite/gfortran.dg/gomp/affinity-1.f90 @@ -9,6 +9,15 @@ j = 8 end do !$omp end parallel do +!$omp parallel do default(none)proc_bind(primary)shared(a) + do i = 1, 10 + j = 4 + do j = 1, 10 + a(i, j) = i + j + end do + j = 8 + end do +!$omp end parallel do !$omp parallel proc_bind (close) !$omp parallel default(none) proc_bind (spread) firstprivate(a) private (i) do i = 1, 10 diff --git a/gcc/testsuite/gfortran.dg/gomp/cancel-1.f90 b/gcc/testsuite/gfortran.dg/gomp/cancel-1.f90 new file mode 100644 index 0000000..d60dd72 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/gomp/cancel-1.f90 @@ -0,0 +1,539 @@ +! { dg-additional-options "-cpp" } + +subroutine f1 + !$omp cancel parallel ! { dg-error "orphaned" } + !$omp cancel do ! { dg-error "orphaned" } + !$omp cancel sections ! { dg-error "orphaned" } + !$omp cancel taskgroup ! { dg-error "orphaned" } + !$omp cancellation point parallel ! { dg-error "orphaned" } + !$omp cancellation point do ! { dg-error "orphaned" } + !$omp cancellation point sections ! { dg-error "orphaned" } + !$omp cancellation point taskgroup ! { dg-error "orphaned" } +end + +subroutine f2 + integer :: i, j + j = 0 + !$omp parallel + !$omp cancel parallel + !$omp cancel do ! { dg-error "not closely nested inside" } + !$omp cancel sections ! { dg-error "not closely nested inside" } + !$omp cancel taskgroup ! { dg-error "not closely nested inside" } + !$omp cancellation point parallel + !$omp cancellation point do ! { dg-error "not closely nested inside" } + !$omp cancellation point sections ! { dg-error "not closely nested inside" } + !$omp cancellation point taskgroup ! { dg-error "not closely nested inside" } + + !$omp master + !$omp cancel parallel ! { dg-error "not closely nested inside" } + !$omp cancel do ! { dg-error "not closely nested inside" } + !$omp cancel sections ! { dg-error "not closely nested inside" } + !$omp cancel taskgroup ! { dg-error "not closely nested inside" } + !$omp cancellation point parallel ! { dg-error "not closely nested inside" } + !$omp cancellation point do ! { dg-error "not closely nested inside" } + !$omp cancellation point sections ! { dg-error "not closely nested inside" } + !$omp cancellation point taskgroup ! { dg-error "not closely nested inside" } + !$omp end master + + !$omp masked + !$omp cancel parallel ! { dg-error "not closely nested inside" } + !$omp cancel do ! { dg-error "not closely nested inside" } + !$omp cancel sections ! { dg-error "not closely nested inside" } + !$omp cancel taskgroup ! { dg-error "not closely nested inside" } + !$omp cancellation point parallel ! { dg-error "not closely nested inside" } + !$omp cancellation point do ! { dg-error "not closely nested inside" } + !$omp cancellation point sections ! { dg-error "not closely nested inside" } + !$omp cancellation point taskgroup ! { dg-error "not closely nested inside" } + !$omp end masked + + !$omp scope + !$omp cancel parallel ! { dg-error "not closely nested inside" } + !$omp cancel do ! { dg-error "not closely nested inside" } + !$omp cancel sections ! { dg-error "not closely nested inside" } + !$omp cancel taskgroup ! { dg-error "not closely nested inside" } + !$omp cancellation point parallel ! { dg-error "not closely nested inside" } + !$omp cancellation point do ! { dg-error "not closely nested inside" } + !$omp cancellation point sections ! { dg-error "not closely nested inside" } + !$omp cancellation point taskgroup ! { dg-error "not closely nested inside" } + !$omp end scope + + !$omp single + !$omp cancel parallel ! { dg-error "not closely nested inside" } + !$omp cancel do ! { dg-error "not closely nested inside" } + !$omp cancel sections ! { dg-error "not closely nested inside" } + !$omp cancel taskgroup ! { dg-error "not closely nested inside" } + !$omp cancellation point parallel ! { dg-error "not closely nested inside" } + !$omp cancellation point do ! { dg-error "not closely nested inside" } + !$omp cancellation point sections ! { dg-error "not closely nested inside" } + !$omp cancellation point taskgroup ! { dg-error "not closely nested inside" } + !$omp end single + + !$omp critical + !$omp cancel parallel ! { dg-error "not closely nested inside" } + !$omp cancel do ! { dg-error "not closely nested inside" } + !$omp cancel sections ! { dg-error "not closely nested inside" } + !$omp cancel taskgroup ! { dg-error "not closely nested inside" } + !$omp cancellation point parallel ! { dg-error "not closely nested inside" } + !$omp cancellation point do ! { dg-error "not closely nested inside" } + !$omp cancellation point sections ! { dg-error "not closely nested inside" } + !$omp cancellation point taskgroup ! { dg-error "not closely nested inside" } + !$omp end critical + + !$omp taskgroup + !$omp cancel parallel ! { dg-error "not closely nested inside" } + !$omp cancel do ! { dg-error "not closely nested inside" } + !$omp cancel sections ! { dg-error "not closely nested inside" } + !$omp cancel taskgroup ! { dg-error "not closely nested inside" } + !$omp cancellation point parallel ! { dg-error "not closely nested inside" } + !$omp cancellation point do ! { dg-error "not closely nested inside" } + !$omp cancellation point sections ! { dg-error "not closely nested inside" } + !$omp cancellation point taskgroup ! { dg-error "not closely nested inside" } + !$omp end taskgroup + + !$omp task + !$omp cancel parallel ! { dg-error "not closely nested inside" } + !$omp cancel do ! { dg-error "not closely nested inside" } + !$omp cancel sections ! { dg-error "not closely nested inside" } + !$omp cancel taskgroup ! { dg-error "construct not closely nested inside of .taskgroup. region" } + !$omp cancellation point parallel ! { dg-error "not closely nested inside" } + !$omp cancellation point do ! { dg-error "not closely nested inside" } + !$omp cancellation point sections ! { dg-error "not closely nested inside" } + !$omp cancellation point taskgroup ! { dg-error "construct not closely nested inside of .taskgroup. region" } + !$omp end task + + !$omp taskgroup + !$omp task + !$omp cancel parallel ! { dg-error "not closely nested inside" } + !$omp cancel do ! { dg-error "not closely nested inside" } + !$omp cancel sections ! { dg-error "not closely nested inside" } + !$omp cancel taskgroup + !$omp cancellation point parallel ! { dg-error "not closely nested inside" } + !$omp cancellation point do ! { dg-error "not closely nested inside" } + !$omp cancellation point sections ! { dg-error "not closely nested inside" } + !$omp cancellation point taskgroup + !$omp end task + !$omp end taskgroup + + !$omp taskloop + do i = 0, 9 + !$omp cancel parallel ! { dg-error "not closely nested inside" } + !$omp cancel do ! { dg-error "not closely nested inside" } + !$omp cancel sections ! { dg-error "not closely nested inside" } + !$omp cancel taskgroup + !$omp cancellation point parallel ! { dg-error "not closely nested inside" } + !$omp cancellation point do ! { dg-error "not closely nested inside" } + !$omp cancellation point sections ! { dg-error "not closely nested inside" } + !$omp cancellation point taskgroup + !$omp task + !$omp cancellation point taskgroup + !$omp cancel taskgroup + !$omp end task + end do + !$omp taskloop nogroup + do i = 0, 9 + !$omp cancel parallel ! { dg-error "not closely nested inside" } + !$omp cancel do ! { dg-error "not closely nested inside" } + !$omp cancel sections ! { dg-error "not closely nested inside" } + !$omp cancel taskgroup ! { dg-error "construct not closely nested inside of .taskgroup. region" } + !$omp cancellation point parallel ! { dg-error "not closely nested inside" } + !$omp cancellation point do ! { dg-error "not closely nested inside" } + !$omp cancellation point sections ! { dg-error "not closely nested inside" } + !$omp cancellation point taskgroup! { dg-error "construct not closely nested inside of .taskgroup. region" } + !$omp task + !$omp cancellation point taskgroup! { dg-error "construct not closely nested inside of .taskgroup. region" } + !$omp cancel taskgroup ! { dg-error "construct not closely nested inside of .taskgroup. region" } + !$omp end task + end do + !$omp taskgroup + !$omp task + !$omp task + !$omp cancellation point taskgroup + !$omp cancel taskgroup + !$omp end task + !$omp end task + !$omp taskloop nogroup + do i = 0, 9 + !$omp task + !$omp cancellation point taskgroup + !$omp cancel taskgroup + !$omp end task + !$omp cancellation point taskgroup + !$omp cancel taskgroup + end do + !$omp end taskgroup + + !$omp taskgroup + !$omp parallel + !$omp task + !$omp cancel taskgroup ! { dg-error "construct not closely nested inside of .taskgroup. region" } + !$omp cancellation point taskgroup ! { dg-error "construct not closely nested inside of .taskgroup. region" } + !$omp end task + !$omp taskloop + do i = 0, 9 + !$omp cancel taskgroup + !$omp cancellation point taskgroup + end do + !$omp taskloop nogroup + do i = 0, 9 + !$omp cancel taskgroup ! { dg-error "construct not closely nested inside of .taskgroup. region" } + !$omp cancellation point taskgroup ! { dg-error "construct not closely nested inside of .taskgroup. region" } + end do + !$omp end parallel + !$omp target + !$omp task + !$omp cancel taskgroup ! { dg-error "construct not closely nested inside of .taskgroup. region" } + !$omp cancellation point taskgroup ! { dg-error "construct not closely nested inside of .taskgroup. region" } + !$omp end task + !$omp end target + !$omp target + !$omp teams + !$omp distribute + do i = 0, 9 + !$omp task + !$omp cancellation point taskgroup ! { dg-error "construct not closely nested inside of .taskgroup. region" } + !$omp end task + end do + !$omp end distribute + !$omp end teams + !$omp end target + !$omp target data map(i) + !$omp task + !$omp cancel taskgroup + !$omp cancellation point taskgroup + !$omp end task + !$omp end target data + !$omp end taskgroup + + !$omp taskloop + do i = 0, 9 + !$omp parallel + !$omp task + !$omp cancel taskgroup ! { dg-error "construct not closely nested inside of .taskgroup. region" } + !$omp cancellation point taskgroup ! { dg-error "construct not closely nested inside of .taskgroup. region" } + !$omp end task + !$omp end parallel + !$omp target + !$omp task + !$omp cancel taskgroup ! { dg-error "construct not closely nested inside of .taskgroup. region" } + !$omp cancellation point taskgroup ! { dg-error "construct not closely nested inside of .taskgroup. region" } + !$omp end task + !$omp end target + !$omp target + !$omp teams + !$omp distribute + do j = 0, 9 + !$omp task + !$omp cancel taskgroup ! { dg-error "construct not closely nested inside of .taskgroup. region" } + !$omp cancellation point taskgroup ! { dg-error "construct not closely nested inside of .taskgroup. region" } + !$omp end task + end do + !$omp end distribute + !$omp end teams + !$omp end target + !$omp target data map(i) + !$omp task + !$omp cancel taskgroup + !$omp cancellation point taskgroup + !$omp end task + !$omp end target data + end do + + !$omp do + do i = 0, 9 + !$omp cancel parallel ! { dg-error "not closely nested inside" } + !$omp cancel do + !$omp cancel sections ! { dg-error "not closely nested inside" } + !$omp cancel taskgroup ! { dg-error "not closely nested inside" } + !$omp cancellation point parallel ! { dg-error "not closely nested inside" } + !$omp cancellation point do + !$omp cancellation point sections ! { dg-error "not closely nested inside" } + !$omp cancellation point taskgroup! { dg-error "not closely nested inside" } + end do + + !$omp do ordered + do i = 0, 9 + !$omp ordered + !$omp cancel parallel ! { dg-error "not closely nested inside" } + !$omp cancel do ! { dg-error "not closely nested inside" } + !$omp cancel sections ! { dg-error "not closely nested inside" } + !$omp cancel taskgroup ! { dg-error "not closely nested inside" } + !$omp cancellation point parallel ! { dg-error "not closely nested inside" } + !$omp cancellation point do ! { dg-error "not closely nested inside" } + !$omp cancellation point sections ! { dg-error "not closely nested inside" } + !$omp cancellation point taskgroup! { dg-error "not closely nested inside" } + !$omp end ordered + end do + !$omp end do + !$omp sections + block + !$omp cancel parallel ! { dg-error "not closely nested inside" } + !$omp cancel do ! { dg-error "not closely nested inside" } + !$omp cancel sections + !$omp cancel taskgroup ! { dg-error "not closely nested inside" } + !$omp cancellation point parallel ! { dg-error "not closely nested inside" } + !$omp cancellation point do ! { dg-error "not closely nested inside" } + !$omp cancellation point sections + !$omp cancellation point taskgroup! { dg-error "not closely nested inside" } + end block + !$omp section + block + !$omp cancel parallel ! { dg-error "not closely nested inside" } + !$omp cancel do ! { dg-error "not closely nested inside" } + !$omp cancel sections + !$omp cancel taskgroup ! { dg-error "not closely nested inside" } + !$omp cancellation point parallel ! { dg-error "not closely nested inside" } + !$omp cancellation point do ! { dg-error "not closely nested inside" } + !$omp cancellation point sections + !$omp cancellation point taskgroup! { dg-error "not closely nested inside" } + end block + !$omp target data map(j) + !$omp cancel parallel ! { dg-error "not closely nested inside" } + !$omp cancel do ! { dg-error "not closely nested inside" } + !$omp cancel sections ! { dg-error "not closely nested inside" } + !$omp cancel taskgroup ! { dg-error "not closely nested inside" } + !$omp cancellation point parallel ! { dg-error "not closely nested inside" } + !$omp cancellation point do ! { dg-error "not closely nested inside" } + !$omp cancellation point sections ! { dg-error "not closely nested inside" } + !$omp cancellation point taskgroup ! { dg-error "not closely nested inside" } + !$omp end target data + !$omp target + !$omp cancel parallel ! { dg-error "not closely nested inside" } + !$omp cancel do ! { dg-error "not closely nested inside" } + !$omp cancel sections ! { dg-error "not closely nested inside" } + !$omp cancel taskgroup ! { dg-error "not closely nested inside" } + !$omp cancellation point parallel ! { dg-error "not closely nested inside" } + !$omp cancellation point do ! { dg-error "not closely nested inside" } + !$omp cancellation point sections ! { dg-error "not closely nested inside" } + !$omp cancellation point taskgroup ! { dg-error "not closely nested inside" } + !$omp end target + !$omp end sections + !$omp end parallel + !$omp target data map(j) + !$omp cancel parallel ! { dg-error "not closely nested inside" } + !$omp cancel do ! { dg-error "not closely nested inside" } + !$omp cancel sections ! { dg-error "not closely nested inside" } + !$omp cancel taskgroup ! { dg-error "not closely nested inside" } + !$omp cancellation point parallel ! { dg-error "not closely nested inside" } + !$omp cancellation point do ! { dg-error "not closely nested inside" } + !$omp cancellation point sections ! { dg-error "not closely nested inside" } + !$omp cancellation point taskgroup ! { dg-error "not closely nested inside" } + !$omp end target data + !$omp target + !$omp cancel parallel ! { dg-error "not closely nested inside" } + !$omp cancel do ! { dg-error "not closely nested inside" } + !$omp cancel sections ! { dg-error "not closely nested inside" } + !$omp cancel taskgroup ! { dg-error "not closely nested inside" } + !$omp cancellation point parallel ! { dg-error "not closely nested inside" } + !$omp cancellation point do ! { dg-error "not closely nested inside" } + !$omp cancellation point sections ! { dg-error "not closely nested inside" } + !$omp cancellation point taskgroup ! { dg-error "not closely nested inside" } + !$omp end target + !$omp target teams + !$omp cancel parallel ! { dg-error "only .distribute., .parallel. or .loop. regions are allowed to be strictly nested" } + !$omp cancel do ! { dg-error "only .distribute., .parallel. or .loop. regions are allowed to be strictly nested" } + !$omp cancel sections ! { dg-error "only .distribute., .parallel. or .loop. regions are allowed to be strictly nested" } + !$omp cancel taskgroup ! { dg-error "only .distribute., .parallel. or .loop. regions are allowed to be strictly nested" } + !$omp cancellation point parallel ! { dg-error "only .distribute., .parallel. or .loop. regions are allowed to be strictly nested" } + !$omp cancellation point do ! { dg-error "only .distribute., .parallel. or .loop. regions are allowed to be strictly nested" } + !$omp cancellation point sections ! { dg-error "only .distribute., .parallel. or .loop. regions are allowed to be strictly nested" } + !$omp cancellation point taskgroup ! { dg-error "only .distribute., .parallel. or .loop. regions are allowed to be strictly nested" } + !$omp end target teams + !$omp target teams distribute + do i = 0, 9 + !$omp cancel parallel ! { dg-error "not closely nested inside" } + !$omp cancel do ! { dg-error "not closely nested inside" } + !$omp cancel sections ! { dg-error "not closely nested inside" } + !$omp cancel taskgroup ! { dg-error "not closely nested inside" } + !$omp cancellation point parallel ! { dg-error "not closely nested inside" } + !$omp cancellation point do ! { dg-error "not closely nested inside" } + !$omp cancellation point sections ! { dg-error "not closely nested inside" } + !$omp cancellation point taskgroup ! { dg-error "not closely nested inside" } + end do + !$omp end target teams distribute + !$omp do + do i = 0, 9 + !$omp cancel parallel ! { dg-error "not closely nested inside" } + !$omp cancel do + !$omp cancel sections ! { dg-error "not closely nested inside" } + !$omp cancel taskgroup ! { dg-error "not closely nested inside" } + !$omp cancellation point parallel ! { dg-error "not closely nested inside" } + !$omp cancellation point do + !$omp cancellation point sections ! { dg-error "not closely nested inside" } + !$omp cancellation point taskgroup ! { dg-error "not closely nested inside" } + end do + !$omp do + do i = 0, 9 + !$omp target data map(j) + !$omp cancel parallel ! { dg-error "not closely nested inside" } + !$omp cancel do ! { dg-error "not closely nested inside" } + !$omp cancel sections ! { dg-error "not closely nested inside" } + !$omp cancel taskgroup ! { dg-error "not closely nested inside" } + !$omp cancellation point parallel ! { dg-error "not closely nested inside" } + !$omp cancellation point do ! { dg-error "not closely nested inside" } + !$omp cancellation point sections ! { dg-error "not closely nested inside" } + !$omp cancellation point taskgroup ! { dg-error "not closely nested inside" } + !$omp end target data + end do + !$omp do + do i = 0, 9 + !$omp target + !$omp cancel parallel ! { dg-error "not closely nested inside" } + !$omp cancel do ! { dg-error "not closely nested inside" } + !$omp cancel sections ! { dg-error "not closely nested inside" } + !$omp cancel taskgroup ! { dg-error "not closely nested inside" } + !$omp cancellation point parallel ! { dg-error "not closely nested inside" } + !$omp cancellation point do ! { dg-error "not closely nested inside" } + !$omp cancellation point sections ! { dg-error "not closely nested inside" } + !$omp cancellation point taskgroup ! { dg-error "not closely nested inside" } + !$omp end target + end do + !$omp do ordered + do i = 0, 9 + !$omp ordered + !$omp target data map(j) + !$omp cancel parallel ! { dg-error "not closely nested inside" } + !$omp cancel do ! { dg-error "not closely nested inside" } + !$omp cancel sections ! { dg-error "not closely nested inside" } + !$omp cancel taskgroup ! { dg-error "not closely nested inside" } + !$omp cancellation point parallel ! { dg-error "not closely nested inside" } + !$omp cancellation point do ! { dg-error "not closely nested inside" } + !$omp cancellation point sections ! { dg-error "not closely nested inside" } + !$omp cancellation point taskgroup! { dg-error "not closely nested inside" } + !$omp end target data + !$omp end ordered + end do + do i = 0, 9 + !$omp ordered + !$omp target + !$omp cancel parallel ! { dg-error "not closely nested inside" } + !$omp cancel do ! { dg-error "not closely nested inside" } + !$omp cancel sections ! { dg-error "not closely nested inside" } + !$omp cancel taskgroup ! { dg-error "not closely nested inside" } + !$omp cancellation point parallel ! { dg-error "not closely nested inside" } + !$omp cancellation point do ! { dg-error "not closely nested inside" } + !$omp cancellation point sections ! { dg-error "not closely nested inside" } + !$omp cancellation point taskgroup! { dg-error "not closely nested inside" } + !$omp end target + !$omp end ordered + end do + !$omp sections + block + !$omp cancel parallel ! { dg-error "not closely nested inside" } + !$omp cancel do ! { dg-error "not closely nested inside" } + !$omp cancel sections + !$omp cancel taskgroup ! { dg-error "not closely nested inside" } + !$omp cancellation point parallel ! { dg-error "not closely nested inside" } + !$omp cancellation point do ! { dg-error "not closely nested inside" } + !$omp cancellation point sections + !$omp cancellation point taskgroup ! { dg-error "not closely nested inside" } + end block + !$omp section + block + !$omp cancel parallel ! { dg-error "not closely nested inside" } + !$omp cancel do ! { dg-error "not closely nested inside" } + !$omp cancel sections + !$omp cancel taskgroup ! { dg-error "not closely nested inside" } + !$omp cancellation point parallel ! { dg-error "not closely nested inside" } + !$omp cancellation point do ! { dg-error "not closely nested inside" } + !$omp cancellation point sections + !$omp cancellation point taskgroup ! { dg-error "not closely nested inside" } + end block + !$omp end sections + !$omp sections + !$omp target data map(j) + !$omp cancel parallel ! { dg-error "not closely nested inside" } + !$omp cancel do ! { dg-error "not closely nested inside" } + !$omp cancel sections ! { dg-error "not closely nested inside" } + !$omp cancel taskgroup ! { dg-error "not closely nested inside" } + !$omp cancellation point parallel ! { dg-error "not closely nested inside" } + !$omp cancellation point do ! { dg-error "not closely nested inside" } + !$omp cancellation point sections ! { dg-error "not closely nested inside" } + !$omp cancellation point taskgroup ! { dg-error "not closely nested inside" } + !$omp end target data + !$omp section + !$omp target data map(j) + !$omp cancel parallel ! { dg-error "not closely nested inside" } + !$omp cancel do ! { dg-error "not closely nested inside" } + !$omp cancel sections ! { dg-error "not closely nested inside" } + !$omp cancel taskgroup ! { dg-error "not closely nested inside" } + !$omp cancellation point parallel ! { dg-error "not closely nested inside" } + !$omp cancellation point do ! { dg-error "not closely nested inside" } + !$omp cancellation point sections ! { dg-error "not closely nested inside" } + !$omp cancellation point taskgroup ! { dg-error "not closely nested inside" } + !$omp end target data + !$omp end sections + !$omp sections + !$omp target + !$omp cancel parallel ! { dg-error "not closely nested inside" } + !$omp cancel do ! { dg-error "not closely nested inside" } + !$omp cancel sections ! { dg-error "not closely nested inside" } + !$omp cancel taskgroup ! { dg-error "not closely nested inside" } + !$omp cancellation point parallel ! { dg-error "not closely nested inside" } + !$omp cancellation point do ! { dg-error "not closely nested inside" } + !$omp cancellation point sections ! { dg-error "not closely nested inside" } + !$omp cancellation point taskgroup ! { dg-error "not closely nested inside" } + !$omp end target + !$omp section + !$omp target + !$omp cancel parallel ! { dg-error "not closely nested inside" } + !$omp cancel do ! { dg-error "not closely nested inside" } + !$omp cancel sections ! { dg-error "not closely nested inside" } + !$omp cancel taskgroup ! { dg-error "not closely nested inside" } + !$omp cancellation point parallel ! { dg-error "not closely nested inside" } + !$omp cancellation point do ! { dg-error "not closely nested inside" } + !$omp cancellation point sections ! { dg-error "not closely nested inside" } + !$omp cancellation point taskgroup ! { dg-error "not closely nested inside" } + !$omp end target + !$omp end sections + !$omp task + !$omp cancel parallel ! { dg-error "not closely nested inside" } + !$omp cancel do ! { dg-error "not closely nested inside" } + !$omp cancel sections ! { dg-error "not closely nested inside" } + !$omp cancel taskgroup + !$omp cancellation point parallel ! { dg-error "not closely nested inside" } + !$omp cancellation point do ! { dg-error "not closely nested inside" } + !$omp cancellation point sections ! { dg-error "not closely nested inside" } + !$omp cancellation point taskgroup + !$omp taskgroup + !$omp cancel parallel ! { dg-error "not closely nested inside" } + !$omp cancel do ! { dg-error "not closely nested inside" } + !$omp cancel sections ! { dg-error "not closely nested inside" } + !$omp cancel taskgroup ! { dg-error "not closely nested inside" } + !$omp cancellation point parallel ! { dg-error "not closely nested inside" } + !$omp cancellation point do ! { dg-error "not closely nested inside" } + !$omp cancellation point sections ! { dg-error "not closely nested inside" } + !$omp cancellation point taskgroup ! { dg-error "not closely nested inside" } + !$omp end taskgroup + !$omp end task +end + +subroutine f3 + integer i + !$omp do + do i = 0, 9 + !$omp cancel do ! { dg-warning "nowait" } + end do + !$omp end do nowait + !$omp sections + block + !$omp cancel sections ! { dg-warning "nowait" } + end block + !$omp section + block + !$omp cancel sections ! { dg-warning "nowait" } + end block + !$omp end sections nowait + !$omp do ordered + do i = 0, 9 + !$omp cancel do ! { dg-warning "ordered" } + !$omp ordered + !$omp end ordered + end do +end + + +subroutine f4 +! if (.false.) then +!$omp cancellation point do ! { dg-error "orphaned 'cancellation point' construct" } +! end if +end diff --git a/gcc/testsuite/gfortran.dg/gomp/cancel-4.f90 b/gcc/testsuite/gfortran.dg/gomp/cancel-4.f90 new file mode 100644 index 0000000..0fb814e --- /dev/null +++ b/gcc/testsuite/gfortran.dg/gomp/cancel-4.f90 @@ -0,0 +1,9 @@ +subroutine f4 + !$omp cancellation point ! { dg-error "Expected construct-type PARALLEL, SECTIONS, DO or TASKGROUP in .OMP CANCELLATION POINT statement at" } + if (.false.) then +!$omp cancellation EKAHI ! { dg-error "Unclassifiable OpenMP directive" } + end if +!$omp cancellation HO OKAHI ! { dg-error "Unclassifiable OpenMP directive" } + +!$omp cancellation point ! { dg-error "Expected construct-type PARALLEL, SECTIONS, DO or TASKGROUP in .OMP CANCELLATION POINT statement at" } +end diff --git a/gcc/testsuite/gfortran.dg/gomp/loop-4.f90 b/gcc/testsuite/gfortran.dg/gomp/loop-4.f90 new file mode 100644 index 0000000..7374589 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/gomp/loop-4.f90 @@ -0,0 +1,279 @@ +module m + use iso_c_binding, only: c_loc + implicit none (type, external) + integer :: v + interface + subroutine foo (); end + integer function omp_get_thread_num (); end + integer function omp_get_num_threads (); end + integer function omp_get_cancellation (); end + integer(c_int) function omp_target_is_present(ptr, device_num) bind(c) + use, intrinsic :: iso_c_binding, only : c_ptr, c_int + type(c_ptr), value :: ptr + integer(c_int), value :: device_num + end + end interface + +contains +subroutine f1(a) + integer :: a(0:) + integer :: i, j + !$omp simd order(concurrent) + do i = 0, 63 + !$omp loop + do j = 0, 63 + a(64 * i + j) = i + j + end do + end do +end + +subroutine f2 (a) + integer :: a(0:) + integer :: i, j + !$omp do simd order(concurrent) + do i = 0, 63 + !$omp loop + do j = 0, 63 + a(64 * i + j) = i + j + end do + end do +end + +subroutine f3 (a) + integer :: a(0:) + integer :: i, j + !$omp do order(concurrent) + do i = 0, 63 + !$omp loop + do j = 0, 63 + a(64 * i + j) = i + j + end do + end do +end + +subroutine f4 (a) + integer, target :: a(0:) + integer :: i, j + !$omp loop order(concurrent) bind(parallel) + do i = 0, 63 + !$omp parallel + call foo () + !$omp end parallel + end do + !$omp loop order(concurrent) bind(parallel) + do i = 0, 63 + !$omp simd + do j = 0, 63 + a(64 * i + j) = i + j + end do + end do + !$omp loop order(concurrent) bind(parallel) + do i = 0, 63 + !$omp loop + do j = 0, 63 + a(64 * i + j) = i + j + end do + end do + !$omp loop order(concurrent) bind(parallel) + do i = 0, 63 + !$omp critical ! { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a 'loop' region" } + call foo () + !$omp end critical + end do + !$omp loop order(concurrent) bind(parallel) + do i = 0, 63 + !$omp ordered simd ! { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a 'loop' region" } + call foo () + !$omp end ordered + end do + !$omp loop order(concurrent) bind(parallel) + do i = 0, 63 + !$omp atomic ! { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a 'loop' region" } + v = v + 1 + end do + !$omp loop order(concurrent) bind(parallel) + do i = 0, 63 + !$omp atomic read ! { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a 'loop' region" } + a(i) = v + end do + !$omp loop order(concurrent) bind(parallel) + do i = 0, 63 + !$omp atomic write ! { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a 'loop' region" } + v = a(i) + end do + !$omp loop order(concurrent) bind(parallel) + do i = 0, 63 + a(i) = a(i) + omp_get_thread_num () ! { dg-error "OpenMP runtime API call '\[^\n\r]*omp_get_thread_num\[^\n\r]*' in a region with 'order\\(concurrent\\)' clause" } + end do + !$omp loop order(concurrent) bind(parallel) + do i = 0, 63 + a(i) = a(i) + omp_get_num_threads () ! { dg-error "OpenMP runtime API call '\[^\n\r]*omp_get_num_threads\[^\n\r]*' in a region with 'order\\(concurrent\\)' clause" } + end do + !$omp loop order(concurrent) bind(parallel) + do i = 0, 63 + a(i) = a(i) + omp_target_is_present (c_loc (a(i)), 0) ! { dg-error "OpenMP runtime API call '\[^\n\r]*omp_target_is_present\[^\n\r]*' in a region with 'order\\(concurrent\\)' clause" } + end do + !$omp loop order(concurrent) bind(parallel) + do i = 0, 63 + a(i) = a(i) + omp_get_cancellation () ! { dg-error "OpenMP runtime API call '\[^\n\r]*omp_get_cancellation\[^\n\r]*' in a region with 'order\\(concurrent\\)' clause" } + end do +end + +subroutine f5 (a) + integer, target :: a(0:) + integer :: i, j + !$omp parallel + !$omp loop + do i = 0, 63 + !$omp parallel + call foo () + !$omp end parallel + end do + !$omp loop + do i = 0, 63 + !$omp simd + do j = 0, 63 + a(64 * i + j) = i + j + end do + end do + !$omp loop + do i = 0, 63 + !$omp loop + do j = 0, 63 + a(64 * i + j) = i + j + end do + end do + !$omp loop + do i = 0, 63 + !$omp critical ! { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a 'loop' region" } + call foo () + !$omp end critical + end do + !$omp loop + do i = 0, 63 + !$omp ordered simd ! { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a 'loop' region" } + call foo () + !$omp end ordered + end do + !$omp loop + do i = 0, 63 + !$omp atomic ! { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a 'loop' region" } + v = v + 1 + end do + !$omp loop + do i = 0, 63 + !$omp atomic read ! { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a 'loop' region" } + a(i) = v + end do + !$omp loop + do i = 0, 63 + !$omp atomic write ! { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a 'loop' region" } + v = a(i) + end do + !$omp loop + do i = 0, 63 + !$omp master ! { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a 'loop' region" } + call foo () + !$omp end master + end do + !$omp loop + do i = 0, 63 + !$omp masked ! { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a 'loop' region" } + call foo () + !$omp end masked + end do + !$omp loop + do i = 0, 63 + !$omp scope ! { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a 'loop' region" } + call foo () + !$omp end scope + end do + !$omp loop + do i = 0, 63 + a(i) = a(i) + omp_get_thread_num () ! { dg-error "OpenMP runtime API call '\[^\n\r]*omp_get_thread_num\[^\n\r]*' in a region with 'order\\(concurrent\\)' clause" } + end do + !$omp loop + do i = 0, 63 + a(i) = a(i) + omp_get_num_threads () ! { dg-error "OpenMP runtime API call '\[^\n\r]*omp_get_num_threads\[^\n\r]*' in a region with 'order\\(concurrent\\)' clause" } + end do + !$omp loop + do i = 0, 63 + a(i) = a(i) + omp_target_is_present (c_loc(a(i)), 0) ! { dg-error "OpenMP runtime API call '\[^\n\r]*omp_target_is_present\[^\n\r]*' in a region with 'order\\(concurrent\\)' clause" } + end do + !$omp loop + do i = 0, 63 + a(i) = a(i) + omp_get_cancellation () ! { dg-error "OpenMP runtime API call '\[^\n\r]*omp_get_cancellation\[^\n\r]*' in a region with 'order\\(concurrent\\)' clause" } + end do + !$omp end parallel +end + +subroutine f6 (a) + integer, target :: a(0:) + integer :: i, j + !$omp master + !$omp loop + do i = 0, 63 + !$omp parallel + call foo () + !$omp end parallel + end do + !$omp loop + do i = 0, 63 + !$omp simd + do j = 0, 63 + a(64 * i + j) = i + j + end do + end do + !$omp loop + do i = 0, 63 + !$omp loop + do j = 0, 63 + a(64 * i + j) = i + j + end do + end do + !$omp loop + do i = 0, 63 + !$omp critical ! { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a 'loop' region" } + call foo () + !$omp end critical + end do + !$omp loop + do i = 0, 63 + !$omp ordered simd ! { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a 'loop' region" } + call foo () + !$omp end ordered + end do + !$omp loop + do i = 0, 63 + !$omp atomic ! { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a 'loop' region" } + v = v + 1 + end do + !$omp loop + do i = 0, 63 + !$omp atomic read ! { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a 'loop' region" } + a(i) = v + end do + !$omp loop + do i = 0, 63 + !$omp atomic write ! { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a 'loop' region" } + v = a(i) + end do + !$omp loop + do i = 0, 63 + a(i) = a(i) + omp_get_thread_num () ! { dg-error "OpenMP runtime API call '\[^\n\r]*omp_get_thread_num\[^\n\r]*' in a region with 'order\\(concurrent\\)' clause" } + end do + !$omp loop + do i = 0, 63 + a(i) = a(i) + omp_get_num_threads () ! { dg-error "OpenMP runtime API call '\[^\n\r]*omp_get_num_threads\[^\n\r]*' in a region with 'order\\(concurrent\\)' clause" } + end do + !$omp loop + do i = 0, 63 + a(i) = a(i) + omp_target_is_present (c_loc(a(i)), 0) ! { dg-error "OpenMP runtime API call '\[^\n\r]*omp_target_is_present\[^\n\r]*' in a region with 'order\\(concurrent\\)' clause" } + end do + !$omp loop + do i = 0, 63 + a(i) = a(i) + omp_get_cancellation () ! { dg-error "OpenMP runtime API call '\[^\n\r]*omp_get_cancellation\[^\n\r]*' in a region with 'order\\(concurrent\\)' clause" } + end do + !$omp end master +end +end module diff --git a/gcc/testsuite/gfortran.dg/gomp/masked-1.f90 b/gcc/testsuite/gfortran.dg/gomp/masked-1.f90 new file mode 100644 index 0000000..1bd6176 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/gomp/masked-1.f90 @@ -0,0 +1,94 @@ +! { dg-additional-options "-ffree-line-length-none" } +subroutine foo (x, a) + implicit none + integer, value :: x + integer, contiguous :: a(0:) + external :: bar + integer :: i + + !$omp masked + call bar () + !$omp end masked + + !$omp masked filter (0) + call bar () + !$omp end masked + + !$omp masked filter (7) + call bar () + !$omp end masked + + !$omp masked filter (x) + call bar () + !$omp end masked + + !$omp masked taskloop simd filter (x) grainsize (12) simdlen (4) + do i = 0, 127 + a(i) = i + end do + !$omp end masked taskloop simd + + !$omp parallel masked filter (x) firstprivate (x) + call bar () + !$omp end parallel masked + + !$omp masked + !$omp masked filter (0) + !$omp masked filter (x) + !$omp end masked + !$omp end masked + !$omp end masked +end + +subroutine foobar (d, f, fi, p, s, g, i1, i2, l, ll, nth, ntm, pp, q, r, r2) + implicit none (type, external) + logical :: i1, i2, fi + integer :: i, d, f, p, s, g, l, ll, nth, ntm, pp, q, r, r2 + allocatable :: q + integer, save :: t + !$omp threadprivate (t) + + !$omp parallel masked & + !$omp& private (p) firstprivate (f) if (parallel: i2) default(shared) shared(s) reduction(+:r) & + !$omp& num_threads (nth) proc_bind(spread) copyin(t) filter (d) ! allocate (f) + ! + !$omp end parallel masked + + !$omp taskgroup task_reduction (+:r2) ! allocate (r2) + !$omp masked taskloop & + !$omp& private (p) firstprivate (f) lastprivate (l) shared (s) default(shared) grainsize (g) collapse(1) untied if(taskloop: i1) final(fi) mergeable priority (pp) & + !$omp& reduction(default, +:r) in_reduction(+:r2) filter (d) ! allocate (f) + do i = 0, 63 + ll = ll + 1 + end do + !$omp end masked taskloop + !$omp end taskgroup + + !$omp taskgroup task_reduction (+:r2) ! allocate (r2) + !$omp masked taskloop simd & + !$omp& private (p) firstprivate (f) lastprivate (l) shared (s) default(shared) grainsize (g) collapse(1) untied if(taskloop: i1) if(simd: i2) final(fi) mergeable priority (pp) & + !$omp& safelen(8) simdlen(4) linear(ll: 1) aligned(q: 32) reduction(default, +:r) in_reduction(+:r2) nontemporal(ntm) & + !$omp& order(concurrent) filter (d) ! allocate (f) + do i = 0, 63 + ll = ll + 1 + end do + !$omp end masked taskloop simd + !$omp end taskgroup + + !$omp parallel masked taskloop & + !$omp& private (p) firstprivate (f) lastprivate (l) shared (s) default(shared) grainsize (g) collapse(1) untied if(taskloop: i1) final(fi) mergeable priority (pp) & + !$omp& reduction(default, +:r) if (parallel: i2) num_threads (nth) proc_bind(spread) copyin(t) filter (d) ! allocate (f) + do i = 0, 63 + ll = ll + 1 + end do + !$omp end parallel masked taskloop + + !$omp parallel masked taskloop simd & + !$omp& private (p) firstprivate (f) lastprivate (l) shared (s) default(shared) grainsize (g) collapse(1) untied if(taskloop: i1) if(simd: i2) final(fi) mergeable priority (pp) & + !$omp& safelen(8) simdlen(4) linear(ll: 1) aligned(q: 32) reduction(default, +:r) nontemporal(ntm) if (parallel: i2) num_threads (nth) proc_bind(spread) copyin(t) & + !$omp& order(concurrent) filter (d) ! allocate (f) + do i = 0, 63 + ll = ll + 1 + end do + !$omp end parallel masked taskloop simd +end subroutine diff --git a/gcc/testsuite/gfortran.dg/gomp/masked-2.f90 b/gcc/testsuite/gfortran.dg/gomp/masked-2.f90 new file mode 100644 index 0000000..95ef78c --- /dev/null +++ b/gcc/testsuite/gfortran.dg/gomp/masked-2.f90 @@ -0,0 +1,46 @@ +module m + implicit none (external, type) + type t + end type t +contains +subroutine foo (x, y, z, a) + external :: bar + type(t) :: x + integer :: y + real :: z + integer :: a(4) + + !$omp masked filter (x) ! { dg-error "FILTER clause at .1. requires a scalar INTEGER expression" } + call bar () + !$omp end masked + + !$omp masked filter (y) ! OK + call bar () + !$omp end masked + + !$omp masked filter (z) ! { dg-error "FILTER clause at .1. requires a scalar INTEGER expression" } + call bar () + !$omp end masked + + !$omp masked filter (a) ! { dg-error "FILTER clause at .1. requires a scalar INTEGER expression" } + call bar () + !$omp end masked + + !$omp masked filter (0.0) ! { dg-error "FILTER clause at .1. requires a scalar INTEGER expression" } + call bar () + !$omp end masked + + !$omp masked filter ([1]) ! { dg-error "FILTER clause at .1. requires a scalar INTEGER expression" } + call bar () + !$omp end masked + + !$omp masked filter (-1) ! { dg-warning "INTEGER expression of FILTER clause at .1. must be non-negative" } + call bar () + !$omp end masked +end +end module + +subroutine bar + !$omp masked filter (0) filter (0) ! { dg-error "27: Failed to match clause" } + call foobar +end diff --git a/gcc/testsuite/gfortran.dg/gomp/masked-3.f90 b/gcc/testsuite/gfortran.dg/gomp/masked-3.f90 new file mode 100644 index 0000000..49c633d --- /dev/null +++ b/gcc/testsuite/gfortran.dg/gomp/masked-3.f90 @@ -0,0 +1,12 @@ +subroutine foo + + !$omp masked + goto 55 ! { dg-error "invalid branch to/from OpenMP structured block" } + ! { dg-warning "Legacy Extension: Label at .1. is not in the same block as the GOTO statement" "" { target *-*-* } .-1 } + !$omp end masked + + !$omp masked +55 continue ! { dg-warning "Legacy Extension: Label at .1. is not in the same block as the GOTO statement" } + return ! { dg-error "invalid branch to/from OpenMP structured block" } + !$omp end masked +end subroutine foo diff --git a/gcc/testsuite/gfortran.dg/gomp/masked-combined-1.f90 b/gcc/testsuite/gfortran.dg/gomp/masked-combined-1.f90 new file mode 100644 index 0000000..23ffb08 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/gomp/masked-combined-1.f90 @@ -0,0 +1,65 @@ +subroutine foo (a, f) + implicit none (type, external) + interface + subroutine bar (x) + integer :: x + end subroutine + end interface + + integer, value :: f + integer, contiguous :: a(0:) + integer :: i, j, k, u, v, w, x, y, z + + !$omp parallel masked default(none) private (k) filter (f) firstprivate (f) + call bar (k) + !$omp end parallel masked + + !$omp parallel masked default(none) private (k) + call bar (k) + !$omp end parallel masked + + !$omp parallel default(none) firstprivate(a, f) shared(x, y, z) + !$omp masked taskloop reduction (+:x) default(none) firstprivate(a) filter (f) + do i = 0, 63 + x = x + a(i) + end do + !$omp end masked taskloop + !$omp masked taskloop simd reduction (+:y) default(none) firstprivate(a) private (i) filter (f) + do i = 0, 63 + y = y + a(i) + end do + !$omp end masked taskloop simd + !$omp masked taskloop simd reduction (+:y) default(none) firstprivate(a) private (i) + do i = 0, 63 + y = y + a(i) + end do + !$omp end masked taskloop simd + !$omp masked taskloop simd collapse(2) reduction (+:z) default(none) firstprivate(a) private (i, j) filter (f) + do j = 0, 0 + do i = 0, 63 + z = z + a(i) + end do + end do + !$omp end masked taskloop simd + !$omp end parallel + + !$omp parallel masked taskloop reduction (+:u) default(none) firstprivate(a, f) filter (f) + do i = 0, 63 + u = u + a(i) + end do + !$omp end parallel masked taskloop + + !$omp parallel masked taskloop simd reduction (+:v) default(none) firstprivate(a, f) filter (f) + do i = 0, 63 + v = v + a(i) + end do + !$omp end parallel masked taskloop simd + + !$omp parallel masked taskloop simd collapse(2) reduction (+:w) default(none) firstprivate(a, f) filter (f) + do j = 0, 0 + do i = 0, 63 + w = w + a(i) + end do + end do + !$omp end parallel masked taskloop simd +end diff --git a/gcc/testsuite/gfortran.dg/gomp/masked-combined-2.f90 b/gcc/testsuite/gfortran.dg/gomp/masked-combined-2.f90 new file mode 100644 index 0000000..c94425f --- /dev/null +++ b/gcc/testsuite/gfortran.dg/gomp/masked-combined-2.f90 @@ -0,0 +1,24 @@ +subroutine foo (a) + implicit none (external, type) + integer, contiguous :: a(0:) + integer :: i, r, s + r = 0; s = 0 + + ! In 'parallel masked taskloop', in_reduction is not permitted. + + !$omp taskgroup task_reduction(+:r) + !$omp parallel masked taskloop in_reduction(+:r) ! { dg-error "36: Failed to match clause" } + do i = 0, 63 + r = r + a(i) + end do + !!$omp end parallel masked taskloop + !$omp end taskgroup + + !$omp taskgroup task_reduction(+:s) + !$omp parallel masked taskloop simd in_reduction(+:s) ! { dg-error "41: Failed to match clause" } + do i = 0, 63 + s = s + a(i) + end do + !!$omp end parallel masked taskloop simd + !$omp end taskgroup +end diff --git a/gcc/testsuite/gfortran.dg/gomp/nesting-1.f90 b/gcc/testsuite/gfortran.dg/gomp/nesting-1.f90 new file mode 100644 index 0000000..af4c2fbf --- /dev/null +++ b/gcc/testsuite/gfortran.dg/gomp/nesting-1.f90 @@ -0,0 +1,68 @@ +module m + implicit none + integer i +contains + +subroutine f_omp_parallel + !$omp parallel + !$omp parallel + !$omp end parallel + + !$omp target + !$omp end target + + !$omp target data map(i) + !$omp end target data + + !$omp target update to(i) + + !$omp target data map(i) + !$omp parallel + !$omp end parallel + + !$omp target + !$omp end target + + !$omp target data map(i) + !$omp end target data + + !$omp target update to(i) + !$omp end target data + !$omp end parallel +end + +subroutine f_omp_target + !$omp target + !$omp parallel + !$omp end parallel + !$omp end target +end + +subroutine f_omp_target_data + !$omp target data map(i) + !$omp parallel + !$omp end parallel + + !$omp target + !$omp end target + + !$omp target data map(i) + !$omp end target data + + !$omp target update to(i) + + !$omp target data map(i) + !$omp parallel + !$omp end parallel + + !$omp target + !$omp end target + + !$omp target data map(i) + !$omp end target data + + !$omp target update to(i) + !$omp end target data + !$omp end target data +end +end module m diff --git a/gcc/testsuite/gfortran.dg/gomp/nesting-2.f90 b/gcc/testsuite/gfortran.dg/gomp/nesting-2.f90 new file mode 100644 index 0000000..2eccdf9 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/gomp/nesting-2.f90 @@ -0,0 +1,165 @@ +subroutine foo + integer :: i, j + !$omp taskloop + do i = 0, 63 + !$omp do ! { dg-error "region may not be closely nested inside of" } + do j = 0, 9 + end do + !$omp single ! { dg-error "region may not be closely nested inside of" } + !$omp end single + !$omp sections ! { dg-error "region may not be closely nested inside of" } + !$omp section + block + end block + !$omp end sections + !$omp barrier ! { dg-error "region may not be closely nested inside of" } + !$omp master ! { dg-error "region may not be closely nested inside of" } -- ? + block; end block ! otherwise not generated + !$omp end master + !$omp masked ! { dg-error "region may not be closely nested inside of" } -- ? + block; end block ! otherwise not generated + !$omp end masked + !$omp scope ! { dg-error "region may not be closely nested inside of" } -- ? + block; end block ! otherwise not generated + !$omp end scope + !$omp ordered ! { dg-error "region may not be closely nested inside of" } + !$omp end ordered + !$omp ordered threads ! { dg-error "region may not be closely nested inside of" } + !$omp end ordered + !$omp ordered simd threads ! { dg-error ".ordered. .simd. must be closely nested inside .simd. region" } + !$omp end ordered + !$omp simd + do j = 0, 9 + !$omp ordered simd + !$omp end ordered + end do + !$omp critical + !$omp simd + do j = 0, 9 + !$omp ordered simd + !$omp end ordered + end do + !$omp end critical + end do + !$omp taskloop + do i = 0, 63 + !$omp parallel + !$omp do + do j = 0, 9 + end do + !$omp single + !$omp end single + !$omp sections + !$omp section + block; end block + !$omp end sections + !$omp barrier + !$omp master + block; end block ! otherwise not generated + !$omp end master + !$omp masked + block; end block ! otherwise not generated + !$omp end masked + !$omp scope + block; end block ! otherwise not generated + !$omp end scope + !$omp ordered ! { dg-error ".ordered. region must be closely nested inside a loop region with an .ordered. clause" } + !$omp end ordered + !$omp ordered threads ! { dg-error ".ordered. region must be closely nested inside a loop region with an .ordered. clause" } + !$omp end ordered + !$omp simd + do j = 0, 9 + !$omp ordered simd + !$omp end ordered + end do + !$omp critical + !$omp simd + do j = 0, 9 + !$omp ordered simd + !$omp end ordered + end do + !$omp end critical + !$omp end parallel + end do + !$omp taskloop + do i = 0, 63 + !$omp target + !$omp do + do j = 0, 9 + end do + !$omp single + !$omp end single + !$omp sections + !$omp section + block; end block + !$omp end sections + !$omp barrier + !$omp master + block; end block ! otherwise not generated + !$omp end master + !$omp masked + block; end block ! otherwise not generated + !$omp end masked + !$omp scope + block; end block ! otherwise not generated + !$omp end scope + !$omp ordered ! { dg-error ".ordered. region must be closely nested inside a loop region with an .ordered. clause" } + !$omp end ordered + !$omp ordered threads ! { dg-error ".ordered. region must be closely nested inside a loop region with an .ordered. clause" } + !$omp end ordered + !$omp simd + do j = 0, 9 + !$omp ordered simd + !$omp end ordered + end do + !$omp critical + !$omp simd + do j = 0, 9 + !$omp ordered simd + !$omp end ordered + end do + !$omp end critical + !$omp end target + end do + !$omp ordered + !$omp ordered ! { dg-error "region may not be closely nested inside of" } + !$omp end ordered + !$omp end ordered + !$omp ordered threads + !$omp ordered ! { dg-error "region may not be closely nested inside of" } + !$omp end ordered + !$omp end ordered + !$omp ordered + !$omp ordered threads ! { dg-error "region may not be closely nested inside of" } + !$omp end ordered + !$omp end ordered + !$omp ordered threads + !$omp ordered threads ! { dg-error "region may not be closely nested inside of" } + !$omp end ordered + !$omp end ordered + !$omp critical + !$omp ordered simd ! { dg-error ".ordered. .simd. must be closely nested inside .simd. region" } + !$omp end ordered + !$omp end critical + !$omp do ordered + do i = 0, 63 + !$omp parallel + !$omp ordered threads ! { dg-error ".ordered. region must be closely nested inside a loop region with an .ordered. clause" } + !$omp end ordered + !$omp end parallel + end do + !$omp do ordered + do i = 0, 63 + !$omp parallel + !$omp ordered ! { dg-error ".ordered. region must be closely nested inside a loop region with an .ordered. clause" } + !$omp end ordered + !$omp end parallel + end do + !$omp do ordered(1) + do i = 0, 63 + !$omp parallel + !$omp ordered depend(source) ! { dg-error ".ordered. construct with .depend. clause must be closely nested inside a loop with .ordered. clause with a parameter" } + !$omp ordered depend(sink: i - 1) ! { dg-error ".ordered. construct with .depend. clause must be closely nested inside a loop with .ordered. clause with a parameter" } + !$omp end parallel + end do +end diff --git a/gcc/testsuite/gfortran.dg/gomp/nesting-3.f90 b/gcc/testsuite/gfortran.dg/gomp/nesting-3.f90 new file mode 100644 index 0000000..cd2e39a --- /dev/null +++ b/gcc/testsuite/gfortran.dg/gomp/nesting-3.f90 @@ -0,0 +1,347 @@ +subroutine f1 + integer i, j + !$omp do + do i = 0, 2 + !$omp do ! { dg-error "may not be closely nested" } + do j = 0, 2 + block; end block + end do + !$omp sections ! { dg-error "may not be closely nested" } + block; end block + !$omp section + block; end block + !$omp end sections + !$omp single ! { dg-error "may not be closely nested" } + block; end block + !$omp end single + !$omp master ! { dg-error "may not be closely nested" } + block; end block + !$omp end master + !$omp masked ! { dg-error "may not be closely nested" } + block; end block + !$omp end masked + !$omp barrier ! { dg-error "may not be closely nested" } + !$omp scope ! { dg-error "may not be closely nested" } + block; end block + !$omp end scope + end do + !$omp sections + !$omp do ! { dg-error "may not be closely nested" } + do j = 0, 2 + block; end block + end do + !$omp end sections + !$omp sections + !$omp sections ! { dg-error "may not be closely nested" } + block; end block + !$omp section + block; end block + !$omp end sections + !$omp end sections + !$omp sections + !$omp single ! { dg-error "may not be closely nested" } + block; end block + !$omp end single + !$omp end sections + !$omp sections + !$omp master ! { dg-error "may not be closely nested" } + block; end block + !$omp end master + !$omp end sections + !$omp sections + !$omp masked ! { dg-error "may not be closely nested" } + block; end block + !$omp end masked + !$omp end sections + !$omp sections + !$omp scope ! { dg-error "may not be closely nested" } + block; end block + !$omp end scope + !$omp end sections + !$omp sections + !$omp section + block; end block + !$omp end sections + !$omp sections + !$omp section + !$omp do ! { dg-error "may not be closely nested" } + do j = 0, 2 + block; end block + end do + !$omp end sections + !$omp sections + !$omp section + !$omp sections ! { dg-error "may not be closely nested" } + block; end block + !$omp section + block; end block + !$omp end sections + !$omp end sections + !$omp sections + !$omp section + !$omp single ! { dg-error "may not be closely nested" } + block; end block + !$omp end single + !$omp end sections + !$omp sections + !$omp section + !$omp master ! { dg-error "may not be closely nested" } + block; end block + !$omp end master + !$omp section + !$omp masked ! { dg-error "may not be closely nested" } + block; end block + !$omp end masked + !$omp end sections + !$omp sections + !$omp section + !$omp scope ! { dg-error "may not be closely nested" } + block; end block + !$omp end scope + !$omp end sections + !$omp single + !$omp do ! { dg-error "may not be closely nested" } + do j = 0, 2 + block; end block + end do + !$omp sections ! { dg-error "may not be closely nested" } + block; end block + !$omp section + block; end block + !$omp end sections + !$omp single ! { dg-error "may not be closely nested" } + block; end block + !$omp end single + !$omp master ! { dg-error "may not be closely nested" } + block; end block + !$omp end master + !$omp masked ! { dg-error "may not be closely nested" } + block; end block + !$omp end masked + !$omp barrier ! { dg-error "may not be closely nested" } + !$omp scope ! { dg-error "may not be closely nested" } + block; end block + !$omp end scope + !$omp end single + !$omp master + !$omp do ! { dg-error "may not be closely nested" } + do j = 0, 2 + block; end block + end do + !$omp sections ! { dg-error "may not be closely nested" } + block; end block + !$omp section + block; end block + !$omp end sections + !$omp single ! { dg-error "may not be closely nested" } + block; end block + !$omp end single + !$omp master + block; end block + !$omp end master + !$omp barrier ! { dg-error "may not be closely nested" } + !$omp scope ! { dg-error "may not be closely nested" } + block; end block + !$omp end scope + !$omp end master + !$omp masked filter (1) + !$omp do ! { dg-error "may not be closely nested" } + do j = 0, 2 + block; end block + end do + !$omp sections ! { dg-error "may not be closely nested" } + block; end block + !$omp section + block; end block + !$omp end sections + !$omp single ! { dg-error "may not be closely nested" } + block; end block + !$omp end single + !$omp master + block; end block + !$omp end master + !$omp barrier ! { dg-error "may not be closely nested" } + !$omp scope ! { dg-error "may not be closely nested" } + block; end block + !$omp end scope + !$omp end masked + !$omp task + !$omp do ! { dg-error "may not be closely nested" } + do j = 0, 2 + block; end block + end do + !$omp sections ! { dg-error "may not be closely nested" } + block; end block + !$omp section + block; end block + !$omp end sections + !$omp single ! { dg-error "may not be closely nested" } + block; end block + !$omp end single + !$omp master ! { dg-error "may not be closely nested" } + block; end block + !$omp end master + !$omp masked ! { dg-error "may not be closely nested" } + block; end block + !$omp end masked + !$omp barrier ! { dg-error "may not be closely nested" } + !$omp scope ! { dg-error "may not be closely nested" } + block; end block + !$omp end scope + !$omp end task + !$omp parallel + !$omp do + do j = 0, 2 + block; end block + end do + !$omp sections + block; end block + !$omp section + block; end block + !$omp end sections + !$omp single + block; end block + !$omp end single + !$omp master + block; end block + !$omp end master + !$omp masked + block; end block + !$omp end masked + !$omp barrier + !$omp scope + block; end block + !$omp end scope + !$omp scope + !$omp scope + block; end block + !$omp end scope + !$omp end scope + !$omp end parallel + !$omp scope + !$omp do + do j = 0, 2 + block; end block + end do + !$omp sections + block; end block + !$omp section + block; end block + !$omp end sections + !$omp single + block; end block + !$omp end single + !$omp master + block; end block + !$omp end master + !$omp masked + block; end block + !$omp end masked + !$omp barrier + !$omp scope + block; end block + !$omp end scope + !$omp scope + !$omp scope + block; end block + !$omp end scope + !$omp end scope + !$omp end scope +end + +subroutine f2 + integer i, j + !$omp ordered + !$omp do ! { dg-error "may not be closely nested" } + do j = 0, 2 + block; end block + end do + !$omp sections ! { dg-error "may not be closely nested" } + block; end block + !$omp section + block; end block + !$omp end sections + !$omp single ! { dg-error "may not be closely nested" } + block; end block + !$omp end single + !$omp master + block; end block + !$omp end master + !$omp masked + block; end block + !$omp end masked + !$omp barrier ! { dg-error "may not be closely nested" } + !$omp scope ! { dg-error "may not be closely nested" } + block; end block + !$omp end scope + !$omp end ordered +end + +subroutine f3 (void) + !$omp critical + !$omp ordered ! { dg-error "may not be closely nested" } + block; end block + !$omp end ordered + !$omp scope ! { dg-error "may not be closely nested" } + block; end block + !$omp end scope + !$omp end critical +end + +subroutine f4 (void) + !$omp task + !$omp ordered ! { dg-error "may not be closely nested" } + block; end block + !$omp end ordered + !$omp scope ! { dg-error "may not be closely nested" } + block; end block + !$omp end scope + !$omp end task +end + +subroutine f5 (void) + integer i + !$omp do + do i = 0, 9 + !$omp ordered ! { dg-error "must be closely nested" } + block; end block + !$omp end ordered + end do + !$omp do ordered + do i = 0, 9 + !$omp ordered + block; end block + !$omp end ordered + end do +end + +subroutine f6 (void) + !$omp critical (foo) + !$omp critical (bar) + block; end block + !$omp end critical (bar) + !$omp end critical (foo) + !$omp critical + !$omp critical (baz) + block; end block + !$omp end critical (baz) + !$omp end critical +end + +subroutine f7 (void) + !$omp critical (foo2) + !$omp critical + block; end block + !$omp end critical + !$omp end critical (foo2) + !$omp critical (bar) + !$omp critical (bar) ! { dg-error "may not be nested" } + block; end block + !$omp end critical (bar) + !$omp end critical (bar) + !$omp critical + !$omp critical ! { dg-error "may not be nested" } + block; end block + !$omp end critical + !$omp end critical +end diff --git a/gcc/testsuite/gfortran.dg/gomp/nowait-1.f90 b/gcc/testsuite/gfortran.dg/gomp/nowait-1.f90 new file mode 100644 index 0000000..b47b4a1 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/gomp/nowait-1.f90 @@ -0,0 +1,19 @@ +subroutine foo + +!$omp do +do i = 1, 2 +end do +!$omp end do nowait foo ! { dg-error "Unexpected junk after NOWAIT clause" } +!$omp end do ! as previous line is ignored + +!$omp scope + block; end block +!$omp end scope bar ! { dg-error "Unexpected junk at" } +!$omp end scope + +!$omp scope + block; end block +!$omp end scope nowait nowait ! { dg-error "Unexpected junk after NOWAIT clause" } +!$omp end scope + +end diff --git a/gcc/testsuite/gfortran.dg/gomp/reduction-task-1.f90 b/gcc/testsuite/gfortran.dg/gomp/reduction-task-1.f90 new file mode 100644 index 0000000..99c097f --- /dev/null +++ b/gcc/testsuite/gfortran.dg/gomp/reduction-task-1.f90 @@ -0,0 +1,112 @@ +module m + implicit none + integer v + interface + subroutine foo(x) + integer, value :: x + end + end interface +contains + +subroutine bar + integer i + !$omp do reduction (task, +: v) + do i = 0, 63 + call foo (i) + end do + !$omp sections reduction (task, +: v) + call foo (-2) + !$omp section + call foo (-3) + !$omp end sections + !$omp parallel reduction (task, +: v) + call foo (-1) + !$omp end parallel + !$omp parallel do reduction (task, +: v) + do i = 0, 63 + call foo (i) + end do + !$omp end parallel do + !$omp parallel sections reduction (task, +: v) + call foo (-2) + !$omp section + call foo (-3) + !$omp end parallel sections + !$omp teams distribute parallel do reduction (task, +: v) ! { dg-bogus "invalid 'task' reduction modifier on construct other than 'parallel', 'do', 'sections' or 'scope'" "PR101948" { xfail *-*-* } } + do i = 0, 63 + call foo (i) + end do + !$omp end teams distribute parallel do + !$omp do reduction (default, +: v) + do i = 0, 63 + call foo (i) + end do + !$omp sections reduction (default, +: v) + call foo (-2) + !$omp section + call foo (-3) + !$omp end sections + !$omp parallel reduction (default, +: v) + call foo (-1) + !$omp end parallel + !$omp parallel do reduction (default, +: v) + do i = 0, 63 + call foo (i) + end do + !$omp end parallel do + !$omp parallel sections reduction (default, +: v) + call foo (-2) + !$omp section + call foo (-3) + !$omp end parallel sections + !$omp teams distribute parallel do reduction (default, +: v) + do i = 0, 63 + call foo (i) + end do + !$omp end teams distribute parallel do + !$omp do reduction (default, +: v) + do i = 0, 63 + call foo (i) + end do + !$omp end do nowait + !$omp sections reduction (default, +: v) + call foo (-2) + !$omp section + call foo (-3) + !$omp end sections nowait + !$omp simd reduction (default, +: v) + do i = 0, 63 + v = v + 1 + end do + !$omp do simd reduction (default, +: v) + do i = 0, 63 + v = v + 1 + end do + !$omp parallel do simd reduction (default, +: v) + do i = 0, 63 + v = v + 1 + end do + !$omp end parallel do simd + !$omp teams distribute parallel do simd reduction (default, +: v) + do i = 0, 63 + v = v + 1 + end do + !$omp end teams distribute parallel do simd + !$omp taskloop reduction (default, +: v) + do i = 0, 63 + call foo (i) + end do + !$omp taskloop simd reduction (default, +: v) + do i = 0, 63 + v = v + 1 + end do + !$omp teams reduction (default, +: v) + call foo (i) + !$omp end teams + !$omp teams distribute reduction (default, +: v) + do i = 0, 63 + call foo (i) + end do + !$omp end teams distribute +end +end diff --git a/gcc/testsuite/gfortran.dg/gomp/reduction-task-2.f90 b/gcc/testsuite/gfortran.dg/gomp/reduction-task-2.f90 new file mode 100644 index 0000000..c4169bc --- /dev/null +++ b/gcc/testsuite/gfortran.dg/gomp/reduction-task-2.f90 @@ -0,0 +1,45 @@ +module m + integer :: v + interface + subroutine foo(i) + integer :: i + end + end interface +end + +subroutine bar + use m + implicit none + integer :: i + !$omp do reduction (task, +: v) ! { dg-error "'task' reduction modifier on a construct with a 'nowait' clause" } + do i = 0, 63 + call foo (i) + end do + !$omp end do nowait + !$omp sections reduction (task, +: v) ! { dg-error "'task' reduction modifier on a construct with a 'nowait' clause" } + call foo (-2) + !$omp section + call foo (-3) + !$omp end sections nowait + !$omp scope reduction (task, +: v) ! { dg-error "'task' reduction modifier on a construct with a 'nowait' clause" } + call foo (-4) + !$omp end scope nowait + !$omp simd reduction (task, +: v) ! { dg-error "invalid 'task' reduction modifier on construct other than 'parallel', 'do', 'sections' or 'scope'" } + do i = 0, 63 + v = v + 1 + end do + !$omp do simd reduction (task, +: v) ! { dg-error "invalid 'task' reduction modifier on construct other than 'parallel', 'do', 'sections' or 'scope'" } + do i = 0, 63 + v = v + 1 + end do + !$omp parallel do simd reduction (task, +: v) ! { dg-error "invalid 'task' reduction modifier on construct other than 'parallel', 'do', 'sections' or 'scope'" } + do i = 0, 63 + v = v + 1 + end do + !$omp end parallel do simd + !$omp teams distribute parallel do simd reduction (task, +: v) ! { dg-error "invalid 'task' reduction modifier on construct other than 'parallel', 'do', 'sections' or 'scope'" } + do i = 0, 63 + v = v + 1 + end do + !$omp end teams distribute parallel do simd +end diff --git a/gcc/testsuite/gfortran.dg/gomp/reduction-task-2a.f90 b/gcc/testsuite/gfortran.dg/gomp/reduction-task-2a.f90 new file mode 100644 index 0000000..37ce1c8 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/gomp/reduction-task-2a.f90 @@ -0,0 +1,30 @@ +module m + integer :: v + interface + subroutine foo(i) + integer :: i + end + end interface +end + +subroutine bar + use m + implicit none + integer :: i + !$omp taskloop reduction (task, +: v) ! { dg-error "Only DEFAULT permitted as reduction-modifier in REDUCTION clause" } + do i = 0, 63 + call foo (i) + end do + !$omp taskloop simd reduction (task, +: v) ! { dg-error "Only DEFAULT permitted as reduction-modifier in REDUCTION clause" } + do i = 0, 63 + v = v + 1 + end do + !$omp teams reduction (task, +: v) ! { dg-error "Only DEFAULT permitted as reduction-modifier in REDUCTION clause" } + call foo (i) + !$omp end teams + !$omp teams distribute reduction (task, +: v) ! { dg-error "Only DEFAULT permitted as reduction-modifier in REDUCTION clause" } + do i = 0, 63 + call foo (i) + end do + !$omp end teams distribute +end diff --git a/gcc/testsuite/gfortran.dg/gomp/reduction-task-3.f90 b/gcc/testsuite/gfortran.dg/gomp/reduction-task-3.f90 new file mode 100644 index 0000000..ebf1f13 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/gomp/reduction-task-3.f90 @@ -0,0 +1,15 @@ +! Fortran testcase of reduction-task-3.f90 ( PR c/91149 ) + +module m + integer :: r +end + +subroutine foo + use m + !$omp parallel reduction(task, +: r) + r = r + 1 + !$omp end parallel + !$omp target parallel reduction(task, +: r) + r = r + 1 + !$omp end target parallel +end diff --git a/gcc/testsuite/gfortran.dg/gomp/reduction4.f90 b/gcc/testsuite/gfortran.dg/gomp/reduction4.f90 index 2e8aaa2..52d504b 100644 --- a/gcc/testsuite/gfortran.dg/gomp/reduction4.f90 +++ b/gcc/testsuite/gfortran.dg/gomp/reduction4.f90 @@ -40,7 +40,7 @@ do i=1,10 a = a + 1 end do -!$omp simd reduction(task,+:a) ! { dg-error "invalid 'task' reduction modifier on construct other than 'parallel', 'do' or 'sections'" } +!$omp simd reduction(task,+:a) ! { dg-error "invalid 'task' reduction modifier on construct other than 'parallel', 'do', 'sections' or 'scope'" } do i=1,10 a = a + 1 end do diff --git a/gcc/testsuite/gfortran.dg/gomp/reduction7.f90 b/gcc/testsuite/gfortran.dg/gomp/reduction7.f90 index 7dc50e1..5f0b7bd 100644 --- a/gcc/testsuite/gfortran.dg/gomp/reduction7.f90 +++ b/gcc/testsuite/gfortran.dg/gomp/reduction7.f90 @@ -2,7 +2,7 @@ implicit none integer :: a, b, i a = 0 -!$omp simd reduction(task,+:a) ! { dg-error "invalid 'task' reduction modifier on construct other than 'parallel', 'do' or 'sections'" } +!$omp simd reduction(task,+:a) ! { dg-error "invalid 'task' reduction modifier on construct other than 'parallel', 'do', 'sections' or 'scope'" } do i=1,10 a = a + 1 end do diff --git a/gcc/testsuite/gfortran.dg/gomp/scan-1.f90 b/gcc/testsuite/gfortran.dg/gomp/scan-1.f90 index 61d8925..f91c7fa 100644 --- a/gcc/testsuite/gfortran.dg/gomp/scan-1.f90 +++ b/gcc/testsuite/gfortran.dg/gomp/scan-1.f90 @@ -105,6 +105,11 @@ subroutine f3 (c, d) ! ... !$omp end teams + !$omp scope reduction (inscan, +: a) + ! { dg-error "'inscan' REDUCTION clause on construct other than DO, SIMD, DO SIMD, PARALLEL DO, PARALLEL DO SIMD" "" { target *-*-* } .-1 } + ! ... + !$omp end scope + !$omp target parallel do reduction (inscan, +: a) map (c, d) ! { dg-error "'inscan' REDUCTION clause on construct other than DO, SIMD, DO SIMD, PARALLEL DO, PARALLEL DO SIMD" "" { target *-*-* } .-1 } do i = 1, 64 diff --git a/gcc/testsuite/gfortran.dg/gomp/scope-1.f90 b/gcc/testsuite/gfortran.dg/gomp/scope-1.f90 new file mode 100644 index 0000000..43ec800 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/gomp/scope-1.f90 @@ -0,0 +1,39 @@ +module m + implicit none (external, type) + integer :: r, r2, r3 +contains + +subroutine foo + integer :: i, j, k + i = 0; j = 0; k = 0 + !$omp scope private (i) reduction (+:r) + i = 1 + r = r + 1 + !$omp end scope nowait + + !$omp scope private (i) reduction (task, +:r) + !$omp scope private (j) reduction (task, +:r2) + !$omp scope private (k) reduction (task, +:r3) + i = 1 + j = 2 + k = 3 + r = r + 1 + r2 = r2 + 1 + r3 = r3 + 1 + !$omp end scope + !$omp end scope + !$omp end scope + !$omp parallel + !$omp scope reduction (+:r) private (i) + !$omp scope reduction (+:r2) private (j) + !$omp single + i = 1 + j = 2 + r = r + 1 + r2 = r2 + 1 + !$omp end single + !$omp end scope nowait + !$omp end scope nowait + !$omp end parallel +end +end module diff --git a/gcc/testsuite/gfortran.dg/gomp/scope-2.f90 b/gcc/testsuite/gfortran.dg/gomp/scope-2.f90 new file mode 100644 index 0000000..a097ced --- /dev/null +++ b/gcc/testsuite/gfortran.dg/gomp/scope-2.f90 @@ -0,0 +1,40 @@ +module m + implicit none (type, external) + integer :: r, r2, r3 = 1 + interface + logical function bar(); end + end interface +contains + +subroutine foo + integer :: i, j, k + i = 0; j = 0; k = 0 + !$omp parallel + if (bar ()) then + !$omp cancel parallel + end if + !$omp scope reduction (+:r) private (i) + !$omp scope reduction (+:r2) private (j) + !$omp single + i = 1; + j = 2; + r = r + 1 + r2 = r2 + 1 + !$omp end single nowait + !$omp end scope + !$omp end scope + !$omp end parallel + + !$omp parallel + if (bar ()) then + !$omp cancel parallel + end if + !$omp scope reduction (task, +:r) private (i) + !$omp scope reduction (task, *:r3) + r = r + 1 + r3 = r3 + 1 + !$omp end scope + !$omp end scope + !$omp end parallel +end +end module diff --git a/gcc/testsuite/gfortran.dg/nothing-1.f90 b/gcc/testsuite/gfortran.dg/nothing-1.f90 new file mode 100644 index 0000000..9fc24d4 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/nothing-1.f90 @@ -0,0 +1,28 @@ +module m + implicit none (type, external) + !$omp nothing + + type t + !$omp nothing + integer s + end type + +contains + +integer function foo (i) + integer :: i + + !$omp nothing + if (.false.) & +& & !$omp nothing + i = i + 1 + +! In the following, '& & !$' is not a valid OpenMP sentinel and, +! hence, the line is regarded as comment + if (.false.) & +& & !$omp nothing + then + end if + foo = i +end +end module diff --git a/gcc/testsuite/gfortran.dg/nothing-2.f90 b/gcc/testsuite/gfortran.dg/nothing-2.f90 new file mode 100644 index 0000000..74a4a5a --- /dev/null +++ b/gcc/testsuite/gfortran.dg/nothing-2.f90 @@ -0,0 +1,7 @@ +pure subroutine foo + !$omp nothing ! { dg-error "OpenMP directives other than SIMD or DECLARE TARGET at .1. may not appear in PURE procedures" } +end subroutine + +subroutine bar + !$omp nothing foo ! { dg-error "Unexpected junk after $OMP NOTHING statement" } +end diff --git a/gcc/testsuite/lib/gfortran.exp b/gcc/testsuite/lib/gfortran.exp index cae6738..43f4d4e 100644 --- a/gcc/testsuite/lib/gfortran.exp +++ b/gcc/testsuite/lib/gfortran.exp @@ -184,7 +184,7 @@ proc gfortran_init { args } { set specpath [get_multilibs] } set gfortran_init_set_GFORTRAN_UNDER_TEST 1 - set GFORTRAN_UNDER_TEST [findfile $base_dir/../../gfortran "$base_dir/../../gfortran -B$base_dir/../../ -B$specpath/libgfortran/ -I$specpath/libgfortran" [findfile $base_dir/gfortran "$base_dir/gfortran -B$base_dir/" [transform gfortran]]] + set GFORTRAN_UNDER_TEST [findfile $base_dir/../../gfortran "$base_dir/../../gfortran -B$base_dir/../../ -B$specpath/libgfortran/" [findfile $base_dir/gfortran "$base_dir/gfortran -B$base_dir/" [transform gfortran]]] } } } diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c index 9883eaa..61b5391 100644 --- a/gcc/tree-cfg.c +++ b/gcc/tree-cfg.c @@ -8075,9 +8075,9 @@ dump_function_to_file (tree fndecl, FILE *file, dump_flags_t flags) : (fun->curr_properties & PROP_cfg) ? "cfg" : ""); - if (cfun->cfg) + if (fun && fun->cfg) { - basic_block bb = ENTRY_BLOCK_PTR_FOR_FN (cfun); + basic_block bb = ENTRY_BLOCK_PTR_FOR_FN (fun); if (bb->count.initialized_p ()) fprintf (file, ",%s(%" PRIu64 ")", profile_quality_as_string (bb->count.quality ()), @@ -8163,8 +8163,8 @@ dump_function_to_file (tree fndecl, FILE *file, dump_flags_t flags) tree name; - if (gimple_in_ssa_p (cfun)) - FOR_EACH_SSA_NAME (ix, name, cfun) + if (gimple_in_ssa_p (fun)) + FOR_EACH_SSA_NAME (ix, name, fun) { if (!SSA_NAME_VAR (name) /* SSA name with decls without a name still get @@ -8200,7 +8200,7 @@ dump_function_to_file (tree fndecl, FILE *file, dump_flags_t flags) fprintf (file, "}\n"); } - else if (fun->curr_properties & PROP_gimple_any) + else if (fun && (fun->curr_properties & PROP_gimple_any)) { /* The function is now in GIMPLE form but the CFG has not been built yet. Emit the single sequence of GIMPLE statements diff --git a/gcc/tree-core.h b/gcc/tree-core.h index bfab988..239a3a3 100644 --- a/gcc/tree-core.h +++ b/gcc/tree-core.h @@ -115,7 +115,10 @@ struct die_struct; #define EAF_NODIRECTESCAPE (1 << 4) /* Nonzero if the argument does not escape to return value. */ -#define EAF_NOT_RETURNED (1 << 8) +#define EAF_NOT_RETURNED (1 << 5) + +/* Nonzero if the argument is not read. */ +#define EAF_NOREAD (1 << 6) /* Call return flags. */ /* Mask for the argument number that is returned. Lower two bits of @@ -476,6 +479,9 @@ enum omp_clause_code { /* OpenMP clause: bind (binding). */ OMP_CLAUSE_BIND, + /* OpenMP clause: filter (integer-expression). */ + OMP_CLAUSE_FILTER, + /* Internally used only clause, holding SIMD uid. */ OMP_CLAUSE__SIMDUID_, @@ -1498,6 +1504,7 @@ enum omp_clause_proc_bind_kind /* Numbers should match omp_proc_bind_t enum in omp.h. */ OMP_CLAUSE_PROC_BIND_FALSE = 0, OMP_CLAUSE_PROC_BIND_TRUE = 1, + OMP_CLAUSE_PROC_BIND_PRIMARY = 2, OMP_CLAUSE_PROC_BIND_MASTER = 2, OMP_CLAUSE_PROC_BIND_CLOSE = 3, OMP_CLAUSE_PROC_BIND_SPREAD = 4, diff --git a/gcc/tree-inline.c b/gcc/tree-inline.c index 8e6cdd3..5955ff1 100644 --- a/gcc/tree-inline.c +++ b/gcc/tree-inline.c @@ -1658,6 +1658,18 @@ remap_gimple_stmt (gimple *stmt, copy_body_data *id) copy = gimple_build_omp_master (s1); break; + case GIMPLE_OMP_MASKED: + s1 = remap_gimple_seq (gimple_omp_body (stmt), id); + copy = gimple_build_omp_masked + (s1, gimple_omp_masked_clauses (stmt)); + break; + + case GIMPLE_OMP_SCOPE: + s1 = remap_gimple_seq (gimple_omp_body (stmt), id); + copy = gimple_build_omp_scope + (s1, gimple_omp_scope_clauses (stmt)); + break; + case GIMPLE_OMP_TASKGROUP: s1 = remap_gimple_seq (gimple_omp_body (stmt), id); copy = gimple_build_omp_taskgroup @@ -2868,7 +2880,7 @@ maybe_move_debug_stmts_to_successors (copy_body_data *id, basic_block new_bb) gimple_set_location (stmt, UNKNOWN_LOCATION); } gsi_remove (&si, false); - gsi_insert_before (&dsi, stmt, GSI_SAME_STMT); + gsi_insert_before (&dsi, stmt, GSI_NEW_STMT); continue; } @@ -2894,7 +2906,7 @@ maybe_move_debug_stmts_to_successors (copy_body_data *id, basic_block new_bb) new_stmt = as_a <gdebug *> (gimple_copy (stmt)); else gcc_unreachable (); - gsi_insert_before (&dsi, new_stmt, GSI_SAME_STMT); + gsi_insert_before (&dsi, new_stmt, GSI_NEW_STMT); id->debug_stmts.safe_push (new_stmt); gsi_prev (&ssi); } @@ -4544,6 +4556,8 @@ estimate_num_insns (gimple *stmt, eni_weights *weights) case GIMPLE_OMP_TASK: case GIMPLE_OMP_CRITICAL: case GIMPLE_OMP_MASTER: + case GIMPLE_OMP_MASKED: + case GIMPLE_OMP_SCOPE: case GIMPLE_OMP_TASKGROUP: case GIMPLE_OMP_ORDERED: case GIMPLE_OMP_SCAN: diff --git a/gcc/tree-nested.c b/gcc/tree-nested.c index 0c3fb02..c7f50eb 100644 --- a/gcc/tree-nested.c +++ b/gcc/tree-nested.c @@ -1033,6 +1033,7 @@ get_frame_field (struct nesting_info *info, tree target_context, } x = build3 (COMPONENT_REF, TREE_TYPE (field), x, field, NULL_TREE); + TREE_THIS_VOLATILE (x) = TREE_THIS_VOLATILE (field); return x; } @@ -1375,6 +1376,7 @@ convert_nonlocal_omp_clauses (tree *pclauses, struct walk_stmt_info *wi) case OMP_CLAUSE_GRAINSIZE: case OMP_CLAUSE_NUM_TASKS: case OMP_CLAUSE_HINT: + case OMP_CLAUSE_FILTER: case OMP_CLAUSE_NUM_GANGS: case OMP_CLAUSE_NUM_WORKERS: case OMP_CLAUSE_VECTOR_LENGTH: @@ -1734,6 +1736,14 @@ convert_nonlocal_reference_stmt (gimple_stmt_iterator *gsi, bool *handled_ops_p, info->suppress_expansion = save_suppress; break; + case GIMPLE_OMP_SCOPE: + save_suppress = info->suppress_expansion; + convert_nonlocal_omp_clauses (gimple_omp_scope_clauses_ptr (stmt), wi); + walk_body (convert_nonlocal_reference_stmt, convert_nonlocal_reference_op, + info, gimple_omp_body_ptr (stmt)); + info->suppress_expansion = save_suppress; + break; + case GIMPLE_OMP_TASKGROUP: save_suppress = info->suppress_expansion; convert_nonlocal_omp_clauses (gimple_omp_taskgroup_clauses_ptr (stmt), wi); @@ -1784,6 +1794,7 @@ convert_nonlocal_reference_stmt (gimple_stmt_iterator *gsi, bool *handled_ops_p, case GIMPLE_OMP_SECTION: case GIMPLE_OMP_MASTER: + case GIMPLE_OMP_MASKED: case GIMPLE_OMP_ORDERED: case GIMPLE_OMP_SCAN: walk_body (convert_nonlocal_reference_stmt, convert_nonlocal_reference_op, @@ -2153,6 +2164,7 @@ convert_local_omp_clauses (tree *pclauses, struct walk_stmt_info *wi) case OMP_CLAUSE_GRAINSIZE: case OMP_CLAUSE_NUM_TASKS: case OMP_CLAUSE_HINT: + case OMP_CLAUSE_FILTER: case OMP_CLAUSE_NUM_GANGS: case OMP_CLAUSE_NUM_WORKERS: case OMP_CLAUSE_VECTOR_LENGTH: @@ -2454,6 +2466,14 @@ convert_local_reference_stmt (gimple_stmt_iterator *gsi, bool *handled_ops_p, info->suppress_expansion = save_suppress; break; + case GIMPLE_OMP_SCOPE: + save_suppress = info->suppress_expansion; + convert_local_omp_clauses (gimple_omp_scope_clauses_ptr (stmt), wi); + walk_body (convert_local_reference_stmt, convert_local_reference_op, + info, gimple_omp_body_ptr (stmt)); + info->suppress_expansion = save_suppress; + break; + case GIMPLE_OMP_TASKGROUP: save_suppress = info->suppress_expansion; convert_local_omp_clauses (gimple_omp_taskgroup_clauses_ptr (stmt), wi); @@ -2517,6 +2537,7 @@ convert_local_reference_stmt (gimple_stmt_iterator *gsi, bool *handled_ops_p, case GIMPLE_OMP_SECTION: case GIMPLE_OMP_MASTER: + case GIMPLE_OMP_MASKED: case GIMPLE_OMP_ORDERED: case GIMPLE_OMP_SCAN: walk_body (convert_local_reference_stmt, convert_local_reference_op, @@ -3026,7 +3047,9 @@ convert_gimple_call (gimple_stmt_iterator *gsi, bool *handled_ops_p, case GIMPLE_OMP_SECTIONS: case GIMPLE_OMP_SECTION: case GIMPLE_OMP_SINGLE: + case GIMPLE_OMP_SCOPE: case GIMPLE_OMP_MASTER: + case GIMPLE_OMP_MASKED: case GIMPLE_OMP_TASKGROUP: case GIMPLE_OMP_ORDERED: case GIMPLE_OMP_SCAN: diff --git a/gcc/tree-pretty-print.c b/gcc/tree-pretty-print.c index 7201bd7..0570fdc 100644 --- a/gcc/tree-pretty-print.c +++ b/gcc/tree-pretty-print.c @@ -1008,6 +1008,8 @@ dump_omp_clause (pretty_printer *pp, tree clause, int spc, dump_flags_t flags) switch (OMP_CLAUSE_PROC_BIND_KIND (clause)) { case OMP_CLAUSE_PROC_BIND_MASTER: + /* Same enum value: case OMP_CLAUSE_PROC_BIND_PRIMARY: */ + /* TODO: Change to 'primary' for OpenMP 5.1. */ pp_string (pp, "master"); break; case OMP_CLAUSE_PROC_BIND_CLOSE: @@ -1083,6 +1085,13 @@ dump_omp_clause (pretty_printer *pp, tree clause, int spc, dump_flags_t flags) pp_right_paren (pp); break; + case OMP_CLAUSE_FILTER: + pp_string (pp, "filter("); + dump_generic_node (pp, OMP_CLAUSE_FILTER_EXPR (clause), + spc, flags, false); + pp_right_paren (pp); + break; + case OMP_CLAUSE_DEFAULTMAP: pp_string (pp, "defaultmap("); switch (OMP_CLAUSE_DEFAULTMAP_BEHAVIOR (clause)) @@ -3584,6 +3593,11 @@ dump_generic_node (pretty_printer *pp, tree node, int spc, dump_flags_t flags, pp_string (pp, "#pragma omp master"); goto dump_omp_body; + case OMP_MASKED: + pp_string (pp, "#pragma omp masked"); + dump_omp_clauses (pp, OMP_MASKED_CLAUSES (node), spc, flags); + goto dump_omp_body; + case OMP_TASKGROUP: pp_string (pp, "#pragma omp taskgroup"); dump_omp_clauses (pp, OMP_TASKGROUP_CLAUSES (node), spc, flags); @@ -3643,6 +3657,11 @@ dump_generic_node (pretty_printer *pp, tree node, int spc, dump_flags_t flags, dump_omp_clauses (pp, OMP_SINGLE_CLAUSES (node), spc, flags); goto dump_omp_body; + case OMP_SCOPE: + pp_string (pp, "#pragma omp scope"); + dump_omp_clauses (pp, OMP_SCOPE_CLAUSES (node), spc, flags); + goto dump_omp_body; + case OMP_CLAUSE: /* If we come here, we're dumping something that's not an OMP construct, for example, OMP clauses attached to a function's '__attribute__'. diff --git a/gcc/tree-profile.c b/gcc/tree-profile.c index 5a74cc9..cf46912 100644 --- a/gcc/tree-profile.c +++ b/gcc/tree-profile.c @@ -250,7 +250,7 @@ gimple_gen_edge_profiler (int edgeno, edge e) { /* __atomic_fetch_add (&counter, 1, MEMMODEL_RELAXED); */ tree addr = tree_coverage_counter_addr (GCOV_COUNTER_ARCS, edgeno); - tree f = builtin_decl_explicit (LONG_LONG_TYPE_SIZE > 32 + tree f = builtin_decl_explicit (TYPE_PRECISION (gcov_type_node) > 32 ? BUILT_IN_ATOMIC_FETCH_ADD_8: BUILT_IN_ATOMIC_FETCH_ADD_4); gcall *stmt = gimple_build_call (f, 3, addr, one, @@ -525,7 +525,7 @@ gimple_gen_time_profiler (unsigned tag) tree_time_profiler_counter); gassign *assign = gimple_build_assign (ptr, NOP_EXPR, addr); gsi_insert_before (&gsi, assign, GSI_NEW_STMT); - tree f = builtin_decl_explicit (LONG_LONG_TYPE_SIZE > 32 + tree f = builtin_decl_explicit (TYPE_PRECISION (gcov_type_node) > 32 ? BUILT_IN_ATOMIC_ADD_FETCH_8: BUILT_IN_ATOMIC_ADD_FETCH_4); gcall *stmt = gimple_build_call (f, 3, ptr, one, diff --git a/gcc/tree-ssa-alias.c b/gcc/tree-ssa-alias.c index cbd51ac..ce667ff 100644 --- a/gcc/tree-ssa-alias.c +++ b/gcc/tree-ssa-alias.c @@ -2870,7 +2870,7 @@ process_args: tree op = gimple_call_arg (call, i); int flags = gimple_call_arg_flags (call, i); - if (flags & EAF_UNUSED) + if (flags & (EAF_UNUSED | EAF_NOREAD)) continue; if (TREE_CODE (op) == WITH_SIZE_EXPR) diff --git a/gcc/tree-ssa-ccp.c b/gcc/tree-ssa-ccp.c index 003c9c2..1a63ae5 100644 --- a/gcc/tree-ssa-ccp.c +++ b/gcc/tree-ssa-ccp.c @@ -1389,6 +1389,66 @@ bit_value_unop (enum tree_code code, signop type_sgn, int type_precision, } } +/* Determine the mask pair *VAL and *MASK from multiplying the + argument mask pair RVAL, RMASK by the unsigned constant C. */ +void +bit_value_mult_const (signop sgn, int width, + widest_int *val, widest_int *mask, + const widest_int &rval, const widest_int &rmask, + widest_int c) +{ + widest_int sum_mask = 0; + + /* Ensure rval_lo only contains known bits. */ + widest_int rval_lo = wi::bit_and_not (rval, rmask); + + if (rval_lo != 0) + { + /* General case (some bits of multiplicand are known set). */ + widest_int sum_val = 0; + while (c != 0) + { + /* Determine the lowest bit set in the multiplier. */ + int bitpos = wi::ctz (c); + widest_int term_mask = rmask << bitpos; + widest_int term_val = rval_lo << bitpos; + + /* sum += term. */ + widest_int lo = sum_val + term_val; + widest_int hi = (sum_val | sum_mask) + (term_val | term_mask); + sum_mask |= term_mask | (lo ^ hi); + sum_val = lo; + + /* Clear this bit in the multiplier. */ + c ^= wi::lshift (1, bitpos); + } + /* Correctly extend the result value. */ + *val = wi::ext (sum_val, width, sgn); + } + else + { + /* Special case (no bits of multiplicand are known set). */ + while (c != 0) + { + /* Determine the lowest bit set in the multiplier. */ + int bitpos = wi::ctz (c); + widest_int term_mask = rmask << bitpos; + + /* sum += term. */ + widest_int hi = sum_mask + term_mask; + sum_mask |= term_mask | hi; + + /* Clear this bit in the multiplier. */ + c ^= wi::lshift (1, bitpos); + } + *val = 0; + } + + /* Correctly extend the result mask. */ + *mask = wi::ext (sum_mask, width, sgn); +} + + /* Apply the operation CODE in type TYPE to the value, mask pairs R1VAL, R1MASK and R2VAL, R2MASK representing a values of type R1TYPE and R2TYPE and set the value, mask pair *VAL and *MASK to the result. */ @@ -1398,7 +1458,7 @@ bit_value_binop (enum tree_code code, signop sgn, int width, widest_int *val, widest_int *mask, signop r1type_sgn, int r1type_precision, const widest_int &r1val, const widest_int &r1mask, - signop r2type_sgn, int r2type_precision, + signop r2type_sgn, int r2type_precision ATTRIBUTE_UNUSED, const widest_int &r2val, const widest_int &r2mask) { bool swap_p = false; @@ -1445,7 +1505,7 @@ bit_value_binop (enum tree_code code, signop sgn, int width, } else { - if (wi::neg_p (shift)) + if (wi::neg_p (shift, r2type_sgn)) { shift = -shift; if (code == RROTATE_EXPR) @@ -1482,7 +1542,7 @@ bit_value_binop (enum tree_code code, signop sgn, int width, } else { - if (wi::neg_p (shift)) + if (wi::neg_p (shift, r2type_sgn)) break; if (code == RSHIFT_EXPR) { @@ -1522,35 +1582,47 @@ bit_value_binop (enum tree_code code, signop sgn, int width, } case MINUS_EXPR: + case POINTER_DIFF_EXPR: { - widest_int temv, temm; - bit_value_unop (NEGATE_EXPR, r2type_sgn, r2type_precision, &temv, &temm, - r2type_sgn, r2type_precision, r2val, r2mask); - bit_value_binop (PLUS_EXPR, sgn, width, val, mask, - r1type_sgn, r1type_precision, r1val, r1mask, - r2type_sgn, r2type_precision, temv, temm); + /* Subtraction is derived from the addition algorithm above. */ + widest_int lo = wi::bit_and_not (r1val, r1mask) - (r2val | r2mask); + lo = wi::ext (lo, width, sgn); + widest_int hi = (r1val | r1mask) - wi::bit_and_not (r2val, r2mask); + hi = wi::ext (hi, width, sgn); + *mask = r1mask | r2mask | (lo ^ hi); + *mask = wi::ext (*mask, width, sgn); + *val = lo; break; } case MULT_EXPR: - { - /* Just track trailing zeros in both operands and transfer - them to the other. */ - int r1tz = wi::ctz (r1val | r1mask); - int r2tz = wi::ctz (r2val | r2mask); - if (r1tz + r2tz >= width) - { - *mask = 0; - *val = 0; - } - else if (r1tz + r2tz > 0) - { - *mask = wi::ext (wi::mask <widest_int> (r1tz + r2tz, true), - width, sgn); - *val = 0; - } - break; - } + if (r2mask == 0 + && !wi::neg_p (r2val, sgn) + && (flag_expensive_optimizations || wi::popcount (r2val) < 8)) + bit_value_mult_const (sgn, width, val, mask, r1val, r1mask, r2val); + else if (r1mask == 0 + && !wi::neg_p (r1val, sgn) + && (flag_expensive_optimizations || wi::popcount (r1val) < 8)) + bit_value_mult_const (sgn, width, val, mask, r2val, r2mask, r1val); + else + { + /* Just track trailing zeros in both operands and transfer + them to the other. */ + int r1tz = wi::ctz (r1val | r1mask); + int r2tz = wi::ctz (r2val | r2mask); + if (r1tz + r2tz >= width) + { + *mask = 0; + *val = 0; + } + else if (r1tz + r2tz > 0) + { + *mask = wi::ext (wi::mask <widest_int> (r1tz + r2tz, true), + width, sgn); + *val = 0; + } + } + break; case EQ_EXPR: case NE_EXPR: diff --git a/gcc/tree-ssa-forwprop.c b/gcc/tree-ssa-forwprop.c index bd64b8e..5b30d4c 100644 --- a/gcc/tree-ssa-forwprop.c +++ b/gcc/tree-ssa-forwprop.c @@ -3190,7 +3190,8 @@ pass_forwprop::execute (function *fun) || (fun->curr_properties & PROP_gimple_lvec)) && gimple_assign_load_p (stmt) && !gimple_has_volatile_ops (stmt) - && !stmt_can_throw_internal (cfun, stmt)) + && !stmt_can_throw_internal (cfun, stmt) + && (!VAR_P (rhs) || !DECL_HARD_REGISTER (rhs))) optimize_vector_load (&gsi); else if (code == COMPLEX_EXPR) diff --git a/gcc/tree-ssa-operands.c b/gcc/tree-ssa-operands.c index c155754..ebf7eea 100644 --- a/gcc/tree-ssa-operands.c +++ b/gcc/tree-ssa-operands.c @@ -834,12 +834,7 @@ operands_scanner::get_expr_operands (tree *expr_p, int flags) get_expr_operands (&TREE_OPERAND (expr, 0), flags); if (code == COMPONENT_REF) - { - if (!(flags & opf_no_vops) - && TREE_THIS_VOLATILE (TREE_OPERAND (expr, 1))) - gimple_set_has_volatile_ops (stmt, true); - get_expr_operands (&TREE_OPERAND (expr, 2), uflags); - } + get_expr_operands (&TREE_OPERAND (expr, 2), uflags); else if (code == ARRAY_REF || code == ARRAY_RANGE_REF) { get_expr_operands (&TREE_OPERAND (expr, 1), uflags); diff --git a/gcc/tree-ssa-sccvn.c b/gcc/tree-ssa-sccvn.c index 01fffcd..82bd10b 100644 --- a/gcc/tree-ssa-sccvn.c +++ b/gcc/tree-ssa-sccvn.c @@ -797,6 +797,7 @@ vn_reference_eq (const_vn_reference_t const vr1, const_vn_reference_t const vr2) vn_reference_op_t vro1, vro2; vn_reference_op_s tem1, tem2; bool deref1 = false, deref2 = false; + bool reverse1 = false, reverse2 = false; for (; vr1->operands.iterate (i, &vro1); i++) { if (vro1->opcode == MEM_REF) @@ -804,6 +805,7 @@ vn_reference_eq (const_vn_reference_t const vr1, const_vn_reference_t const vr2) /* Do not look through a storage order barrier. */ else if (vro1->opcode == VIEW_CONVERT_EXPR && vro1->reverse) return false; + reverse1 |= vro1->reverse; if (known_eq (vro1->off, -1)) break; off1 += vro1->off; @@ -815,11 +817,12 @@ vn_reference_eq (const_vn_reference_t const vr1, const_vn_reference_t const vr2) /* Do not look through a storage order barrier. */ else if (vro2->opcode == VIEW_CONVERT_EXPR && vro2->reverse) return false; + reverse2 |= vro2->reverse; if (known_eq (vro2->off, -1)) break; off2 += vro2->off; } - if (maybe_ne (off1, off2)) + if (maybe_ne (off1, off2) || reverse1 != reverse2) return false; if (deref1 && vro1->opcode == ADDR_EXPR) { @@ -916,6 +919,9 @@ copy_reference_ops_from_ref (tree ref, vec<vn_reference_op_s> *result) temp.type = NULL_TREE; temp.op0 = TREE_OPERAND (ref, 1); temp.op1 = TREE_OPERAND (ref, 2); + temp.reverse = (AGGREGATE_TYPE_P (TREE_TYPE (TREE_OPERAND (ref, 0))) + && TYPE_REVERSE_STORAGE_ORDER + (TREE_TYPE (TREE_OPERAND (ref, 0)))); { tree this_offset = component_ref_field_offset (ref); if (this_offset @@ -962,6 +968,9 @@ copy_reference_ops_from_ref (tree ref, vec<vn_reference_op_s> *result) * vn_ref_op_align_unit (&temp)); off.to_shwi (&temp.off); } + temp.reverse = (AGGREGATE_TYPE_P (TREE_TYPE (TREE_OPERAND (ref, 0))) + && TYPE_REVERSE_STORAGE_ORDER + (TREE_TYPE (TREE_OPERAND (ref, 0)))); } break; case VAR_DECL: @@ -1583,6 +1592,26 @@ contains_storage_order_barrier_p (vec<vn_reference_op_s> ops) return false; } +/* Return true if OPS represent an access with reverse storage order. */ + +static bool +reverse_storage_order_for_component_p (vec<vn_reference_op_s> ops) +{ + unsigned i = 0; + if (ops[i].opcode == REALPART_EXPR || ops[i].opcode == IMAGPART_EXPR) + ++i; + switch (ops[i].opcode) + { + case ARRAY_REF: + case COMPONENT_REF: + case BIT_FIELD_REF: + case MEM_REF: + return ops[i].reverse; + default: + return false; + } +} + /* Transform any SSA_NAME's in a vector of vn_reference_op_s structures into their value numbers. This is done in-place, and the vector passed in is returned. *VALUEIZED_ANYTHING will specify @@ -2899,6 +2928,7 @@ vn_reference_lookup_3 (ao_ref *ref, tree vuse, void *data_, routines to extract the assigned bits. */ else if (known_eq (ref->size, maxsize) && is_gimple_reg_type (vr->type) + && !reverse_storage_order_for_component_p (vr->operands) && !contains_storage_order_barrier_p (vr->operands) && gimple_assign_single_p (def_stmt) && CHAR_BIT == 8 @@ -3050,6 +3080,7 @@ vn_reference_lookup_3 (ao_ref *ref, tree vuse, void *data_, to access pieces from or we can combine to a larger entity. */ else if (known_eq (ref->size, maxsize) && is_gimple_reg_type (vr->type) + && !reverse_storage_order_for_component_p (vr->operands) && !contains_storage_order_barrier_p (vr->operands) && gimple_assign_single_p (def_stmt) && TREE_CODE (gimple_assign_rhs1 (def_stmt)) == SSA_NAME) diff --git a/gcc/tree-ssa-structalias.c b/gcc/tree-ssa-structalias.c index c694926..fb0e429 100644 --- a/gcc/tree-ssa-structalias.c +++ b/gcc/tree-ssa-structalias.c @@ -4063,8 +4063,14 @@ handle_rhs_call (gcall *stmt, vec<ce_s> *results) tree arg = gimple_call_arg (stmt, i); int flags = gimple_call_arg_flags (stmt, i); - /* If the argument is not used we can ignore it. */ - if (flags & EAF_UNUSED) + /* If the argument is not used we can ignore it. + Similarly argument is invisile for us if it not clobbered, does not + escape, is not read and can not be returned. */ + if ((flags & EAF_UNUSED) + || ((flags & (EAF_NOCLOBBER | EAF_NOESCAPE | EAF_NOREAD + | EAF_NOT_RETURNED)) + == (EAF_NOCLOBBER | EAF_NOESCAPE | EAF_NOREAD + | EAF_NOT_RETURNED))) continue; /* As we compute ESCAPED context-insensitive we do not gain @@ -4316,7 +4322,9 @@ handle_pure_call (gcall *stmt, vec<ce_s> *results) int flags = gimple_call_arg_flags (stmt, i); /* If the argument is not used we can ignore it. */ - if (flags & EAF_UNUSED) + if ((flags & EAF_UNUSED) + || (flags & (EAF_NOT_RETURNED | EAF_NOREAD)) + == (EAF_NOT_RETURNED | EAF_NOREAD)) continue; if (!uses) { diff --git a/gcc/tree-ssa-threadbackward.c b/gcc/tree-ssa-threadbackward.c index e237eb4..3aad1493 100644 --- a/gcc/tree-ssa-threadbackward.c +++ b/gcc/tree-ssa-threadbackward.c @@ -51,12 +51,9 @@ class back_threader_registry { public: back_threader_registry (int max_allowable_paths); - ~back_threader_registry (); bool register_path (const vec<basic_block> &, edge taken); bool thread_through_all_blocks (); - private: - vec<vec<basic_block>> m_all_paths; jump_thread_path_registry m_lowlevel_registry; const int m_max_allowable_paths; int m_threaded_paths; @@ -72,24 +69,19 @@ public: { } bool profitable_path_p (const vec<basic_block> &, tree name, edge taken, bool *irreducible_loop = NULL); - private: const bool m_speed_p; }; -// Ranger based backwards threader. - class back_threader { - // Temporary until we remove old code. - friend bool path_is_unreachable_p (const vec<jump_thread_edge *> &); - public: - back_threader (back_threader_profitability &, back_threader_registry &); + back_threader (bool speed_p); ~back_threader (); - void find_paths (basic_block bb, tree name); - + void maybe_thread_block (basic_block bb); + bool thread_through_all_blocks (); private: + void find_paths (basic_block bb, tree name); void maybe_register_path (edge taken_edge); bool find_paths_to_names (basic_block bb, bitmap imports); bool resolve_def (tree name, bitmap interesting, vec<tree> &worklist); @@ -98,8 +90,8 @@ private: edge find_taken_edge_cond (const vec<basic_block> &path, gcond *); edge find_taken_edge_switch (const vec<basic_block> &path, gswitch *); - back_threader_registry &m_registry; - back_threader_profitability &m_profit; + back_threader_registry m_registry; + back_threader_profitability m_profit; gimple_ranger m_ranger; path_range_query m_solver; @@ -123,10 +115,9 @@ private: // in a the given direction. const edge back_threader::UNREACHABLE_EDGE = (edge) -1; -back_threader::back_threader (back_threader_profitability &profit, - back_threader_registry ®istry) - : m_registry (registry), - m_profit (profit), +back_threader::back_threader (bool speed_p) + : m_registry (param_max_fsm_thread_paths), + m_profit (speed_p), m_solver (m_ranger) { m_last_stmt = NULL; @@ -456,74 +447,9 @@ back_threader::find_paths (basic_block bb, tree name) } } -// Dump a sequence of BBs through the CFG. - -DEBUG_FUNCTION void -dump_path (FILE *dump_file, const vec<basic_block> &path) -{ - for (size_t i = 0; i < path.length (); ++i) - { - fprintf (dump_file, "BB%d", path[i]->index); - if (i + 1 < path.length ()) - fprintf (dump_file, " <- "); - } - fprintf (dump_file, "\n"); -} - -DEBUG_FUNCTION void -debug (const vec <basic_block> &path) -{ - dump_path (stderr, path); -} - -class thread_jumps -{ -public: - thread_jumps (bool speed_p = true) - : m_profit (speed_p), - m_registry (param_max_fsm_thread_paths), - m_back_threader (m_profit, m_registry) - { } - void find_jump_threads_backwards (basic_block bb); - void find_jump_threads_backwards_with_ranger (basic_block bb); - bool thread_through_all_blocks (); - -private: - void maybe_register_path (const vec<basic_block> &m_path, - tree name, - edge taken_edge); - edge find_taken_edge (const vec<basic_block> &path, tree arg); - void handle_assignment (gimple *stmt, basic_block def_bb); - void handle_phi (gphi *phi, basic_block def_bb); - void fsm_find_control_statement_thread_paths (tree name); - bool check_subpath_and_update_thread_path (basic_block last_bb, - basic_block new_bb, - int *next_path_length); - - /* Hash to keep track of seen bbs. */ - hash_set<basic_block> m_visited_bbs; - /* Current path we're analyzing. */ - auto_vec<basic_block> m_path; - /* Tracks if we have recursed through a loop PHI node. */ - bool m_seen_loop_phi; - - tree m_name; - back_threader_profitability m_profit; - back_threader_registry m_registry; - back_threader m_back_threader; -}; - -// Perform the actual jump threading for the all queued paths. - -bool -thread_jumps::thread_through_all_blocks () -{ - return m_registry.thread_through_all_blocks (); -} - -/* Simple helper to get the last statement from BB, which is assumed - to be a control statement. Return NULL if the last statement is - not a control statement. */ +// Simple helper to get the last statement from BB, which is assumed +// to be a control statement. Return NULL if the last statement is +// not a control statement. static gimple * get_gimple_control_stmt (basic_block bb) @@ -540,55 +466,65 @@ get_gimple_control_stmt (basic_block bb) return NULL; } -/* Return true if the CFG contains at least one path from START_BB to - END_BB. When a path is found, record in PATH the blocks from - END_BB to START_BB. LOCAL_VISITED_BBS is used to make sure we - don't fall into an infinite loop. Bound the recursion to basic - blocks belonging to LOOP. */ +// Search backwards from BB looking for paths where the final +// conditional maybe threaded to a successor block. Record such paths +// for jump threading. -static bool -fsm_find_thread_path (basic_block start_bb, basic_block end_bb, - vec<basic_block> &path, - hash_set<basic_block> &local_visited_bbs, - loop_p loop) +void +back_threader::maybe_thread_block (basic_block bb) { - if (loop != start_bb->loop_father) - return false; + gimple *stmt = get_gimple_control_stmt (bb); + if (!stmt) + return; - if (start_bb == end_bb) - { - path.safe_push (start_bb); - return true; - } + enum gimple_code code = gimple_code (stmt); + tree name; + if (code == GIMPLE_SWITCH) + name = gimple_switch_index (as_a <gswitch *> (stmt)); + else if (code == GIMPLE_COND) + name = gimple_cond_lhs (stmt); + else if (code == GIMPLE_GOTO) + name = gimple_goto_dest (stmt); + else + name = NULL; + + find_paths (bb, name); +} + +// Perform the actual jump threading for the all queued paths. + +bool +back_threader::thread_through_all_blocks () +{ + return m_registry.thread_through_all_blocks (); +} + +// Dump a sequence of BBs through the CFG. - if (!local_visited_bbs.add (start_bb)) +DEBUG_FUNCTION void +dump_path (FILE *dump_file, const vec<basic_block> &path) +{ + for (size_t i = 0; i < path.length (); ++i) { - edge e; - edge_iterator ei; - FOR_EACH_EDGE (e, ei, start_bb->succs) - if (fsm_find_thread_path (e->dest, end_bb, path, local_visited_bbs, - loop)) - { - path.safe_push (start_bb); - return true; - } + fprintf (dump_file, "BB%d", path[i]->index); + if (i + 1 < path.length ()) + fprintf (dump_file, " <- "); } + fprintf (dump_file, "\n"); +} - return false; +DEBUG_FUNCTION void +debug (const vec <basic_block> &path) +{ + dump_path (stderr, path); } back_threader_registry::back_threader_registry (int max_allowable_paths) : m_max_allowable_paths (max_allowable_paths) { - m_all_paths.create (5); m_threaded_paths = 0; } -back_threader_registry::~back_threader_registry () -{ - m_all_paths.release (); -} - bool back_threader_registry::thread_through_all_blocks () { @@ -881,39 +817,6 @@ back_threader_profitability::profitable_path_p (const vec<basic_block> &m_path, return true; } -/* Return the taken edge out of a path, assuming that the underlying assignment - or PHI SSA resolves to ARG. */ - -edge -thread_jumps::find_taken_edge (const vec<basic_block> &path, tree arg) -{ - if (TREE_CODE_CLASS (TREE_CODE (arg)) != tcc_constant) - return NULL; - - gcc_checking_assert (!path.is_empty ()); - gimple *stmt = get_gimple_control_stmt (m_path[0]); - - /* We have found a constant value for ARG. For GIMPLE_SWITCH - and GIMPLE_GOTO, we use it as-is. However, for a GIMPLE_COND - we need to substitute, fold and simplify so we can determine - the edge taken out of the last block. */ - if (gimple_code (stmt) == GIMPLE_COND) - { - enum tree_code cond_code = gimple_cond_code (stmt); - - /* We know the underyling format of the condition. */ - arg = fold_binary (cond_code, boolean_type_node, - arg, gimple_cond_rhs (stmt)); - } - - /* If this path threaded through the loop latch back into the - same loop and the destination does not dominate the loop - latch, then this thread would create an irreducible loop. - - We have to know the outgoing edge to figure this out. */ - return ::find_taken_edge (m_path[0], arg); -} - /* The current path PATH is a vector of blocks forming a jump threading path in reverse order. TAKEN_EDGE is the edge taken from path[0]. @@ -962,331 +865,6 @@ back_threader_registry::register_path (const vec<basic_block> &m_path, return true; } -/* While following a chain of SSA_NAME definitions, we jumped from a - definition in LAST_BB to a definition in NEW_BB (walking - backwards). - - Verify there is a single path between the blocks and none of the - blocks in the path is already in VISITED_BBS. If so, then update - VISISTED_BBS, add the new blocks to PATH and return TRUE. - Otherwise return FALSE. - - Store the length of the subpath in NEXT_PATH_LENGTH. */ - -bool -thread_jumps::check_subpath_and_update_thread_path (basic_block last_bb, - basic_block new_bb, - int *next_path_length) -{ - edge e; - int e_count = 0; - edge_iterator ei; - auto_vec<basic_block> next_path; - - FOR_EACH_EDGE (e, ei, last_bb->preds) - { - hash_set<basic_block> local_visited_bbs; - - if (fsm_find_thread_path (new_bb, e->src, next_path, - local_visited_bbs, e->src->loop_father)) - ++e_count; - - /* If there is more than one path, stop. */ - if (e_count > 1) - return false; - } - - /* Stop if we have not found a path: this could occur when the recursion - is stopped by one of the bounds. */ - if (e_count == 0) - return false; - - /* Make sure we haven't already visited any of the nodes in - NEXT_PATH. Don't add them here to avoid pollution. */ - for (unsigned int i = 0; i + 1 < next_path.length (); i++) - { - if (m_visited_bbs.contains (next_path[i])) - return false; - } - - /* Now add the nodes to VISISTED_BBS. */ - for (unsigned int i = 0; i + 1 < next_path.length (); i++) - m_visited_bbs.add (next_path[i]); - - /* Append all the nodes from NEXT_PATH to PATH. */ - m_path.safe_splice (next_path); - *next_path_length = next_path.length (); - - return true; -} - -/* If this is a profitable jump thread path, register it. - - NAME is an SSA NAME with a possible constant value of ARG on PATH. - - DEF_BB is the basic block that ultimately defines the constant. */ - -void -thread_jumps::maybe_register_path (const vec<basic_block> &m_path, - tree name, - edge taken_edge) -{ - bool irreducible = false; - bool profitable = m_profit.profitable_path_p (m_path, name, taken_edge, - &irreducible); - if (profitable) - { - if (!m_registry.register_path (m_path, taken_edge)) - return; - - if (irreducible) - vect_free_loop_info_assumptions (m_path[0]->loop_father); - } -} - -/* Given PHI which defines NAME in block DEF_BB, recurse through the - PHI's arguments searching for paths where NAME will ultimately have - a constant value. - - PATH contains the series of blocks to traverse that will result in - NAME having a constant value. */ - -void -thread_jumps::handle_phi (gphi *phi, basic_block def_bb) -{ - /* Iterate over the arguments of PHI. */ - for (unsigned int i = 0; i < gimple_phi_num_args (phi); i++) - { - tree arg = gimple_phi_arg_def (phi, i); - basic_block bbi = gimple_phi_arg_edge (phi, i)->src; - - /* Skip edges pointing outside the current loop. */ - if (!arg || def_bb->loop_father != bbi->loop_father) - continue; - - if (TREE_CODE (arg) == SSA_NAME) - { - m_path.safe_push (bbi); - /* Recursively follow SSA_NAMEs looking for a constant - definition. */ - fsm_find_control_statement_thread_paths (arg); - - m_path.pop (); - continue; - } - - m_path.safe_push (bbi); - edge taken_edge = find_taken_edge (m_path, arg); - if (taken_edge) - maybe_register_path (m_path, m_name, taken_edge); - m_path.pop (); - } -} - -/* Return TRUE if STMT is a gimple assignment we want to either directly - handle or recurse through. Return FALSE otherwise. - - Note that adding more cases here requires adding cases to handle_assignment - below. */ - -static bool -handle_assignment_p (gimple *stmt) -{ - if (is_gimple_assign (stmt)) - { - enum tree_code def_code = gimple_assign_rhs_code (stmt); - - /* If the RHS is an SSA_NAME, then we will recurse through it. - Go ahead and filter out cases where the SSA_NAME is a default - definition. There's little to be gained by trying to handle that. */ - if (def_code == SSA_NAME - && !SSA_NAME_IS_DEFAULT_DEF (gimple_assign_rhs1 (stmt))) - return true; - - /* If the RHS is a constant, then it's a terminal that we'll want - to handle as well. */ - if (TREE_CODE_CLASS (def_code) == tcc_constant) - return true; - } - - /* Anything not explicitly allowed is not handled. */ - return false; -} - -/* Given STMT which defines NAME in block DEF_BB, recurse through the - PHI's arguments searching for paths where NAME will ultimately have - a constant value. - - PATH contains the series of blocks to traverse that will result in - NAME having a constant value. */ - -void -thread_jumps::handle_assignment (gimple *stmt, basic_block def_bb) -{ - tree arg = gimple_assign_rhs1 (stmt); - - if (TREE_CODE (arg) == SSA_NAME) - fsm_find_control_statement_thread_paths (arg); - else - { - if (CHECKING_P) - { - gcc_assert (!m_path.is_empty ()); - basic_block top = m_path[m_path.length () - 1]; - gcc_assert (top == def_bb); - } - edge taken_edge = find_taken_edge (m_path, arg); - if (taken_edge) - maybe_register_path (m_path, m_name, taken_edge); - } -} - -/* We trace the value of the SSA_NAME NAME back through any phi nodes - looking for places where it gets a constant value and save the - path. */ - -void -thread_jumps::fsm_find_control_statement_thread_paths (tree name) -{ - /* If NAME appears in an abnormal PHI, then don't try to trace its - value back through PHI nodes. */ - if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (name)) - return; - - gimple *def_stmt = SSA_NAME_DEF_STMT (name); - basic_block def_bb = gimple_bb (def_stmt); - - if (def_bb == NULL) - return; - - /* We allow the SSA chain to contains PHIs and simple copies and constant - initializations. */ - if (gimple_code (def_stmt) != GIMPLE_PHI - && gimple_code (def_stmt) != GIMPLE_ASSIGN) - return; - - if (gimple_code (def_stmt) == GIMPLE_PHI - && (gimple_phi_num_args (def_stmt) - >= (unsigned) param_fsm_maximum_phi_arguments)) - return; - - if (is_gimple_assign (def_stmt) - && ! handle_assignment_p (def_stmt)) - return; - - /* Avoid infinite recursion. */ - if (m_visited_bbs.add (def_bb)) - return; - - int next_path_length = 0; - basic_block last_bb_in_path = m_path.last (); - - if (loop_containing_stmt (def_stmt)->header == gimple_bb (def_stmt)) - { - /* Do not walk through more than one loop PHI node. */ - if (m_seen_loop_phi) - return; - m_seen_loop_phi = true; - } - - /* Following the chain of SSA_NAME definitions, we jumped from a definition in - LAST_BB_IN_PATH to a definition in DEF_BB. When these basic blocks are - different, append to PATH the blocks from LAST_BB_IN_PATH to DEF_BB. */ - if (def_bb != last_bb_in_path) - { - /* When DEF_BB == LAST_BB_IN_PATH, then the first block in the path - will already be in VISITED_BBS. When they are not equal, then we - must ensure that first block is accounted for to ensure we do not - create bogus jump threading paths. */ - m_visited_bbs.add (m_path[0]); - if (!check_subpath_and_update_thread_path (last_bb_in_path, def_bb, - &next_path_length)) - return; - } - - gcc_assert (m_path.last () == def_bb); - - if (gimple_code (def_stmt) == GIMPLE_PHI) - handle_phi (as_a <gphi *> (def_stmt), def_bb); - else if (gimple_code (def_stmt) == GIMPLE_ASSIGN) - handle_assignment (def_stmt, def_bb); - - /* Remove all the nodes that we added from NEXT_PATH. */ - if (next_path_length) - m_path.truncate (m_path.length () - next_path_length); -} - -/* Search backwards from BB looking for paths where NAME (an SSA_NAME) - is a constant. Record such paths for jump threading. - - It is assumed that BB ends with a control statement and that by - finding a path where NAME is a constant, we can thread the path. - SPEED_P indicates that we could increase code size to improve the - code path. */ - -void -thread_jumps::find_jump_threads_backwards (basic_block bb) -{ - if (param_threader_mode & THREADER_MODE_RANGER) - { - find_jump_threads_backwards_with_ranger (bb); - return; - } - - gimple *stmt = get_gimple_control_stmt (bb); - if (!stmt) - return; - - enum gimple_code code = gimple_code (stmt); - tree name = NULL; - if (code == GIMPLE_SWITCH) - name = gimple_switch_index (as_a <gswitch *> (stmt)); - else if (code == GIMPLE_GOTO) - name = gimple_goto_dest (stmt); - else if (code == GIMPLE_COND) - { - if (TREE_CODE (gimple_cond_lhs (stmt)) == SSA_NAME - && TREE_CODE_CLASS (TREE_CODE (gimple_cond_rhs (stmt))) == tcc_constant - && (INTEGRAL_TYPE_P (TREE_TYPE (gimple_cond_lhs (stmt))) - || POINTER_TYPE_P (TREE_TYPE (gimple_cond_lhs (stmt))))) - name = gimple_cond_lhs (stmt); - } - - if (!name || TREE_CODE (name) != SSA_NAME) - return; - - /* Initialize pass local data that's different for each BB. */ - m_path.truncate (0); - m_path.safe_push (bb); - m_visited_bbs.empty (); - m_seen_loop_phi = false; - m_name = name; - - fsm_find_control_statement_thread_paths (name); -} - -// Like find_jump_threads_backwards(), but using ranger. - -void -thread_jumps::find_jump_threads_backwards_with_ranger (basic_block bb) -{ - gimple *stmt = get_gimple_control_stmt (bb); - if (!stmt) - return; - - enum gimple_code code = gimple_code (stmt); - tree name = NULL; - if (code == GIMPLE_SWITCH) - name = gimple_switch_index (as_a <gswitch *> (stmt)); - else if (code == GIMPLE_GOTO) - name = gimple_goto_dest (stmt); - else if (code == GIMPLE_COND) - name = gimple_cond_lhs (stmt); - - m_name = name; - m_back_threader.find_paths (bb, name); -} - namespace { const pass_data pass_data_thread_jumps = @@ -1327,12 +905,12 @@ static bool try_thread_blocks (function *fun) { /* Try to thread each block with more than one successor. */ - thread_jumps threader; + back_threader threader (/*speed_p=*/true); basic_block bb; FOR_EACH_BB_FN (bb, fun) { if (EDGE_COUNT (bb->succs) > 1) - threader.find_jump_threads_backwards (bb); + threader.maybe_thread_block (bb); } return threader.thread_through_all_blocks (); } @@ -1390,19 +968,18 @@ pass_early_thread_jumps::gate (function *fun ATTRIBUTE_UNUSED) return true; } - unsigned int pass_early_thread_jumps::execute (function *fun) { loop_optimizer_init (AVOID_CFG_MODIFICATIONS); /* Try to thread each block with more than one successor. */ - thread_jumps threader (/*speed_p=*/false); + back_threader threader (/*speed_p=*/false); basic_block bb; FOR_EACH_BB_FN (bb, fun) { if (EDGE_COUNT (bb->succs) > 1) - threader.find_jump_threads_backwards (bb); + threader.maybe_thread_block (bb); } threader.thread_through_all_blocks (); diff --git a/gcc/tree-ssa-uninit.c b/gcc/tree-ssa-uninit.c index 5d7bc80..ad2cf48 100644 --- a/gcc/tree-ssa-uninit.c +++ b/gcc/tree-ssa-uninit.c @@ -283,6 +283,64 @@ builtin_call_nomodifying_p (gimple *stmt) return true; } +/* If ARG is a FNDECL parameter declared with attribute access none or + write_only issue a warning for its read access via PTR. */ + +static void +maybe_warn_read_write_only (tree fndecl, gimple *stmt, tree arg, tree ptr) +{ + if (!fndecl) + return; + + if (get_no_uninit_warning (arg)) + return; + + tree fntype = TREE_TYPE (fndecl); + if (!fntype) + return; + + /* Initialize a map of attribute access specifications for arguments + to the function function call. */ + rdwr_map rdwr_idx; + init_attr_rdwr_indices (&rdwr_idx, TYPE_ATTRIBUTES (fntype)); + + unsigned argno = 0; + tree parms = DECL_ARGUMENTS (fndecl); + for (tree parm = parms; parm; parm = TREE_CHAIN (parm), ++argno) + { + if (parm != arg) + continue; + + const attr_access* access = rdwr_idx.get (argno); + if (!access) + break; + + if (access->mode != access_none + && access->mode != access_write_only) + continue; + + location_t stmtloc + = linemap_resolve_location (line_table, gimple_location (stmt), + LRK_SPELLING_LOCATION, NULL); + + if (!warning_at (stmtloc, OPT_Wmaybe_uninitialized, + "%qE may be used uninitialized", ptr)) + break; + + suppress_warning (arg, OPT_Wmaybe_uninitialized); + + const char* const access_str = + TREE_STRING_POINTER (access->to_external_string ()); + + location_t parmloc = DECL_SOURCE_LOCATION (parm); + inform (parmloc, "accessing argument %u of a function declared with " + "attribute %<%s%>", + argno + 1, access_str); + + break; + } +} + /* Callback for walk_aliased_vdefs. */ static bool @@ -350,7 +408,9 @@ struct wlimits }; /* Determine if REF references an uninitialized operand and diagnose - it if so. */ + it if so. STMS is the referencing statement. LHS is the result + of the access and may be null. RHS is the variable referenced by + the access; it may not be null. */ static tree maybe_warn_operand (ao_ref &ref, gimple *stmt, tree lhs, tree rhs, @@ -497,14 +557,25 @@ maybe_warn_operand (ao_ref &ref, gimple *stmt, tree lhs, tree rhs, /* Do not warn if it can be initialized outside this function. If we did not reach function entry then we found killing clobbers on all paths to entry. */ - if (!found_alloc - && fentry_reached - /* ??? We'd like to use ref_may_alias_global_p but that - excludes global readonly memory and thus we get bogus - warnings from p = cond ? "a" : "b" for example. */ - && (!VAR_P (base) - || is_global_var (base))) - return NULL_TREE; + if (!found_alloc && fentry_reached) + { + if (TREE_CODE (base) == SSA_NAME) + { + tree var = SSA_NAME_VAR (base); + if (var && TREE_CODE (var) == PARM_DECL) + { + maybe_warn_read_write_only (cfun->decl, stmt, var, rhs); + return NULL_TREE; + } + } + + if (!VAR_P (base) + || is_global_var (base)) + /* ??? We'd like to use ref_may_alias_global_p but that + excludes global readonly memory and thus we get bogus + warnings from p = cond ? "a" : "b" for example. */ + return NULL_TREE; + } /* Strip the address-of expression from arrays passed to functions. */ if (TREE_CODE (rhs) == ADDR_EXPR) @@ -641,7 +712,7 @@ maybe_warn_pass_by_reference (gcall *stmt, wlimits &wlims) wlims.always_executed = false; /* Ignore args we are not going to read from. */ - if (gimple_call_arg_flags (stmt, argno - 1) & EAF_UNUSED) + if (gimple_call_arg_flags (stmt, argno - 1) & (EAF_UNUSED | EAF_NOREAD)) continue; tree arg = gimple_call_arg (stmt, argno - 1); diff --git a/gcc/tree-switch-conversion.c b/gcc/tree-switch-conversion.c index 294b545..244cf4b 100644 --- a/gcc/tree-switch-conversion.c +++ b/gcc/tree-switch-conversion.c @@ -1091,7 +1091,7 @@ group_cluster::dump (FILE *f, bool details) for (unsigned i = 0; i < m_cases.length (); i++) { simple_cluster *sc = static_cast<simple_cluster *> (m_cases[i]); - comparison_count += sc->m_range_p ? 2 : 1; + comparison_count += sc->get_comparison_count (); } unsigned HOST_WIDE_INT range = get_range (get_low (), get_high ()); @@ -1186,11 +1186,24 @@ jump_table_cluster::find_jump_tables (vec<cluster *> &clusters) min.quick_push (min_cluster_item (0, 0, 0)); + unsigned HOST_WIDE_INT max_ratio + = (optimize_insn_for_size_p () + ? param_jump_table_max_growth_ratio_for_size + : param_jump_table_max_growth_ratio_for_speed); + for (unsigned i = 1; i <= l; i++) { /* Set minimal # of clusters with i-th item to infinite. */ min.quick_push (min_cluster_item (INT_MAX, INT_MAX, INT_MAX)); + /* Pre-calculate number of comparisons for the clusters. */ + HOST_WIDE_INT comparison_count = 0; + for (unsigned k = 0; k <= i - 1; k++) + { + simple_cluster *sc = static_cast<simple_cluster *> (clusters[k]); + comparison_count += sc->get_comparison_count (); + } + for (unsigned j = 0; j < i; j++) { unsigned HOST_WIDE_INT s = min[j].m_non_jt_cases; @@ -1201,10 +1214,15 @@ jump_table_cluster::find_jump_tables (vec<cluster *> &clusters) if ((min[j].m_count + 1 < min[i].m_count || (min[j].m_count + 1 == min[i].m_count && s < min[i].m_non_jt_cases)) - && can_be_handled (clusters, j, i - 1)) + && can_be_handled (clusters, j, i - 1, max_ratio, + comparison_count)) min[i] = min_cluster_item (min[j].m_count + 1, j, s); + + simple_cluster *sc = static_cast<simple_cluster *> (clusters[j]); + comparison_count -= sc->get_comparison_count (); } + gcc_checking_assert (comparison_count == 0); gcc_checking_assert (min[i].m_count != INT_MAX); } @@ -1242,7 +1260,9 @@ jump_table_cluster::find_jump_tables (vec<cluster *> &clusters) bool jump_table_cluster::can_be_handled (const vec<cluster *> &clusters, - unsigned start, unsigned end) + unsigned start, unsigned end, + unsigned HOST_WIDE_INT max_ratio, + unsigned HOST_WIDE_INT comparison_count) { /* If the switch is relatively small such that the cost of one indirect jump on the target are higher than the cost of a @@ -1261,10 +1281,6 @@ jump_table_cluster::can_be_handled (const vec<cluster *> &clusters, if (start == end) return true; - unsigned HOST_WIDE_INT max_ratio - = (optimize_insn_for_size_p () - ? param_jump_table_max_growth_ratio_for_size - : param_jump_table_max_growth_ratio_for_speed); unsigned HOST_WIDE_INT range = get_range (clusters[start]->get_low (), clusters[end]->get_high ()); /* Check overflow. */ @@ -1278,18 +1294,6 @@ jump_table_cluster::can_be_handled (const vec<cluster *> &clusters, if (lhs < range) return false; - /* First make quick guess as each cluster - can add at maximum 2 to the comparison_count. */ - if (lhs > 2 * max_ratio * (end - start + 1)) - return false; - - unsigned HOST_WIDE_INT comparison_count = 0; - for (unsigned i = start; i <= end; i++) - { - simple_cluster *sc = static_cast<simple_cluster *> (clusters[i]); - comparison_count += sc->m_range_p ? 2 : 1; - } - return lhs <= max_ratio * comparison_count; } diff --git a/gcc/tree-switch-conversion.h b/gcc/tree-switch-conversion.h index d76f19b..a375e52 100644 --- a/gcc/tree-switch-conversion.h +++ b/gcc/tree-switch-conversion.h @@ -180,6 +180,13 @@ public: return tree_int_cst_equal (get_low (), get_high ()); } + /* Return number of comparisons needed for the case. */ + unsigned + get_comparison_count () + { + return m_range_p ? 2 : 1; + } + /* Low value of the case. */ tree m_low; @@ -267,9 +274,12 @@ public: static vec<cluster *> find_jump_tables (vec<cluster *> &clusters); /* Return true when cluster starting at START and ending at END (inclusive) - can build a jump-table. */ + can build a jump-table. COMPARISON_COUNT is number of comparison + operations needed if the clusters are expanded as decision tree. + MAX_RATIO tells about the maximum code growth (in percent). */ static bool can_be_handled (const vec<cluster *> &clusters, unsigned start, - unsigned end); + unsigned end, unsigned HOST_WIDE_INT max_ratio, + unsigned HOST_WIDE_INT comparison_count); /* Return true if cluster starting at START and ending at END (inclusive) is profitable transformation. */ diff --git a/gcc/tree-vect-data-refs.c b/gcc/tree-vect-data-refs.c index d594c0a..b7dde07 100644 --- a/gcc/tree-vect-data-refs.c +++ b/gcc/tree-vect-data-refs.c @@ -3735,11 +3735,17 @@ vect_gather_scatter_fn_p (vec_info *vinfo, bool read_p, bool masked_p, return false; /* Work out which function we need. */ - internal_fn ifn; + internal_fn ifn, alt_ifn; if (read_p) - ifn = masked_p ? IFN_MASK_GATHER_LOAD : IFN_GATHER_LOAD; + { + ifn = masked_p ? IFN_MASK_GATHER_LOAD : IFN_GATHER_LOAD; + alt_ifn = IFN_MASK_GATHER_LOAD; + } else - ifn = masked_p ? IFN_MASK_SCATTER_STORE : IFN_SCATTER_STORE; + { + ifn = masked_p ? IFN_MASK_SCATTER_STORE : IFN_SCATTER_STORE; + alt_ifn = IFN_MASK_SCATTER_STORE; + } for (;;) { @@ -3755,6 +3761,16 @@ vect_gather_scatter_fn_p (vec_info *vinfo, bool read_p, bool masked_p, *offset_vectype_out = offset_vectype; return true; } + else if (!masked_p + && internal_gather_scatter_fn_supported_p (alt_ifn, vectype, + memory_type, + offset_vectype, + scale)) + { + *ifn_out = alt_ifn; + *offset_vectype_out = offset_vectype; + return true; + } if (TYPE_PRECISION (offset_type) >= POINTER_SIZE && TYPE_PRECISION (offset_type) >= element_bits) diff --git a/gcc/tree-vect-loop.c b/gcc/tree-vect-loop.c index 37c7daa..995d143 100644 --- a/gcc/tree-vect-loop.c +++ b/gcc/tree-vect-loop.c @@ -7234,6 +7234,14 @@ vectorizable_reduction (loop_vec_info loop_vinfo, dump_printf (MSG_NOTE, "proceeding using word mode.\n"); } + if (vect_emulated_vector_p (vectype_in) + && !vect_can_vectorize_without_simd_p (code)) + { + if (dump_enabled_p ()) + dump_printf (MSG_NOTE, "using word mode not possible.\n"); + return false; + } + /* lane-reducing operations have to go through vect_transform_reduction. For the other cases try without the single cycle optimization. */ if (!ok) @@ -7936,6 +7944,16 @@ vectorizable_phi (vec_info *, return true; } +/* Return true if VECTYPE represents a vector that requires lowering + by the vector lowering pass. */ + +bool +vect_emulated_vector_p (tree vectype) +{ + return (!VECTOR_MODE_P (TYPE_MODE (vectype)) + && (!VECTOR_BOOLEAN_TYPE_P (vectype) + || TYPE_PRECISION (TREE_TYPE (vectype)) != 1)); +} /* Return true if we can emulate CODE on an integer mode representation of a vector. */ diff --git a/gcc/tree-vect-patterns.c b/gcc/tree-vect-patterns.c index 25de97b..8997340 100644 --- a/gcc/tree-vect-patterns.c +++ b/gcc/tree-vect-patterns.c @@ -4820,6 +4820,9 @@ vect_recog_gather_scatter_pattern (vec_info *vinfo, if (mask) mask = vect_convert_mask_for_vectype (mask, gs_vectype, stmt_info, loop_vinfo); + else if (gs_info.ifn == IFN_MASK_SCATTER_STORE + || gs_info.ifn == IFN_MASK_GATHER_LOAD) + mask = build_int_cst (TREE_TYPE (truth_type_for (gs_vectype)), -1); /* Get the invariant base and non-invariant offset, converting the latter to the same width as the vector elements. */ @@ -4847,11 +4850,11 @@ vect_recog_gather_scatter_pattern (vec_info *vinfo, { tree rhs = vect_get_store_rhs (stmt_info); if (mask != NULL) - pattern_stmt = gimple_build_call_internal (IFN_MASK_SCATTER_STORE, 5, + pattern_stmt = gimple_build_call_internal (gs_info.ifn, 5, base, offset, scale, rhs, mask); else - pattern_stmt = gimple_build_call_internal (IFN_SCATTER_STORE, 4, + pattern_stmt = gimple_build_call_internal (gs_info.ifn, 4, base, offset, scale, rhs); } gimple_call_set_nothrow (pattern_stmt, true); diff --git a/gcc/tree-vect-slp.c b/gcc/tree-vect-slp.c index d169bed..4dcc70c 100644 --- a/gcc/tree-vect-slp.c +++ b/gcc/tree-vect-slp.c @@ -4861,12 +4861,14 @@ vectorizable_bb_reduc_epilogue (slp_instance instance, return false; /* There's no way to cost a horizontal vector reduction via REDUC_FN so - cost log2 vector operations plus shuffles. */ + cost log2 vector operations plus shuffles and one extraction. */ unsigned steps = floor_log2 (vect_nunits_for_cost (vectype)); record_stmt_cost (cost_vec, steps, vector_stmt, instance->root_stmts[0], vectype, 0, vect_body); record_stmt_cost (cost_vec, steps, vec_perm, instance->root_stmts[0], vectype, 0, vect_body); + record_stmt_cost (cost_vec, 1, vec_to_scalar, instance->root_stmts[0], + vectype, 0, vect_body); return true; } diff --git a/gcc/tree-vect-stmts.c b/gcc/tree-vect-stmts.c index 5b94d41..4e0b2ad 100644 --- a/gcc/tree-vect-stmts.c +++ b/gcc/tree-vect-stmts.c @@ -2377,9 +2377,11 @@ get_load_store_type (vec_info *vinfo, stmt_vec_info stmt_info, return false; } else if (!TYPE_VECTOR_SUBPARTS (vectype).is_constant () - || !known_eq (TYPE_VECTOR_SUBPARTS (vectype), - TYPE_VECTOR_SUBPARTS - (gs_info->offset_vectype))) + || !TYPE_VECTOR_SUBPARTS + (gs_info->offset_vectype).is_constant () + || !constant_multiple_p (TYPE_VECTOR_SUBPARTS + (gs_info->offset_vectype), + TYPE_VECTOR_SUBPARTS (vectype))) { if (dump_enabled_p ()) dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, @@ -2508,14 +2510,6 @@ vect_check_scalar_mask (vec_info *vinfo, stmt_vec_info stmt_info, return false; } - if (TREE_CODE (*mask) != SSA_NAME) - { - if (dump_enabled_p ()) - dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, - "mask argument is not an SSA name.\n"); - return false; - } - /* If the caller is not prepared for adjusting an external/constant SLP mask vector type fail. */ if (slp_node @@ -2928,11 +2922,10 @@ vect_build_gather_load_calls (vec_info *vinfo, stmt_vec_info stmt_info, containing loop. */ static void -vect_get_gather_scatter_ops (vec_info *vinfo, +vect_get_gather_scatter_ops (loop_vec_info loop_vinfo, class loop *loop, stmt_vec_info stmt_info, gather_scatter_info *gs_info, - tree *dataref_ptr, vec<tree> *vec_offset, - unsigned ncopies) + tree *dataref_ptr, vec<tree> *vec_offset) { gimple_seq stmts = NULL; *dataref_ptr = force_gimple_operand (gs_info->base, &stmts, true, NULL_TREE); @@ -2943,8 +2936,10 @@ vect_get_gather_scatter_ops (vec_info *vinfo, new_bb = gsi_insert_seq_on_edge_immediate (pe, stmts); gcc_assert (!new_bb); } - vect_get_vec_defs_for_operand (vinfo, stmt_info, ncopies, gs_info->offset, - vec_offset, gs_info->offset_vectype); + unsigned ncopies = vect_get_num_copies (loop_vinfo, gs_info->offset_vectype); + vect_get_vec_defs_for_operand (loop_vinfo, stmt_info, ncopies, + gs_info->offset, vec_offset, + gs_info->offset_vectype); } /* Prepare to implement a grouped or strided load or store using @@ -5682,15 +5677,11 @@ vectorizable_shift (vec_info *vinfo, if (dump_enabled_p ()) dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, "op not supported by target.\n"); - /* Check only during analysis. */ - if (maybe_ne (GET_MODE_SIZE (vec_mode), UNITS_PER_WORD) - || (!vec_stmt - && !vect_can_vectorize_without_simd_p (code))) - return false; - if (dump_enabled_p ()) - dump_printf_loc (MSG_NOTE, vect_location, - "proceeding using word mode.\n"); + return false; } + /* vector lowering cannot optimize vector shifts using word arithmetic. */ + if (vect_emulated_vector_p (vectype)) + return false; if (!vec_stmt) /* transformation not required. */ { @@ -6076,6 +6067,7 @@ vectorizable_operation (vec_info *vinfo, != CODE_FOR_nothing); } + bool using_emulated_vectors_p = vect_emulated_vector_p (vectype); if (!target_support_p) { if (dump_enabled_p ()) @@ -6088,6 +6080,15 @@ vectorizable_operation (vec_info *vinfo, if (dump_enabled_p ()) dump_printf_loc (MSG_NOTE, vect_location, "proceeding using word mode.\n"); + using_emulated_vectors_p = true; + } + + if (using_emulated_vectors_p + && !vect_can_vectorize_without_simd_p (code)) + { + if (dump_enabled_p ()) + dump_printf (MSG_NOTE, "using word mode not possible.\n"); + return false; } int reduc_idx = STMT_VINFO_REDUC_IDX (stmt_info); @@ -6134,6 +6135,29 @@ vectorizable_operation (vec_info *vinfo, DUMP_VECT_SCOPE ("vectorizable_operation"); vect_model_simple_cost (vinfo, stmt_info, ncopies, dt, ndts, slp_node, cost_vec); + if (using_emulated_vectors_p) + { + /* The above vect_model_simple_cost call handles constants + in the prologue and (mis-)costs one of the stmts as + vector stmt. See tree-vect-generic.c:do_plus_minus/do_negate + for the actual lowering that will be applied. */ + unsigned n + = slp_node ? SLP_TREE_NUMBER_OF_VEC_STMTS (slp_node) : ncopies; + switch (code) + { + case PLUS_EXPR: + n *= 5; + break; + case MINUS_EXPR: + n *= 6; + break; + case NEGATE_EXPR: + n *= 4; + break; + default:; + } + record_stmt_cost (cost_vec, n, scalar_stmt, stmt_info, 0, vect_body); + } return true; } @@ -8043,8 +8067,9 @@ vectorizable_store (vec_info *vinfo, } else if (STMT_VINFO_GATHER_SCATTER_P (stmt_info)) { - vect_get_gather_scatter_ops (vinfo, loop, stmt_info, &gs_info, - &dataref_ptr, &vec_offsets, ncopies); + vect_get_gather_scatter_ops (loop_vinfo, loop, stmt_info, + &gs_info, &dataref_ptr, + &vec_offsets); vec_offset = vec_offsets[0]; } else @@ -9347,9 +9372,9 @@ vectorizable_load (vec_info *vinfo, } else if (STMT_VINFO_GATHER_SCATTER_P (stmt_info)) { - vect_get_gather_scatter_ops (vinfo, loop, stmt_info, &gs_info, - &dataref_ptr, &vec_offsets, ncopies); - vec_offset = vec_offsets[0]; + vect_get_gather_scatter_ops (loop_vinfo, loop, stmt_info, + &gs_info, &dataref_ptr, + &vec_offsets); } else dataref_ptr @@ -9366,9 +9391,7 @@ vectorizable_load (vec_info *vinfo, if (dataref_offset) dataref_offset = int_const_binop (PLUS_EXPR, dataref_offset, bump); - else if (STMT_VINFO_GATHER_SCATTER_P (stmt_info)) - vec_offset = vec_offsets[j]; - else + else if (!STMT_VINFO_GATHER_SCATTER_P (stmt_info)) dataref_ptr = bump_vector_ptr (vinfo, dataref_ptr, ptr_incr, gsi, stmt_info, bump); if (mask) @@ -9461,6 +9484,8 @@ vectorizable_load (vec_info *vinfo, if (memory_access_type == VMAT_GATHER_SCATTER && gs_info.ifn != IFN_LAST) { + if (STMT_VINFO_GATHER_SCATTER_P (stmt_info)) + vec_offset = vec_offsets[j]; tree zero = build_zero_cst (vectype); tree scale = size_int (gs_info.scale); gcall *call; @@ -9483,9 +9508,18 @@ vectorizable_load (vec_info *vinfo, gcc_assert (!final_mask); unsigned HOST_WIDE_INT const_nunits = nunits.to_constant (); + unsigned HOST_WIDE_INT const_offset_nunits + = TYPE_VECTOR_SUBPARTS (gs_info.offset_vectype) + .to_constant (); vec<constructor_elt, va_gc> *ctor_elts; vec_alloc (ctor_elts, const_nunits); gimple_seq stmts = NULL; + /* We support offset vectors with more elements + than the data vector for now. */ + unsigned HOST_WIDE_INT factor + = const_offset_nunits / const_nunits; + vec_offset = vec_offsets[j / factor]; + unsigned elt_offset = (j % factor) * const_nunits; tree idx_type = TREE_TYPE (TREE_TYPE (vec_offset)); tree scale = size_int (gs_info.scale); align @@ -9496,7 +9530,8 @@ vectorizable_load (vec_info *vinfo, { tree boff = size_binop (MULT_EXPR, TYPE_SIZE (idx_type), - bitsize_int (k)); + bitsize_int + (k + elt_offset)); tree idx = gimple_build (&stmts, BIT_FIELD_REF, idx_type, vec_offset, TYPE_SIZE (idx_type), diff --git a/gcc/tree-vectorizer.h b/gcc/tree-vectorizer.h index de0ecf8..9c2c29d 100644 --- a/gcc/tree-vectorizer.h +++ b/gcc/tree-vectorizer.h @@ -2061,6 +2061,7 @@ extern bool vectorizable_lc_phi (loop_vec_info, stmt_vec_info, gimple **, slp_tree); extern bool vectorizable_phi (vec_info *, stmt_vec_info, gimple **, slp_tree, stmt_vector_for_cost *); +extern bool vect_emulated_vector_p (tree); extern bool vect_can_vectorize_without_simd_p (tree_code); extern int vect_get_known_peeling_cost (loop_vec_info, int, int *, stmt_vector_for_cost *, @@ -350,6 +350,7 @@ unsigned const char omp_clause_num_ops[] = 0, /* OMP_CLAUSE_DEFAULTMAP */ 0, /* OMP_CLAUSE_ORDER */ 0, /* OMP_CLAUSE_BIND */ + 1, /* OMP_CLAUSE_FILTER */ 1, /* OMP_CLAUSE__SIMDUID_ */ 0, /* OMP_CLAUSE__SIMT_ */ 0, /* OMP_CLAUSE_INDEPENDENT */ @@ -438,6 +439,7 @@ const char * const omp_clause_code_name[] = "defaultmap", "order", "bind", + "filter", "_simduid_", "_simt_", "independent", @@ -11126,6 +11128,7 @@ walk_tree_1 (tree *tp, walk_tree_fn func, void *data, case OMP_CLAUSE_GRAINSIZE: case OMP_CLAUSE_NUM_TASKS: case OMP_CLAUSE_HINT: + case OMP_CLAUSE_FILTER: case OMP_CLAUSE_TO_DECLARE: case OMP_CLAUSE_LINK: case OMP_CLAUSE_DETACH: @@ -14311,17 +14314,28 @@ verify_type_context (location_t loc, type_context_kind context, || targetm.verify_type_context (loc, context, type, silent_p)); } -/* Return that NEW_ASM and DELETE_ASM name a valid pair of new and - delete operators. */ +/* Return true if NEW_ASM and DELETE_ASM name a valid pair of new and + delete operators. Return false if they may or may not name such + a pair and, when nonnull, set *PCERTAIN to true if they certainly + do not. */ bool -valid_new_delete_pair_p (tree new_asm, tree delete_asm) +valid_new_delete_pair_p (tree new_asm, tree delete_asm, + bool *pcertain /* = NULL */) { + bool certain; + if (!pcertain) + pcertain = &certain; + const char *new_name = IDENTIFIER_POINTER (new_asm); const char *delete_name = IDENTIFIER_POINTER (delete_asm); unsigned int new_len = IDENTIFIER_LENGTH (new_asm); unsigned int delete_len = IDENTIFIER_LENGTH (delete_asm); + /* The following failures are due to invalid names so they're not + considered certain mismatches. */ + *pcertain = false; + if (new_len < 5 || delete_len < 6) return false; if (new_name[0] == '_') @@ -14334,11 +14348,19 @@ valid_new_delete_pair_p (tree new_asm, tree delete_asm) ++delete_name, --delete_len; if (new_len < 4 || delete_len < 5) return false; + + /* The following failures are due to names of user-defined operators + so they're also not considered certain mismatches. */ + /* *_len is now just the length after initial underscores. */ if (new_name[0] != 'Z' || new_name[1] != 'n') return false; if (delete_name[0] != 'Z' || delete_name[1] != 'd') return false; + + /* The following failures are certain mismatches. */ + *pcertain = true; + /* _Znw must match _Zdl, _Zna must match _Zda. */ if ((new_name[2] != 'w' || delete_name[2] != 'l') && (new_name[2] != 'a' || delete_name[2] != 'a')) @@ -14377,6 +14399,9 @@ valid_new_delete_pair_p (tree new_asm, tree delete_asm) && !memcmp (delete_name + 5, "St11align_val_tRKSt9nothrow_t", 29)) return true; } + + /* The negative result is conservative. */ + *pcertain = false; return false; } @@ -14439,6 +14464,60 @@ fndecl_dealloc_argno (tree fndecl) return UINT_MAX; } +/* If EXPR refers to a character array or pointer declared attribute + nonstring, return a decl for that array or pointer and set *REF + to the referenced enclosing object or pointer. Otherwise return + null. */ + +tree +get_attr_nonstring_decl (tree expr, tree *ref) +{ + tree decl = expr; + tree var = NULL_TREE; + if (TREE_CODE (decl) == SSA_NAME) + { + gimple *def = SSA_NAME_DEF_STMT (decl); + + if (is_gimple_assign (def)) + { + tree_code code = gimple_assign_rhs_code (def); + if (code == ADDR_EXPR + || code == COMPONENT_REF + || code == VAR_DECL) + decl = gimple_assign_rhs1 (def); + } + else + var = SSA_NAME_VAR (decl); + } + + if (TREE_CODE (decl) == ADDR_EXPR) + decl = TREE_OPERAND (decl, 0); + + /* To simplify calling code, store the referenced DECL regardless of + the attribute determined below, but avoid storing the SSA_NAME_VAR + obtained above (it's not useful for dataflow purposes). */ + if (ref) + *ref = decl; + + /* Use the SSA_NAME_VAR that was determined above to see if it's + declared nonstring. Otherwise drill down into the referenced + DECL. */ + if (var) + decl = var; + else if (TREE_CODE (decl) == ARRAY_REF) + decl = TREE_OPERAND (decl, 0); + else if (TREE_CODE (decl) == COMPONENT_REF) + decl = TREE_OPERAND (decl, 1); + else if (TREE_CODE (decl) == MEM_REF) + return get_attr_nonstring_decl (TREE_OPERAND (decl, 0), ref); + + if (DECL_P (decl) + && lookup_attribute ("nonstring", DECL_ATTRIBUTES (decl))) + return decl; + + return NULL_TREE; +} + #if CHECKING_P namespace selftest { diff --git a/gcc/tree.def b/gcc/tree.def index eda050b..e27bc3e 100644 --- a/gcc/tree.def +++ b/gcc/tree.def @@ -1213,11 +1213,21 @@ DEFTREECODE (OMP_CRITICAL, "omp_critical", tcc_statement, 3) Operand 1: OMP_SINGLE_CLAUSES: List of clauses. */ DEFTREECODE (OMP_SINGLE, "omp_single", tcc_statement, 2) +/* OpenMP - #pragma omp scope + Operand 0: OMP_SCOPE_BODY: Masked section body. + Operand 1: OMP_SCOPE_CLAUSES: List of clauses. */ +DEFTREECODE (OMP_SCOPE, "omp_scope", tcc_statement, 2) + /* OpenMP - #pragma omp taskgroup Operand 0: OMP_TASKGROUP_BODY: Taskgroup body. Operand 1: OMP_SINGLE_CLAUSES: List of clauses. */ DEFTREECODE (OMP_TASKGROUP, "omp_taskgroup", tcc_statement, 2) +/* OpenMP - #pragma omp masked + Operand 0: OMP_MASKED_BODY: Masked section body. + Operand 1: OMP_MASKED_CLAUSES: List of clauses. */ +DEFTREECODE (OMP_MASKED, "omp_masked", tcc_statement, 2) + /* OpenMP - #pragma omp scan Operand 0: OMP_SCAN_BODY: Scan body. Operand 1: OMP_SCAN_CLAUSES: List of clauses. */ @@ -1427,8 +1427,14 @@ class auto_suppress_location_wrappers #define OMP_SINGLE_BODY(NODE) TREE_OPERAND (OMP_SINGLE_CHECK (NODE), 0) #define OMP_SINGLE_CLAUSES(NODE) TREE_OPERAND (OMP_SINGLE_CHECK (NODE), 1) +#define OMP_SCOPE_BODY(NODE) TREE_OPERAND (OMP_SCOPE_CHECK (NODE), 0) +#define OMP_SCOPE_CLAUSES(NODE) TREE_OPERAND (OMP_SCOPE_CHECK (NODE), 1) + #define OMP_MASTER_BODY(NODE) TREE_OPERAND (OMP_MASTER_CHECK (NODE), 0) +#define OMP_MASKED_BODY(NODE) TREE_OPERAND (OMP_MASKED_CHECK (NODE), 0) +#define OMP_MASKED_CLAUSES(NODE) TREE_OPERAND (OMP_MASKED_CHECK (NODE), 1) + #define OMP_TASKGROUP_BODY(NODE) TREE_OPERAND (OMP_TASKGROUP_CHECK (NODE), 0) #define OMP_TASKGROUP_CLAUSES(NODE) \ TREE_OPERAND (OMP_TASKGROUP_CHECK (NODE), 1) @@ -1508,6 +1514,11 @@ class auto_suppress_location_wrappers #define OMP_MASTER_COMBINED(NODE) \ (OMP_MASTER_CHECK (NODE)->base.private_flag) +/* True on an OMP_MASKED statement if it represents an explicit + combined masked constructs. */ +#define OMP_MASKED_COMBINED(NODE) \ + (OMP_MASKED_CHECK (NODE)->base.private_flag) + /* Memory order for OMP_ATOMIC*. */ #define OMP_ATOMIC_MEMORY_ORDER(NODE) \ (TREE_RANGE_CHECK (NODE, OMP_ATOMIC, \ @@ -1592,6 +1603,8 @@ class auto_suppress_location_wrappers OMP_CLAUSE_OPERAND (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_NUM_TASKS), 0) #define OMP_CLAUSE_HINT_EXPR(NODE) \ OMP_CLAUSE_OPERAND (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_HINT), 0) +#define OMP_CLAUSE_FILTER_EXPR(NODE) \ + OMP_CLAUSE_OPERAND (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_FILTER), 0) #define OMP_CLAUSE_GRAINSIZE_EXPR(NODE) \ OMP_CLAUSE_OPERAND (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_GRAINSIZE),0) @@ -5396,7 +5409,9 @@ extern bool gimple_canonical_types_compatible_p (const_tree, const_tree, extern bool type_with_interoperable_signedness (const_tree); extern bitmap get_nonnull_args (const_tree); extern int get_range_pos_neg (tree); -extern bool valid_new_delete_pair_p (tree, tree); + +/* Return true for a valid pair of new and delete operators. */ +extern bool valid_new_delete_pair_p (tree, tree, bool * = NULL); /* Return simplified tree code of type that is used for canonical type merging. */ @@ -6473,4 +6488,10 @@ extern void copy_warning (tree, const_tree); value if it isn't. */ extern unsigned fndecl_dealloc_argno (tree); +/* If an expression refers to a character array or pointer declared + attribute nonstring, return a decl for that array or pointer and + if nonnull, set the second argument to the referenced enclosing + object or pointer. Otherwise return null. */ +extern tree get_attr_nonstring_decl (tree, tree * = NULL); + #endif /* GCC_TREE_H */ |